diff --git a/deps/http_parser/README.md b/deps/http_parser/README.md new file mode 100644 index 0000000000..26c3e968c7 --- /dev/null +++ b/deps/http_parser/README.md @@ -0,0 +1,75 @@ +HTTP Parser +=========== + +This is a parser for HTTP messages written in C. It parses both requests +and responses. The parser is designed to be used in performance HTTP +applications. It does not make any allocations, it does not buffer data, and +it can be interrupted at anytime. It only requires about 100 bytes of data +per message stream (in a web server that is per connection). + +Features: + + * No dependencies + * Parses both requests and responses. + * Handles keep-alive streams. + * Decodes chunked encoding. + * Extracts the following data from a message + * header fields and values + * content-length + * request method + * response status code + * transfer-encoding + * http version + * request path, query string, fragment + * message body + +Usage +----- + +One `http_parser` object is used per TCP connection. Initialize the struct +using `http_parser_init()` and set the callbacks. That might look something +like this: + + http_parser *parser = malloc(sizeof(http_parser)); + http_parser_init(parser, HTTP_REQUEST); + parser->on_path = my_path_callback; + parser->on_header_field = my_header_field_callback; + parser->data = my_socket; + +When data is received on the socket execute the parser and check for errors. + + size_t len = 80*1024; + char buf[len]; + ssize_t recved; + + recved = read(fd, buf, len); + if (recved != 0) // handle error + + http_parser_execute(parser, buf, recved); + + if (http_parser_has_error(parser)) { + // handle error. usually just close the connection + } + +During the `http_parser_execute()` call, the callbacks set in `http_parser` +will be executed. The parser maintains state and never looks behind, so +buffering the data is not necessary. If you need to save certain data for +later usage, you can do that from the callbacks. (You can also `read()` into +a heap allocated buffer to avoid copying memory around if this fits your +application.) + +The parser decodes the transfer-encoding for both requests and responses +transparently. That is, a chunked encoding is decoded before being sent to +the on_body callback. + +It does not decode the content-encoding (gzip). Not all HTTP applications +need to inspect the body. Decoding gzip is non-neglagable amount of +processing (and requires making allocations). HTTP proxies using this +parser, for example, would not want such a feature. + +Releases +-------- + + * [0.1](http://s3.amazonaws.com/four.livejournal/20090427/http_parser-0.1.tar.gz) + +The source repo is at [github](http://github.com/ry/http-parser). diff --git a/deps/http_parser/http_parser.c b/deps/http_parser/http_parser.c new file mode 100644 index 0000000000..ad115740f5 --- /dev/null +++ b/deps/http_parser/http_parser.c @@ -0,0 +1,5776 @@ +#line 1 "http_parser.rl" +/* Copyright (c) 2008, 2009 Ryan Dahl (ry@tinyclouds.org) + * + * Based on Zed Shaw's Mongrel. + * Copyright (c) 2005 Zed A. Shaw + * + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "http_parser.h" + +#include + +static int unhex[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + }; +#define TRUE 1 +#define FALSE 0 +#define MIN(a,b) (a < b ? a : b) +#define NULL (void*)(0) + +#define REMAINING (pe - p) +#define CALLBACK(FOR) \ + if (parser->FOR##_mark && parser->on_##FOR) { \ + callback_return_value = \ + parser->on_##FOR(parser, parser->FOR##_mark, p - parser->FOR##_mark); \ + } + +#define RESET_PARSER(parser) \ + parser->chunk_size = 0; \ + parser->eating = 0; \ + parser->header_field_mark = NULL; \ + parser->header_value_mark = NULL; \ + parser->query_string_mark = NULL; \ + parser->path_mark = NULL; \ + parser->uri_mark = NULL; \ + parser->fragment_mark = NULL; \ + parser->status_code = 0; \ + parser->method = 0; \ + parser->transfer_encoding = HTTP_IDENTITY; \ + parser->version_major = 0; \ + parser->version_minor = 0; \ + parser->keep_alive = -1; \ + parser->content_length = 0; \ + parser->body_read = 0; + +#define END_REQUEST \ +do { \ + if (parser->on_message_complete) { \ + callback_return_value = \ + parser->on_message_complete(parser); \ + } \ + RESET_PARSER(parser); \ +} while (0) + +#define SKIP_BODY(nskip) \ +do { \ + tmp = (nskip); \ + if (parser->on_body && tmp > 0) { \ + callback_return_value = parser->on_body(parser, p, tmp); \ + } \ + if (callback_return_value == 0) { \ + p += tmp; \ + parser->body_read += tmp; \ + parser->chunk_size -= tmp; \ + if (0 == parser->chunk_size) { \ + parser->eating = FALSE; \ + if (parser->transfer_encoding == HTTP_IDENTITY) { \ + END_REQUEST; \ + } \ + } else { \ + parser->eating = TRUE; \ + } \ + } \ +} while (0) + +#line 340 "http_parser.rl" + + + +#line 106 "http_parser.c" +static const int http_parser_start = 1; +static const int http_parser_first_final = 267; +static const int http_parser_error = 0; + +static const int http_parser_en_ChunkedBody = 2; +static const int http_parser_en_ChunkedBody_chunk_chunk_end = 12; +static const int http_parser_en_Requests = 269; +static const int http_parser_en_Responses = 270; +static const int http_parser_en_main = 1; + +#line 343 "http_parser.rl" + +void +http_parser_init (http_parser *parser, enum http_parser_type type) +{ + int cs = 0; + +#line 124 "http_parser.c" + { + cs = http_parser_start; + } +#line 349 "http_parser.rl" + parser->cs = cs; + parser->type = type; + + parser->on_message_begin = NULL; + parser->on_path = NULL; + parser->on_query_string = NULL; + parser->on_uri = NULL; + parser->on_header_field = NULL; + parser->on_header_value = NULL; + parser->on_headers_complete = NULL; + parser->on_body = NULL; + parser->on_message_complete = NULL; + + RESET_PARSER(parser); +} + +/** exec **/ +size_t +http_parser_execute (http_parser *parser, const char *buffer, size_t len) +{ + size_t tmp; // REMOVE ME this is extremely hacky + int callback_return_value = 0; + const char *p, *pe; + int cs = parser->cs; + + p = buffer; + pe = buffer+len; + + if (0 < parser->chunk_size && parser->eating) { + /* eat body */ + SKIP_BODY(MIN(len, parser->chunk_size)); + if (callback_return_value != 0) goto out; + } + + if (parser->header_field_mark) parser->header_field_mark = buffer; + if (parser->header_value_mark) parser->header_value_mark = buffer; + if (parser->fragment_mark) parser->fragment_mark = buffer; + if (parser->query_string_mark) parser->query_string_mark = buffer; + if (parser->path_mark) parser->path_mark = buffer; + if (parser->uri_mark) parser->uri_mark = buffer; + + +#line 171 "http_parser.c" + { + if ( p == pe ) + goto _test_eof; + goto _resume; + +_again: + switch ( cs ) { + case 1: goto st1; + case 267: goto st267; + case 0: goto st0; + case 2: goto st2; + case 3: goto st3; + case 4: goto st4; + case 5: goto st5; + case 6: goto st6; + case 268: goto st268; + case 7: goto st7; + case 8: goto st8; + case 9: goto st9; + case 10: goto st10; + case 11: goto st11; + case 12: goto st12; + case 13: goto st13; + case 14: goto st14; + case 15: goto st15; + case 16: goto st16; + case 17: goto st17; + case 18: goto st18; + case 19: goto st19; + case 269: goto st269; + case 20: goto st20; + case 21: goto st21; + case 22: goto st22; + case 23: goto st23; + case 24: goto st24; + case 25: goto st25; + case 26: goto st26; + case 27: goto st27; + case 28: goto st28; + case 29: goto st29; + case 30: goto st30; + case 31: goto st31; + case 32: goto st32; + case 33: goto st33; + case 34: goto st34; + case 35: goto st35; + case 36: goto st36; + case 37: goto st37; + case 38: goto st38; + case 39: goto st39; + case 40: goto st40; + case 41: goto st41; + case 42: goto st42; + case 43: goto st43; + case 44: goto st44; + case 45: goto st45; + case 46: goto st46; + case 47: goto st47; + case 48: goto st48; + case 49: goto st49; + case 50: goto st50; + case 51: goto st51; + case 52: goto st52; + case 53: goto st53; + case 54: goto st54; + case 55: goto st55; + case 56: goto st56; + case 57: goto st57; + case 58: goto st58; + case 59: goto st59; + case 60: goto st60; + case 61: goto st61; + case 62: goto st62; + case 63: goto st63; + case 64: goto st64; + case 65: goto st65; + case 66: goto st66; + case 67: goto st67; + case 68: goto st68; + case 69: goto st69; + case 70: goto st70; + case 71: goto st71; + case 72: goto st72; + case 73: goto st73; + case 74: goto st74; + case 75: goto st75; + case 76: goto st76; + case 77: goto st77; + case 78: goto st78; + case 79: goto st79; + case 80: goto st80; + case 81: goto st81; + case 82: goto st82; + case 83: goto st83; + case 84: goto st84; + case 85: goto st85; + case 86: goto st86; + case 87: goto st87; + case 88: goto st88; + case 89: goto st89; + case 90: goto st90; + case 91: goto st91; + case 92: goto st92; + case 93: goto st93; + case 94: goto st94; + case 95: goto st95; + case 96: goto st96; + case 97: goto st97; + case 98: goto st98; + case 99: goto st99; + case 100: goto st100; + case 101: goto st101; + case 102: goto st102; + case 103: goto st103; + case 104: goto st104; + case 105: goto st105; + case 106: goto st106; + case 107: goto st107; + case 108: goto st108; + case 109: goto st109; + case 110: goto st110; + case 111: goto st111; + case 112: goto st112; + case 113: goto st113; + case 114: goto st114; + case 115: goto st115; + case 116: goto st116; + case 117: goto st117; + case 118: goto st118; + case 119: goto st119; + case 120: goto st120; + case 121: goto st121; + case 122: goto st122; + case 123: goto st123; + case 124: goto st124; + case 125: goto st125; + case 126: goto st126; + case 127: goto st127; + case 128: goto st128; + case 129: goto st129; + case 130: goto st130; + case 131: goto st131; + case 132: goto st132; + case 133: goto st133; + case 134: goto st134; + case 135: goto st135; + case 136: goto st136; + case 137: goto st137; + case 138: goto st138; + case 139: goto st139; + case 140: goto st140; + case 141: goto st141; + case 142: goto st142; + case 143: goto st143; + case 144: goto st144; + case 145: goto st145; + case 146: goto st146; + case 147: goto st147; + case 148: goto st148; + case 149: goto st149; + case 150: goto st150; + case 151: goto st151; + case 152: goto st152; + case 153: goto st153; + case 154: goto st154; + case 155: goto st155; + case 156: goto st156; + case 157: goto st157; + case 158: goto st158; + case 159: goto st159; + case 160: goto st160; + case 161: goto st161; + case 162: goto st162; + case 163: goto st163; + case 164: goto st164; + case 165: goto st165; + case 166: goto st166; + case 167: goto st167; + case 168: goto st168; + case 169: goto st169; + case 170: goto st170; + case 171: goto st171; + case 172: goto st172; + case 173: goto st173; + case 174: goto st174; + case 175: goto st175; + case 176: goto st176; + case 177: goto st177; + case 178: goto st178; + case 179: goto st179; + case 180: goto st180; + case 181: goto st181; + case 270: goto st270; + case 182: goto st182; + case 183: goto st183; + case 184: goto st184; + case 185: goto st185; + case 186: goto st186; + case 187: goto st187; + case 188: goto st188; + case 189: goto st189; + case 190: goto st190; + case 191: goto st191; + case 192: goto st192; + case 193: goto st193; + case 194: goto st194; + case 195: goto st195; + case 196: goto st196; + case 197: goto st197; + case 198: goto st198; + case 199: goto st199; + case 200: goto st200; + case 201: goto st201; + case 202: goto st202; + case 203: goto st203; + case 204: goto st204; + case 205: goto st205; + case 206: goto st206; + case 207: goto st207; + case 208: goto st208; + case 209: goto st209; + case 210: goto st210; + case 211: goto st211; + case 212: goto st212; + case 213: goto st213; + case 214: goto st214; + case 215: goto st215; + case 216: goto st216; + case 217: goto st217; + case 218: goto st218; + case 219: goto st219; + case 220: goto st220; + case 221: goto st221; + case 222: goto st222; + case 223: goto st223; + case 224: goto st224; + case 225: goto st225; + case 226: goto st226; + case 227: goto st227; + case 228: goto st228; + case 229: goto st229; + case 230: goto st230; + case 231: goto st231; + case 232: goto st232; + case 233: goto st233; + case 234: goto st234; + case 235: goto st235; + case 236: goto st236; + case 237: goto st237; + case 238: goto st238; + case 239: goto st239; + case 240: goto st240; + case 241: goto st241; + case 242: goto st242; + case 243: goto st243; + case 244: goto st244; + case 245: goto st245; + case 246: goto st246; + case 247: goto st247; + case 248: goto st248; + case 249: goto st249; + case 250: goto st250; + case 251: goto st251; + case 252: goto st252; + case 253: goto st253; + case 254: goto st254; + case 255: goto st255; + case 256: goto st256; + case 257: goto st257; + case 258: goto st258; + case 259: goto st259; + case 260: goto st260; + case 261: goto st261; + case 262: goto st262; + case 263: goto st263; + case 264: goto st264; + case 265: goto st265; + case 266: goto st266; + default: break; + } + + if ( ++p == pe ) + goto _test_eof; +_resume: + switch ( cs ) + { +st1: + if ( ++p == pe ) + goto _test_eof1; +case 1: + goto tr0; +tr0: +#line 331 "http_parser.rl" + { + p--; + if (parser->type == HTTP_REQUEST) { + {goto st269;} + } else { + {goto st270;} + } + } + goto st267; +st267: + if ( ++p == pe ) + goto _test_eof267; +case 267: +#line 478 "http_parser.c" + goto st0; +st0: +cs = 0; + goto _out; +st2: + if ( ++p == pe ) + goto _test_eof2; +case 2: + if ( (*p) == 48 ) + goto tr1; + if ( (*p) < 65 ) { + if ( 49 <= (*p) && (*p) <= 57 ) + goto tr3; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto tr3; + } else + goto tr3; + goto st0; +tr1: +#line 186 "http_parser.rl" + { + parser->chunk_size *= 16; + parser->chunk_size += unhex[(int)*p]; + } + goto st3; +st3: + if ( ++p == pe ) + goto _test_eof3; +case 3: +#line 509 "http_parser.c" + switch( (*p) ) { + case 13: goto st4; + case 48: goto tr1; + case 59: goto st17; + } + if ( (*p) < 65 ) { + if ( 49 <= (*p) && (*p) <= 57 ) + goto tr3; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto tr3; + } else + goto tr3; + goto st0; +st4: + if ( ++p == pe ) + goto _test_eof4; +case 4: + if ( (*p) == 10 ) + goto st5; + goto st0; +st5: + if ( ++p == pe ) + goto _test_eof5; +case 5: + switch( (*p) ) { + case 13: goto st6; + case 33: goto st7; + case 124: goto st7; + case 126: goto st7; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st7; + } else if ( (*p) >= 35 ) + goto st7; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st7; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st7; + } else + goto st7; + } else + goto st7; + goto st0; +st6: + if ( ++p == pe ) + goto _test_eof6; +case 6: + if ( (*p) == 10 ) + goto tr9; + goto st0; +tr9: + cs = 268; +#line 203 "http_parser.rl" + { + END_REQUEST; + if (parser->type == HTTP_REQUEST) { + cs = 269; + } else { + cs = 270; + } + } + goto _again; +st268: + if ( ++p == pe ) + goto _test_eof268; +case 268: +#line 582 "http_parser.c" + goto st0; +st7: + if ( ++p == pe ) + goto _test_eof7; +case 7: + switch( (*p) ) { + case 33: goto st7; + case 58: goto st8; + case 124: goto st7; + case 126: goto st7; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st7; + } else if ( (*p) >= 35 ) + goto st7; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st7; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st7; + } else + goto st7; + } else + goto st7; + goto st0; +st8: + if ( ++p == pe ) + goto _test_eof8; +case 8: + if ( (*p) == 13 ) + goto st4; + goto st8; +tr3: +#line 186 "http_parser.rl" + { + parser->chunk_size *= 16; + parser->chunk_size += unhex[(int)*p]; + } + goto st9; +st9: + if ( ++p == pe ) + goto _test_eof9; +case 9: +#line 630 "http_parser.c" + switch( (*p) ) { + case 13: goto st10; + case 59: goto st14; + } + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr3; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto tr3; + } else + goto tr3; + goto st0; +st10: + if ( ++p == pe ) + goto _test_eof10; +case 10: + if ( (*p) == 10 ) + goto st11; + goto st0; +st11: + if ( ++p == pe ) + goto _test_eof11; +case 11: + goto tr14; +tr14: +#line 191 "http_parser.rl" + { + SKIP_BODY(MIN(parser->chunk_size, REMAINING)); + if (callback_return_value != 0) {p++; cs = 12; goto _out;} + + p--; + if (parser->chunk_size > REMAINING) { + {p++; cs = 12; goto _out;} + } else { + {goto st12;} + } + } + goto st12; +st12: + if ( ++p == pe ) + goto _test_eof12; +case 12: +#line 674 "http_parser.c" + if ( (*p) == 13 ) + goto st13; + goto st0; +st13: + if ( ++p == pe ) + goto _test_eof13; +case 13: + if ( (*p) == 10 ) + goto st2; + goto st0; +st14: + if ( ++p == pe ) + goto _test_eof14; +case 14: + switch( (*p) ) { + case 13: goto st10; + case 32: goto st14; + case 33: goto st15; + case 59: goto st14; + case 61: goto st16; + case 124: goto st15; + case 126: goto st15; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st15; + } else if ( (*p) >= 35 ) + goto st15; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st15; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st15; + } else + goto st15; + } else + goto st15; + goto st0; +st15: + if ( ++p == pe ) + goto _test_eof15; +case 15: + switch( (*p) ) { + case 13: goto st10; + case 33: goto st15; + case 59: goto st14; + case 61: goto st16; + case 124: goto st15; + case 126: goto st15; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st15; + } else if ( (*p) >= 35 ) + goto st15; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st15; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st15; + } else + goto st15; + } else + goto st15; + goto st0; +st16: + if ( ++p == pe ) + goto _test_eof16; +case 16: + switch( (*p) ) { + case 13: goto st10; + case 33: goto st16; + case 59: goto st14; + case 124: goto st16; + case 126: goto st16; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st16; + } else if ( (*p) >= 35 ) + goto st16; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st16; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st16; + } else + goto st16; + } else + goto st16; + goto st0; +st17: + if ( ++p == pe ) + goto _test_eof17; +case 17: + switch( (*p) ) { + case 13: goto st4; + case 32: goto st17; + case 33: goto st18; + case 59: goto st17; + case 61: goto st19; + case 124: goto st18; + case 126: goto st18; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st18; + } else if ( (*p) >= 35 ) + goto st18; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st18; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st18; + } else + goto st18; + } else + goto st18; + goto st0; +st18: + if ( ++p == pe ) + goto _test_eof18; +case 18: + switch( (*p) ) { + case 13: goto st4; + case 33: goto st18; + case 59: goto st17; + case 61: goto st19; + case 124: goto st18; + case 126: goto st18; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st18; + } else if ( (*p) >= 35 ) + goto st18; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st18; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st18; + } else + goto st18; + } else + goto st18; + goto st0; +st19: + if ( ++p == pe ) + goto _test_eof19; +case 19: + switch( (*p) ) { + case 13: goto st4; + case 33: goto st19; + case 59: goto st17; + case 124: goto st19; + case 126: goto st19; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st19; + } else if ( (*p) >= 35 ) + goto st19; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st19; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st19; + } else + goto st19; + } else + goto st19; + goto st0; +tr45: + cs = 269; +#line 146 "http_parser.rl" + { + if(parser->on_headers_complete) { + callback_return_value = parser->on_headers_complete(parser); + if (callback_return_value != 0) {p++; goto _out;} + } + } +#line 212 "http_parser.rl" + { + if (parser->transfer_encoding == HTTP_CHUNKED) { + cs = 2; + } else { + /* this is pretty stupid. i'd prefer to combine this with skip_chunk_data */ + parser->chunk_size = parser->content_length; + p += 1; + + SKIP_BODY(MIN(REMAINING, parser->content_length)); + if (callback_return_value != 0) {p++; goto _out;} + + p--; + if(parser->chunk_size > REMAINING) { + {p++; goto _out;} + } + } + } + goto _again; +st269: + if ( ++p == pe ) + goto _test_eof269; +case 269: +#line 897 "http_parser.c" + switch( (*p) ) { + case 67: goto tr311; + case 68: goto tr312; + case 71: goto tr313; + case 72: goto tr314; + case 76: goto tr315; + case 77: goto tr316; + case 79: goto tr317; + case 80: goto tr318; + case 84: goto tr319; + case 85: goto tr320; + } + goto st0; +tr311: +#line 153 "http_parser.rl" + { + if(parser->on_message_begin) { + callback_return_value = parser->on_message_begin(parser); + if (callback_return_value != 0) {p++; cs = 20; goto _out;} + } + } + goto st20; +st20: + if ( ++p == pe ) + goto _test_eof20; +case 20: +#line 924 "http_parser.c" + if ( (*p) == 79 ) + goto st21; + goto st0; +st21: + if ( ++p == pe ) + goto _test_eof21; +case 21: + if ( (*p) == 80 ) + goto st22; + goto st0; +st22: + if ( ++p == pe ) + goto _test_eof22; +case 22: + if ( (*p) == 89 ) + goto st23; + goto st0; +st23: + if ( ++p == pe ) + goto _test_eof23; +case 23: + if ( (*p) == 32 ) + goto tr24; + goto st0; +tr24: +#line 256 "http_parser.rl" + { parser->method = HTTP_COPY; } + goto st24; +tr154: +#line 257 "http_parser.rl" + { parser->method = HTTP_DELETE; } + goto st24; +tr157: +#line 258 "http_parser.rl" + { parser->method = HTTP_GET; } + goto st24; +tr161: +#line 259 "http_parser.rl" + { parser->method = HTTP_HEAD; } + goto st24; +tr165: +#line 260 "http_parser.rl" + { parser->method = HTTP_LOCK; } + goto st24; +tr171: +#line 261 "http_parser.rl" + { parser->method = HTTP_MKCOL; } + goto st24; +tr174: +#line 262 "http_parser.rl" + { parser->method = HTTP_MOVE; } + goto st24; +tr181: +#line 263 "http_parser.rl" + { parser->method = HTTP_OPTIONS; } + goto st24; +tr187: +#line 264 "http_parser.rl" + { parser->method = HTTP_POST; } + goto st24; +tr195: +#line 265 "http_parser.rl" + { parser->method = HTTP_PROPFIND; } + goto st24; +tr200: +#line 266 "http_parser.rl" + { parser->method = HTTP_PROPPATCH; } + goto st24; +tr202: +#line 267 "http_parser.rl" + { parser->method = HTTP_PUT; } + goto st24; +tr207: +#line 268 "http_parser.rl" + { parser->method = HTTP_TRACE; } + goto st24; +tr213: +#line 269 "http_parser.rl" + { parser->method = HTTP_UNLOCK; } + goto st24; +st24: + if ( ++p == pe ) + goto _test_eof24; +case 24: +#line 1009 "http_parser.c" + switch( (*p) ) { + case 42: goto tr25; + case 43: goto tr26; + case 47: goto tr27; + case 58: goto tr28; + } + if ( (*p) < 65 ) { + if ( 45 <= (*p) && (*p) <= 57 ) + goto tr26; + } else if ( (*p) > 90 ) { + if ( 97 <= (*p) && (*p) <= 122 ) + goto tr26; + } else + goto tr26; + goto st0; +tr25: +#line 108 "http_parser.rl" + { parser->uri_mark = p; } + goto st25; +st25: + if ( ++p == pe ) + goto _test_eof25; +case 25: +#line 1033 "http_parser.c" + switch( (*p) ) { + case 32: goto tr29; + case 35: goto tr30; + } + goto st0; +tr29: +#line 122 "http_parser.rl" + { + CALLBACK(uri); + if (callback_return_value != 0) {p++; cs = 26; goto _out;} + parser->uri_mark = NULL; + } + goto st26; +tr124: +#line 105 "http_parser.rl" + { parser->fragment_mark = p; } +#line 128 "http_parser.rl" + { + CALLBACK(fragment); + if (callback_return_value != 0) {p++; cs = 26; goto _out;} + parser->fragment_mark = NULL; + } + goto st26; +tr127: +#line 128 "http_parser.rl" + { + CALLBACK(fragment); + if (callback_return_value != 0) {p++; cs = 26; goto _out;} + parser->fragment_mark = NULL; + } + goto st26; +tr135: +#line 140 "http_parser.rl" + { + CALLBACK(path); + if (callback_return_value != 0) {p++; cs = 26; goto _out;} + parser->path_mark = NULL; + } +#line 122 "http_parser.rl" + { + CALLBACK(uri); + if (callback_return_value != 0) {p++; cs = 26; goto _out;} + parser->uri_mark = NULL; + } + goto st26; +tr141: +#line 106 "http_parser.rl" + { parser->query_string_mark = p; } +#line 134 "http_parser.rl" + { + CALLBACK(query_string); + if (callback_return_value != 0) {p++; cs = 26; goto _out;} + parser->query_string_mark = NULL; + } +#line 122 "http_parser.rl" + { + CALLBACK(uri); + if (callback_return_value != 0) {p++; cs = 26; goto _out;} + parser->uri_mark = NULL; + } + goto st26; +tr145: +#line 134 "http_parser.rl" + { + CALLBACK(query_string); + if (callback_return_value != 0) {p++; cs = 26; goto _out;} + parser->query_string_mark = NULL; + } +#line 122 "http_parser.rl" + { + CALLBACK(uri); + if (callback_return_value != 0) {p++; cs = 26; goto _out;} + parser->uri_mark = NULL; + } + goto st26; +st26: + if ( ++p == pe ) + goto _test_eof26; +case 26: +#line 1113 "http_parser.c" + if ( (*p) == 72 ) + goto st27; + goto st0; +st27: + if ( ++p == pe ) + goto _test_eof27; +case 27: + if ( (*p) == 84 ) + goto st28; + goto st0; +st28: + if ( ++p == pe ) + goto _test_eof28; +case 28: + if ( (*p) == 84 ) + goto st29; + goto st0; +st29: + if ( ++p == pe ) + goto _test_eof29; +case 29: + if ( (*p) == 80 ) + goto st30; + goto st0; +st30: + if ( ++p == pe ) + goto _test_eof30; +case 30: + if ( (*p) == 47 ) + goto st31; + goto st0; +st31: + if ( ++p == pe ) + goto _test_eof31; +case 31: + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr36; + goto st0; +tr36: +#line 176 "http_parser.rl" + { + parser->version_major *= 10; + parser->version_major += *p - '0'; + } + goto st32; +st32: + if ( ++p == pe ) + goto _test_eof32; +case 32: +#line 1163 "http_parser.c" + if ( (*p) == 46 ) + goto st33; + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr36; + goto st0; +st33: + if ( ++p == pe ) + goto _test_eof33; +case 33: + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr38; + goto st0; +tr38: +#line 181 "http_parser.rl" + { + parser->version_minor *= 10; + parser->version_minor += *p - '0'; + } + goto st34; +st34: + if ( ++p == pe ) + goto _test_eof34; +case 34: +#line 1187 "http_parser.c" + if ( (*p) == 13 ) + goto st35; + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr38; + goto st0; +tr49: +#line 104 "http_parser.rl" + { parser->header_value_mark = p; } +#line 116 "http_parser.rl" + { + CALLBACK(header_value); + if (callback_return_value != 0) {p++; cs = 35; goto _out;} + parser->header_value_mark = NULL; + } + goto st35; +tr52: +#line 116 "http_parser.rl" + { + CALLBACK(header_value); + if (callback_return_value != 0) {p++; cs = 35; goto _out;} + parser->header_value_mark = NULL; + } + goto st35; +tr71: +#line 174 "http_parser.rl" + { parser->keep_alive = FALSE; } +#line 116 "http_parser.rl" + { + CALLBACK(header_value); + if (callback_return_value != 0) {p++; cs = 35; goto _out;} + parser->header_value_mark = NULL; + } + goto st35; +tr81: +#line 173 "http_parser.rl" + { parser->keep_alive = TRUE; } +#line 116 "http_parser.rl" + { + CALLBACK(header_value); + if (callback_return_value != 0) {p++; cs = 35; goto _out;} + parser->header_value_mark = NULL; + } + goto st35; +tr122: +#line 170 "http_parser.rl" + { parser->transfer_encoding = HTTP_IDENTITY; } +#line 116 "http_parser.rl" + { + CALLBACK(header_value); + if (callback_return_value != 0) {p++; cs = 35; goto _out;} + parser->header_value_mark = NULL; + } + goto st35; +st35: + if ( ++p == pe ) + goto _test_eof35; +case 35: +#line 1245 "http_parser.c" + if ( (*p) == 10 ) + goto st36; + goto st0; +st36: + if ( ++p == pe ) + goto _test_eof36; +case 36: + switch( (*p) ) { + case 13: goto st37; + case 33: goto tr42; + case 67: goto tr43; + case 84: goto tr44; + case 99: goto tr43; + case 116: goto tr44; + case 124: goto tr42; + case 126: goto tr42; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto tr42; + } else if ( (*p) >= 35 ) + goto tr42; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr42; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto tr42; + } else + goto tr42; + } else + goto tr42; + goto st0; +st37: + if ( ++p == pe ) + goto _test_eof37; +case 37: + if ( (*p) == 10 ) + goto tr45; + goto st0; +tr42: +#line 103 "http_parser.rl" + { parser->header_field_mark = p; } + goto st38; +st38: + if ( ++p == pe ) + goto _test_eof38; +case 38: +#line 1296 "http_parser.c" + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +tr47: +#line 110 "http_parser.rl" + { + CALLBACK(header_field); + if (callback_return_value != 0) {p++; cs = 39; goto _out;} + parser->header_field_mark = NULL; + } + goto st39; +st39: + if ( ++p == pe ) + goto _test_eof39; +case 39: +#line 1333 "http_parser.c" + switch( (*p) ) { + case 13: goto tr49; + case 32: goto st39; + } + goto tr48; +tr48: +#line 104 "http_parser.rl" + { parser->header_value_mark = p; } + goto st40; +st40: + if ( ++p == pe ) + goto _test_eof40; +case 40: +#line 1347 "http_parser.c" + if ( (*p) == 13 ) + goto tr52; + goto st40; +tr43: +#line 103 "http_parser.rl" + { parser->header_field_mark = p; } + goto st41; +st41: + if ( ++p == pe ) + goto _test_eof41; +case 41: +#line 1359 "http_parser.c" + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 79: goto st42; + case 111: goto st42; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st42: + if ( ++p == pe ) + goto _test_eof42; +case 42: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 78: goto st43; + case 110: goto st43; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st43: + if ( ++p == pe ) + goto _test_eof43; +case 43: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 78: goto st44; + case 84: goto st67; + case 110: goto st44; + case 116: goto st67; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st44: + if ( ++p == pe ) + goto _test_eof44; +case 44: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 69: goto st45; + case 101: goto st45; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st45: + if ( ++p == pe ) + goto _test_eof45; +case 45: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 67: goto st46; + case 99: goto st46; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st46: + if ( ++p == pe ) + goto _test_eof46; +case 46: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 84: goto st47; + case 116: goto st47; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st47: + if ( ++p == pe ) + goto _test_eof47; +case 47: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 73: goto st48; + case 105: goto st48; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st48: + if ( ++p == pe ) + goto _test_eof48; +case 48: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 79: goto st49; + case 111: goto st49; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st49: + if ( ++p == pe ) + goto _test_eof49; +case 49: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 78: goto st50; + case 110: goto st50; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st50: + if ( ++p == pe ) + goto _test_eof50; +case 50: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr63; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +tr63: +#line 110 "http_parser.rl" + { + CALLBACK(header_field); + if (callback_return_value != 0) {p++; cs = 51; goto _out;} + parser->header_field_mark = NULL; + } + goto st51; +st51: + if ( ++p == pe ) + goto _test_eof51; +case 51: +#line 1668 "http_parser.c" + switch( (*p) ) { + case 13: goto tr49; + case 32: goto st51; + case 67: goto tr65; + case 75: goto tr66; + case 99: goto tr65; + case 107: goto tr66; + } + goto tr48; +tr65: +#line 104 "http_parser.rl" + { parser->header_value_mark = p; } + goto st52; +st52: + if ( ++p == pe ) + goto _test_eof52; +case 52: +#line 1686 "http_parser.c" + switch( (*p) ) { + case 13: goto tr52; + case 76: goto st53; + case 108: goto st53; + } + goto st40; +st53: + if ( ++p == pe ) + goto _test_eof53; +case 53: + switch( (*p) ) { + case 13: goto tr52; + case 79: goto st54; + case 111: goto st54; + } + goto st40; +st54: + if ( ++p == pe ) + goto _test_eof54; +case 54: + switch( (*p) ) { + case 13: goto tr52; + case 83: goto st55; + case 115: goto st55; + } + goto st40; +st55: + if ( ++p == pe ) + goto _test_eof55; +case 55: + switch( (*p) ) { + case 13: goto tr52; + case 69: goto st56; + case 101: goto st56; + } + goto st40; +st56: + if ( ++p == pe ) + goto _test_eof56; +case 56: + if ( (*p) == 13 ) + goto tr71; + goto st40; +tr66: +#line 104 "http_parser.rl" + { parser->header_value_mark = p; } + goto st57; +st57: + if ( ++p == pe ) + goto _test_eof57; +case 57: +#line 1738 "http_parser.c" + switch( (*p) ) { + case 13: goto tr52; + case 69: goto st58; + case 101: goto st58; + } + goto st40; +st58: + if ( ++p == pe ) + goto _test_eof58; +case 58: + switch( (*p) ) { + case 13: goto tr52; + case 69: goto st59; + case 101: goto st59; + } + goto st40; +st59: + if ( ++p == pe ) + goto _test_eof59; +case 59: + switch( (*p) ) { + case 13: goto tr52; + case 80: goto st60; + case 112: goto st60; + } + goto st40; +st60: + if ( ++p == pe ) + goto _test_eof60; +case 60: + switch( (*p) ) { + case 13: goto tr52; + case 45: goto st61; + } + goto st40; +st61: + if ( ++p == pe ) + goto _test_eof61; +case 61: + switch( (*p) ) { + case 13: goto tr52; + case 65: goto st62; + case 97: goto st62; + } + goto st40; +st62: + if ( ++p == pe ) + goto _test_eof62; +case 62: + switch( (*p) ) { + case 13: goto tr52; + case 76: goto st63; + case 108: goto st63; + } + goto st40; +st63: + if ( ++p == pe ) + goto _test_eof63; +case 63: + switch( (*p) ) { + case 13: goto tr52; + case 73: goto st64; + case 105: goto st64; + } + goto st40; +st64: + if ( ++p == pe ) + goto _test_eof64; +case 64: + switch( (*p) ) { + case 13: goto tr52; + case 86: goto st65; + case 118: goto st65; + } + goto st40; +st65: + if ( ++p == pe ) + goto _test_eof65; +case 65: + switch( (*p) ) { + case 13: goto tr52; + case 69: goto st66; + case 101: goto st66; + } + goto st40; +st66: + if ( ++p == pe ) + goto _test_eof66; +case 66: + if ( (*p) == 13 ) + goto tr81; + goto st40; +st67: + if ( ++p == pe ) + goto _test_eof67; +case 67: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 69: goto st68; + case 101: goto st68; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st68: + if ( ++p == pe ) + goto _test_eof68; +case 68: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 78: goto st69; + case 110: goto st69; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st69: + if ( ++p == pe ) + goto _test_eof69; +case 69: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 84: goto st70; + case 116: goto st70; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st70: + if ( ++p == pe ) + goto _test_eof70; +case 70: + switch( (*p) ) { + case 33: goto st38; + case 45: goto st71; + case 46: goto st38; + case 58: goto tr47; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 48 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 57 ) { + if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else if ( (*p) >= 65 ) + goto st38; + } else + goto st38; + goto st0; +st71: + if ( ++p == pe ) + goto _test_eof71; +case 71: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 76: goto st72; + case 108: goto st72; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st72: + if ( ++p == pe ) + goto _test_eof72; +case 72: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 69: goto st73; + case 101: goto st73; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st73: + if ( ++p == pe ) + goto _test_eof73; +case 73: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 78: goto st74; + case 110: goto st74; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st74: + if ( ++p == pe ) + goto _test_eof74; +case 74: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 71: goto st75; + case 103: goto st75; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st75: + if ( ++p == pe ) + goto _test_eof75; +case 75: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 84: goto st76; + case 116: goto st76; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st76: + if ( ++p == pe ) + goto _test_eof76; +case 76: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 72: goto st77; + case 104: goto st77; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st77: + if ( ++p == pe ) + goto _test_eof77; +case 77: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr92; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +tr92: +#line 110 "http_parser.rl" + { + CALLBACK(header_field); + if (callback_return_value != 0) {p++; cs = 78; goto _out;} + parser->header_field_mark = NULL; + } + goto st78; +st78: + if ( ++p == pe ) + goto _test_eof78; +case 78: +#line 2168 "http_parser.c" + switch( (*p) ) { + case 13: goto tr49; + case 32: goto st78; + } + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr94; + goto tr48; +tr94: +#line 160 "http_parser.rl" + { + parser->content_length *= 10; + parser->content_length += *p - '0'; + } +#line 104 "http_parser.rl" + { parser->header_value_mark = p; } + goto st79; +tr95: +#line 160 "http_parser.rl" + { + parser->content_length *= 10; + parser->content_length += *p - '0'; + } + goto st79; +st79: + if ( ++p == pe ) + goto _test_eof79; +case 79: +#line 2196 "http_parser.c" + if ( (*p) == 13 ) + goto tr52; + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr95; + goto st40; +tr44: +#line 103 "http_parser.rl" + { parser->header_field_mark = p; } + goto st80; +st80: + if ( ++p == pe ) + goto _test_eof80; +case 80: +#line 2210 "http_parser.c" + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 82: goto st81; + case 114: goto st81; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st81: + if ( ++p == pe ) + goto _test_eof81; +case 81: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 65: goto st82; + case 97: goto st82; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 66 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st82: + if ( ++p == pe ) + goto _test_eof82; +case 82: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 78: goto st83; + case 110: goto st83; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st83: + if ( ++p == pe ) + goto _test_eof83; +case 83: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 83: goto st84; + case 115: goto st84; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st84: + if ( ++p == pe ) + goto _test_eof84; +case 84: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 70: goto st85; + case 102: goto st85; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st85: + if ( ++p == pe ) + goto _test_eof85; +case 85: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 69: goto st86; + case 101: goto st86; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st86: + if ( ++p == pe ) + goto _test_eof86; +case 86: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 82: goto st87; + case 114: goto st87; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st87: + if ( ++p == pe ) + goto _test_eof87; +case 87: + switch( (*p) ) { + case 33: goto st38; + case 45: goto st88; + case 46: goto st38; + case 58: goto tr47; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 48 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 57 ) { + if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else if ( (*p) >= 65 ) + goto st38; + } else + goto st38; + goto st0; +st88: + if ( ++p == pe ) + goto _test_eof88; +case 88: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 69: goto st89; + case 101: goto st89; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st89: + if ( ++p == pe ) + goto _test_eof89; +case 89: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 78: goto st90; + case 110: goto st90; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st90: + if ( ++p == pe ) + goto _test_eof90; +case 90: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 67: goto st91; + case 99: goto st91; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st91: + if ( ++p == pe ) + goto _test_eof91; +case 91: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 79: goto st92; + case 111: goto st92; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st92: + if ( ++p == pe ) + goto _test_eof92; +case 92: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 68: goto st93; + case 100: goto st93; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st93: + if ( ++p == pe ) + goto _test_eof93; +case 93: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 73: goto st94; + case 105: goto st94; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st94: + if ( ++p == pe ) + goto _test_eof94; +case 94: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 78: goto st95; + case 110: goto st95; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st95: + if ( ++p == pe ) + goto _test_eof95; +case 95: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr47; + case 71: goto st96; + case 103: goto st96; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +st96: + if ( ++p == pe ) + goto _test_eof96; +case 96: + switch( (*p) ) { + case 33: goto st38; + case 58: goto tr112; + case 124: goto st38; + case 126: goto st38; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st38; + } else if ( (*p) >= 35 ) + goto st38; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st38; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st38; + } else + goto st38; + } else + goto st38; + goto st0; +tr112: +#line 171 "http_parser.rl" + { parser->transfer_encoding = HTTP_CHUNKED; } +#line 110 "http_parser.rl" + { + CALLBACK(header_field); + if (callback_return_value != 0) {p++; cs = 97; goto _out;} + parser->header_field_mark = NULL; + } + goto st97; +st97: + if ( ++p == pe ) + goto _test_eof97; +case 97: +#line 2726 "http_parser.c" + switch( (*p) ) { + case 13: goto tr49; + case 32: goto st97; + case 105: goto tr114; + } + goto tr48; +tr114: +#line 104 "http_parser.rl" + { parser->header_value_mark = p; } + goto st98; +st98: + if ( ++p == pe ) + goto _test_eof98; +case 98: +#line 2741 "http_parser.c" + switch( (*p) ) { + case 13: goto tr52; + case 100: goto st99; + } + goto st40; +st99: + if ( ++p == pe ) + goto _test_eof99; +case 99: + switch( (*p) ) { + case 13: goto tr52; + case 101: goto st100; + } + goto st40; +st100: + if ( ++p == pe ) + goto _test_eof100; +case 100: + switch( (*p) ) { + case 13: goto tr52; + case 110: goto st101; + } + goto st40; +st101: + if ( ++p == pe ) + goto _test_eof101; +case 101: + switch( (*p) ) { + case 13: goto tr52; + case 116: goto st102; + } + goto st40; +st102: + if ( ++p == pe ) + goto _test_eof102; +case 102: + switch( (*p) ) { + case 13: goto tr52; + case 105: goto st103; + } + goto st40; +st103: + if ( ++p == pe ) + goto _test_eof103; +case 103: + switch( (*p) ) { + case 13: goto tr52; + case 116: goto st104; + } + goto st40; +st104: + if ( ++p == pe ) + goto _test_eof104; +case 104: + switch( (*p) ) { + case 13: goto tr52; + case 121: goto st105; + } + goto st40; +st105: + if ( ++p == pe ) + goto _test_eof105; +case 105: + if ( (*p) == 13 ) + goto tr122; + goto st40; +tr30: +#line 122 "http_parser.rl" + { + CALLBACK(uri); + if (callback_return_value != 0) {p++; cs = 106; goto _out;} + parser->uri_mark = NULL; + } + goto st106; +tr136: +#line 140 "http_parser.rl" + { + CALLBACK(path); + if (callback_return_value != 0) {p++; cs = 106; goto _out;} + parser->path_mark = NULL; + } +#line 122 "http_parser.rl" + { + CALLBACK(uri); + if (callback_return_value != 0) {p++; cs = 106; goto _out;} + parser->uri_mark = NULL; + } + goto st106; +tr142: +#line 106 "http_parser.rl" + { parser->query_string_mark = p; } +#line 134 "http_parser.rl" + { + CALLBACK(query_string); + if (callback_return_value != 0) {p++; cs = 106; goto _out;} + parser->query_string_mark = NULL; + } +#line 122 "http_parser.rl" + { + CALLBACK(uri); + if (callback_return_value != 0) {p++; cs = 106; goto _out;} + parser->uri_mark = NULL; + } + goto st106; +tr146: +#line 134 "http_parser.rl" + { + CALLBACK(query_string); + if (callback_return_value != 0) {p++; cs = 106; goto _out;} + parser->query_string_mark = NULL; + } +#line 122 "http_parser.rl" + { + CALLBACK(uri); + if (callback_return_value != 0) {p++; cs = 106; goto _out;} + parser->uri_mark = NULL; + } + goto st106; +st106: + if ( ++p == pe ) + goto _test_eof106; +case 106: +#line 2864 "http_parser.c" + switch( (*p) ) { + case 32: goto tr124; + case 37: goto tr125; + case 60: goto st0; + case 62: goto st0; + case 127: goto st0; + } + if ( (*p) > 31 ) { + if ( 34 <= (*p) && (*p) <= 35 ) + goto st0; + } else if ( (*p) >= 0 ) + goto st0; + goto tr123; +tr123: +#line 105 "http_parser.rl" + { parser->fragment_mark = p; } + goto st107; +st107: + if ( ++p == pe ) + goto _test_eof107; +case 107: +#line 2886 "http_parser.c" + switch( (*p) ) { + case 32: goto tr127; + case 37: goto st108; + case 60: goto st0; + case 62: goto st0; + case 127: goto st0; + } + if ( (*p) > 31 ) { + if ( 34 <= (*p) && (*p) <= 35 ) + goto st0; + } else if ( (*p) >= 0 ) + goto st0; + goto st107; +tr125: +#line 105 "http_parser.rl" + { parser->fragment_mark = p; } + goto st108; +st108: + if ( ++p == pe ) + goto _test_eof108; +case 108: +#line 2908 "http_parser.c" + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st109; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st109; + } else + goto st109; + goto st0; +st109: + if ( ++p == pe ) + goto _test_eof109; +case 109: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st107; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st107; + } else + goto st107; + goto st0; +tr26: +#line 108 "http_parser.rl" + { parser->uri_mark = p; } + goto st110; +st110: + if ( ++p == pe ) + goto _test_eof110; +case 110: +#line 2939 "http_parser.c" + switch( (*p) ) { + case 43: goto st110; + case 58: goto st111; + } + if ( (*p) < 48 ) { + if ( 45 <= (*p) && (*p) <= 46 ) + goto st110; + } else if ( (*p) > 57 ) { + if ( (*p) > 90 ) { + if ( 97 <= (*p) && (*p) <= 122 ) + goto st110; + } else if ( (*p) >= 65 ) + goto st110; + } else + goto st110; + goto st0; +tr28: +#line 108 "http_parser.rl" + { parser->uri_mark = p; } + goto st111; +st111: + if ( ++p == pe ) + goto _test_eof111; +case 111: +#line 2964 "http_parser.c" + switch( (*p) ) { + case 32: goto tr29; + case 34: goto st0; + case 35: goto tr30; + case 37: goto st112; + case 60: goto st0; + case 62: goto st0; + case 127: goto st0; + } + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto st111; +st112: + if ( ++p == pe ) + goto _test_eof112; +case 112: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st113; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st113; + } else + goto st113; + goto st0; +st113: + if ( ++p == pe ) + goto _test_eof113; +case 113: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st111; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st111; + } else + goto st111; + goto st0; +tr27: +#line 108 "http_parser.rl" + { parser->uri_mark = p; } +#line 107 "http_parser.rl" + { parser->path_mark = p; } + goto st114; +st114: + if ( ++p == pe ) + goto _test_eof114; +case 114: +#line 3013 "http_parser.c" + switch( (*p) ) { + case 32: goto tr135; + case 34: goto st0; + case 35: goto tr136; + case 37: goto st115; + case 60: goto st0; + case 62: goto st0; + case 63: goto tr138; + case 127: goto st0; + } + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto st114; +st115: + if ( ++p == pe ) + goto _test_eof115; +case 115: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st116; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st116; + } else + goto st116; + goto st0; +st116: + if ( ++p == pe ) + goto _test_eof116; +case 116: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st114; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st114; + } else + goto st114; + goto st0; +tr138: +#line 140 "http_parser.rl" + { + CALLBACK(path); + if (callback_return_value != 0) {p++; cs = 117; goto _out;} + parser->path_mark = NULL; + } + goto st117; +st117: + if ( ++p == pe ) + goto _test_eof117; +case 117: +#line 3065 "http_parser.c" + switch( (*p) ) { + case 32: goto tr141; + case 34: goto st0; + case 35: goto tr142; + case 37: goto tr143; + case 60: goto st0; + case 62: goto st0; + case 127: goto st0; + } + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto tr140; +tr140: +#line 106 "http_parser.rl" + { parser->query_string_mark = p; } + goto st118; +st118: + if ( ++p == pe ) + goto _test_eof118; +case 118: +#line 3086 "http_parser.c" + switch( (*p) ) { + case 32: goto tr145; + case 34: goto st0; + case 35: goto tr146; + case 37: goto st119; + case 60: goto st0; + case 62: goto st0; + case 127: goto st0; + } + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto st118; +tr143: +#line 106 "http_parser.rl" + { parser->query_string_mark = p; } + goto st119; +st119: + if ( ++p == pe ) + goto _test_eof119; +case 119: +#line 3107 "http_parser.c" + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st120; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st120; + } else + goto st120; + goto st0; +st120: + if ( ++p == pe ) + goto _test_eof120; +case 120: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st118; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st118; + } else + goto st118; + goto st0; +tr312: +#line 153 "http_parser.rl" + { + if(parser->on_message_begin) { + callback_return_value = parser->on_message_begin(parser); + if (callback_return_value != 0) {p++; cs = 121; goto _out;} + } + } + goto st121; +st121: + if ( ++p == pe ) + goto _test_eof121; +case 121: +#line 3143 "http_parser.c" + if ( (*p) == 69 ) + goto st122; + goto st0; +st122: + if ( ++p == pe ) + goto _test_eof122; +case 122: + if ( (*p) == 76 ) + goto st123; + goto st0; +st123: + if ( ++p == pe ) + goto _test_eof123; +case 123: + if ( (*p) == 69 ) + goto st124; + goto st0; +st124: + if ( ++p == pe ) + goto _test_eof124; +case 124: + if ( (*p) == 84 ) + goto st125; + goto st0; +st125: + if ( ++p == pe ) + goto _test_eof125; +case 125: + if ( (*p) == 69 ) + goto st126; + goto st0; +st126: + if ( ++p == pe ) + goto _test_eof126; +case 126: + if ( (*p) == 32 ) + goto tr154; + goto st0; +tr313: +#line 153 "http_parser.rl" + { + if(parser->on_message_begin) { + callback_return_value = parser->on_message_begin(parser); + if (callback_return_value != 0) {p++; cs = 127; goto _out;} + } + } + goto st127; +st127: + if ( ++p == pe ) + goto _test_eof127; +case 127: +#line 3195 "http_parser.c" + if ( (*p) == 69 ) + goto st128; + goto st0; +st128: + if ( ++p == pe ) + goto _test_eof128; +case 128: + if ( (*p) == 84 ) + goto st129; + goto st0; +st129: + if ( ++p == pe ) + goto _test_eof129; +case 129: + if ( (*p) == 32 ) + goto tr157; + goto st0; +tr314: +#line 153 "http_parser.rl" + { + if(parser->on_message_begin) { + callback_return_value = parser->on_message_begin(parser); + if (callback_return_value != 0) {p++; cs = 130; goto _out;} + } + } + goto st130; +st130: + if ( ++p == pe ) + goto _test_eof130; +case 130: +#line 3226 "http_parser.c" + if ( (*p) == 69 ) + goto st131; + goto st0; +st131: + if ( ++p == pe ) + goto _test_eof131; +case 131: + if ( (*p) == 65 ) + goto st132; + goto st0; +st132: + if ( ++p == pe ) + goto _test_eof132; +case 132: + if ( (*p) == 68 ) + goto st133; + goto st0; +st133: + if ( ++p == pe ) + goto _test_eof133; +case 133: + if ( (*p) == 32 ) + goto tr161; + goto st0; +tr315: +#line 153 "http_parser.rl" + { + if(parser->on_message_begin) { + callback_return_value = parser->on_message_begin(parser); + if (callback_return_value != 0) {p++; cs = 134; goto _out;} + } + } + goto st134; +st134: + if ( ++p == pe ) + goto _test_eof134; +case 134: +#line 3264 "http_parser.c" + if ( (*p) == 79 ) + goto st135; + goto st0; +st135: + if ( ++p == pe ) + goto _test_eof135; +case 135: + if ( (*p) == 67 ) + goto st136; + goto st0; +st136: + if ( ++p == pe ) + goto _test_eof136; +case 136: + if ( (*p) == 75 ) + goto st137; + goto st0; +st137: + if ( ++p == pe ) + goto _test_eof137; +case 137: + if ( (*p) == 32 ) + goto tr165; + goto st0; +tr316: +#line 153 "http_parser.rl" + { + if(parser->on_message_begin) { + callback_return_value = parser->on_message_begin(parser); + if (callback_return_value != 0) {p++; cs = 138; goto _out;} + } + } + goto st138; +st138: + if ( ++p == pe ) + goto _test_eof138; +case 138: +#line 3302 "http_parser.c" + switch( (*p) ) { + case 75: goto st139; + case 79: goto st143; + } + goto st0; +st139: + if ( ++p == pe ) + goto _test_eof139; +case 139: + if ( (*p) == 67 ) + goto st140; + goto st0; +st140: + if ( ++p == pe ) + goto _test_eof140; +case 140: + if ( (*p) == 79 ) + goto st141; + goto st0; +st141: + if ( ++p == pe ) + goto _test_eof141; +case 141: + if ( (*p) == 76 ) + goto st142; + goto st0; +st142: + if ( ++p == pe ) + goto _test_eof142; +case 142: + if ( (*p) == 32 ) + goto tr171; + goto st0; +st143: + if ( ++p == pe ) + goto _test_eof143; +case 143: + if ( (*p) == 86 ) + goto st144; + goto st0; +st144: + if ( ++p == pe ) + goto _test_eof144; +case 144: + if ( (*p) == 69 ) + goto st145; + goto st0; +st145: + if ( ++p == pe ) + goto _test_eof145; +case 145: + if ( (*p) == 32 ) + goto tr174; + goto st0; +tr317: +#line 153 "http_parser.rl" + { + if(parser->on_message_begin) { + callback_return_value = parser->on_message_begin(parser); + if (callback_return_value != 0) {p++; cs = 146; goto _out;} + } + } + goto st146; +st146: + if ( ++p == pe ) + goto _test_eof146; +case 146: +#line 3370 "http_parser.c" + if ( (*p) == 80 ) + goto st147; + goto st0; +st147: + if ( ++p == pe ) + goto _test_eof147; +case 147: + if ( (*p) == 84 ) + goto st148; + goto st0; +st148: + if ( ++p == pe ) + goto _test_eof148; +case 148: + if ( (*p) == 73 ) + goto st149; + goto st0; +st149: + if ( ++p == pe ) + goto _test_eof149; +case 149: + if ( (*p) == 79 ) + goto st150; + goto st0; +st150: + if ( ++p == pe ) + goto _test_eof150; +case 150: + if ( (*p) == 78 ) + goto st151; + goto st0; +st151: + if ( ++p == pe ) + goto _test_eof151; +case 151: + if ( (*p) == 83 ) + goto st152; + goto st0; +st152: + if ( ++p == pe ) + goto _test_eof152; +case 152: + if ( (*p) == 32 ) + goto tr181; + goto st0; +tr318: +#line 153 "http_parser.rl" + { + if(parser->on_message_begin) { + callback_return_value = parser->on_message_begin(parser); + if (callback_return_value != 0) {p++; cs = 153; goto _out;} + } + } + goto st153; +st153: + if ( ++p == pe ) + goto _test_eof153; +case 153: +#line 3429 "http_parser.c" + switch( (*p) ) { + case 79: goto st154; + case 82: goto st157; + case 85: goto st169; + } + goto st0; +st154: + if ( ++p == pe ) + goto _test_eof154; +case 154: + if ( (*p) == 83 ) + goto st155; + goto st0; +st155: + if ( ++p == pe ) + goto _test_eof155; +case 155: + if ( (*p) == 84 ) + goto st156; + goto st0; +st156: + if ( ++p == pe ) + goto _test_eof156; +case 156: + if ( (*p) == 32 ) + goto tr187; + goto st0; +st157: + if ( ++p == pe ) + goto _test_eof157; +case 157: + if ( (*p) == 79 ) + goto st158; + goto st0; +st158: + if ( ++p == pe ) + goto _test_eof158; +case 158: + if ( (*p) == 80 ) + goto st159; + goto st0; +st159: + if ( ++p == pe ) + goto _test_eof159; +case 159: + switch( (*p) ) { + case 70: goto st160; + case 80: goto st164; + } + goto st0; +st160: + if ( ++p == pe ) + goto _test_eof160; +case 160: + if ( (*p) == 73 ) + goto st161; + goto st0; +st161: + if ( ++p == pe ) + goto _test_eof161; +case 161: + if ( (*p) == 78 ) + goto st162; + goto st0; +st162: + if ( ++p == pe ) + goto _test_eof162; +case 162: + if ( (*p) == 68 ) + goto st163; + goto st0; +st163: + if ( ++p == pe ) + goto _test_eof163; +case 163: + if ( (*p) == 32 ) + goto tr195; + goto st0; +st164: + if ( ++p == pe ) + goto _test_eof164; +case 164: + if ( (*p) == 65 ) + goto st165; + goto st0; +st165: + if ( ++p == pe ) + goto _test_eof165; +case 165: + if ( (*p) == 84 ) + goto st166; + goto st0; +st166: + if ( ++p == pe ) + goto _test_eof166; +case 166: + if ( (*p) == 67 ) + goto st167; + goto st0; +st167: + if ( ++p == pe ) + goto _test_eof167; +case 167: + if ( (*p) == 72 ) + goto st168; + goto st0; +st168: + if ( ++p == pe ) + goto _test_eof168; +case 168: + if ( (*p) == 32 ) + goto tr200; + goto st0; +st169: + if ( ++p == pe ) + goto _test_eof169; +case 169: + if ( (*p) == 84 ) + goto st170; + goto st0; +st170: + if ( ++p == pe ) + goto _test_eof170; +case 170: + if ( (*p) == 32 ) + goto tr202; + goto st0; +tr319: +#line 153 "http_parser.rl" + { + if(parser->on_message_begin) { + callback_return_value = parser->on_message_begin(parser); + if (callback_return_value != 0) {p++; cs = 171; goto _out;} + } + } + goto st171; +st171: + if ( ++p == pe ) + goto _test_eof171; +case 171: +#line 3570 "http_parser.c" + if ( (*p) == 82 ) + goto st172; + goto st0; +st172: + if ( ++p == pe ) + goto _test_eof172; +case 172: + if ( (*p) == 65 ) + goto st173; + goto st0; +st173: + if ( ++p == pe ) + goto _test_eof173; +case 173: + if ( (*p) == 67 ) + goto st174; + goto st0; +st174: + if ( ++p == pe ) + goto _test_eof174; +case 174: + if ( (*p) == 69 ) + goto st175; + goto st0; +st175: + if ( ++p == pe ) + goto _test_eof175; +case 175: + if ( (*p) == 32 ) + goto tr207; + goto st0; +tr320: +#line 153 "http_parser.rl" + { + if(parser->on_message_begin) { + callback_return_value = parser->on_message_begin(parser); + if (callback_return_value != 0) {p++; cs = 176; goto _out;} + } + } + goto st176; +st176: + if ( ++p == pe ) + goto _test_eof176; +case 176: +#line 3615 "http_parser.c" + if ( (*p) == 78 ) + goto st177; + goto st0; +st177: + if ( ++p == pe ) + goto _test_eof177; +case 177: + if ( (*p) == 76 ) + goto st178; + goto st0; +st178: + if ( ++p == pe ) + goto _test_eof178; +case 178: + if ( (*p) == 79 ) + goto st179; + goto st0; +st179: + if ( ++p == pe ) + goto _test_eof179; +case 179: + if ( (*p) == 67 ) + goto st180; + goto st0; +st180: + if ( ++p == pe ) + goto _test_eof180; +case 180: + if ( (*p) == 75 ) + goto st181; + goto st0; +st181: + if ( ++p == pe ) + goto _test_eof181; +case 181: + if ( (*p) == 32 ) + goto tr213; + goto st0; +tr233: + cs = 270; +#line 146 "http_parser.rl" + { + if(parser->on_headers_complete) { + callback_return_value = parser->on_headers_complete(parser); + if (callback_return_value != 0) {p++; goto _out;} + } + } +#line 212 "http_parser.rl" + { + if (parser->transfer_encoding == HTTP_CHUNKED) { + cs = 2; + } else { + /* this is pretty stupid. i'd prefer to combine this with skip_chunk_data */ + parser->chunk_size = parser->content_length; + p += 1; + + SKIP_BODY(MIN(REMAINING, parser->content_length)); + if (callback_return_value != 0) {p++; goto _out;} + + p--; + if(parser->chunk_size > REMAINING) { + {p++; goto _out;} + } + } + } + goto _again; +st270: + if ( ++p == pe ) + goto _test_eof270; +case 270: +#line 3686 "http_parser.c" + if ( (*p) == 72 ) + goto tr321; + goto st0; +tr321: +#line 153 "http_parser.rl" + { + if(parser->on_message_begin) { + callback_return_value = parser->on_message_begin(parser); + if (callback_return_value != 0) {p++; cs = 182; goto _out;} + } + } + goto st182; +st182: + if ( ++p == pe ) + goto _test_eof182; +case 182: +#line 3703 "http_parser.c" + if ( (*p) == 84 ) + goto st183; + goto st0; +st183: + if ( ++p == pe ) + goto _test_eof183; +case 183: + if ( (*p) == 84 ) + goto st184; + goto st0; +st184: + if ( ++p == pe ) + goto _test_eof184; +case 184: + if ( (*p) == 80 ) + goto st185; + goto st0; +st185: + if ( ++p == pe ) + goto _test_eof185; +case 185: + if ( (*p) == 47 ) + goto st186; + goto st0; +st186: + if ( ++p == pe ) + goto _test_eof186; +case 186: + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr218; + goto st0; +tr218: +#line 176 "http_parser.rl" + { + parser->version_major *= 10; + parser->version_major += *p - '0'; + } + goto st187; +st187: + if ( ++p == pe ) + goto _test_eof187; +case 187: +#line 3746 "http_parser.c" + if ( (*p) == 46 ) + goto st188; + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr218; + goto st0; +st188: + if ( ++p == pe ) + goto _test_eof188; +case 188: + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr220; + goto st0; +tr220: +#line 181 "http_parser.rl" + { + parser->version_minor *= 10; + parser->version_minor += *p - '0'; + } + goto st189; +st189: + if ( ++p == pe ) + goto _test_eof189; +case 189: +#line 3770 "http_parser.c" + if ( (*p) == 32 ) + goto st190; + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr220; + goto st0; +st190: + if ( ++p == pe ) + goto _test_eof190; +case 190: + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr222; + goto st0; +tr222: +#line 165 "http_parser.rl" + { + parser->status_code *= 10; + parser->status_code += *p - '0'; + } + goto st191; +st191: + if ( ++p == pe ) + goto _test_eof191; +case 191: +#line 3794 "http_parser.c" + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr223; + goto st0; +tr223: +#line 165 "http_parser.rl" + { + parser->status_code *= 10; + parser->status_code += *p - '0'; + } + goto st192; +st192: + if ( ++p == pe ) + goto _test_eof192; +case 192: +#line 3809 "http_parser.c" + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr224; + goto st0; +tr224: +#line 165 "http_parser.rl" + { + parser->status_code *= 10; + parser->status_code += *p - '0'; + } + goto st193; +st193: + if ( ++p == pe ) + goto _test_eof193; +case 193: +#line 3824 "http_parser.c" + if ( (*p) == 32 ) + goto st194; + goto st0; +st194: + if ( ++p == pe ) + goto _test_eof194; +case 194: + if ( (*p) < 11 ) { + if ( 0 <= (*p) && (*p) <= 9 ) + goto st195; + } else if ( (*p) > 12 ) { + if ( 14 <= (*p) ) + goto st195; + } else + goto st195; + goto st0; +st195: + if ( ++p == pe ) + goto _test_eof195; +case 195: + if ( (*p) == 13 ) + goto st196; + if ( (*p) > 9 ) { + if ( 11 <= (*p) ) + goto st195; + } else if ( (*p) >= 0 ) + goto st195; + goto st0; +tr237: +#line 104 "http_parser.rl" + { parser->header_value_mark = p; } +#line 116 "http_parser.rl" + { + CALLBACK(header_value); + if (callback_return_value != 0) {p++; cs = 196; goto _out;} + parser->header_value_mark = NULL; + } + goto st196; +tr240: +#line 116 "http_parser.rl" + { + CALLBACK(header_value); + if (callback_return_value != 0) {p++; cs = 196; goto _out;} + parser->header_value_mark = NULL; + } + goto st196; +tr259: +#line 174 "http_parser.rl" + { parser->keep_alive = FALSE; } +#line 116 "http_parser.rl" + { + CALLBACK(header_value); + if (callback_return_value != 0) {p++; cs = 196; goto _out;} + parser->header_value_mark = NULL; + } + goto st196; +tr269: +#line 173 "http_parser.rl" + { parser->keep_alive = TRUE; } +#line 116 "http_parser.rl" + { + CALLBACK(header_value); + if (callback_return_value != 0) {p++; cs = 196; goto _out;} + parser->header_value_mark = NULL; + } + goto st196; +tr310: +#line 170 "http_parser.rl" + { parser->transfer_encoding = HTTP_IDENTITY; } +#line 116 "http_parser.rl" + { + CALLBACK(header_value); + if (callback_return_value != 0) {p++; cs = 196; goto _out;} + parser->header_value_mark = NULL; + } + goto st196; +st196: + if ( ++p == pe ) + goto _test_eof196; +case 196: +#line 3905 "http_parser.c" + if ( (*p) == 10 ) + goto st197; + goto st0; +st197: + if ( ++p == pe ) + goto _test_eof197; +case 197: + switch( (*p) ) { + case 13: goto st198; + case 33: goto tr230; + case 67: goto tr231; + case 84: goto tr232; + case 99: goto tr231; + case 116: goto tr232; + case 124: goto tr230; + case 126: goto tr230; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto tr230; + } else if ( (*p) >= 35 ) + goto tr230; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr230; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto tr230; + } else + goto tr230; + } else + goto tr230; + goto st0; +st198: + if ( ++p == pe ) + goto _test_eof198; +case 198: + if ( (*p) == 10 ) + goto tr233; + goto st0; +tr230: +#line 103 "http_parser.rl" + { parser->header_field_mark = p; } + goto st199; +st199: + if ( ++p == pe ) + goto _test_eof199; +case 199: +#line 3956 "http_parser.c" + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +tr235: +#line 110 "http_parser.rl" + { + CALLBACK(header_field); + if (callback_return_value != 0) {p++; cs = 200; goto _out;} + parser->header_field_mark = NULL; + } + goto st200; +st200: + if ( ++p == pe ) + goto _test_eof200; +case 200: +#line 3993 "http_parser.c" + switch( (*p) ) { + case 13: goto tr237; + case 32: goto st200; + } + goto tr236; +tr236: +#line 104 "http_parser.rl" + { parser->header_value_mark = p; } + goto st201; +st201: + if ( ++p == pe ) + goto _test_eof201; +case 201: +#line 4007 "http_parser.c" + if ( (*p) == 13 ) + goto tr240; + goto st201; +tr231: +#line 103 "http_parser.rl" + { parser->header_field_mark = p; } + goto st202; +st202: + if ( ++p == pe ) + goto _test_eof202; +case 202: +#line 4019 "http_parser.c" + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 79: goto st203; + case 111: goto st203; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st203: + if ( ++p == pe ) + goto _test_eof203; +case 203: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 78: goto st204; + case 110: goto st204; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st204: + if ( ++p == pe ) + goto _test_eof204; +case 204: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 78: goto st205; + case 84: goto st228; + case 110: goto st205; + case 116: goto st228; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st205: + if ( ++p == pe ) + goto _test_eof205; +case 205: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 69: goto st206; + case 101: goto st206; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st206: + if ( ++p == pe ) + goto _test_eof206; +case 206: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 67: goto st207; + case 99: goto st207; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st207: + if ( ++p == pe ) + goto _test_eof207; +case 207: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 84: goto st208; + case 116: goto st208; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st208: + if ( ++p == pe ) + goto _test_eof208; +case 208: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 73: goto st209; + case 105: goto st209; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st209: + if ( ++p == pe ) + goto _test_eof209; +case 209: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 79: goto st210; + case 111: goto st210; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st210: + if ( ++p == pe ) + goto _test_eof210; +case 210: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 78: goto st211; + case 110: goto st211; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st211: + if ( ++p == pe ) + goto _test_eof211; +case 211: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr251; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +tr251: +#line 110 "http_parser.rl" + { + CALLBACK(header_field); + if (callback_return_value != 0) {p++; cs = 212; goto _out;} + parser->header_field_mark = NULL; + } + goto st212; +st212: + if ( ++p == pe ) + goto _test_eof212; +case 212: +#line 4328 "http_parser.c" + switch( (*p) ) { + case 13: goto tr237; + case 32: goto st212; + case 67: goto tr253; + case 75: goto tr254; + case 99: goto tr253; + case 107: goto tr254; + } + goto tr236; +tr253: +#line 104 "http_parser.rl" + { parser->header_value_mark = p; } + goto st213; +st213: + if ( ++p == pe ) + goto _test_eof213; +case 213: +#line 4346 "http_parser.c" + switch( (*p) ) { + case 13: goto tr240; + case 76: goto st214; + case 108: goto st214; + } + goto st201; +st214: + if ( ++p == pe ) + goto _test_eof214; +case 214: + switch( (*p) ) { + case 13: goto tr240; + case 79: goto st215; + case 111: goto st215; + } + goto st201; +st215: + if ( ++p == pe ) + goto _test_eof215; +case 215: + switch( (*p) ) { + case 13: goto tr240; + case 83: goto st216; + case 115: goto st216; + } + goto st201; +st216: + if ( ++p == pe ) + goto _test_eof216; +case 216: + switch( (*p) ) { + case 13: goto tr240; + case 69: goto st217; + case 101: goto st217; + } + goto st201; +st217: + if ( ++p == pe ) + goto _test_eof217; +case 217: + if ( (*p) == 13 ) + goto tr259; + goto st201; +tr254: +#line 104 "http_parser.rl" + { parser->header_value_mark = p; } + goto st218; +st218: + if ( ++p == pe ) + goto _test_eof218; +case 218: +#line 4398 "http_parser.c" + switch( (*p) ) { + case 13: goto tr240; + case 69: goto st219; + case 101: goto st219; + } + goto st201; +st219: + if ( ++p == pe ) + goto _test_eof219; +case 219: + switch( (*p) ) { + case 13: goto tr240; + case 69: goto st220; + case 101: goto st220; + } + goto st201; +st220: + if ( ++p == pe ) + goto _test_eof220; +case 220: + switch( (*p) ) { + case 13: goto tr240; + case 80: goto st221; + case 112: goto st221; + } + goto st201; +st221: + if ( ++p == pe ) + goto _test_eof221; +case 221: + switch( (*p) ) { + case 13: goto tr240; + case 45: goto st222; + } + goto st201; +st222: + if ( ++p == pe ) + goto _test_eof222; +case 222: + switch( (*p) ) { + case 13: goto tr240; + case 65: goto st223; + case 97: goto st223; + } + goto st201; +st223: + if ( ++p == pe ) + goto _test_eof223; +case 223: + switch( (*p) ) { + case 13: goto tr240; + case 76: goto st224; + case 108: goto st224; + } + goto st201; +st224: + if ( ++p == pe ) + goto _test_eof224; +case 224: + switch( (*p) ) { + case 13: goto tr240; + case 73: goto st225; + case 105: goto st225; + } + goto st201; +st225: + if ( ++p == pe ) + goto _test_eof225; +case 225: + switch( (*p) ) { + case 13: goto tr240; + case 86: goto st226; + case 118: goto st226; + } + goto st201; +st226: + if ( ++p == pe ) + goto _test_eof226; +case 226: + switch( (*p) ) { + case 13: goto tr240; + case 69: goto st227; + case 101: goto st227; + } + goto st201; +st227: + if ( ++p == pe ) + goto _test_eof227; +case 227: + if ( (*p) == 13 ) + goto tr269; + goto st201; +st228: + if ( ++p == pe ) + goto _test_eof228; +case 228: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 69: goto st229; + case 101: goto st229; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st229: + if ( ++p == pe ) + goto _test_eof229; +case 229: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 78: goto st230; + case 110: goto st230; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st230: + if ( ++p == pe ) + goto _test_eof230; +case 230: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 84: goto st231; + case 116: goto st231; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st231: + if ( ++p == pe ) + goto _test_eof231; +case 231: + switch( (*p) ) { + case 33: goto st199; + case 45: goto st232; + case 46: goto st199; + case 58: goto tr235; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 48 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 57 ) { + if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else if ( (*p) >= 65 ) + goto st199; + } else + goto st199; + goto st0; +st232: + if ( ++p == pe ) + goto _test_eof232; +case 232: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 76: goto st233; + case 108: goto st233; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st233: + if ( ++p == pe ) + goto _test_eof233; +case 233: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 69: goto st234; + case 101: goto st234; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st234: + if ( ++p == pe ) + goto _test_eof234; +case 234: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 78: goto st235; + case 110: goto st235; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st235: + if ( ++p == pe ) + goto _test_eof235; +case 235: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 71: goto st236; + case 103: goto st236; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st236: + if ( ++p == pe ) + goto _test_eof236; +case 236: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 84: goto st237; + case 116: goto st237; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st237: + if ( ++p == pe ) + goto _test_eof237; +case 237: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 72: goto st238; + case 104: goto st238; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st238: + if ( ++p == pe ) + goto _test_eof238; +case 238: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr280; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +tr280: +#line 110 "http_parser.rl" + { + CALLBACK(header_field); + if (callback_return_value != 0) {p++; cs = 239; goto _out;} + parser->header_field_mark = NULL; + } + goto st239; +st239: + if ( ++p == pe ) + goto _test_eof239; +case 239: +#line 4828 "http_parser.c" + switch( (*p) ) { + case 13: goto tr237; + case 32: goto st239; + } + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr282; + goto tr236; +tr282: +#line 160 "http_parser.rl" + { + parser->content_length *= 10; + parser->content_length += *p - '0'; + } +#line 104 "http_parser.rl" + { parser->header_value_mark = p; } + goto st240; +tr283: +#line 160 "http_parser.rl" + { + parser->content_length *= 10; + parser->content_length += *p - '0'; + } + goto st240; +st240: + if ( ++p == pe ) + goto _test_eof240; +case 240: +#line 4856 "http_parser.c" + if ( (*p) == 13 ) + goto tr240; + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr283; + goto st201; +tr232: +#line 103 "http_parser.rl" + { parser->header_field_mark = p; } + goto st241; +st241: + if ( ++p == pe ) + goto _test_eof241; +case 241: +#line 4870 "http_parser.c" + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 82: goto st242; + case 114: goto st242; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st242: + if ( ++p == pe ) + goto _test_eof242; +case 242: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 65: goto st243; + case 97: goto st243; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 66 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st243: + if ( ++p == pe ) + goto _test_eof243; +case 243: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 78: goto st244; + case 110: goto st244; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st244: + if ( ++p == pe ) + goto _test_eof244; +case 244: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 83: goto st245; + case 115: goto st245; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st245: + if ( ++p == pe ) + goto _test_eof245; +case 245: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 70: goto st246; + case 102: goto st246; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st246: + if ( ++p == pe ) + goto _test_eof246; +case 246: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 69: goto st247; + case 101: goto st247; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st247: + if ( ++p == pe ) + goto _test_eof247; +case 247: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 82: goto st248; + case 114: goto st248; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st248: + if ( ++p == pe ) + goto _test_eof248; +case 248: + switch( (*p) ) { + case 33: goto st199; + case 45: goto st249; + case 46: goto st199; + case 58: goto tr235; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 48 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 57 ) { + if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else if ( (*p) >= 65 ) + goto st199; + } else + goto st199; + goto st0; +st249: + if ( ++p == pe ) + goto _test_eof249; +case 249: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 69: goto st250; + case 101: goto st250; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st250: + if ( ++p == pe ) + goto _test_eof250; +case 250: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 78: goto st251; + case 110: goto st251; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st251: + if ( ++p == pe ) + goto _test_eof251; +case 251: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 67: goto st252; + case 99: goto st252; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st252: + if ( ++p == pe ) + goto _test_eof252; +case 252: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 79: goto st253; + case 111: goto st253; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st253: + if ( ++p == pe ) + goto _test_eof253; +case 253: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 68: goto st254; + case 100: goto st254; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st254: + if ( ++p == pe ) + goto _test_eof254; +case 254: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 73: goto st255; + case 105: goto st255; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st255: + if ( ++p == pe ) + goto _test_eof255; +case 255: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 78: goto st256; + case 110: goto st256; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st256: + if ( ++p == pe ) + goto _test_eof256; +case 256: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr235; + case 71: goto st257; + case 103: goto st257; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +st257: + if ( ++p == pe ) + goto _test_eof257; +case 257: + switch( (*p) ) { + case 33: goto st199; + case 58: goto tr300; + case 124: goto st199; + case 126: goto st199; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st199; + } else if ( (*p) >= 35 ) + goto st199; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st199; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st199; + } else + goto st199; + } else + goto st199; + goto st0; +tr300: +#line 171 "http_parser.rl" + { parser->transfer_encoding = HTTP_CHUNKED; } +#line 110 "http_parser.rl" + { + CALLBACK(header_field); + if (callback_return_value != 0) {p++; cs = 258; goto _out;} + parser->header_field_mark = NULL; + } + goto st258; +st258: + if ( ++p == pe ) + goto _test_eof258; +case 258: +#line 5386 "http_parser.c" + switch( (*p) ) { + case 13: goto tr237; + case 32: goto st258; + case 105: goto tr302; + } + goto tr236; +tr302: +#line 104 "http_parser.rl" + { parser->header_value_mark = p; } + goto st259; +st259: + if ( ++p == pe ) + goto _test_eof259; +case 259: +#line 5401 "http_parser.c" + switch( (*p) ) { + case 13: goto tr240; + case 100: goto st260; + } + goto st201; +st260: + if ( ++p == pe ) + goto _test_eof260; +case 260: + switch( (*p) ) { + case 13: goto tr240; + case 101: goto st261; + } + goto st201; +st261: + if ( ++p == pe ) + goto _test_eof261; +case 261: + switch( (*p) ) { + case 13: goto tr240; + case 110: goto st262; + } + goto st201; +st262: + if ( ++p == pe ) + goto _test_eof262; +case 262: + switch( (*p) ) { + case 13: goto tr240; + case 116: goto st263; + } + goto st201; +st263: + if ( ++p == pe ) + goto _test_eof263; +case 263: + switch( (*p) ) { + case 13: goto tr240; + case 105: goto st264; + } + goto st201; +st264: + if ( ++p == pe ) + goto _test_eof264; +case 264: + switch( (*p) ) { + case 13: goto tr240; + case 116: goto st265; + } + goto st201; +st265: + if ( ++p == pe ) + goto _test_eof265; +case 265: + switch( (*p) ) { + case 13: goto tr240; + case 121: goto st266; + } + goto st201; +st266: + if ( ++p == pe ) + goto _test_eof266; +case 266: + if ( (*p) == 13 ) + goto tr310; + goto st201; + } + _test_eof1: cs = 1; goto _test_eof; + _test_eof267: cs = 267; goto _test_eof; + _test_eof2: cs = 2; goto _test_eof; + _test_eof3: cs = 3; goto _test_eof; + _test_eof4: cs = 4; goto _test_eof; + _test_eof5: cs = 5; goto _test_eof; + _test_eof6: cs = 6; goto _test_eof; + _test_eof268: cs = 268; goto _test_eof; + _test_eof7: cs = 7; goto _test_eof; + _test_eof8: cs = 8; goto _test_eof; + _test_eof9: cs = 9; goto _test_eof; + _test_eof10: cs = 10; goto _test_eof; + _test_eof11: cs = 11; goto _test_eof; + _test_eof12: cs = 12; goto _test_eof; + _test_eof13: cs = 13; goto _test_eof; + _test_eof14: cs = 14; goto _test_eof; + _test_eof15: cs = 15; goto _test_eof; + _test_eof16: cs = 16; goto _test_eof; + _test_eof17: cs = 17; goto _test_eof; + _test_eof18: cs = 18; goto _test_eof; + _test_eof19: cs = 19; goto _test_eof; + _test_eof269: cs = 269; goto _test_eof; + _test_eof20: cs = 20; goto _test_eof; + _test_eof21: cs = 21; goto _test_eof; + _test_eof22: cs = 22; goto _test_eof; + _test_eof23: cs = 23; goto _test_eof; + _test_eof24: cs = 24; goto _test_eof; + _test_eof25: cs = 25; goto _test_eof; + _test_eof26: cs = 26; goto _test_eof; + _test_eof27: cs = 27; goto _test_eof; + _test_eof28: cs = 28; goto _test_eof; + _test_eof29: cs = 29; goto _test_eof; + _test_eof30: cs = 30; goto _test_eof; + _test_eof31: cs = 31; goto _test_eof; + _test_eof32: cs = 32; goto _test_eof; + _test_eof33: cs = 33; goto _test_eof; + _test_eof34: cs = 34; goto _test_eof; + _test_eof35: cs = 35; goto _test_eof; + _test_eof36: cs = 36; goto _test_eof; + _test_eof37: cs = 37; goto _test_eof; + _test_eof38: cs = 38; goto _test_eof; + _test_eof39: cs = 39; goto _test_eof; + _test_eof40: cs = 40; goto _test_eof; + _test_eof41: cs = 41; goto _test_eof; + _test_eof42: cs = 42; goto _test_eof; + _test_eof43: cs = 43; goto _test_eof; + _test_eof44: cs = 44; goto _test_eof; + _test_eof45: cs = 45; goto _test_eof; + _test_eof46: cs = 46; goto _test_eof; + _test_eof47: cs = 47; goto _test_eof; + _test_eof48: cs = 48; goto _test_eof; + _test_eof49: cs = 49; goto _test_eof; + _test_eof50: cs = 50; goto _test_eof; + _test_eof51: cs = 51; goto _test_eof; + _test_eof52: cs = 52; goto _test_eof; + _test_eof53: cs = 53; goto _test_eof; + _test_eof54: cs = 54; goto _test_eof; + _test_eof55: cs = 55; goto _test_eof; + _test_eof56: cs = 56; goto _test_eof; + _test_eof57: cs = 57; goto _test_eof; + _test_eof58: cs = 58; goto _test_eof; + _test_eof59: cs = 59; goto _test_eof; + _test_eof60: cs = 60; goto _test_eof; + _test_eof61: cs = 61; goto _test_eof; + _test_eof62: cs = 62; goto _test_eof; + _test_eof63: cs = 63; goto _test_eof; + _test_eof64: cs = 64; goto _test_eof; + _test_eof65: cs = 65; goto _test_eof; + _test_eof66: cs = 66; goto _test_eof; + _test_eof67: cs = 67; goto _test_eof; + _test_eof68: cs = 68; goto _test_eof; + _test_eof69: cs = 69; goto _test_eof; + _test_eof70: cs = 70; goto _test_eof; + _test_eof71: cs = 71; goto _test_eof; + _test_eof72: cs = 72; goto _test_eof; + _test_eof73: cs = 73; goto _test_eof; + _test_eof74: cs = 74; goto _test_eof; + _test_eof75: cs = 75; goto _test_eof; + _test_eof76: cs = 76; goto _test_eof; + _test_eof77: cs = 77; goto _test_eof; + _test_eof78: cs = 78; goto _test_eof; + _test_eof79: cs = 79; goto _test_eof; + _test_eof80: cs = 80; goto _test_eof; + _test_eof81: cs = 81; goto _test_eof; + _test_eof82: cs = 82; goto _test_eof; + _test_eof83: cs = 83; goto _test_eof; + _test_eof84: cs = 84; goto _test_eof; + _test_eof85: cs = 85; goto _test_eof; + _test_eof86: cs = 86; goto _test_eof; + _test_eof87: cs = 87; goto _test_eof; + _test_eof88: cs = 88; goto _test_eof; + _test_eof89: cs = 89; goto _test_eof; + _test_eof90: cs = 90; goto _test_eof; + _test_eof91: cs = 91; goto _test_eof; + _test_eof92: cs = 92; goto _test_eof; + _test_eof93: cs = 93; goto _test_eof; + _test_eof94: cs = 94; goto _test_eof; + _test_eof95: cs = 95; goto _test_eof; + _test_eof96: cs = 96; goto _test_eof; + _test_eof97: cs = 97; goto _test_eof; + _test_eof98: cs = 98; goto _test_eof; + _test_eof99: cs = 99; goto _test_eof; + _test_eof100: cs = 100; goto _test_eof; + _test_eof101: cs = 101; goto _test_eof; + _test_eof102: cs = 102; goto _test_eof; + _test_eof103: cs = 103; goto _test_eof; + _test_eof104: cs = 104; goto _test_eof; + _test_eof105: cs = 105; goto _test_eof; + _test_eof106: cs = 106; goto _test_eof; + _test_eof107: cs = 107; goto _test_eof; + _test_eof108: cs = 108; goto _test_eof; + _test_eof109: cs = 109; goto _test_eof; + _test_eof110: cs = 110; goto _test_eof; + _test_eof111: cs = 111; goto _test_eof; + _test_eof112: cs = 112; goto _test_eof; + _test_eof113: cs = 113; goto _test_eof; + _test_eof114: cs = 114; goto _test_eof; + _test_eof115: cs = 115; goto _test_eof; + _test_eof116: cs = 116; goto _test_eof; + _test_eof117: cs = 117; goto _test_eof; + _test_eof118: cs = 118; goto _test_eof; + _test_eof119: cs = 119; goto _test_eof; + _test_eof120: cs = 120; goto _test_eof; + _test_eof121: cs = 121; goto _test_eof; + _test_eof122: cs = 122; goto _test_eof; + _test_eof123: cs = 123; goto _test_eof; + _test_eof124: cs = 124; goto _test_eof; + _test_eof125: cs = 125; goto _test_eof; + _test_eof126: cs = 126; goto _test_eof; + _test_eof127: cs = 127; goto _test_eof; + _test_eof128: cs = 128; goto _test_eof; + _test_eof129: cs = 129; goto _test_eof; + _test_eof130: cs = 130; goto _test_eof; + _test_eof131: cs = 131; goto _test_eof; + _test_eof132: cs = 132; goto _test_eof; + _test_eof133: cs = 133; goto _test_eof; + _test_eof134: cs = 134; goto _test_eof; + _test_eof135: cs = 135; goto _test_eof; + _test_eof136: cs = 136; goto _test_eof; + _test_eof137: cs = 137; goto _test_eof; + _test_eof138: cs = 138; goto _test_eof; + _test_eof139: cs = 139; goto _test_eof; + _test_eof140: cs = 140; goto _test_eof; + _test_eof141: cs = 141; goto _test_eof; + _test_eof142: cs = 142; goto _test_eof; + _test_eof143: cs = 143; goto _test_eof; + _test_eof144: cs = 144; goto _test_eof; + _test_eof145: cs = 145; goto _test_eof; + _test_eof146: cs = 146; goto _test_eof; + _test_eof147: cs = 147; goto _test_eof; + _test_eof148: cs = 148; goto _test_eof; + _test_eof149: cs = 149; goto _test_eof; + _test_eof150: cs = 150; goto _test_eof; + _test_eof151: cs = 151; goto _test_eof; + _test_eof152: cs = 152; goto _test_eof; + _test_eof153: cs = 153; goto _test_eof; + _test_eof154: cs = 154; goto _test_eof; + _test_eof155: cs = 155; goto _test_eof; + _test_eof156: cs = 156; goto _test_eof; + _test_eof157: cs = 157; goto _test_eof; + _test_eof158: cs = 158; goto _test_eof; + _test_eof159: cs = 159; goto _test_eof; + _test_eof160: cs = 160; goto _test_eof; + _test_eof161: cs = 161; goto _test_eof; + _test_eof162: cs = 162; goto _test_eof; + _test_eof163: cs = 163; goto _test_eof; + _test_eof164: cs = 164; goto _test_eof; + _test_eof165: cs = 165; goto _test_eof; + _test_eof166: cs = 166; goto _test_eof; + _test_eof167: cs = 167; goto _test_eof; + _test_eof168: cs = 168; goto _test_eof; + _test_eof169: cs = 169; goto _test_eof; + _test_eof170: cs = 170; goto _test_eof; + _test_eof171: cs = 171; goto _test_eof; + _test_eof172: cs = 172; goto _test_eof; + _test_eof173: cs = 173; goto _test_eof; + _test_eof174: cs = 174; goto _test_eof; + _test_eof175: cs = 175; goto _test_eof; + _test_eof176: cs = 176; goto _test_eof; + _test_eof177: cs = 177; goto _test_eof; + _test_eof178: cs = 178; goto _test_eof; + _test_eof179: cs = 179; goto _test_eof; + _test_eof180: cs = 180; goto _test_eof; + _test_eof181: cs = 181; goto _test_eof; + _test_eof270: cs = 270; goto _test_eof; + _test_eof182: cs = 182; goto _test_eof; + _test_eof183: cs = 183; goto _test_eof; + _test_eof184: cs = 184; goto _test_eof; + _test_eof185: cs = 185; goto _test_eof; + _test_eof186: cs = 186; goto _test_eof; + _test_eof187: cs = 187; goto _test_eof; + _test_eof188: cs = 188; goto _test_eof; + _test_eof189: cs = 189; goto _test_eof; + _test_eof190: cs = 190; goto _test_eof; + _test_eof191: cs = 191; goto _test_eof; + _test_eof192: cs = 192; goto _test_eof; + _test_eof193: cs = 193; goto _test_eof; + _test_eof194: cs = 194; goto _test_eof; + _test_eof195: cs = 195; goto _test_eof; + _test_eof196: cs = 196; goto _test_eof; + _test_eof197: cs = 197; goto _test_eof; + _test_eof198: cs = 198; goto _test_eof; + _test_eof199: cs = 199; goto _test_eof; + _test_eof200: cs = 200; goto _test_eof; + _test_eof201: cs = 201; goto _test_eof; + _test_eof202: cs = 202; goto _test_eof; + _test_eof203: cs = 203; goto _test_eof; + _test_eof204: cs = 204; goto _test_eof; + _test_eof205: cs = 205; goto _test_eof; + _test_eof206: cs = 206; goto _test_eof; + _test_eof207: cs = 207; goto _test_eof; + _test_eof208: cs = 208; goto _test_eof; + _test_eof209: cs = 209; goto _test_eof; + _test_eof210: cs = 210; goto _test_eof; + _test_eof211: cs = 211; goto _test_eof; + _test_eof212: cs = 212; goto _test_eof; + _test_eof213: cs = 213; goto _test_eof; + _test_eof214: cs = 214; goto _test_eof; + _test_eof215: cs = 215; goto _test_eof; + _test_eof216: cs = 216; goto _test_eof; + _test_eof217: cs = 217; goto _test_eof; + _test_eof218: cs = 218; goto _test_eof; + _test_eof219: cs = 219; goto _test_eof; + _test_eof220: cs = 220; goto _test_eof; + _test_eof221: cs = 221; goto _test_eof; + _test_eof222: cs = 222; goto _test_eof; + _test_eof223: cs = 223; goto _test_eof; + _test_eof224: cs = 224; goto _test_eof; + _test_eof225: cs = 225; goto _test_eof; + _test_eof226: cs = 226; goto _test_eof; + _test_eof227: cs = 227; goto _test_eof; + _test_eof228: cs = 228; goto _test_eof; + _test_eof229: cs = 229; goto _test_eof; + _test_eof230: cs = 230; goto _test_eof; + _test_eof231: cs = 231; goto _test_eof; + _test_eof232: cs = 232; goto _test_eof; + _test_eof233: cs = 233; goto _test_eof; + _test_eof234: cs = 234; goto _test_eof; + _test_eof235: cs = 235; goto _test_eof; + _test_eof236: cs = 236; goto _test_eof; + _test_eof237: cs = 237; goto _test_eof; + _test_eof238: cs = 238; goto _test_eof; + _test_eof239: cs = 239; goto _test_eof; + _test_eof240: cs = 240; goto _test_eof; + _test_eof241: cs = 241; goto _test_eof; + _test_eof242: cs = 242; goto _test_eof; + _test_eof243: cs = 243; goto _test_eof; + _test_eof244: cs = 244; goto _test_eof; + _test_eof245: cs = 245; goto _test_eof; + _test_eof246: cs = 246; goto _test_eof; + _test_eof247: cs = 247; goto _test_eof; + _test_eof248: cs = 248; goto _test_eof; + _test_eof249: cs = 249; goto _test_eof; + _test_eof250: cs = 250; goto _test_eof; + _test_eof251: cs = 251; goto _test_eof; + _test_eof252: cs = 252; goto _test_eof; + _test_eof253: cs = 253; goto _test_eof; + _test_eof254: cs = 254; goto _test_eof; + _test_eof255: cs = 255; goto _test_eof; + _test_eof256: cs = 256; goto _test_eof; + _test_eof257: cs = 257; goto _test_eof; + _test_eof258: cs = 258; goto _test_eof; + _test_eof259: cs = 259; goto _test_eof; + _test_eof260: cs = 260; goto _test_eof; + _test_eof261: cs = 261; goto _test_eof; + _test_eof262: cs = 262; goto _test_eof; + _test_eof263: cs = 263; goto _test_eof; + _test_eof264: cs = 264; goto _test_eof; + _test_eof265: cs = 265; goto _test_eof; + _test_eof266: cs = 266; goto _test_eof; + + _test_eof: {} + _out: {} + } +#line 391 "http_parser.rl" + + parser->cs = cs; + + CALLBACK(header_field); + CALLBACK(header_value); + CALLBACK(fragment); + CALLBACK(query_string); + CALLBACK(path); + CALLBACK(uri); + +out: + assert(p <= pe && "buffer overflow after parsing execute"); + return(p - buffer); +} + +int +http_parser_has_error (http_parser *parser) +{ + return parser->cs == http_parser_error; +} + +int +http_parser_should_keep_alive (http_parser *parser) +{ + if (parser->keep_alive == -1) + if (parser->version_major == 1) + return (parser->version_minor != 0); + else if (parser->version_major == 0) + return FALSE; + else + return TRUE; + else + return parser->keep_alive; +} diff --git a/deps/http_parser/http_parser.h b/deps/http_parser/http_parser.h new file mode 100644 index 0000000000..d41580e677 --- /dev/null +++ b/deps/http_parser/http_parser.h @@ -0,0 +1,127 @@ +/* Copyright (c) 2008 Ryan Dahl (ry@tinyclouds.org) + * All rights reserved. + * + * This parser is based on code from Zed Shaw's Mongrel. + * Copyright (c) 2005 Zed A. Shaw + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef http_parser_h +#define http_parser_h +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct http_parser http_parser; + +/* Callbacks should return non-zero to indicate an error. The parse will + * then halt execution. + * + * http_data_cb does not return data chunks. It will be call arbitrarally + * many times for each string. E.G. you might get 10 callbacks for "on_path" + * each providing just a few characters more data. + */ +typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); +typedef int (*http_cb) (http_parser*); + +/* Request Methods */ +#define HTTP_COPY 0x0001 +#define HTTP_DELETE 0x0002 +#define HTTP_GET 0x0004 +#define HTTP_HEAD 0x0008 +#define HTTP_LOCK 0x0010 +#define HTTP_MKCOL 0x0020 +#define HTTP_MOVE 0x0040 +#define HTTP_OPTIONS 0x0080 +#define HTTP_POST 0x0100 +#define HTTP_PROPFIND 0x0200 +#define HTTP_PROPPATCH 0x0400 +#define HTTP_PUT 0x0800 +#define HTTP_TRACE 0x1000 +#define HTTP_UNLOCK 0x2000 + +/* Transfer Encodings */ +#define HTTP_IDENTITY 0x01 +#define HTTP_CHUNKED 0x02 + +enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE }; + +struct http_parser { + /** PRIVATE **/ + int cs; + enum http_parser_type type; + + size_t chunk_size; + unsigned eating:1; + size_t body_read; + + const char *header_field_mark; + const char *header_value_mark; + const char *query_string_mark; + const char *path_mark; + const char *uri_mark; + const char *fragment_mark; + + /** READ-ONLY **/ + unsigned short status_code; /* responses only */ + unsigned short method; /* requests only */ + short transfer_encoding; + unsigned short version_major; + unsigned short version_minor; + short keep_alive; + size_t content_length; + + /** PUBLIC **/ + void *data; /* A pointer to get hook to the "connection" or "socket" object */ + + /* an ordered list of callbacks */ + + http_cb on_message_begin; + + /* requests only */ + http_data_cb on_path; + http_data_cb on_query_string; + http_data_cb on_uri; + http_data_cb on_fragment; + + http_data_cb on_header_field; + http_data_cb on_header_value; + http_cb on_headers_complete; + http_data_cb on_body; + http_cb on_message_complete; +}; + +/* Initializes an http_parser structure. The second argument specifies if + * it will be parsing requests or responses. + */ +void http_parser_init (http_parser *parser, enum http_parser_type); + +size_t http_parser_execute (http_parser *parser, const char *data, size_t len); + +int http_parser_has_error (http_parser *parser); + +int http_parser_should_keep_alive (http_parser *parser); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/deps/http_parser/http_parser.rl b/deps/http_parser/http_parser.rl new file mode 100644 index 0000000000..3b4700f852 --- /dev/null +++ b/deps/http_parser/http_parser.rl @@ -0,0 +1,424 @@ +/* Copyright (c) 2008, 2009 Ryan Dahl (ry@tinyclouds.org) + * + * Based on Zed Shaw's Mongrel. + * Copyright (c) 2005 Zed A. Shaw + * + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "http_parser.h" + +#include + +static int unhex[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + }; +#define TRUE 1 +#define FALSE 0 +#define MIN(a,b) (a < b ? a : b) +#define NULL (void*)(0) + +#define REMAINING (pe - p) +#define CALLBACK(FOR) \ + if (parser->FOR##_mark && parser->on_##FOR) { \ + callback_return_value = \ + parser->on_##FOR(parser, parser->FOR##_mark, p - parser->FOR##_mark); \ + } + +#define RESET_PARSER(parser) \ + parser->chunk_size = 0; \ + parser->eating = 0; \ + parser->header_field_mark = NULL; \ + parser->header_value_mark = NULL; \ + parser->query_string_mark = NULL; \ + parser->path_mark = NULL; \ + parser->uri_mark = NULL; \ + parser->fragment_mark = NULL; \ + parser->status_code = 0; \ + parser->method = 0; \ + parser->transfer_encoding = HTTP_IDENTITY; \ + parser->version_major = 0; \ + parser->version_minor = 0; \ + parser->keep_alive = -1; \ + parser->content_length = 0; \ + parser->body_read = 0; + +#define END_REQUEST \ +do { \ + if (parser->on_message_complete) { \ + callback_return_value = \ + parser->on_message_complete(parser); \ + } \ + RESET_PARSER(parser); \ +} while (0) + +#define SKIP_BODY(nskip) \ +do { \ + tmp = (nskip); \ + if (parser->on_body && tmp > 0) { \ + callback_return_value = parser->on_body(parser, p, tmp); \ + } \ + if (callback_return_value == 0) { \ + p += tmp; \ + parser->body_read += tmp; \ + parser->chunk_size -= tmp; \ + if (0 == parser->chunk_size) { \ + parser->eating = FALSE; \ + if (parser->transfer_encoding == HTTP_IDENTITY) { \ + END_REQUEST; \ + } \ + } else { \ + parser->eating = TRUE; \ + } \ + } \ +} while (0) + +%%{ + machine http_parser; + + action mark_header_field { parser->header_field_mark = p; } + action mark_header_value { parser->header_value_mark = p; } + action mark_fragment { parser->fragment_mark = p; } + action mark_query_string { parser->query_string_mark = p; } + action mark_request_path { parser->path_mark = p; } + action mark_request_uri { parser->uri_mark = p; } + + action header_field { + CALLBACK(header_field); + if (callback_return_value != 0) fbreak; + parser->header_field_mark = NULL; + } + + action header_value { + CALLBACK(header_value); + if (callback_return_value != 0) fbreak; + parser->header_value_mark = NULL; + } + + action request_uri { + CALLBACK(uri); + if (callback_return_value != 0) fbreak; + parser->uri_mark = NULL; + } + + action fragment { + CALLBACK(fragment); + if (callback_return_value != 0) fbreak; + parser->fragment_mark = NULL; + } + + action query_string { + CALLBACK(query_string); + if (callback_return_value != 0) fbreak; + parser->query_string_mark = NULL; + } + + action request_path { + CALLBACK(path); + if (callback_return_value != 0) fbreak; + parser->path_mark = NULL; + } + + action headers_complete { + if(parser->on_headers_complete) { + callback_return_value = parser->on_headers_complete(parser); + if (callback_return_value != 0) fbreak; + } + } + + action begin_message { + if(parser->on_message_begin) { + callback_return_value = parser->on_message_begin(parser); + if (callback_return_value != 0) fbreak; + } + } + + action content_length { + parser->content_length *= 10; + parser->content_length += *p - '0'; + } + + action status_code { + parser->status_code *= 10; + parser->status_code += *p - '0'; + } + + action use_identity_encoding { parser->transfer_encoding = HTTP_IDENTITY; } + action use_chunked_encoding { parser->transfer_encoding = HTTP_CHUNKED; } + + action set_keep_alive { parser->keep_alive = TRUE; } + action set_not_keep_alive { parser->keep_alive = FALSE; } + + action version_major { + parser->version_major *= 10; + parser->version_major += *p - '0'; + } + + action version_minor { + parser->version_minor *= 10; + parser->version_minor += *p - '0'; + } + + action add_to_chunk_size { + parser->chunk_size *= 16; + parser->chunk_size += unhex[(int)*p]; + } + + action skip_chunk_data { + SKIP_BODY(MIN(parser->chunk_size, REMAINING)); + if (callback_return_value != 0) fbreak; + + fhold; + if (parser->chunk_size > REMAINING) { + fbreak; + } else { + fgoto chunk_end; + } + } + + action end_chunked_body { + END_REQUEST; + if (parser->type == HTTP_REQUEST) { + fnext Requests; + } else { + fnext Responses; + } + } + + action body_logic { + if (parser->transfer_encoding == HTTP_CHUNKED) { + fnext ChunkedBody; + } else { + /* this is pretty stupid. i'd prefer to combine this with skip_chunk_data */ + parser->chunk_size = parser->content_length; + p += 1; + + SKIP_BODY(MIN(REMAINING, parser->content_length)); + if (callback_return_value != 0) fbreak; + + fhold; + if(parser->chunk_size > REMAINING) { + fbreak; + } + } + } + + + CRLF = "\r\n"; + +# character types + CTL = (cntrl | 127); + safe = ("$" | "-" | "_" | "."); + extra = ("!" | "*" | "'" | "(" | ")" | ","); + reserved = (";" | "/" | "?" | ":" | "@" | "&" | "=" | "+"); + unsafe = (CTL | " " | "\"" | "#" | "%" | "<" | ">"); + national = any -- (alpha | digit | reserved | extra | safe | unsafe); + unreserved = (alpha | digit | safe | extra | national); + escape = ("%" xdigit xdigit); + uchar = (unreserved | escape); + pchar = (uchar | ":" | "@" | "&" | "=" | "+"); + tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" + | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t"); + +# elements + token = (ascii -- (CTL | tspecials)); + quote = "\""; +# qdtext = token -- "\""; +# quoted_pair = "\" ascii; +# quoted_string = "\"" (qdtext | quoted_pair )* "\""; + +# headers + + Method = ( "COPY" %{ parser->method = HTTP_COPY; } + | "DELETE" %{ parser->method = HTTP_DELETE; } + | "GET" %{ parser->method = HTTP_GET; } + | "HEAD" %{ parser->method = HTTP_HEAD; } + | "LOCK" %{ parser->method = HTTP_LOCK; } + | "MKCOL" %{ parser->method = HTTP_MKCOL; } + | "MOVE" %{ parser->method = HTTP_MOVE; } + | "OPTIONS" %{ parser->method = HTTP_OPTIONS; } + | "POST" %{ parser->method = HTTP_POST; } + | "PROPFIND" %{ parser->method = HTTP_PROPFIND; } + | "PROPPATCH" %{ parser->method = HTTP_PROPPATCH; } + | "PUT" %{ parser->method = HTTP_PUT; } + | "TRACE" %{ parser->method = HTTP_TRACE; } + | "UNLOCK" %{ parser->method = HTTP_UNLOCK; } + ); # Not allowing extension methods + + HTTP_Version = "HTTP/" digit+ $version_major "." digit+ $version_minor; + + scheme = ( alpha | digit | "+" | "-" | "." )* ; + absolute_uri = (scheme ":" (uchar | reserved )*); + path = ( pchar+ ( "/" pchar* )* ) ; + query = ( uchar | reserved )* >mark_query_string %query_string ; + param = ( pchar | "/" )* ; + params = ( param ( ";" param )* ) ; + rel_path = ( path? (";" params)? ) ; + absolute_path = ( "/"+ rel_path ) >mark_request_path %request_path ("?" query)?; + Request_URI = ( "*" | absolute_uri | absolute_path ) >mark_request_uri %request_uri; + Fragment = ( uchar | reserved )* >mark_fragment %fragment; + + field_name = ( token -- ":" )+; + Field_Name = field_name >mark_header_field %header_field; + + field_value = ((any - " ") any*)?; + Field_Value = field_value >mark_header_value %header_value; + + hsep = ":" " "*; + header = (field_name hsep field_value) :> CRLF; + Header = ( ("Content-Length"i hsep digit+ $content_length) + | ("Connection"i hsep + ( "Keep-Alive"i %set_keep_alive + | "close"i %set_not_keep_alive + ) + ) + | ("Transfer-Encoding"i %use_chunked_encoding hsep "identity" %use_identity_encoding) + | (Field_Name hsep Field_Value) + ) :> CRLF; + + Headers = (Header)* :> CRLF @headers_complete; + + Request_Line = ( Method " " Request_URI ("#" Fragment)? " " HTTP_Version CRLF ) ; + + StatusCode = (digit digit digit) $status_code; + ReasonPhrase = ascii+ -- ("\r" | "\n"); + StatusLine = HTTP_Version " " StatusCode " " ReasonPhrase CRLF; + +# chunked message + trailing_headers = header*; + #chunk_ext_val = token | quoted_string; + chunk_ext_val = token*; + chunk_ext_name = token*; + chunk_extension = ( ";" " "* chunk_ext_name ("=" chunk_ext_val)? )*; + last_chunk = "0"+ chunk_extension CRLF; + chunk_size = (xdigit* [1-9a-fA-F] xdigit*) $add_to_chunk_size; + chunk_end = CRLF; + chunk_body = any >skip_chunk_data; + chunk_begin = chunk_size chunk_extension CRLF; + chunk = chunk_begin chunk_body chunk_end; + ChunkedBody := chunk* last_chunk trailing_headers CRLF @end_chunked_body; + + Request = (Request_Line Headers) >begin_message @body_logic; + Response = (StatusLine Headers) >begin_message @body_logic; + + Requests := Request*; + Responses := Response*; + + main := any >{ + fhold; + if (parser->type == HTTP_REQUEST) { + fgoto Requests; + } else { + fgoto Responses; + } + }; + +}%% + +%% write data; + +void +http_parser_init (http_parser *parser, enum http_parser_type type) +{ + int cs = 0; + %% write init; + parser->cs = cs; + parser->type = type; + + parser->on_message_begin = NULL; + parser->on_path = NULL; + parser->on_query_string = NULL; + parser->on_uri = NULL; + parser->on_header_field = NULL; + parser->on_header_value = NULL; + parser->on_headers_complete = NULL; + parser->on_body = NULL; + parser->on_message_complete = NULL; + + RESET_PARSER(parser); +} + +/** exec **/ +size_t +http_parser_execute (http_parser *parser, const char *buffer, size_t len) +{ + size_t tmp; // REMOVE ME this is extremely hacky + int callback_return_value = 0; + const char *p, *pe; + int cs = parser->cs; + + p = buffer; + pe = buffer+len; + + if (0 < parser->chunk_size && parser->eating) { + /* eat body */ + SKIP_BODY(MIN(len, parser->chunk_size)); + if (callback_return_value != 0) goto out; + } + + if (parser->header_field_mark) parser->header_field_mark = buffer; + if (parser->header_value_mark) parser->header_value_mark = buffer; + if (parser->fragment_mark) parser->fragment_mark = buffer; + if (parser->query_string_mark) parser->query_string_mark = buffer; + if (parser->path_mark) parser->path_mark = buffer; + if (parser->uri_mark) parser->uri_mark = buffer; + + %% write exec; + + parser->cs = cs; + + CALLBACK(header_field); + CALLBACK(header_value); + CALLBACK(fragment); + CALLBACK(query_string); + CALLBACK(path); + CALLBACK(uri); + +out: + assert(p <= pe && "buffer overflow after parsing execute"); + return(p - buffer); +} + +int +http_parser_has_error (http_parser *parser) +{ + return parser->cs == http_parser_error; +} + +int +http_parser_should_keep_alive (http_parser *parser) +{ + if (parser->keep_alive == -1) + if (parser->version_major == 1) + return (parser->version_minor != 0); + else if (parser->version_major == 0) + return FALSE; + else + return TRUE; + else + return parser->keep_alive; +} diff --git a/deps/http_parser/test.c b/deps/http_parser/test.c new file mode 100644 index 0000000000..e1d10314c5 --- /dev/null +++ b/deps/http_parser/test.c @@ -0,0 +1,748 @@ +#include "http_parser.h" +#include +#include +#include +#include +#include + +#undef TRUE +#define TRUE 1 +#undef FALSE +#define FALSE 0 + +#define MAX_HEADERS 10 +#define MAX_ELEMENT_SIZE 500 + +static http_parser parser; +struct message { + const char *name; // for debugging purposes + const char *raw; + enum http_parser_type type; + int method; + int status_code; + char request_path[MAX_ELEMENT_SIZE]; + char request_uri[MAX_ELEMENT_SIZE]; + char fragment[MAX_ELEMENT_SIZE]; + char query_string[MAX_ELEMENT_SIZE]; + char body[MAX_ELEMENT_SIZE]; + int num_headers; + enum { NONE=0, FIELD, VALUE } last_header_element; + char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE]; + int should_keep_alive; +}; + +static struct message messages[5]; +static int num_messages; + +/* * R E Q U E S T S * */ +const struct message requests[] = +#define CURL_GET 0 +{ {.name= "curl get" + ,.type= HTTP_REQUEST + ,.raw= "GET /test HTTP/1.1\r\n" + "User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1\r\n" + "Host: 0.0.0.0=5000\r\n" + "Accept: */*\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/test" + ,.request_uri= "/test" + ,.num_headers= 3 + ,.headers= + { { "User-Agent", "curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1" } + , { "Host", "0.0.0.0=5000" } + , { "Accept", "*/*" } + } + ,.body= "" + } + +#define FIREFOX_GET 1 +, {.name= "firefox get" + ,.type= HTTP_REQUEST + ,.raw= "GET /favicon.ico HTTP/1.1\r\n" + "Host: 0.0.0.0=5000\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n" + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" + "Accept-Language: en-us,en;q=0.5\r\n" + "Accept-Encoding: gzip,deflate\r\n" + "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" + "Keep-Alive: 300\r\n" + "Connection: keep-alive\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/favicon.ico" + ,.request_uri= "/favicon.ico" + ,.num_headers= 8 + ,.headers= + { { "Host", "0.0.0.0=5000" } + , { "User-Agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0" } + , { "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" } + , { "Accept-Language", "en-us,en;q=0.5" } + , { "Accept-Encoding", "gzip,deflate" } + , { "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" } + , { "Keep-Alive", "300" } + , { "Connection", "keep-alive" } + } + ,.body= "" + } + +#define DUMBFUCK 2 +, {.name= "dumbfuck" + ,.type= HTTP_REQUEST + ,.raw= "GET /dumbfuck HTTP/1.1\r\n" + "aaaaaaaaaaaaa:++++++++++\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/dumbfuck" + ,.request_uri= "/dumbfuck" + ,.num_headers= 1 + ,.headers= + { { "aaaaaaaaaaaaa", "++++++++++" } + } + ,.body= "" + } + +#define FRAGMENT_IN_URI 3 +, {.name= "fragment in uri" + ,.type= HTTP_REQUEST + ,.raw= "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.method= HTTP_GET + ,.query_string= "page=1" + ,.fragment= "posts-17408" + ,.request_path= "/forums/1/topics/2375" + /* XXX request uri does not include fragment? */ + ,.request_uri= "/forums/1/topics/2375?page=1" + ,.num_headers= 0 + ,.body= "" + } + +#define GET_NO_HEADERS_NO_BODY 4 +, {.name= "get no headers no body" + ,.type= HTTP_REQUEST + ,.raw= "GET /get_no_headers_no_body/world HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/get_no_headers_no_body/world" + ,.request_uri= "/get_no_headers_no_body/world" + ,.num_headers= 0 + ,.body= "" + } + +#define GET_ONE_HEADER_NO_BODY 5 +, {.name= "get one header no body" + ,.type= HTTP_REQUEST + ,.raw= "GET /get_one_header_no_body HTTP/1.1\r\n" + "Accept: */*\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/get_one_header_no_body" + ,.request_uri= "/get_one_header_no_body" + ,.num_headers= 1 + ,.headers= + { { "Accept" , "*/*" } + } + ,.body= "" + } + +#define GET_FUNKY_CONTENT_LENGTH 6 +, {.name= "get funky content length body hello" + ,.type= HTTP_REQUEST + ,.raw= "GET /get_funky_content_length_body_hello HTTP/1.0\r\n" + "conTENT-Length: 5\r\n" + "\r\n" + "HELLO" + ,.should_keep_alive= FALSE + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/get_funky_content_length_body_hello" + ,.request_uri= "/get_funky_content_length_body_hello" + ,.num_headers= 1 + ,.headers= + { { "conTENT-Length" , "5" } + } + ,.body= "HELLO" + } + +#define POST_IDENTITY_BODY_WORLD 7 +, {.name= "post identity body world" + ,.type= HTTP_REQUEST + ,.raw= "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n" + "Accept: */*\r\n" + "Transfer-Encoding: identity\r\n" + "Content-Length: 5\r\n" + "\r\n" + "World" + ,.should_keep_alive= TRUE + ,.method= HTTP_POST + ,.query_string= "q=search" + ,.fragment= "hey" + ,.request_path= "/post_identity_body_world" + ,.request_uri= "/post_identity_body_world?q=search" + ,.num_headers= 3 + ,.headers= + { { "Accept", "*/*" } + , { "Transfer-Encoding", "identity" } + , { "Content-Length", "5" } + } + ,.body= "World" + } + +#define POST_CHUNKED_ALL_YOUR_BASE 8 +, {.name= "post - chunked body: all your base are belong to us" + ,.type= HTTP_REQUEST + ,.raw= "POST /post_chunked_all_your_base HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "1e\r\nall your base are belong to us\r\n" + "0\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/post_chunked_all_your_base" + ,.request_uri= "/post_chunked_all_your_base" + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding" , "chunked" } + } + ,.body= "all your base are belong to us" + } + +#define TWO_CHUNKS_MULT_ZERO_END 9 +, {.name= "two chunks ; triple zero ending" + ,.type= HTTP_REQUEST + ,.raw= "POST /two_chunks_mult_zero_end HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "5\r\nhello\r\n" + "6\r\n world\r\n" + "000\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/two_chunks_mult_zero_end" + ,.request_uri= "/two_chunks_mult_zero_end" + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding", "chunked" } + } + ,.body= "hello world" + } + +#define CHUNKED_W_TRAILING_HEADERS 10 +, {.name= "chunked with trailing headers. blech." + ,.type= HTTP_REQUEST + ,.raw= "POST /chunked_w_trailing_headers HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "5\r\nhello\r\n" + "6\r\n world\r\n" + "0\r\n" + "Vary: *\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/chunked_w_trailing_headers" + ,.request_uri= "/chunked_w_trailing_headers" + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding", "chunked" } + } + ,.body= "hello world" + } + +#define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11 +, {.name= "with bullshit after the length" + ,.type= HTTP_REQUEST + ,.raw= "POST /chunked_w_bullshit_after_length HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n" + "6; blahblah; blah\r\n world\r\n" + "0\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/chunked_w_bullshit_after_length" + ,.request_uri= "/chunked_w_bullshit_after_length" + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding", "chunked" } + } + ,.body= "hello world" + } + +, {.name= NULL } /* sentinel */ +}; + +/* * R E S P O N S E S * */ +const struct message responses[] = +{ {.name= "google 301" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 301 Moved Permanently\r\n" + "Location: http://www.google.com/\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Date: Sun, 26 Apr 2009 11:11:49 GMT\r\n" + "Expires: Tue, 26 May 2009 11:11:49 GMT\r\n" + "Cache-Control: public, max-age=2592000\r\n" + "Server: gws\r\n" + "Content-Length: 219\r\n" + "\r\n" + "\n" + "301 Moved\n" + "

301 Moved

\n" + "The document has moved\n" + "here.\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.status_code= 301 + ,.num_headers= 7 + ,.headers= + { { "Location", "http://www.google.com/" } + , { "Content-Type", "text/html; charset=UTF-8" } + , { "Date", "Sun, 26 Apr 2009 11:11:49 GMT" } + , { "Expires", "Tue, 26 May 2009 11:11:49 GMT" } + , { "Cache-Control", "public, max-age=2592000" } + , { "Server", "gws" } + , { "Content-Length", "219" } + } + ,.body= "\n" + "301 Moved\n" + "

301 Moved

\n" + "The document has moved\n" + "here.\r\n" + "\r\n" + } + +, {.name= "404 no headers no body" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 404 Not Found\r\n\r\n" + ,.should_keep_alive= TRUE + ,.status_code= 404 + ,.num_headers= 0 + ,.headers= {} + ,.body= "" + } + +, {.name= NULL } /* sentinel */ +}; + +int +request_path_cb (http_parser *_, const char *p, size_t len) +{ + strncat(messages[num_messages].request_path, p, len); + return 0; +} + +int +request_uri_cb (http_parser *_, const char *p, size_t len) +{ + strncat(messages[num_messages].request_uri, p, len); + return 0; +} + +int +query_string_cb (http_parser *_, const char *p, size_t len) +{ + strncat(messages[num_messages].query_string, p, len); + return 0; +} + +int +fragment_cb (http_parser *_, const char *p, size_t len) +{ + strncat(messages[num_messages].fragment, p, len); + return 0; +} + +int +header_field_cb (http_parser *_, const char *p, size_t len) +{ + struct message *m = &messages[num_messages]; + + if (m->last_header_element != FIELD) + m->num_headers++; + + strncat(m->headers[m->num_headers-1][0], p, len); + + m->last_header_element = FIELD; + + return 0; +} + +int +header_value_cb (http_parser *_, const char *p, size_t len) +{ + struct message *m = &messages[num_messages]; + + strncat(m->headers[m->num_headers-1][1], p, len); + + m->last_header_element = VALUE; + + return 0; +} + +int +body_cb (http_parser *_, const char *p, size_t len) +{ + strncat(messages[num_messages].body, p, len); + // printf("body_cb: '%s'\n", requests[num_messages].body); + return 0; +} + +int +message_complete_cb (http_parser *parser) +{ + messages[num_messages].method = parser->method; + messages[num_messages].status_code = parser->status_code; + + num_messages++; + return 0; +} + +int +message_begin_cb (http_parser *_) +{ + return 0; +} + +void +parser_init (enum http_parser_type type) +{ + num_messages = 0; + + http_parser_init(&parser, type); + + memset(&messages, 0, sizeof messages); + + parser.on_message_begin = message_begin_cb; + parser.on_header_field = header_field_cb; + parser.on_header_value = header_value_cb; + parser.on_path = request_path_cb; + parser.on_uri = request_uri_cb; + parser.on_fragment = fragment_cb; + parser.on_query_string = query_string_cb; + parser.on_body = body_cb; + parser.on_headers_complete = NULL; + parser.on_message_complete = message_complete_cb; +} + +void +message_eq (int index, const struct message *expected) +{ + int i; + struct message *m = &messages[index]; + + assert(m->method == expected->method); + assert(m->status_code == expected->status_code); + + assert(0 == strcmp(m->body, expected->body)); + assert(0 == strcmp(m->fragment, expected->fragment)); + assert(0 == strcmp(m->query_string, expected->query_string)); + assert(0 == strcmp(m->request_path, expected->request_path)); + assert(0 == strcmp(m->request_uri, expected->request_uri)); + assert(m->num_headers == expected->num_headers); + for (i = 0; i < m->num_headers; i++) { + assert(0 == strcmp(m->headers[i][0], expected->headers[i][0])); + assert(0 == strcmp(m->headers[i][1], expected->headers[i][1])); + } +} + +void +parse_messages (int message_count, const struct message *input_messages[]) +{ + // Concat the input messages + size_t length = 0; + int i; + for (i = 0; i < message_count; i++) { + length += strlen(input_messages[i]->raw); + } + char total[length + 1]; + total[0] = '\0'; + + for (i = 0; i < message_count; i++) { + strcat(total, input_messages[i]->raw); + } + + // Parse the stream + size_t traversed = 0; + parser_init(HTTP_REQUEST); + + traversed = http_parser_execute(&parser, total, length); + + assert(!http_parser_has_error(&parser)); + assert(num_messages == message_count); + + for (i = 0; i < message_count; i++) { + message_eq(i, input_messages[i]); + } +} + + +void +test_message (const struct message *message) +{ + size_t traversed = 0; + parser_init(message->type); + + traversed = http_parser_execute(&parser, message->raw, strlen(message->raw)); + assert(!http_parser_has_error(&parser)); + assert(num_messages == 1); + + message_eq(0, message); +} + +void +test_error (const char *buf) +{ + size_t traversed = 0; + parser_init(HTTP_REQUEST); + + traversed = http_parser_execute(&parser, buf, strlen(buf)); + + assert(http_parser_has_error(&parser)); +} + +void +test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3) +{ + char total[ strlen(r1->raw) + + strlen(r2->raw) + + strlen(r3->raw) + + 1 + ]; + total[0] = '\0'; + + strcat(total, r1->raw); + strcat(total, r2->raw); + strcat(total, r3->raw); + + size_t traversed = 0; + parser_init(HTTP_REQUEST); + + traversed = http_parser_execute(&parser, total, strlen(total)); + + assert(! http_parser_has_error(&parser) ); + assert(num_messages == 3); + message_eq(0, r1); + message_eq(1, r2); + message_eq(2, r3); +} + +/* SCAN through every possible breaking to make sure the + * parser can handle getting the content in any chunks that + * might come from the socket + */ +void +test_scan (const struct message *r1, const struct message *r2, const struct message *r3) +{ + char total[80*1024] = "\0"; + char buf1[80*1024] = "\0"; + char buf2[80*1024] = "\0"; + char buf3[80*1024] = "\0"; + + strcat(total, r1->raw); + strcat(total, r2->raw); + strcat(total, r3->raw); + + int total_len = strlen(total); + + int total_ops = (total_len - 1) * (total_len - 2) / 2; + int ops = 0 ; + + int i,j; + for (j = 2; j < total_len; j ++ ) { + for (i = 1; i < j; i ++ ) { + + if (ops % 1000 == 0) { + printf("\b\b\b\b%3.0f%%", 100 * (float)ops /(float)total_ops); + fflush(stdout); + } + ops += 1; + + parser_init(HTTP_REQUEST); + + int buf1_len = i; + strncpy(buf1, total, buf1_len); + buf1[buf1_len] = 0; + + int buf2_len = j - i; + strncpy(buf2, total+i, buf2_len); + buf2[buf2_len] = 0; + + int buf3_len = total_len - j; + strncpy(buf3, total+j, buf3_len); + buf3[buf3_len] = 0; + + /* + printf("buf1: %s - %d\n", buf1, buf1_len); + printf("buf2: %s - %d \n", buf2, buf2_len ); + printf("buf3: %s - %d\n\n", buf3, buf3_len); + */ + + http_parser_execute(&parser, buf1, buf1_len); + + assert(!http_parser_has_error(&parser)); + + http_parser_execute(&parser, buf2, buf2_len); + + assert(!http_parser_has_error(&parser)); + + http_parser_execute(&parser, buf3, buf3_len); + + assert(! http_parser_has_error(&parser)); + + assert(3 == num_messages); + + message_eq(0, r1); + message_eq(1, r2); + message_eq(2, r3); + } + } + printf("\b\b\b\b100%\n"); +} + +int +main (void) +{ + int i, j, k; + + printf("sizeof(http_parser) = %d\n", sizeof(http_parser)); + + int request_count; + for (request_count = 0; requests[request_count].name; request_count++); + + int response_count; + for (response_count = 0; responses[response_count].name; response_count++); + + + //// RESPONSES + + for (i = 0; i < response_count; i++) { + test_message(&responses[i]); + } + + + + puts("responses okay"); + + + + /// REQUESTS + + + test_error("hello world"); + test_error("GET / HTP/1.1\r\n\r\n"); + + const char *dumbfuck2 = + "GET / HTTP/1.1\r\n" + "X-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n" + "\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n" + "\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n" + "\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n" + "\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n" + "\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n" + "\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n" + "\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n" + "\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n" + "\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n" + "\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n" + "\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n" + "\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n" + "\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgHTTPAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n" + "\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n" + "\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n" + "\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n" + "\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n" + "\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n" + "\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n" + "\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n" + "\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n" + "\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n" + "\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n" + "\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n" + "\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n" + "\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n" + "\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n" + "\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n" + "\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n" + "\tRA==\r\n" + "\t-----END CERTIFICATE-----\r\n" + "\r\n"; + test_error(dumbfuck2); + + // no content-length + // error if there is a body without content length + const char *bad_get_no_headers_no_body = "GET /bad_get_no_headers_no_body/world HTTP/1.1\r\n" + "Accept: */*\r\n" + "\r\n" + "HELLO"; + test_error(bad_get_no_headers_no_body); + + + /* TODO sending junk and large headers gets rejected */ + + + /* check to make sure our predefined requests are okay */ + for (i = 0; requests[i].name; i++) { + test_message(&requests[i]); + } + + for (i = 0; i < request_count; i++) { + for (j = 0; j < request_count; j++) { + for (k = 0; k < request_count; k++) { + //printf("%d %d %d\n", i, j, k); + test_multiple3(&requests[i], &requests[j], &requests[k]); + } + } + } + + printf("request scan 1/3 "); + test_scan( &requests[GET_NO_HEADERS_NO_BODY] + , &requests[GET_ONE_HEADER_NO_BODY] + , &requests[GET_NO_HEADERS_NO_BODY] + ); + + printf("request scan 2/3 "); + test_scan( &requests[GET_FUNKY_CONTENT_LENGTH] + , &requests[POST_IDENTITY_BODY_WORLD] + , &requests[POST_CHUNKED_ALL_YOUR_BASE] + ); + + printf("request scan 3/3 "); + test_scan( &requests[TWO_CHUNKS_MULT_ZERO_END] + , &requests[CHUNKED_W_TRAILING_HEADERS] + , &requests[CHUNKED_W_BULLSHIT_AFTER_LENGTH] + ); + + puts("requests okay"); + + + return 0; +} diff --git a/deps/libebb/.gitignore b/deps/libebb/.gitignore deleted file mode 100644 index f65038b4e3..0000000000 --- a/deps/libebb/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.o -examples/hello_world -test_request_parser -ebb_request_parser.c -tags diff --git a/deps/libebb/LICENSE b/deps/libebb/LICENSE deleted file mode 100644 index 91b52e6a4c..0000000000 --- a/deps/libebb/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (c) 2008 Ryan Dahl (ry@ndahl.us) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/deps/libebb/README b/deps/libebb/README deleted file mode 100644 index d5b7ce3a4b..0000000000 --- a/deps/libebb/README +++ /dev/null @@ -1,7 +0,0 @@ -see doc/index.html and examples/hello_world.c for explanation - -webpage: http://tinyclouds.org/libebb/ -git repository: http://github.com/ry/libebb/tree/master - -To build libebb please edit config.mk to reflect your system's parameters. - diff --git a/deps/libebb/config.mk b/deps/libebb/config.mk deleted file mode 100644 index 5564bddebf..0000000000 --- a/deps/libebb/config.mk +++ /dev/null @@ -1,38 +0,0 @@ -PREFIX = $(HOME)/local/libebb - -# libev -EVINC = $(HOME)/local/libev/include -EVLIB = $(HOME)/local/libev/lib -EVLIBS = -L${EVLIB} -lev - -# GnuTLS, comment if you don't want it (necessary for HTTPS) -GNUTLSLIB = /usr/lib -GNUTLSINC = /usr/include -GNUTLSLIBS = -L${GNUTLSLIB} -lgnutls -GNUTLSFLAGS = -DHAVE_GNUTLS - -# includes and libs -INCS = -I${EVINC} -I${GNUTLSINC} -LIBS = ${EVLIBS} ${GNUTLSLIBS} -lefence - -# flags -CPPFLAGS = -DVERSION=\"$(VERSION)\" ${GNUTLSFLAGS} -CFLAGS = -O2 -g -Wall ${INCS} ${CPPFLAGS} -fPIC -LDFLAGS = -s ${LIBS} -LDOPT = -shared -SUFFIX = so -SONAME = -Wl,-soname,$(OUTPUT_LIB) - -# Solaris -#CFLAGS = -fast ${INCS} -DVERSION=\"$(VERSION)\" -fPIC -#LDFLAGS = ${LIBS} -#SONAME = - -# Darwin -# LDOPT = -dynamiclib -# SUFFIX = dylib -# SONAME = -current_version $(VERSION) -compatibility_version $(VERSION) - -# compiler and linker -CC = cc -RANLIB = ranlib diff --git a/deps/libebb/doc/icon.png b/deps/libebb/doc/icon.png deleted file mode 100644 index 702f4b5bba..0000000000 Binary files a/deps/libebb/doc/icon.png and /dev/null differ diff --git a/deps/libebb/doc/index.html b/deps/libebb/doc/index.html deleted file mode 100644 index 612c9e9fbf..0000000000 --- a/deps/libebb/doc/index.html +++ /dev/null @@ -1,240 +0,0 @@ - - - -
- -

libebb

- -

- libebb is a lightweight HTTP server library for C. It lays the - foundation for writing a web server by providing the socket juggling - and request parsing. By implementing the HTTP/1.1 grammar provided in - RFC2612, libebb understands most most valid HTTP/1.1 connections - (persistent, pipelined, and chunked requests included) and rejects - invalid or malicious requests. libebb supports SSL over HTTP. -

- -

- The library embraces a minimalistic single-threaded evented design. - No control is removed from the user. For example, all allocations are - done through callbacks so that the user might implement in optimal - ways for their specific application. By design libebb is not - thread-safe and all provided callbacks must not block. libebb uses - the high-performance - libev event loop, but does not control it. The user of the library may - start and stop the loop at will, they may attach thier own watchers. -

- -

- libebb depends on POSIX sockets, libev, and optionally GnuTLS. -

- -

- libebb is in the early stages of development and probably contains - many bugs. The API is subject to radical changes. If you're - interested checkout - the source code and join the mailing - list. A release will be made when it proves stable. -

- -

libebb is released under the - X11 license.

- -

Usage

- -

- libebb is a simple API, mostly it is providing callbacks. There are - two types of callbacks that one will work with: -

- -
    -
  • callbacks to allocate and initialize data for libebb. These are - named new_* like new_connection and - new_request
  • -
  • callbacks which happen on an event and might provide a pointer to - a chunk of data. These are named on_* like - on_body and on_close.
  • -
- -

- In libebb there are three important classes: ebb_server, - ebb_connection, and ebb_request. - Each server has many peer connections. Each peer connection may have many - requests. - There are two additional classes ebb_buf and ebb_request_parser - which may or may not be useful. -

- -

ebb_server

-

- ebb_server represents a single web server listening on a - single port. The user must allocate the structure themselves, then - call ebb_server_init() and provide a libev event loop. - ebb_server_set_secure() will make the server understand - HTTPS connections. -

- -

- After initialized the ebb_server_listen_on_port() can be - called to open the server up to new connections. libebb does not - control the event loop, it is the user's responsibility to start the - event loop (using ev_loop()) after - ebb_server_listen_on_port() is called. -

- -

- To accept connections you must provide the new server with a callback - called new_connection. This callback must return an allocated - and initialized ebb_connection structure. - To set this callback do -

- -
my_server->new_connection = my_new_connection_callback;
- -

- Additional documentation can be found in ebb.h -

- -

ebb_connection

- -

- This structure contains information and callbacks for a single client - connection. It is allocated and initialized through the - new_connection callback in ebb_server. - To initialize a newly allocated ebb_connection use - ebb_connection_init(). -

- -

- After ebb_connection_init() is called a number of - callbacks can be set: new_request, new_buf, - on_timeout, and on_close. -

- -

- When an ebb_connection is returned to an - ebb_server, data is immediately data is read from the - socket. This data must be stored somewhere. Because libebb is - agnostic about allocation decisions, it passes this off to the user in - the form of a callback: connection->new_buf. This - callback returns a newly allocated and initialized - ebb_buf structure. How much libebb attempts to read from - the socket is determined by how large the returned - ebb_buf structure is. Using new_buf is - optional. By default libebb reads data into a static buffer - (allocated at compile time), writing over it on each read. In many - web server using the static buffer will be sufficent because callbacks - made during the parsing will buffer the data elsewhere. Providing a - new_buf callback is necessary only if you want to save - the raw data coming from the socket. -

- -

- The new_request callback is called at the beginning of a - request. It must return a newly allocated and initialized - ebb_request structure. Because HTTP/1.1 supports peristant - connections, there may be many requests per connection. -

- -

- You may access the file descriptor for the client socket inside the - ebb_connection structure. Writing the response, in valid - HTTP, is the user's responsibility. Remember, requests must be - returned to client in the same order that they were received. -

- -

- A convience function, ebb_connection_write, is provided - which will write a single string to the peer. You may use - this function or you may write to the file descriptor directly. -

- -

- To close a peer connection use - ebb_connnection_schedule_close(). Because SSL may require - some additional communication to close the connection properly, the - file descriptor cannot be closed immediately. The - on_close callback will be made when the peer socket is - finally closed. - Only once on_close is called may the - user free the ebb_connection structure. -

- - -

ebb_request

- -

- This structure provides information about a request. For example, - request->method == EBB_POST would mean the method of - the request is POST. There are also many callbacks - which can be set to handle data from a request as it is parsed. -

- -

- The on_uri callback and all other - ebb_element_cb callbacks provide pointers to request - data. The annoying thing is they do not necessarily provide a - complete string. This is because the reads from the socket may not - contain an entire request and for efficency libebb does not attempt to - buffer the data. Theoretically, one might receive an - on_uri callback 10 times, each providing just a single - character of the request's URI. See ebb_request_parser.h for - a full list of callbacks that you may provide. (If you don't set them, - they are ignored.) -

- -

- The on_complete callback is called at the end of - each request. - Only once on_complete is called may the - user free the ebb_request structure. -

- -

Example

- -

- A simple example is provided in examples/hello_world.c. -

- -
- diff --git a/deps/libebb/ebb.c b/deps/libebb/ebb.c deleted file mode 100644 index a4c5e78ac6..0000000000 --- a/deps/libebb/ebb.c +++ /dev/null @@ -1,798 +0,0 @@ -/* This file is part of libebb. - * - * Copyright (c) 2008 Ryan Dahl (ry@ndahl.us) - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include -#include -#include -#include -#include -#include /* TCP_NODELAY */ -#include /* inet_ntoa */ -#include /* inet_ntoa */ -#include -#include /* perror */ -#include /* perror */ -#include /* for the default methods */ -#include - -#include "ebb.h" -#include "ebb_request_parser.h" -#ifdef HAVE_GNUTLS -# include -# include "rbtree.h" /* for session_cache */ -#endif - -#ifndef TRUE -# define TRUE 1 -#endif -#ifndef FALSE -# define FALSE 0 -#endif -#ifndef MIN -# define MIN(a,b) (a < b ? a : b) -#endif - -#define error(FORMAT, ...) fprintf(stderr, "error: " FORMAT "\n", ##__VA_ARGS__) - -#define CONNECTION_HAS_SOMETHING_TO_WRITE (connection->to_write != NULL) - -static void -set_nonblock (int fd) -{ - int flags = fcntl(fd, F_GETFL, 0); - int r = fcntl(fd, F_SETFL, flags | O_NONBLOCK); - assert(0 <= r && "Setting socket non-block failed!"); -} - -static ssize_t -nosigpipe_push(void *data, const void *buf, size_t len) -{ - int fd = (int)data; - int flags = 0; -#ifdef MSG_NOSIGNAL - flags = MSG_NOSIGNAL; -#endif - return send(fd, buf, len, flags); -} - -static void -close_connection(ebb_connection *connection) -{ -#ifdef HAVE_GNUTLS - if(connection->server->secure) - ev_io_stop(connection->server->loop, &connection->handshake_watcher); -#endif - ev_io_stop(connection->server->loop, &connection->read_watcher); - ev_io_stop(connection->server->loop, &connection->write_watcher); - ev_timer_stop(connection->server->loop, &connection->timeout_watcher); - - if(0 > close(connection->fd)) - error("problem closing connection fd"); - - connection->open = FALSE; - - if(connection->on_close) - connection->on_close(connection); - /* No access to the connection past this point! - * The user is allowed to free in the callback - */ -} - -#ifdef HAVE_GNUTLS -#define GNUTLS_NEED_WRITE (gnutls_record_get_direction(connection->session) == 1) -#define GNUTLS_NEED_READ (gnutls_record_get_direction(connection->session) == 0) - -#define EBB_MAX_SESSION_KEY 32 -#define EBB_MAX_SESSION_VALUE 512 - -struct session_cache { - struct rbtree_node_t node; - - gnutls_datum_t key; - gnutls_datum_t value; - - char key_storage[EBB_MAX_SESSION_KEY]; - char value_storage[EBB_MAX_SESSION_VALUE]; -}; - -static int -session_cache_compare (void *left, void *right) -{ - gnutls_datum_t *left_key = left; - gnutls_datum_t *right_key = right; - if(left_key->size < right_key->size) - return -1; - else if(left_key->size > right_key->size) - return 1; - else - return memcmp( left_key->data - , right_key->data - , MIN(left_key->size, right_key->size) - ); -} - -static int -session_cache_store(void *data, gnutls_datum_t key, gnutls_datum_t value) -{ - rbtree tree = data; - - if( tree == NULL - || key.size > EBB_MAX_SESSION_KEY - || value.size > EBB_MAX_SESSION_VALUE - ) return -1; - - struct session_cache *cache = gnutls_malloc(sizeof(struct session_cache)); - - memcpy (cache->key_storage, key.data, key.size); - cache->key.size = key.size; - cache->key.data = (void*)cache->key_storage; - - memcpy (cache->value_storage, value.data, value.size); - cache->value.size = value.size; - cache->value.data = (void*)cache->value_storage; - - cache->node.key = &cache->key; - cache->node.value = &cache; - - rbtree_insert(tree, (rbtree_node)cache); - - //printf("session_cache_store\n"); - - return 0; -} - -static gnutls_datum_t -session_cache_retrieve (void *data, gnutls_datum_t key) -{ - rbtree tree = data; - gnutls_datum_t res = { NULL, 0 }; - struct session_cache *cache = rbtree_lookup(tree, &key); - - if(cache == NULL) - return res; - - res.size = cache->value.size; - res.data = gnutls_malloc (res.size); - if(res.data == NULL) - return res; - - memcpy(res.data, cache->value.data, res.size); - - //printf("session_cache_retrieve\n"); - - return res; -} - -static int -session_cache_remove (void *data, gnutls_datum_t key) -{ - rbtree tree = data; - - if(tree == NULL) - return -1; - - struct session_cache *cache = (struct session_cache *)rbtree_delete(tree, &key); - if(cache == NULL) - return -1; - - gnutls_free(cache); - - //printf("session_cache_remove\n"); - - return 0; -} - -static void -on_handshake(struct ev_loop *loop ,ev_io *watcher, int revents) -{ - ebb_connection *connection = watcher->data; - - //printf("on_handshake\n"); - - assert(ev_is_active(&connection->timeout_watcher)); - assert(!ev_is_active(&connection->read_watcher)); - assert(!ev_is_active(&connection->write_watcher)); - - if(EV_ERROR & revents) { - error("on_handshake() got error event, closing connection.n"); - goto error; - } - - int r = gnutls_handshake(connection->session); - if(r < 0) { - if(gnutls_error_is_fatal(r)) goto error; - if(r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN) - ev_io_set( watcher - , connection->fd - , (GNUTLS_NEED_WRITE ? EV_WRITE : EV_READ) - ); - return; - } - - ebb_connection_reset_timeout(connection); - ev_io_stop(loop, watcher); - - ev_io_start(loop, &connection->read_watcher); - if(CONNECTION_HAS_SOMETHING_TO_WRITE) - ev_io_start(loop, &connection->write_watcher); - - return; -error: - close_connection(connection); -} - -#endif /* HAVE_GNUTLS */ - - -/* Internal callback - * called by connection->timeout_watcher - */ -static void -on_timeout(struct ev_loop *loop, ev_timer *watcher, int revents) -{ - ebb_connection *connection = watcher->data; - - assert(watcher == &connection->timeout_watcher); - - //printf("on_timeout\n"); - - /* if on_timeout returns true, we don't time out */ - if(connection->on_timeout) { - int r = connection->on_timeout(connection); - - if(r == EBB_AGAIN) { - ebb_connection_reset_timeout(connection); - return; - } - } - - ebb_connection_schedule_close(connection); -} - -/* Internal callback - * called by connection->read_watcher - */ -static void -on_readable(struct ev_loop *loop, ev_io *watcher, int revents) -{ - ebb_connection *connection = watcher->data; - char recv_buffer[TCP_MAXWIN]; - ssize_t recved; - - //printf("on_readable\n"); - // TODO -- why is this broken? - //assert(ev_is_active(&connection->timeout_watcher)); - assert(watcher == &connection->read_watcher); - - if(EV_ERROR & revents) { - error("on_readable() got error event, closing connection."); - goto error; - } - -#ifdef HAVE_GNUTLS - assert(!ev_is_active(&connection->handshake_watcher)); - - if(connection->server->secure) { - recved = gnutls_record_recv( connection->session - , recv_buffer - , TCP_MAXWIN - ); - if(recved <= 0) { - if(gnutls_error_is_fatal(recved)) goto error; - if( (recved == GNUTLS_E_INTERRUPTED || recved == GNUTLS_E_AGAIN) - && GNUTLS_NEED_WRITE - ) ev_io_start(loop, &connection->write_watcher); - return; - } - } else { -#endif /* HAVE_GNUTLS */ - - recved = recv(connection->fd, recv_buffer, TCP_MAXWIN, 0); - if(recved <= 0) goto error; - -#ifdef HAVE_GNUTLS - } -#endif /* HAVE_GNUTLS */ - - ebb_connection_reset_timeout(connection); - - ebb_request_parser_execute(&connection->parser, recv_buffer, recved); - - /* parse error? just drop the client. screw the 400 response */ - if(ebb_request_parser_has_error(&connection->parser)) goto error; - return; -error: - ebb_connection_schedule_close(connection); -} - -/* Internal callback - * called by connection->write_watcher - */ -static void -on_writable(struct ev_loop *loop, ev_io *watcher, int revents) -{ - ebb_connection *connection = watcher->data; - ssize_t sent; - - //printf("on_writable\n"); - - assert(CONNECTION_HAS_SOMETHING_TO_WRITE); - assert(connection->written <= connection->to_write_len); - // TODO -- why is this broken? - //assert(ev_is_active(&connection->timeout_watcher)); - assert(watcher == &connection->write_watcher); - - if(connection->to_write == 0) - goto stop_writing; - -#ifdef HAVE_GNUTLS - assert(!ev_is_active(&connection->handshake_watcher)); - - if(connection->server->secure) { - sent = gnutls_record_send( connection->session - , connection->to_write + connection->written - , connection->to_write_len - connection->written - ); - if(sent < 0) { - if(gnutls_error_is_fatal(sent)) goto error; - if( (sent == GNUTLS_E_INTERRUPTED || sent == GNUTLS_E_AGAIN) - && GNUTLS_NEED_READ - ) ev_io_stop(loop, watcher); - return; - } - } else { -#endif /* HAVE_GNUTLS */ - - sent = nosigpipe_push( (void*)connection->fd - , connection->to_write + connection->written - , connection->to_write_len - connection->written - ); - if(sent < 0) goto error; - if(sent == 0) return; - -#ifdef HAVE_GNUTLS - } -#endif /* HAVE_GNUTLS */ - - ebb_connection_reset_timeout(connection); - - connection->written += sent; - - if(connection->written == connection->to_write_len) { - goto stop_writing; - } - return; -stop_writing: - ev_io_stop(loop, watcher); - connection->to_write = NULL; - - if(connection->after_write_cb) - connection->after_write_cb(connection); - return; -error: - error("close connection on write."); - ebb_connection_schedule_close(connection); -} - -#ifdef HAVE_GNUTLS - -static void -on_goodbye_tls(struct ev_loop *loop, ev_io *watcher, int revents) -{ - ebb_connection *connection = watcher->data; - assert(watcher == &connection->goodbye_tls_watcher); - - if(EV_ERROR & revents) { - error("on_goodbye() got error event, closing connection."); - goto die; - } - - int r = gnutls_bye(connection->session, GNUTLS_SHUT_RDWR); - if(r < 0) { - if(gnutls_error_is_fatal(r)) goto die; - if(r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN) - ev_io_set( watcher - , connection->fd - , (GNUTLS_NEED_WRITE ? EV_WRITE : EV_READ) - ); - return; - } - -die: - ev_io_stop(loop, watcher); - if(connection->session) - gnutls_deinit(connection->session); - close_connection(connection); -} -#endif /* HAVE_GNUTLS*/ - -static void -on_goodbye(struct ev_loop *loop, ev_timer *watcher, int revents) -{ - ebb_connection *connection = watcher->data; - assert(watcher == &connection->goodbye_watcher); - - close_connection(connection); -} - - -static ebb_request* -new_request_wrapper(void *data) -{ - ebb_connection *connection = data; - if(connection->new_request) - return connection->new_request(connection); - return NULL; -} - -/* Internal callback - * Called by server->connection_watcher. - */ -static void -on_connection(struct ev_loop *loop, ev_io *watcher, int revents) -{ - ebb_server *server = watcher->data; - - //printf("on connection!\n"); - - assert(server->listening); - assert(server->loop == loop); - assert(&server->connection_watcher == watcher); - - if(EV_ERROR & revents) { - error("on_connection() got error event, closing server."); - ebb_server_unlisten(server); - return; - } - - struct sockaddr_in addr; // connector's address information - socklen_t addr_len = sizeof(addr); - int fd = accept( server->fd - , (struct sockaddr*) & addr - , & addr_len - ); - if(fd < 0) { - perror("accept()"); - return; - } - - ebb_connection *connection = NULL; - if(server->new_connection) - connection = server->new_connection(server, &addr); - if(connection == NULL) { - close(fd); - return; - } - - set_nonblock(fd); - connection->fd = fd; - connection->open = TRUE; - connection->server = server; - memcpy(&connection->sockaddr, &addr, addr_len); - if(server->port[0] != '\0') - connection->ip = inet_ntoa(connection->sockaddr.sin_addr); - -#ifdef SO_NOSIGPIPE - int arg = 1; - setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &arg, sizeof(int)); -#endif - -#ifdef HAVE_GNUTLS - if(server->secure) { - gnutls_init(&connection->session, GNUTLS_SERVER); - gnutls_transport_set_lowat(connection->session, 0); - gnutls_set_default_priority(connection->session); - gnutls_credentials_set(connection->session, GNUTLS_CRD_CERTIFICATE, connection->server->credentials); - - gnutls_transport_set_ptr(connection->session, (gnutls_transport_ptr) fd); - gnutls_transport_set_push_function(connection->session, nosigpipe_push); - - gnutls_db_set_ptr (connection->session, &server->session_cache); - gnutls_db_set_store_function (connection->session, session_cache_store); - gnutls_db_set_retrieve_function (connection->session, session_cache_retrieve); - gnutls_db_set_remove_function (connection->session, session_cache_remove); - } - - ev_io_set(&connection->handshake_watcher, connection->fd, EV_READ | EV_WRITE); -#endif /* HAVE_GNUTLS */ - - /* Note: not starting the write watcher until there is data to be written */ - ev_io_set(&connection->write_watcher, connection->fd, EV_WRITE); - ev_io_set(&connection->read_watcher, connection->fd, EV_READ); - /* XXX: seperate error watcher? */ - - ev_timer_again(loop, &connection->timeout_watcher); - -#ifdef HAVE_GNUTLS - if(server->secure) { - ev_io_start(loop, &connection->handshake_watcher); - return; - } -#endif - - ev_io_start(loop, &connection->read_watcher); -} - -/** - * Begin the server listening on a file descriptor. This DOES NOT start the - * event loop. Start the event loop after making this call. - */ -int -ebb_server_listen_on_fd(ebb_server *server, const int fd) -{ - assert(server->listening == FALSE); - - if (listen(fd, EBB_MAX_CONNECTIONS) < 0) { - perror("listen()"); - return -1; - } - - set_nonblock(fd); /* XXX superfluous? */ - - server->fd = fd; - server->listening = TRUE; - - ev_io_set (&server->connection_watcher, server->fd, EV_READ); - ev_io_start (server->loop, &server->connection_watcher); - - return server->fd; -} - - -/** - * Begin the server listening on a file descriptor This DOES NOT start the - * event loop. Start the event loop after making this call. - */ -int -ebb_server_listen_on_port(ebb_server *server, const int port) -{ - int fd = -1; - struct linger ling = {0, 0}; - struct sockaddr_in addr; - int flags = 1; - - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - perror("socket()"); - goto error; - } - - flags = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags)); - setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)); - setsockopt(fd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling)); - - /* XXX: Sending single byte chunks in a response body? Perhaps there is a - * need to enable the Nagel algorithm dynamically. For now disabling. - */ - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)); - - /* the memset call clears nonstandard fields in some impementations that - * otherwise mess things up. - */ - memset(&addr, 0, sizeof(addr)); - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - perror("bind()"); - goto error; - } - - int ret = ebb_server_listen_on_fd(server, fd); - if (ret >= 0) { - sprintf(server->port, "%d", port); - } - return ret; -error: - if(fd > 0) close(fd); - return -1; -} - -/** - * Stops the server. Will not accept new connections. Does not drop - * existing connections. - */ -void -ebb_server_unlisten(ebb_server *server) -{ - if(server->listening) { - ev_io_stop(server->loop, &server->connection_watcher); - close(server->fd); - server->port[0] = '\0'; - server->listening = FALSE; - } -} - -/** - * Initialize an ebb_server structure. After calling ebb_server_init set - * the callback server->new_connection and, optionally, callback data - * server->data. The new connection MUST be initialized with - * ebb_connection_init before returning it to the server. - * - * @param server the server to initialize - * @param loop a libev loop - */ -void -ebb_server_init(ebb_server *server, struct ev_loop *loop) -{ - server->loop = loop; - server->listening = FALSE; - server->port[0] = '\0'; - server->fd = -1; - server->connection_watcher.data = server; - ev_init (&server->connection_watcher, on_connection); - server->secure = FALSE; - -#ifdef HAVE_GNUTLS - rbtree_init(&server->session_cache, session_cache_compare); - server->credentials = NULL; -#endif - - server->new_connection = NULL; - server->data = NULL; -} - - -#ifdef HAVE_GNUTLS -/* similar to server_init. - * - * the user of secure server might want to set additional callbacks from - * GNUTLS. In particular - * gnutls_global_set_mem_functions() - * gnutls_global_set_log_function() - * Also see the note above ebb_connection_init() about setting gnutls cache - * access functions - * - * cert_file: the filename of a PEM certificate file - * - * key_file: the filename of a private key. Currently only PKCS-1 encoded - * RSA and DSA private keys are accepted. - */ -int -ebb_server_set_secure (ebb_server *server, const char *cert_file, const char *key_file) -{ - server->secure = TRUE; - gnutls_global_init(); - gnutls_certificate_allocate_credentials(&server->credentials); - /* todo gnutls_certificate_free_credentials */ - int r = gnutls_certificate_set_x509_key_file( server->credentials - , cert_file - , key_file - , GNUTLS_X509_FMT_PEM - ); - if(r < 0) { - error("loading certificates"); - return -1; - } - return 1; -} -#endif /* HAVE_GNUTLS */ - -/** - * Initialize an ebb_connection structure. After calling this function you - * must setup callbacks for the different actions the server can take. See - * server.h for which callbacks are availible. - * - * This should be called immediately after allocating space for a new - * ebb_connection structure. Most likely, this will only be called within - * the ebb_server->new_connection callback which you supply. - * - * If using SSL do consider setting - * gnutls_db_set_retrieve_function (connection->session, _); - * gnutls_db_set_remove_function (connection->session, _); - * gnutls_db_set_store_function (connection->session, _); - * gnutls_db_set_ptr (connection->session, _); - * To provide a better means of storing SSL session caches. libebb provides - * only a simple default implementation. - * - * @param connection the connection to initialize - * @param timeout the timeout in seconds - */ -void -ebb_connection_init(ebb_connection *connection) -{ - connection->fd = -1; - connection->server = NULL; - connection->ip = NULL; - connection->open = FALSE; - - ebb_request_parser_init( &connection->parser ); - connection->parser.data = connection; - connection->parser.new_request = new_request_wrapper; - - ev_init (&connection->write_watcher, on_writable); - connection->write_watcher.data = connection; - connection->to_write = NULL; - - ev_init(&connection->read_watcher, on_readable); - connection->read_watcher.data = connection; - -#ifdef HAVE_GNUTLS - connection->handshake_watcher.data = connection; - ev_init(&connection->handshake_watcher, on_handshake); - - ev_init(&connection->goodbye_tls_watcher, on_goodbye_tls); - connection->goodbye_tls_watcher.data = connection; - - connection->session = NULL; -#endif /* HAVE_GNUTLS */ - - ev_timer_init(&connection->goodbye_watcher, on_goodbye, 0., 0.); - connection->goodbye_watcher.data = connection; - - ev_timer_init(&connection->timeout_watcher, on_timeout, 0., EBB_DEFAULT_TIMEOUT); - connection->timeout_watcher.data = connection; - - connection->new_request = NULL; - connection->on_timeout = NULL; - connection->on_close = NULL; - connection->data = NULL; -} - -void -ebb_connection_schedule_close (ebb_connection *connection) -{ -#ifdef HAVE_GNUTLS - if(connection->server->secure) { - ev_io_set(&connection->goodbye_tls_watcher, connection->fd, EV_READ | EV_WRITE); - ev_io_start(connection->server->loop, &connection->goodbye_tls_watcher); - return; - } -#endif - ev_timer_start(connection->server->loop, &connection->goodbye_watcher); -} - -/* - * Resets the timeout to stay alive for another connection->timeout seconds - */ -void -ebb_connection_reset_timeout(ebb_connection *connection) -{ - ev_timer_again(connection->server->loop, &connection->timeout_watcher); -} - -/** - * Writes a string to the socket. This is actually sets a watcher - * which may take multiple iterations to write the entire string. - * - * This can only be called once at a time. If you call it again - * while the connection is writing another buffer the ebb_connection_write - * will return FALSE and ignore the request. - */ -int -ebb_connection_write (ebb_connection *connection, const char *buf, size_t len, ebb_after_write_cb cb) -{ - if(ev_is_active(&connection->write_watcher)) - return FALSE; - assert(!CONNECTION_HAS_SOMETHING_TO_WRITE); - connection->to_write = buf; - connection->to_write_len = len; - connection->written = 0; - connection->after_write_cb = cb; - ev_io_start(connection->server->loop, &connection->write_watcher); - return TRUE; -} - diff --git a/deps/libebb/ebb.h b/deps/libebb/ebb.h deleted file mode 100644 index e5e90b495e..0000000000 --- a/deps/libebb/ebb.h +++ /dev/null @@ -1,120 +0,0 @@ -/* This file is part of libebb. - * - * Copyright (c) 2008 Ryan Dahl (ry@ndahl.us) - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef EBB_H -#define EBB_H - -#include -#include -#include -#ifdef HAVE_GNUTLS -# include -# include "rbtree.h" /* for ebb_server.session_cache */ -#endif -#include "ebb_request_parser.h" - -#define EBB_MAX_CONNECTIONS 1024 -#define EBB_DEFAULT_TIMEOUT 30.0 - -#define EBB_AGAIN 0 -#define EBB_STOP 1 - -typedef struct ebb_server ebb_server; -typedef struct ebb_connection ebb_connection; -typedef void (*ebb_after_write_cb) (ebb_connection *connection); -typedef void (*ebb_connection_cb)(ebb_connection *connection, void *data); - -struct ebb_server { - int fd; /* ro */ - struct sockaddr_in sockaddr; /* ro */ - socklen_t socklen; /* ro */ - char port[6]; /* ro */ - struct ev_loop *loop; /* ro */ - unsigned listening:1; /* ro */ - unsigned secure:1; /* ro */ -#ifdef HAVE_GNUTLS - gnutls_certificate_credentials_t credentials; /* private */ - struct rbtree_t session_cache; /* private */ -#endif - ev_io connection_watcher; /* private */ - - /* Public */ - - /* Allocates and initializes an ebb_connection. NULL by default. */ - ebb_connection* (*new_connection) (ebb_server*, struct sockaddr_in*); - - void *data; -}; - -struct ebb_connection { - int fd; /* ro */ - struct sockaddr_in sockaddr; /* ro */ - socklen_t socklen; /* ro */ - ebb_server *server; /* ro */ - char *ip; /* ro */ - unsigned open:1; /* ro */ - - const char *to_write; /* ro */ - size_t to_write_len; /* ro */ - size_t written; /* ro */ - ebb_after_write_cb after_write_cb; /* ro */ - - ebb_request_parser parser; /* private */ - ev_io write_watcher; /* private */ - ev_io read_watcher; /* private */ - ev_timer timeout_watcher; /* private */ - ev_timer goodbye_watcher; /* private */ -#ifdef HAVE_GNUTLS - ev_io handshake_watcher; /* private */ - gnutls_session_t session; /* private */ - ev_io goodbye_tls_watcher; /* private */ -#endif - - /* Public */ - - ebb_request* (*new_request) (ebb_connection*); - - /* Returns EBB_STOP or EBB_AGAIN. NULL by default. */ - int (*on_timeout) (ebb_connection*); - - void (*on_close) (ebb_connection*); - - void *data; -}; - -void ebb_server_init (ebb_server *server, struct ev_loop *loop); -#ifdef HAVE_GNUTLS -int ebb_server_set_secure (ebb_server *server, const char *cert_file, - const char *key_file); -#endif -int ebb_server_listen_on_port (ebb_server *server, const int port); -int ebb_server_listen_on_fd (ebb_server *server, const int sfd); -void ebb_server_unlisten (ebb_server *server); - -void ebb_connection_init (ebb_connection *); -void ebb_connection_schedule_close (ebb_connection *); -void ebb_connection_reset_timeout (ebb_connection *); -int ebb_connection_write (ebb_connection *, const char *buf, size_t len, ebb_after_write_cb); - -#endif diff --git a/deps/libebb/ebb_request_parser.h b/deps/libebb/ebb_request_parser.h deleted file mode 100644 index 93d502f4b5..0000000000 --- a/deps/libebb/ebb_request_parser.h +++ /dev/null @@ -1,117 +0,0 @@ -/* This file is part of the libebb web server library - * - * Copyright (c) 2008 Ryan Dahl (ry@ndahl.us) - * All rights reserved. - * - * This parser is based on code from Zed Shaw's Mongrel. - * Copyright (c) 2005 Zed A. Shaw - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef ebb_request_parser_h -#define ebb_request_parser_h -#ifdef __cplusplus -extern "C" { -#endif - - -#include - -typedef struct ebb_request ebb_request; -typedef struct ebb_request_parser ebb_request_parser; -typedef void (*ebb_header_cb)(ebb_request*, const char *at, size_t length, int header_index); -typedef void (*ebb_element_cb)(ebb_request*, const char *at, size_t length); - -#define EBB_MAX_MULTIPART_BOUNDARY_LEN 20 - -/* HTTP Methods */ -#define EBB_COPY 0x00000001 -#define EBB_DELETE 0x00000002 -#define EBB_GET 0x00000004 -#define EBB_HEAD 0x00000008 -#define EBB_LOCK 0x00000010 -#define EBB_MKCOL 0x00000020 -#define EBB_MOVE 0x00000040 -#define EBB_OPTIONS 0x00000080 -#define EBB_POST 0x00000100 -#define EBB_PROPFIND 0x00000200 -#define EBB_PROPPATCH 0x00000400 -#define EBB_PUT 0x00000800 -#define EBB_TRACE 0x00001000 -#define EBB_UNLOCK 0x00002000 - -/* Transfer Encodings */ -#define EBB_IDENTITY 0x00000001 -#define EBB_CHUNKED 0x00000002 - -struct ebb_request { - int method; - int transfer_encoding; /* ro */ - int expect_continue; /* ro */ - unsigned int version_major; /* ro */ - unsigned int version_minor; /* ro */ - int number_of_headers; /* ro */ - int keep_alive; /* private - use ebb_request_should_keep_alive */ - size_t content_length; /* ro - 0 if unknown */ - size_t body_read; /* ro */ - - /* Public - ordered list of callbacks */ - ebb_element_cb on_path; - ebb_element_cb on_query_string; - ebb_element_cb on_uri; - ebb_element_cb on_fragment; - ebb_header_cb on_header_field; - ebb_header_cb on_header_value; - void (*on_headers_complete)(ebb_request *); - ebb_element_cb on_body; - void (*on_complete)(ebb_request *); - void *data; -}; - -struct ebb_request_parser { - int cs; /* private */ - size_t chunk_size; /* private */ - unsigned eating:1; /* private */ - ebb_request *current_request; /* ro */ - const char *header_field_mark; - const char *header_value_mark; - const char *query_string_mark; - const char *path_mark; - const char *uri_mark; - const char *fragment_mark; - - /* Public */ - ebb_request* (*new_request)(void*); - void *data; -}; - -void ebb_request_parser_init(ebb_request_parser *parser); -size_t ebb_request_parser_execute(ebb_request_parser *parser, const char *data, size_t len); -int ebb_request_parser_has_error(ebb_request_parser *parser); -int ebb_request_parser_is_finished(ebb_request_parser *parser); -void ebb_request_init(ebb_request *); -int ebb_request_should_keep_alive(ebb_request *request); -#define ebb_request_has_body(request) \ - (request->transfer_encoding == EBB_CHUNKED || request->content_length > 0 ) - -#ifdef __cplusplus -} -#endif -#endif diff --git a/deps/libebb/ebb_request_parser.rl b/deps/libebb/ebb_request_parser.rl deleted file mode 100644 index 63e36a8a49..0000000000 --- a/deps/libebb/ebb_request_parser.rl +++ /dev/null @@ -1,413 +0,0 @@ -/* This file is part of the libebb web server library - * - * Copyright (c) 2008 Ryan Dahl (ry@ndahl.us) - * All rights reserved. - * - * This parser is based on code from Zed Shaw's Mongrel. - * Copyright (c) 2005 Zed A. Shaw - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "ebb_request_parser.h" - -#include -#include - -static int unhex[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - }; -#define TRUE 1 -#define FALSE 0 -#define MIN(a,b) (a < b ? a : b) - -#define REMAINING (pe - p) -#define CURRENT (parser->current_request) -#define CONTENT_LENGTH (parser->current_request->content_length) -#define CALLBACK(FOR) \ - if(parser->FOR##_mark && CURRENT->on_##FOR) { \ - CURRENT->on_##FOR( CURRENT \ - , parser->FOR##_mark \ - , p - parser->FOR##_mark \ - ); \ - } -#define HEADER_CALLBACK(FOR) \ - if(parser->FOR##_mark && CURRENT->on_##FOR) { \ - CURRENT->on_##FOR( CURRENT \ - , parser->FOR##_mark \ - , p - parser->FOR##_mark \ - , CURRENT->number_of_headers \ - ); \ - } -#define END_REQUEST \ - if(CURRENT->on_complete) \ - CURRENT->on_complete(CURRENT); \ - CURRENT = NULL; - - -%%{ - machine ebb_request_parser; - - action mark_header_field { parser->header_field_mark = p; } - action mark_header_value { parser->header_value_mark = p; } - action mark_fragment { parser->fragment_mark = p; } - action mark_query_string { parser->query_string_mark = p; } - action mark_request_path { parser->path_mark = p; } - action mark_request_uri { parser->uri_mark = p; } - - action write_field { - HEADER_CALLBACK(header_field); - parser->header_field_mark = NULL; - } - - action write_value { - HEADER_CALLBACK(header_value); - parser->header_value_mark = NULL; - } - - action request_uri { - CALLBACK(uri); - parser->uri_mark = NULL; - } - - action fragment { - CALLBACK(fragment); - parser->fragment_mark = NULL; - } - - action query_string { - CALLBACK(query_string); - parser->query_string_mark = NULL; - } - - action request_path { - CALLBACK(path); - parser->path_mark = NULL; - } - - action content_length { - CURRENT->content_length *= 10; - CURRENT->content_length += *p - '0'; - } - - action use_identity_encoding { CURRENT->transfer_encoding = EBB_IDENTITY; } - action use_chunked_encoding { CURRENT->transfer_encoding = EBB_CHUNKED; } - - action set_keep_alive { CURRENT->keep_alive = TRUE; } - action set_not_keep_alive { CURRENT->keep_alive = FALSE; } - - action expect_continue { - CURRENT->expect_continue = TRUE; - } - - action trailer { - /* not implemenetd yet. (do requests even have trailing headers?) */ - } - - action version_major { - CURRENT->version_major *= 10; - CURRENT->version_major += *p - '0'; - } - - action version_minor { - CURRENT->version_minor *= 10; - CURRENT->version_minor += *p - '0'; - } - - action end_header_line { - CURRENT->number_of_headers++; - } - - action end_headers { - if(CURRENT->on_headers_complete) - CURRENT->on_headers_complete(CURRENT); - } - - action add_to_chunk_size { - parser->chunk_size *= 16; - parser->chunk_size += unhex[(int)*p]; - } - - action skip_chunk_data { - skip_body(&p, parser, MIN(parser->chunk_size, REMAINING)); - fhold; - if(parser->chunk_size > REMAINING) { - fbreak; - } else { - fgoto chunk_end; - } - } - - action end_chunked_body { - END_REQUEST; - fnext main; - } - - action start_req { - assert(CURRENT == NULL); - CURRENT = parser->new_request(parser->data); - } - - action body_logic { - if(CURRENT->transfer_encoding == EBB_CHUNKED) { - fnext ChunkedBody; - } else { - /* this is pretty stupid. i'd prefer to combine this with skip_chunk_data */ - parser->chunk_size = CURRENT->content_length; - p += 1; - skip_body(&p, parser, MIN(REMAINING, CURRENT->content_length)); - fhold; - if(parser->chunk_size > REMAINING) { - fbreak; - } - } - } - -# -## -### -#### HTTP/1.1 STATE MACHINE -### -## RequestHeaders and character types are from -# Zed Shaw's beautiful Mongrel parser. - - CRLF = "\r\n"; - -# character types - CTL = (cntrl | 127); - safe = ("$" | "-" | "_" | "."); - extra = ("!" | "*" | "'" | "(" | ")" | ","); - reserved = (";" | "/" | "?" | ":" | "@" | "&" | "=" | "+"); - unsafe = (CTL | " " | "\"" | "#" | "%" | "<" | ">"); - national = any -- (alpha | digit | reserved | extra | safe | unsafe); - unreserved = (alpha | digit | safe | extra | national); - escape = ("%" xdigit xdigit); - uchar = (unreserved | escape); - pchar = (uchar | ":" | "@" | "&" | "=" | "+"); - tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t"); - -# elements - token = (ascii -- (CTL | tspecials)); - quote = "\""; -# qdtext = token -- "\""; -# quoted_pair = "\" ascii; -# quoted_string = "\"" (qdtext | quoted_pair )* "\""; - -# headers - - Method = ( "COPY" %{ CURRENT->method = EBB_COPY; } - | "DELETE" %{ CURRENT->method = EBB_DELETE; } - | "GET" %{ CURRENT->method = EBB_GET; } - | "HEAD" %{ CURRENT->method = EBB_HEAD; } - | "LOCK" %{ CURRENT->method = EBB_LOCK; } - | "MKCOL" %{ CURRENT->method = EBB_MKCOL; } - | "MOVE" %{ CURRENT->method = EBB_MOVE; } - | "OPTIONS" %{ CURRENT->method = EBB_OPTIONS; } - | "POST" %{ CURRENT->method = EBB_POST; } - | "PROPFIND" %{ CURRENT->method = EBB_PROPFIND; } - | "PROPPATCH" %{ CURRENT->method = EBB_PROPPATCH; } - | "PUT" %{ CURRENT->method = EBB_PUT; } - | "TRACE" %{ CURRENT->method = EBB_TRACE; } - | "UNLOCK" %{ CURRENT->method = EBB_UNLOCK; } - ); # Not allowing extension methods - - HTTP_Version = "HTTP/" digit+ $version_major "." digit+ $version_minor; - - scheme = ( alpha | digit | "+" | "-" | "." )* ; - absolute_uri = (scheme ":" (uchar | reserved )*); - path = ( pchar+ ( "/" pchar* )* ) ; - query = ( uchar | reserved )* >mark_query_string %query_string ; - param = ( pchar | "/" )* ; - params = ( param ( ";" param )* ) ; - rel_path = ( path? (";" params)? ) ; - absolute_path = ( "/"+ rel_path ) >mark_request_path %request_path ("?" query)?; - Request_URI = ( "*" | absolute_uri | absolute_path ) >mark_request_uri %request_uri; - Fragment = ( uchar | reserved )* >mark_fragment %fragment; - - field_name = ( token -- ":" )+; - Field_Name = field_name >mark_header_field %write_field; - - field_value = ((any - " ") any*)?; - Field_Value = field_value >mark_header_value %write_value; - - hsep = ":" " "*; - header = (field_name hsep field_value) :> CRLF; - Header = ( ("Content-Length"i hsep digit+ $content_length) - | ("Connection"i hsep - ( "Keep-Alive"i %set_keep_alive - | "close"i %set_not_keep_alive - ) - ) - | ("Transfer-Encoding"i %use_chunked_encoding hsep "identity" %use_identity_encoding) - # | ("Expect"i hsep "100-continue"i %expect_continue) - # | ("Trailer"i hsep field_value %trailer) - | (Field_Name hsep Field_Value) - ) :> CRLF; - - Request_Line = ( Method " " Request_URI ("#" Fragment)? " " HTTP_Version CRLF ) ; - RequestHeader = Request_Line (Header %end_header_line)* :> CRLF @end_headers; - -# chunked message - trailing_headers = header*; - #chunk_ext_val = token | quoted_string; - chunk_ext_val = token*; - chunk_ext_name = token*; - chunk_extension = ( ";" " "* chunk_ext_name ("=" chunk_ext_val)? )*; - last_chunk = "0"+ chunk_extension CRLF; - chunk_size = (xdigit* [1-9a-fA-F] xdigit*) $add_to_chunk_size; - chunk_end = CRLF; - chunk_body = any >skip_chunk_data; - chunk_begin = chunk_size chunk_extension CRLF; - chunk = chunk_begin chunk_body chunk_end; - ChunkedBody := chunk* last_chunk trailing_headers CRLF @end_chunked_body; - - Request = RequestHeader >start_req @body_logic; - - main := Request*; # sequence of requests (for keep-alive) -}%% - -%% write data; - -static void -skip_body(const char **p, ebb_request_parser *parser, size_t nskip) { - if(CURRENT->on_body && nskip > 0) { - CURRENT->on_body(CURRENT, *p, nskip); - } - CURRENT->body_read += nskip; - parser->chunk_size -= nskip; - *p += nskip; - if(0 == parser->chunk_size) { - parser->eating = FALSE; - if(CURRENT->transfer_encoding == EBB_IDENTITY) { - END_REQUEST; - } - } else { - parser->eating = TRUE; - } -} - -void ebb_request_parser_init(ebb_request_parser *parser) -{ - int cs = 0; - %% write init; - parser->cs = cs; - - parser->chunk_size = 0; - parser->eating = 0; - - parser->current_request = NULL; - - parser->header_field_mark = parser->header_value_mark = - parser->query_string_mark = parser->path_mark = - parser->uri_mark = parser->fragment_mark = NULL; - - parser->new_request = NULL; -} - - -/** exec **/ -size_t ebb_request_parser_execute(ebb_request_parser *parser, const char *buffer, size_t len) -{ - const char *p, *pe; - int cs = parser->cs; - - assert(parser->new_request && "undefined callback"); - - p = buffer; - pe = buffer+len; - - if(0 < parser->chunk_size && parser->eating) { - /* eat body */ - size_t eat = MIN(len, parser->chunk_size); - skip_body(&p, parser, eat); - } - - if(parser->header_field_mark) parser->header_field_mark = buffer; - if(parser->header_value_mark) parser->header_value_mark = buffer; - if(parser->fragment_mark) parser->fragment_mark = buffer; - if(parser->query_string_mark) parser->query_string_mark = buffer; - if(parser->path_mark) parser->path_mark = buffer; - if(parser->uri_mark) parser->uri_mark = buffer; - - %% write exec; - - parser->cs = cs; - - HEADER_CALLBACK(header_field); - HEADER_CALLBACK(header_value); - CALLBACK(fragment); - CALLBACK(query_string); - CALLBACK(path); - CALLBACK(uri); - - assert(p <= pe && "buffer overflow after parsing execute"); - - return(p - buffer); -} - -int ebb_request_parser_has_error(ebb_request_parser *parser) -{ - return parser->cs == ebb_request_parser_error; -} - -int ebb_request_parser_is_finished(ebb_request_parser *parser) -{ - return parser->cs == ebb_request_parser_first_final; -} - -void ebb_request_init(ebb_request *request) -{ - request->expect_continue = FALSE; - request->body_read = 0; - request->content_length = 0; - request->version_major = 0; - request->version_minor = 0; - request->number_of_headers = 0; - request->transfer_encoding = EBB_IDENTITY; - request->keep_alive = -1; - - request->on_complete = NULL; - request->on_headers_complete = NULL; - request->on_body = NULL; - request->on_header_field = NULL; - request->on_header_value = NULL; - request->on_uri = NULL; - request->on_fragment = NULL; - request->on_path = NULL; - request->on_query_string = NULL; -} - -int ebb_request_should_keep_alive(ebb_request *request) -{ - if(request->keep_alive == -1) - if(request->version_major == 1) - return (request->version_minor != 0); - else if(request->version_major == 0) - return FALSE; - else - return TRUE; - else - return request->keep_alive; -} diff --git a/deps/libebb/examples/ca-cert.pem b/deps/libebb/examples/ca-cert.pem deleted file mode 100644 index 606283b1ec..0000000000 --- a/deps/libebb/examples/ca-cert.pem +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBzDCCATegAwIBAgIESIuNVTALBgkqhkiG9w0BAQUwADAeFw0wODA3MjYyMDQ3 -MTlaFw0xMTA0MjIyMDQ3MjVaMAAwgZwwCwYJKoZIhvcNAQEBA4GMADCBiAKBgOm9 -l/FoXbTIcEusk/QlS5YrlR04+oWIbSdZIf3GJBEWEUPljDxAX96qHsTcaVnGK+EP -keU4cIZvdY+hzbqa5cc1j2/9IeJNejL8gpQ/ocyMM69yq5Ib2F8K4mGWm1xr30hU -bYpY5D0MrZ1b0HtYFVc8KVAr0ADGG+pye0P9c3B/AgMBAAGjWjBYMAwGA1UdEwEB -/wQCMAAwFAYDVR0RBA0wC4IJbG9jYWxob3N0MBMGA1UdJQQMMAoGCCsGAQUFBwMB -MB0GA1UdDgQWBBTYgVB7kJnnm+jgX9DgrapzGfUmxjALBgkqhkiG9w0BAQUDgYEA -GkadA2H8CAzU3w4oCGZu9Ry9Tj/9Agw1XMFKvoJuG7VLPk7+B25JvNFVsmpROLxO -0TJ6mIU2hz5/rLvEfTBGQ+DYtbsjIxCz1fD7R5c1kKBtA0d0u8mY8pTlPNlxFPSW -3ymx5DB2zyDa/HuX6m6/VmzMYmA0vp7Dp1cl+pA9Nhs= ------END CERTIFICATE----- diff --git a/deps/libebb/examples/ca-key.pem b/deps/libebb/examples/ca-key.pem deleted file mode 100644 index afb953d69b..0000000000 --- a/deps/libebb/examples/ca-key.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQDpvZfxaF20yHBLrJP0JUuWK5UdOPqFiG0nWSH9xiQRFhFD5Yw8 -QF/eqh7E3GlZxivhD5HlOHCGb3WPoc26muXHNY9v/SHiTXoy/IKUP6HMjDOvcquS -G9hfCuJhlptca99IVG2KWOQ9DK2dW9B7WBVXPClQK9AAxhvqcntD/XNwfwIDAQAB -AoGAJqo3LTbfcV1KvinhG5zjwQaalwfq4RXtQHoNFmalZrIozvt01C6t7S5lApmX -T8NpVMR3lNxeOM7NOqJAXuLqqVVqk81YEYuMx6E4gB/Ifl7jVZk1jstmLILhh59D -pXrlpzvvm5X2hVsI7lp/YGAvtdLS1iVy37bGgmQWfCeeZiECQQDtZLfcJb4oE1yR -ZfLOcPDlBCw02wGMNFpAjwbspf/du3Yn3ONWHVfhSCCcCe262h9PLblL97LoB+gF -OHOlM9JvAkEA/A+U3/p9pwL4L742pxZP62/rmk6p5mZFIykk2jIUTpdilXBWBlcT -OjgjnpquZpwnaClmvgFpkzdhIPF7Nq4K8QJBAITVKagOmnOUOeTF1fI78h9DkXTV -4uzP0nxzS52ZWS16Gqg9ihuCecz97flB+Prn2EMWw6tFY58/5U0ehF85OxMCQQDF -08TYdVSg+6emcPeb89sNwW18UjjuZ13j1qrhxWRCunXZK62YlEa27tCl7mjqh6w2 -CChm/9zIejJ1FJHLvJVBAkBj63ZbwggMYkxuj60jIBbNrEtDx9y7zM0sXkiJqcKp -5uGtJNafG+yZrLAHE6/b4aqUOtGsCGsiZpT9ms7CoaVr ------END RSA PRIVATE KEY----- diff --git a/deps/libebb/examples/hello_world.c b/deps/libebb/examples/hello_world.c deleted file mode 100644 index bec0070937..0000000000 --- a/deps/libebb/examples/hello_world.c +++ /dev/null @@ -1,101 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include "ebb.h" - -#define MSG ("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 12\r\n\r\nhello world\n") -static int c = 0; - -struct hello_connection { - unsigned int responses_to_write; -}; - -void on_close(ebb_connection *connection) -{ - free(connection->data); - free(connection); -} - -static void continue_responding(ebb_connection *connection) -{ - int r; - struct hello_connection *connection_data = connection->data; - //printf("response complete \n"); - if(--connection_data->responses_to_write > 0) { - /* write another response */ - r = ebb_connection_write(connection, MSG, sizeof MSG, continue_responding); - assert(r); - } else { - ebb_connection_schedule_close(connection); - } -} - -static void request_complete(ebb_request *request) -{ - //printf("request complete \n"); - ebb_connection *connection = request->data; - struct hello_connection *connection_data = connection->data; - - if(ebb_request_should_keep_alive(request)) - connection_data->responses_to_write++; - else - connection_data->responses_to_write = 1; - - ebb_connection_write(connection, MSG, sizeof MSG, continue_responding); - free(request); -} - -static ebb_request* new_request(ebb_connection *connection) -{ - //printf("request %d\n", ++c); - ebb_request *request = malloc(sizeof(ebb_request)); - ebb_request_init(request); - request->data = connection; - request->on_complete = request_complete; - return request; -} - -ebb_connection* new_connection(ebb_server *server, struct sockaddr_in *addr) -{ - struct hello_connection *connection_data = malloc(sizeof(struct hello_connection)); - if(connection_data == NULL) - return NULL; - connection_data->responses_to_write = 0; - - ebb_connection *connection = malloc(sizeof(ebb_connection)); - if(connection == NULL) { - free(connection_data); - return NULL; - } - - ebb_connection_init(connection); - connection->data = connection_data; - connection->new_request = new_request; - connection->on_close = on_close; - - printf("connection: %d\n", c++); - return connection; -} - -int main(int argc, char **_) -{ - struct ev_loop *loop = ev_default_loop(0); - ebb_server server; - - ebb_server_init(&server, loop); - if(argc > 1) { - printf("using SSL\n"); - ebb_server_set_secure(&server, "ca-cert.pem", "ca-key.pem"); - } - server.new_connection = new_connection; - - printf("hello_world listening on port 5000\n"); - ebb_server_listen_on_port(&server, 5000); - ev_loop(loop, 0); - - return 0; -} diff --git a/deps/libebb/rbtree.c b/deps/libebb/rbtree.c deleted file mode 100644 index 4a66972a26..0000000000 --- a/deps/libebb/rbtree.c +++ /dev/null @@ -1,412 +0,0 @@ -/* Copyright (c) 2008 Derrick Coetzee - * http://en.literateprograms.org/Red-black_tree_(C)?oldid=7982 - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the - * following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT - * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR - * THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include "rbtree.h" -#include - -#ifndef NULL -# define NULL ((void*)0) -#endif - - -typedef rbtree_node node; -typedef enum rbtree_node_color color; - - -static node grandparent(node n); -static node sibling(node n); -static node uncle(node n); -static void verify_properties(rbtree t); -static void verify_property_1(node root); -/* static void verify_property_2(node root); */ -static color node_color(node n); -static void verify_property_4(node root); -/* static void verify_property_5(node root); */ -static void verify_property_5_helper(node n, int black_count, int* black_count_path); - -static node lookup_node(rbtree t, void* key); -static void rotate_left(rbtree t, node n); -static void rotate_right(rbtree t, node n); - -static void replace_node(rbtree t, node oldn, node newn); -static void insert_case1(rbtree t, node n); -static void insert_case2(rbtree t, node n); -static void insert_case3(rbtree t, node n); -static void insert_case4(rbtree t, node n); -static void insert_case5(rbtree t, node n); -static node maximum_node(node root); -static void delete_case1(rbtree t, node n); -static void delete_case2(rbtree t, node n); -static void delete_case3(rbtree t, node n); -static void delete_case4(rbtree t, node n); -static void delete_case5(rbtree t, node n); -static void delete_case6(rbtree t, node n); - -node grandparent(node n) { - assert (n != NULL); - assert (n->parent != NULL); /* Not the root node */ - assert (n->parent->parent != NULL); /* Not child of root */ - return n->parent->parent; -} - -node sibling(node n) { - assert (n != NULL); - assert (n->parent != NULL); /* Root node has no sibling */ - if (n == n->parent->left) - return n->parent->right; - else - return n->parent->left; -} - -node uncle(node n) { - assert (n != NULL); - assert (n->parent != NULL); /* Root node has no uncle */ - assert (n->parent->parent != NULL); /* Children of root have no uncle */ - return sibling(n->parent); -} - -void verify_properties(rbtree t) { -#ifdef VERIFY_RBTREE - verify_property_1(t->root); - verify_property_2(t->root); - /* Property 3 is implicit */ - verify_property_4(t->root); - verify_property_5(t->root); -#endif -} - -void verify_property_1(node n) { - assert(node_color(n) == RED || node_color(n) == BLACK); - if (n == NULL) return; - verify_property_1(n->left); - verify_property_1(n->right); -} - -/* -void verify_property_2(node root) { - assert(node_color(root) == BLACK); -} -*/ - -color node_color(node n) { - return n == NULL ? BLACK : n->color; -} - -void verify_property_4(node n) { - if (node_color(n) == RED) { - assert (node_color(n->left) == BLACK); - assert (node_color(n->right) == BLACK); - assert (node_color(n->parent) == BLACK); - } - if (n == NULL) return; - verify_property_4(n->left); - verify_property_4(n->right); -} - -/* -void verify_property_5(node root) { - int black_count_path = -1; - verify_property_5_helper(root, 0, &black_count_path); -} -*/ - -void verify_property_5_helper(node n, int black_count, int* path_black_count) { - if (node_color(n) == BLACK) { - black_count++; - } - if (n == NULL) { - if (*path_black_count == -1) { - *path_black_count = black_count; - } else { - assert (black_count == *path_black_count); - } - return; - } - verify_property_5_helper(n->left, black_count, path_black_count); - verify_property_5_helper(n->right, black_count, path_black_count); -} - -void rbtree_init(rbtree t, rbtree_compare_func compare) { - t->root = NULL; - t->compare = compare; - verify_properties(t); -} - -node lookup_node(rbtree t, void* key) { - node n = t->root; - while (n != NULL) { - int comp_result = t->compare(key, n->key); - if (comp_result == 0) { - return n; - } else if (comp_result < 0) { - n = n->left; - } else { - assert(comp_result > 0); - n = n->right; - } - } - return n; -} - -void* rbtree_lookup(rbtree t, void* key) { - node n = lookup_node(t, key); - return n == NULL ? NULL : n->value; -} - -void rotate_left(rbtree t, node n) { - node r = n->right; - replace_node(t, n, r); - n->right = r->left; - if (r->left != NULL) { - r->left->parent = n; - } - r->left = n; - n->parent = r; -} - -void rotate_right(rbtree t, node n) { - node L = n->left; - replace_node(t, n, L); - n->left = L->right; - if (L->right != NULL) { - L->right->parent = n; - } - L->right = n; - n->parent = L; -} - -void replace_node(rbtree t, node oldn, node newn) { - if (oldn->parent == NULL) { - t->root = newn; - } else { - if (oldn == oldn->parent->left) - oldn->parent->left = newn; - else - oldn->parent->right = newn; - } - if (newn != NULL) { - newn->parent = oldn->parent; - } -} - -void rbtree_insert(rbtree t, rbtree_node inserted_node) { - inserted_node->color = RED; - inserted_node->left = NULL; - inserted_node->right = NULL; - inserted_node->parent = NULL; - - if (t->root == NULL) { - t->root = inserted_node; - } else { - node n = t->root; - while (1) { - int comp_result = t->compare(inserted_node->key, n->key); - if (comp_result == 0) { - n->value = inserted_node->value; - return; - } else if (comp_result < 0) { - if (n->left == NULL) { - n->left = inserted_node; - break; - } else { - n = n->left; - } - } else { - assert (comp_result > 0); - if (n->right == NULL) { - n->right = inserted_node; - break; - } else { - n = n->right; - } - } - } - inserted_node->parent = n; - } - insert_case1(t, inserted_node); - verify_properties(t); -} - -void insert_case1(rbtree t, node n) { - if (n->parent == NULL) - n->color = BLACK; - else - insert_case2(t, n); -} - -void insert_case2(rbtree t, node n) { - if (node_color(n->parent) == BLACK) - return; /* Tree is still valid */ - else - insert_case3(t, n); -} - -void insert_case3(rbtree t, node n) { - if (node_color(uncle(n)) == RED) { - n->parent->color = BLACK; - uncle(n)->color = BLACK; - grandparent(n)->color = RED; - insert_case1(t, grandparent(n)); - } else { - insert_case4(t, n); - } -} - -void insert_case4(rbtree t, node n) { - if (n == n->parent->right && n->parent == grandparent(n)->left) { - rotate_left(t, n->parent); - n = n->left; - } else if (n == n->parent->left && n->parent == grandparent(n)->right) { - rotate_right(t, n->parent); - n = n->right; - } - insert_case5(t, n); -} - -void insert_case5(rbtree t, node n) { - n->parent->color = BLACK; - grandparent(n)->color = RED; - if (n == n->parent->left && n->parent == grandparent(n)->left) { - rotate_right(t, grandparent(n)); - } else { - assert (n == n->parent->right && n->parent == grandparent(n)->right); - rotate_left(t, grandparent(n)); - } -} - -rbtree_node rbtree_delete(rbtree t, void* key) { - node child; - node n = lookup_node(t, key); - if (n == NULL) return NULL; /* Key not found, do nothing */ - if (n->left != NULL && n->right != NULL) { - /* Copy key/value from predecessor and then delete it instead */ - node pred = maximum_node(n->left); - n->key = pred->key; - n->value = pred->value; - n = pred; - } - - assert(n->left == NULL || n->right == NULL); - child = n->right == NULL ? n->left : n->right; - if (node_color(n) == BLACK) { - n->color = node_color(child); - delete_case1(t, n); - } - replace_node(t, n, child); - - verify_properties(t); - return n; -} - -static node maximum_node(node n) { - assert (n != NULL); - while (n->right != NULL) { - n = n->right; - } - return n; -} - -void delete_case1(rbtree t, node n) { - if (n->parent == NULL) - return; - else - delete_case2(t, n); -} - -void delete_case2(rbtree t, node n) { - if (node_color(sibling(n)) == RED) { - n->parent->color = RED; - sibling(n)->color = BLACK; - if (n == n->parent->left) - rotate_left(t, n->parent); - else - rotate_right(t, n->parent); - } - delete_case3(t, n); -} - -void delete_case3(rbtree t, node n) { - if (node_color(n->parent) == BLACK && - node_color(sibling(n)) == BLACK && - node_color(sibling(n)->left) == BLACK && - node_color(sibling(n)->right) == BLACK) - { - sibling(n)->color = RED; - delete_case1(t, n->parent); - } - else - delete_case4(t, n); -} - -void delete_case4(rbtree t, node n) { - if (node_color(n->parent) == RED && - node_color(sibling(n)) == BLACK && - node_color(sibling(n)->left) == BLACK && - node_color(sibling(n)->right) == BLACK) - { - sibling(n)->color = RED; - n->parent->color = BLACK; - } - else - delete_case5(t, n); -} - -void delete_case5(rbtree t, node n) { - if (n == n->parent->left && - node_color(sibling(n)) == BLACK && - node_color(sibling(n)->left) == RED && - node_color(sibling(n)->right) == BLACK) - { - sibling(n)->color = RED; - sibling(n)->left->color = BLACK; - rotate_right(t, sibling(n)); - } - else if (n == n->parent->right && - node_color(sibling(n)) == BLACK && - node_color(sibling(n)->right) == RED && - node_color(sibling(n)->left) == BLACK) - { - sibling(n)->color = RED; - sibling(n)->right->color = BLACK; - rotate_left(t, sibling(n)); - } - delete_case6(t, n); -} - -void delete_case6(rbtree t, node n) { - sibling(n)->color = node_color(n->parent); - n->parent->color = BLACK; - if (n == n->parent->left) { - assert (node_color(sibling(n)->right) == RED); - sibling(n)->right->color = BLACK; - rotate_left(t, n->parent); - } - else - { - assert (node_color(sibling(n)->left) == RED); - sibling(n)->left->color = BLACK; - rotate_right(t, n->parent); - } -} - - diff --git a/deps/libebb/rbtree.h b/deps/libebb/rbtree.h deleted file mode 100644 index 5962a3c118..0000000000 --- a/deps/libebb/rbtree.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright (c) 2008 Derrick Coetzee - * http://en.literateprograms.org/Red-black_tree_(C)?oldid=7982 - * Small changes by Ryah Dahl - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the - * following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT - * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR - * THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _RBTREE_H_ -#define _RBTREE_H_ - -enum rbtree_node_color { RED, BLACK }; - -typedef int (*rbtree_compare_func)(void* left_key, void* right_key); - -typedef struct rbtree_node_t { - struct rbtree_node_t* left; /* private */ - struct rbtree_node_t* right; /* private */ - struct rbtree_node_t* parent; /* private */ - enum rbtree_node_color color; /* private */ - void* key; /* public */ - void* value; /* public */ -} *rbtree_node; - -typedef struct rbtree_t { - rbtree_node root; /* private */ - rbtree_compare_func compare; /* private */ -} *rbtree; - - -void rbtree_init(rbtree t, rbtree_compare_func); -void* rbtree_lookup(rbtree t, void* key); -void rbtree_insert(rbtree t, rbtree_node); -/* you must free the returned node */ -rbtree_node rbtree_delete(rbtree t, void* key); - -#endif - diff --git a/deps/libebb/test_examples.rb b/deps/libebb/test_examples.rb deleted file mode 100644 index 2af658cab8..0000000000 --- a/deps/libebb/test_examples.rb +++ /dev/null @@ -1,60 +0,0 @@ -require 'test/unit' -require 'socket' - -REQ = "GET /hello/%d HTTP/1.1\r\n\r\n" -HOST = '0.0.0.0' -PORT = 5000 - -class TCPSocket - def full_send(string) - written = 0 - while(written < string.length) - sent = write(string) - string = string.slice(sent, 10000) - end - written - end - - def full_read - response = "" - while chunk = read(10000) - response += chunk - end - response - end - -end - -class EbbTest < Test::Unit::TestCase - - def setup - @socket = TCPSocket.new(HOST, PORT) - end - - def test_bad_req - @socket.full_send("hello") - assert_equal "", @socket.full_read - #assert @socket.closed? - end - - def test_single - written = 0 - req = REQ % 1 - @socket.full_send(req) - response = @socket.full_read() - count = 0 - response.scan("hello world") { count += 1 } - - assert_equal 1, count - end - - def test_pipeline - written = 0 - req = (REQ % 1) + (REQ % 2) + (REQ % 3) + (REQ % 4) - @socket.full_send(req) - response = @socket.full_read() - count = 0 - response.scan("hello world") { count += 1 } - assert_equal 4, count - end -end diff --git a/deps/libebb/test_rbtree.c b/deps/libebb/test_rbtree.c deleted file mode 100644 index f5ee1d6cd1..0000000000 --- a/deps/libebb/test_rbtree.c +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (c) 2008 Derrick Coetzee - * http://en.literateprograms.org/Red-black_tree_(C)?oldid=7982 - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the - * following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT - * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR - * THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include "rbtree.h" -#include -#include -#include /* rand(), malloc(), free() */ - -static int compare_int(void* left, void* right); -static void print_tree(rbtree t); -static void print_tree_helper(rbtree_node n, int indent); - -int compare_int(void* leftp, void* rightp) { - int left = (int)leftp; - int right = (int)rightp; - if (left < right) - return -1; - else if (left > right) - return 1; - else { - assert (left == right); - return 0; - } -} - -#define INDENT_STEP 4 - -void print_tree_helper(rbtree_node n, int indent); - -void print_tree(rbtree t) { - print_tree_helper(t->root, 0); - puts(""); -} - -void print_tree_helper(rbtree_node n, int indent) { - int i; - if (n == NULL) { - fputs("", stdout); - return; - } - if (n->right != NULL) { - print_tree_helper(n->right, indent + INDENT_STEP); - } - for(i=0; icolor == BLACK) - printf("%d\n", (int)n->key); - else - printf("<%d>\n", (int)n->key); - if (n->left != NULL) { - print_tree_helper(n->left, indent + INDENT_STEP); - } -} - -int main() { - int i; - struct rbtree_t t; - rbtree_init(&t, compare_int); - print_tree(&t); - - for(i=0; i<5000; i++) { - int x = rand() % 10000; - int y = rand() % 10000; -#ifdef TRACE - print_tree(&t); - printf("Inserting %d -> %d\n\n", x, y); -#endif - rbtree_node node = (rbtree_node) malloc(sizeof(struct rbtree_node_t)); - node->key = (void*)x; - node->value = (void*)y; - rbtree_insert(&t, node); - assert(rbtree_lookup(&t, (void*)x) == (void*)y); - } - for(i=0; i<60000; i++) { - int x = rand() % 10000; -#ifdef TRACE - print_tree(&t); - printf("Deleting key %d\n\n", x); -#endif - rbtree_node n = rbtree_delete(&t, (void*)x); - if(n != NULL) { - free(n); - } - } - printf("Okay\n"); - return 0; -} - diff --git a/deps/libebb/test_request_parser.c b/deps/libebb/test_request_parser.c deleted file mode 100644 index 5a5dca38f1..0000000000 --- a/deps/libebb/test_request_parser.c +++ /dev/null @@ -1,746 +0,0 @@ -/* unit tests for request parser - * Copyright 2008 ryah dahl, ry@ndahl.us - * - * This software may be distributed under the "MIT" license included in the - * README - */ -#include "ebb_request_parser.h" -#include -#include -#include -#include - -#define TRUE 1 -#define FALSE 0 - -#define MAX_HEADERS 500 -#define MAX_ELEMENT_SIZE 500 - -static ebb_request_parser parser; -struct request_data { - const char *raw; - int request_method; - char request_path[MAX_ELEMENT_SIZE]; - char request_uri[MAX_ELEMENT_SIZE]; - char fragment[MAX_ELEMENT_SIZE]; - char query_string[MAX_ELEMENT_SIZE]; - char body[MAX_ELEMENT_SIZE]; - int num_headers; - char header_fields[MAX_HEADERS][MAX_ELEMENT_SIZE]; - char header_values[MAX_HEADERS][MAX_ELEMENT_SIZE]; - int should_keep_alive; - ebb_request request; -}; -static struct request_data requests[5]; -static int num_requests; - -const struct request_data curl_get = - { raw: "GET /test HTTP/1.1\r\n" - "User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1\r\n" - "Host: 0.0.0.0:5000\r\n" - "Accept: */*\r\n" - "\r\n" - , should_keep_alive: TRUE - , request_method: EBB_GET - , query_string: "" - , fragment: "" - , request_path: "/test" - , request_uri: "/test" - , num_headers: 3 - , header_fields: { "User-Agent", "Host", "Accept" } - , header_values: { "curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1", "0.0.0.0:5000", "*/*" } - , body: "" - }; - -const struct request_data firefox_get = - { raw: "GET /favicon.ico HTTP/1.1\r\n" - "Host: 0.0.0.0:5000\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n" - "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" - "Accept-Language: en-us,en;q=0.5\r\n" - "Accept-Encoding: gzip,deflate\r\n" - "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" - "Keep-Alive: 300\r\n" - "Connection: keep-alive\r\n" - "\r\n" - , should_keep_alive: TRUE - , request_method: EBB_GET - , query_string: "" - , fragment: "" - , request_path: "/favicon.ico" - , request_uri: "/favicon.ico" - , num_headers: 8 - , header_fields: - { "Host" - , "User-Agent" - , "Accept" - , "Accept-Language" - , "Accept-Encoding" - , "Accept-Charset" - , "Keep-Alive" - , "Connection" - } - , header_values: - { "0.0.0.0:5000" - , "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0" - , "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" - , "en-us,en;q=0.5" - , "gzip,deflate" - , "ISO-8859-1,utf-8;q=0.7,*;q=0.7" - , "300" - , "keep-alive" - } - , body: "" - }; - -const struct request_data dumbfuck = - { raw: "GET /dumbfuck HTTP/1.1\r\n" - "aaaaaaaaaaaaa:++++++++++\r\n" - "\r\n" - , should_keep_alive: TRUE - , request_method: EBB_GET - , query_string: "" - , fragment: "" - , request_path: "/dumbfuck" - , request_uri: "/dumbfuck" - , num_headers: 1 - , header_fields: { "aaaaaaaaaaaaa" } - , header_values: { "++++++++++" } - , body: "" - }; - -const struct request_data fragment_in_uri = - { raw: "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n" - "\r\n" - , should_keep_alive: TRUE - , request_method: EBB_GET - , query_string: "page=1" - , fragment: "posts-17408" - , request_path: "/forums/1/topics/2375" - /* XXX request uri does not include fragment? */ - , request_uri: "/forums/1/topics/2375?page=1" - , num_headers: 0 - , body: "" - }; - - -// get - no headers - no body -const struct request_data get_no_headers_no_body = - { raw: "GET /get_no_headers_no_body/world HTTP/1.1\r\n" - "\r\n" - , should_keep_alive: TRUE - , request_method: EBB_GET - , query_string: "" - , fragment: "" - , request_path: "/get_no_headers_no_body/world" - , request_uri: "/get_no_headers_no_body/world" - , num_headers: 0 - , body: "" - }; - -// get - one header - no body -const struct request_data get_one_header_no_body = - { raw: "GET /get_one_header_no_body HTTP/1.1\r\n" - "Accept: */*\r\n" - "\r\n" - , should_keep_alive: TRUE - , request_method: EBB_GET - , query_string: "" - , fragment: "" - , request_path: "/get_one_header_no_body" - , request_uri: "/get_one_header_no_body" - , num_headers: 1 - , header_fields: { "Accept" } - , header_values: { "*/*" } - , body: "" - }; - -// get - no headers - body "HELLO" -const struct request_data get_funky_content_length_body_hello = - { raw: "GET /get_funky_content_length_body_hello HTTP/1.0\r\n" - "conTENT-Length: 5\r\n" - "\r\n" - "HELLO" - , should_keep_alive: FALSE - , request_method: EBB_GET - , query_string: "" - , fragment: "" - , request_path: "/get_funky_content_length_body_hello" - , request_uri: "/get_funky_content_length_body_hello" - , num_headers: 1 - , header_fields: { "conTENT-Length" } - , header_values: { "5" } - , body: "HELLO" - }; - -// post - one header - body "World" -const struct request_data post_identity_body_world = - { raw: "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n" - "Accept: */*\r\n" - "Transfer-Encoding: identity\r\n" - "Content-Length: 5\r\n" - "\r\n" - "World" - , should_keep_alive: TRUE - , request_method: EBB_POST - , query_string: "q=search" - , fragment: "hey" - , request_path: "/post_identity_body_world" - , request_uri: "/post_identity_body_world?q=search" - , num_headers: 3 - , header_fields: { "Accept", "Transfer-Encoding", "Content-Length" } - , header_values: { "*/*", "identity", "5" } - , body: "World" - }; - -// post - no headers - chunked body "all your base are belong to us" -const struct request_data post_chunked_all_your_base = - { raw: "POST /post_chunked_all_your_base HTTP/1.1\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "1e\r\nall your base are belong to us\r\n" - "0\r\n" - "\r\n" - , should_keep_alive: TRUE - , request_method: EBB_POST - , query_string: "" - , fragment: "" - , request_path: "/post_chunked_all_your_base" - , request_uri: "/post_chunked_all_your_base" - , num_headers: 1 - , header_fields: { "Transfer-Encoding" } - , header_values: { "chunked" } - , body: "all your base are belong to us" - }; - -// two chunks ; triple zero ending -const struct request_data two_chunks_mult_zero_end = - { raw: "POST /two_chunks_mult_zero_end HTTP/1.1\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "5\r\nhello\r\n" - "6\r\n world\r\n" - "000\r\n" - "\r\n" - , should_keep_alive: TRUE - , request_method: EBB_POST - , query_string: "" - , fragment: "" - , request_path: "/two_chunks_mult_zero_end" - , request_uri: "/two_chunks_mult_zero_end" - , num_headers: 1 - , header_fields: { "Transfer-Encoding" } - , header_values: { "chunked" } - , body: "hello world" - }; - - -// chunked with trailing headers. blech. -const struct request_data chunked_w_trailing_headers = - { raw: "POST /chunked_w_trailing_headers HTTP/1.1\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "5\r\nhello\r\n" - "6\r\n world\r\n" - "0\r\n" - "Vary: *\r\n" - "Content-Type: text/plain\r\n" - "\r\n" - , should_keep_alive: TRUE - , request_method: EBB_POST - , query_string: "" - , fragment: "" - , request_path: "/chunked_w_trailing_headers" - , request_uri: "/chunked_w_trailing_headers" - , num_headers: 1 - , header_fields: { "Transfer-Encoding" } - , header_values: { "chunked" } - , body: "hello world" - }; - -// with bullshit after the length -const struct request_data chunked_w_bullshit_after_length = - { raw: "POST /chunked_w_bullshit_after_length HTTP/1.1\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n" - "6; blahblah; blah\r\n world\r\n" - "0\r\n" - "\r\n" - , should_keep_alive: TRUE - , request_method: EBB_POST - , query_string: "" - , fragment: "" - , request_path: "/chunked_w_bullshit_after_length" - , request_uri: "/chunked_w_bullshit_after_length" - , num_headers: 1 - , header_fields: { "Transfer-Encoding" } - , header_values: { "chunked" } - , body: "hello world" - }; - -const struct request_data *fixtures[] = - { &curl_get - , &firefox_get - , &dumbfuck - , &fragment_in_uri - , &get_no_headers_no_body - , &get_one_header_no_body - , &get_funky_content_length_body_hello - , &post_identity_body_world - , &post_chunked_all_your_base - , &two_chunks_mult_zero_end - , &chunked_w_trailing_headers - , &chunked_w_bullshit_after_length - , NULL - }; - - -int request_data_eq - ( struct request_data *r1 - , const struct request_data *r2 - ) -{ - if(ebb_request_should_keep_alive(&r1->request) != r2->should_keep_alive) { - printf("requests disagree on keep-alive"); - return FALSE; - } - - if(0 != strcmp(r1->body, r2->body)) { - printf("body '%s' != '%s'\n", r1->body, r2->body); - return FALSE; - } - if(0 != strcmp(r1->fragment, r2->fragment)) { - printf("fragment '%s' != '%s'\n", r1->fragment, r2->fragment); - return FALSE; - } - if(0 != strcmp(r1->query_string, r2->query_string)) { - printf("query_string '%s' != '%s'\n", r1->query_string, r2->query_string); - return FALSE; - } - if(r1->request.method != r2->request_method) { - printf("request_method '%d' != '%d'\n", r1->request.method, r2->request_method); - return FALSE; - } - if(0 != strcmp(r1->request_path, r2->request_path)) { - printf("request_path '%s' != '%s'\n", r1->request_path, r2->request_path); - return FALSE; - } - if(0 != strcmp(r1->request_uri, r2->request_uri)) { - printf("request_uri '%s' != '%s'\n", r1->request_uri, r2->request_uri); - return FALSE; - } - if(r1->num_headers != r2->num_headers) { - printf("num_headers '%d' != '%d'\n", r1->num_headers, r2->num_headers); - return FALSE; - } - int i; - for(i = 0; i < r1->num_headers; i++) { - if(0 != strcmp(r1->header_fields[i], r2->header_fields[i])) { - printf("header field '%s' != '%s'\n", r1->header_fields[i], r2->header_fields[i]); - return FALSE; - } - if(0 != strcmp(r1->header_values[i], r2->header_values[i])) { - printf("header field '%s' != '%s'\n", r1->header_values[i], r2->header_values[i]); - return FALSE; - } - } - return TRUE; -} - -int request_eq - ( int index - , const struct request_data *expected - ) -{ - return request_data_eq(&requests[index], expected); -} - -void request_complete(ebb_request *info) -{ - num_requests++; -} - -void request_path_cb(ebb_request *request, const char *p, size_t len) -{ - strncat(requests[num_requests].request_path, p, len); -} - -void request_uri_cb(ebb_request *request, const char *p, size_t len) -{ - strncat(requests[num_requests].request_uri, p, len); -} - -void query_string_cb(ebb_request *request, const char *p, size_t len) -{ - strncat(requests[num_requests].query_string, p, len); -} - -void fragment_cb(ebb_request *request, const char *p, size_t len) -{ - strncat(requests[num_requests].fragment, p, len); -} - -void header_field_cb(ebb_request *request, const char *p, size_t len, int header_index) -{ - strncat(requests[num_requests].header_fields[header_index], p, len); -} - -void header_value_cb(ebb_request *request, const char *p, size_t len, int header_index) -{ - strncat(requests[num_requests].header_values[header_index], p, len); - requests[num_requests].num_headers = header_index + 1; -} - -void body_handler(ebb_request *request, const char *p, size_t len) -{ - strncat(requests[num_requests].body, p, len); - // printf("body_handler: '%s'\n", requests[num_requests].body); -} - -ebb_request* new_request () -{ - requests[num_requests].num_headers = 0; - requests[num_requests].request_method = -1; - requests[num_requests].request_path[0] = 0; - requests[num_requests].request_uri[0] = 0; - requests[num_requests].fragment[0] = 0; - requests[num_requests].query_string[0] = 0; - requests[num_requests].body[0] = 0; - int i; - for(i = 0; i < MAX_HEADERS; i++) { - requests[num_requests].header_fields[i][0] = 0; - requests[num_requests].header_values[i][0] = 0; - } - - ebb_request *r = &requests[num_requests].request; - ebb_request_init(r); - - r->on_complete = request_complete; - r->on_header_field = header_field_cb; - r->on_header_value = header_value_cb; - r->on_path = request_path_cb; - r->on_uri = request_uri_cb; - r->on_fragment = fragment_cb; - r->on_query_string = query_string_cb; - r->on_body = body_handler; - r->on_headers_complete = NULL; - - r->data = &requests[num_requests]; - // printf("new request %d\n", num_requests); - return r; -} - -void parser_init() -{ - num_requests = 0; - - ebb_request_parser_init(&parser); - - parser.new_request = new_request; -} - -int test_request - ( const struct request_data *request_data - ) -{ - size_t traversed = 0; - parser_init(); - - traversed = ebb_request_parser_execute( &parser - , request_data->raw - , strlen(request_data->raw) - ); - if( ebb_request_parser_has_error(&parser) ) - return FALSE; - if(! ebb_request_parser_is_finished(&parser) ) - return FALSE; - if(num_requests != 1) - return FALSE; - - return request_eq(0, request_data); -} - -int test_error - ( const char *buf - ) -{ - size_t traversed = 0; - parser_init(); - - traversed = ebb_request_parser_execute(&parser, buf, strlen(buf)); - - return ebb_request_parser_has_error(&parser); -} - - -int test_multiple3 - ( const struct request_data *r1 - , const struct request_data *r2 - , const struct request_data *r3 - ) -{ - char total[80*1024] = "\0"; - - strcat(total, r1->raw); - strcat(total, r2->raw); - strcat(total, r3->raw); - - size_t traversed = 0; - parser_init(); - - traversed = ebb_request_parser_execute(&parser, total, strlen(total)); - - - if( ebb_request_parser_has_error(&parser) ) - return FALSE; - if(! ebb_request_parser_is_finished(&parser) ) - return FALSE; - if(num_requests != 3) - return FALSE; - - if(!request_eq(0, r1)){ - printf("request 1 error.\n"); - return FALSE; - } - if(!request_eq(1, r2)){ - printf("request 2 error.\n"); - return FALSE; - } - if(!request_eq(2, r3)){ - printf("request 3 error.\n"); - return FALSE; - } - - return TRUE; -} - -/** - * SCAN through every possible breaking to make sure the - * parser can handle getting the content in any chunks that - * might come from the socket - */ -int test_scan2 - ( const struct request_data *r1 - , const struct request_data *r2 - , const struct request_data *r3 - ) -{ - char total[80*1024] = "\0"; - char buf1[80*1024] = "\0"; - char buf2[80*1024] = "\0"; - - strcat(total, r1->raw); - strcat(total, r2->raw); - strcat(total, r3->raw); - - int total_len = strlen(total); - - //printf("total_len = %d\n", total_len); - int i; - for(i = 1; i < total_len - 1; i ++ ) { - - parser_init(); - - int buf1_len = i; - strncpy(buf1, total, buf1_len); - buf1[buf1_len] = 0; - - int buf2_len = total_len - i; - strncpy(buf2, total+i, buf2_len); - buf2[buf2_len] = 0; - - ebb_request_parser_execute(&parser, buf1, buf1_len); - - if( ebb_request_parser_has_error(&parser) ) { - return FALSE; - } - /* - if(ebb_request_parser_is_finished(&parser)) - return FALSE; - */ - - ebb_request_parser_execute(&parser, buf2, buf2_len); - - if( ebb_request_parser_has_error(&parser)) - return FALSE; - if(!ebb_request_parser_is_finished(&parser)) - return FALSE; - - if(3 != num_requests) { - printf("scan error: got %d requests in iteration %d\n", num_requests, i); - return FALSE; - } - - if(!request_eq(0, r1)) { - printf("not maching r1\n"); - return FALSE; - } - if(!request_eq(1, r2)) { - printf("not maching r2\n"); - return FALSE; - } - if(!request_eq(2, r3)) { - printf("not maching r3\n"); - return FALSE; - } - } - return TRUE; -} - -int test_scan3 - ( const struct request_data *r1 - , const struct request_data *r2 - , const struct request_data *r3 - ) -{ - char total[80*1024] = "\0"; - char buf1[80*1024] = "\0"; - char buf2[80*1024] = "\0"; - char buf3[80*1024] = "\0"; - - strcat(total, r1->raw); - strcat(total, r2->raw); - strcat(total, r3->raw); - - int total_len = strlen(total); - - //printf("total_len = %d\n", total_len); - int i,j; - for(j = 2; j < total_len - 1; j ++ ) { - for(i = 1; i < j; i ++ ) { - - parser_init(); - - - - - int buf1_len = i; - strncpy(buf1, total, buf1_len); - buf1[buf1_len] = 0; - - int buf2_len = j - i; - strncpy(buf2, total+i, buf2_len); - buf2[buf2_len] = 0; - - int buf3_len = total_len - j; - strncpy(buf3, total+j, buf3_len); - buf3[buf3_len] = 0; - - /* - printf("buf1: %s - %d\n", buf1, buf1_len); - printf("buf2: %s - %d \n", buf2, buf2_len ); - printf("buf3: %s - %d\n\n", buf3, buf3_len); - */ - - ebb_request_parser_execute(&parser, buf1, buf1_len); - - if( ebb_request_parser_has_error(&parser) ) { - return FALSE; - } - - ebb_request_parser_execute(&parser, buf2, buf2_len); - - if( ebb_request_parser_has_error(&parser) ) { - return FALSE; - } - - ebb_request_parser_execute(&parser, buf3, buf3_len); - - if( ebb_request_parser_has_error(&parser)) - return FALSE; - if(!ebb_request_parser_is_finished(&parser)) - return FALSE; - - if(3 != num_requests) { - printf("scan error: only got %d requests in iteration %d\n", num_requests, i); - return FALSE; - } - - if(!request_eq(0, r1)) { - printf("not maching r1\n"); - return FALSE; - } - if(!request_eq(1, r2)) { - printf("not maching r2\n"); - return FALSE; - } - if(!request_eq(2, r3)) { - printf("not maching r3\n"); - return FALSE; - } - } - } - return TRUE; -} - -int main() -{ - - assert(test_error("hello world")); - assert(test_error("GET / HTP/1.1\r\n\r\n")); - - assert(test_request(&curl_get)); - assert(test_request(&firefox_get)); - - // Zed's header tests - - assert(test_request(&dumbfuck)); - - const char *dumbfuck2 = "GET / HTTP/1.1\r\nX-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgEBBAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n\tRA==\r\n\t-----END CERTIFICATE-----\r\n\r\n"; - assert(test_error(dumbfuck2)); - - assert(test_request(&fragment_in_uri)); - - /* TODO sending junk and large headers gets rejected */ - - - /* check to make sure our predefined requests are okay */ - - assert(test_request(&get_no_headers_no_body)); - assert(test_request(&get_one_header_no_body)); - assert(test_request(&get_no_headers_no_body)); - - // no content-length - const char *bad_get_no_headers_no_body = "GET /bad_get_no_headers_no_body/world HTTP/1.1\r\nAccept: */*\r\nHELLO\r\n"; - assert(test_error(bad_get_no_headers_no_body)); // error if there is a body without content length - - assert(test_request(&get_funky_content_length_body_hello)); - assert(test_request(&post_identity_body_world)); - assert(test_request(&post_chunked_all_your_base)); - assert(test_request(&two_chunks_mult_zero_end)); - assert(test_request(&chunked_w_trailing_headers)); - - assert(test_request(&chunked_w_bullshit_after_length)); - assert(1 == requests[0].request.version_major); - assert(1 == requests[0].request.version_minor); - - // three requests - no bodies - assert( test_multiple3( &get_no_headers_no_body - , &get_one_header_no_body - , &get_no_headers_no_body - )); - - // three requests - one body - assert( test_multiple3(&get_no_headers_no_body, &get_funky_content_length_body_hello, &get_no_headers_no_body)); - - // three requests with bodies -- last is chunked - assert( test_multiple3(&get_funky_content_length_body_hello, &post_identity_body_world, &post_chunked_all_your_base)); - - // three chunked requests - assert( test_multiple3(&two_chunks_mult_zero_end, &post_chunked_all_your_base, &chunked_w_trailing_headers)); - - - assert(test_scan2(&get_no_headers_no_body, &get_one_header_no_body, &get_no_headers_no_body)); - assert(test_scan2(&get_funky_content_length_body_hello, &post_identity_body_world, &post_chunked_all_your_base)); - assert(test_scan2(&two_chunks_mult_zero_end, &chunked_w_trailing_headers, &chunked_w_bullshit_after_length)); - - assert(test_scan3(&get_no_headers_no_body, &get_one_header_no_body, &get_no_headers_no_body)); - assert(test_scan3(&get_funky_content_length_body_hello, &post_identity_body_world, &post_chunked_all_your_base)); - assert(test_scan3(&two_chunks_mult_zero_end, &chunked_w_trailing_headers, &chunked_w_bullshit_after_length)); - - - printf("okay\n"); - return 0; -} - diff --git a/ragel.py b/ragel.py deleted file mode 100644 index 3bb96ace9b..0000000000 --- a/ragel.py +++ /dev/null @@ -1,35 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 - -"Ragel: '.rl' files are converted into .c files using 'ragel': {.rl -> .c -> .o}" - -import TaskGen, Task, Runner - - -def rageltaskfun(task): - env = task.env - ragelbin = env.get_flat('RAGEL') - if ragelbin: - if task.inputs[0].srcpath(env) == '../src/config_parser.rl': - cmd = '%s -o %s -C -T0 %s' % (ragelbin, task.outputs[0].bldpath(env), task.inputs[0].srcpath(env)) - else: - cmd = '%s -o %s -C -T1 %s' % (ragelbin, task.outputs[0].bldpath(env), task.inputs[0].srcpath(env)) - else: - src = task.inputs[0].srcpath(env) - src = src[:src.rfind('.')] + '.c' - cmd = 'cp %s %s' % (src, task.outputs[0].bldpath(env)) - return task.generator.bld.exec_command(cmd) - -rageltask = Task.task_type_from_func('ragel', rageltaskfun, vars = ['RAGEL'], color = 'BLUE', ext_in = '.rl', ext_out = '.c', before = 'c') - -@TaskGen.extension('.rl') -@TaskGen.before('apply_core') -def ragel(self, node): - out = node.change_ext('.c') - self.allnodes.append(out) - tsk = self.create_task('ragel') - tsk.set_inputs(node) - tsk.set_outputs(out) - -def detect(conf): - dang = conf.find_program('ragel', var='RAGEL') diff --git a/src/http.cc b/src/http.cc index a162fa05ff..6c699b3fb9 100644 --- a/src/http.cc +++ b/src/http.cc @@ -1,691 +1,61 @@ #include "node.h" #include "http.h" - -#include -#include - -#include -#include +#include #include +#include using namespace v8; +using namespace node; using namespace std; -static Persistent request_template; - -// globals -static Persistent path_str; -static Persistent uri_str; -static Persistent query_string_str; -static Persistent fragment_str; -static Persistent method_str; -static Persistent http_version_str; -static Persistent headers_str; - -static Persistent on_request_str; -static Persistent on_body_str; -static Persistent respond_str; - -static Persistent copy_str; -static Persistent delete_str; -static Persistent get_str; -static Persistent head_str; -static Persistent lock_str; -static Persistent mkcol_str; -static Persistent move_str; -static Persistent options_str; -static Persistent post_str; -static Persistent propfind_str; -static Persistent proppatch_str; -static Persistent put_str; -static Persistent trace_str; -static Persistent unlock_str; - -#define INVALID_STATE_ERR 1 - -class HttpServer { -public: - HttpServer (Handle _js_server); - ~HttpServer (); - - int Start(struct addrinfo *servinfo); - void Stop(); - - Handle Callback() - { - HandleScope scope; - Handle value = js_server->Get(on_request_str); - return scope.Close(value); - } - -private: - oi_server server; - Persistent js_server; -}; - -class HttpRequest; - -class Connection { -public: - Connection(); - ~Connection(); - - void Parse(const void *buf, size_t count); - void Write(); - void Close(); - void AddRequest (HttpRequest *request); - - oi_socket socket; - Persistent js_onrequest; - -private: - ebb_request_parser parser; - list requests; - list finished_requests; - friend class HttpServer; -}; - -class HttpRequest { - public: - HttpRequest (Connection &c); - /* Deleted from C++ as soon as possible. - * Javascript object might linger. This is okay - */ - ~HttpRequest(); - - void MakeBodyCallback (const char *base, size_t length); - Local CreateJSObject (); - void Respond (Handle data); - - string path; - string query_string; - string fragment; - string uri; - - list header_fields; - list header_values; - - Connection &connection; - ebb_request parser_info; - - list output; - bool done; - Persistent js_object; -}; - -static Handle -GetMethodString (int method) -{ - switch(method) { - case EBB_COPY: return copy_str; - case EBB_DELETE: return delete_str; - case EBB_GET: return get_str; - case EBB_HEAD: return head_str; - case EBB_LOCK: return lock_str; - case EBB_MKCOL: return mkcol_str; - case EBB_MOVE: return move_str; - case EBB_OPTIONS: return options_str; - case EBB_POST: return post_str; - case EBB_PROPFIND: return propfind_str; - case EBB_PROPPATCH: return proppatch_str; - case EBB_PUT: return put_str; - case EBB_TRACE: return trace_str; - case EBB_UNLOCK: return unlock_str; - } - return Null(); -} - -static Handle -RespondCallback (const Arguments& args) -{ - HandleScope scope; - - Handle v = args.Holder()->GetInternalField(0); - if(v->IsUndefined()) { - // check that args.Holder()->GetInternalField(0) - // is not NULL if so raise INVALID_STATE_ERR - printf("null request external\n"); - ThrowException(Integer::New(INVALID_STATE_ERR)); - return Undefined(); - } - Handle field = Handle::Cast(v); - HttpRequest* request = static_cast(field->Value()); - request->Respond(args[0]); - return Undefined(); -} - void -HttpRequest::Respond (Handle data) -{ - if(data == Null()) { - done = true; - } else { - Handle s = data->ToString(); - - size_t l1 = s->Utf8Length(), l2; - oi_buf *buf = oi_buf_new2(l1); - l2 = s->WriteUtf8(buf->base, l1); - assert(l1 == l2); - - output.push_back(buf); - } - connection.Write(); -} - - -static void -on_path (ebb_request *req, const char *buf, size_t len) -{ - HttpRequest *request = static_cast (req->data); - request->path.append(buf, len); -} - -static void -on_uri (ebb_request *req, const char *buf, size_t len) -{ - HttpRequest *request = static_cast (req->data); - request->uri.append(buf, len); -} - -static void -on_query_string (ebb_request *req, const char *buf, size_t len) -{ - HttpRequest *request = static_cast (req->data); - request->query_string.append(buf, len); -} - -static void -on_fragment (ebb_request *req, const char *buf, size_t len) -{ - HttpRequest *request = static_cast (req->data); - request->fragment.append(buf, len); -} - -static const char upcase[] = - "\0______________________________" - "_________________0123456789_____" - "__ABCDEFGHIJKLMNOPQRSTUVWXYZ____" - "__ABCDEFGHIJKLMNOPQRSTUVWXYZ____" - "________________________________" - "________________________________" - "________________________________" - "________________________________"; - -static void -on_header_field (ebb_request *req, const char *buf, size_t len, int header_index) +HTTPClient::Initialize (Handle target) { - HttpRequest *request = static_cast (req->data); - - char upbuf[len]; - - for(int i = 0; i < len; i++) - upbuf[i] = upcase[buf[i]]; - - if( request->header_fields.size() == header_index - 1) { - request->header_fields.back().append(upbuf, len); - } else { - request->header_fields.push_back( string(upbuf, len) ); - } -} - -static void -on_header_value (ebb_request *req, const char *buf, size_t len, int header_index) -{ - HttpRequest *request = static_cast (req->data); - - if( request->header_values.size() == header_index - 1) { - request->header_values.back().append(buf, len); - } else { - request->header_values.push_back( string(buf, len) ); - } -} - -static void -on_headers_complete (ebb_request *req) -{ - HttpRequest *request = static_cast (req->data); - HandleScope scope; - Handle js_request = request->CreateJSObject(); - - // Set up an exception handler before calling the Process function - TryCatch try_catch; - - // Invoke the process function, giving the global object as 'this' - // and one argument, the request. - const int argc = 1; - Handle argv[argc] = { js_request }; - Handle r = request->connection.js_onrequest->Call(Context::GetCurrent()->Global(), argc, argv); - - if(try_catch.HasCaught()) - node::fatal_exception(try_catch); -} - -static void -on_request_complete (ebb_request *req) -{ - HttpRequest *request = static_cast (req->data); - request->MakeBodyCallback(NULL, 0); // EOF -} - -static void -on_body (ebb_request *req, const char *base, size_t length) -{ - HttpRequest *request = static_cast (req->data); - - if(length) - request->MakeBodyCallback(base, length); -} - -static ebb_request * on_request - ( void *data - ) -{ - Connection *connection = static_cast (data); + Local t = FunctionTemplate::New(HTTPClient::v8New); + t->InstanceTemplate()->SetInternalFieldCount(1); + target->Set(String::NewSymbol("HTTPClient"), t->GetFunction()); - HttpRequest *request = new HttpRequest(*connection); - connection->AddRequest(request); - - return &request->parser_info; + NODE_SET_METHOD(t->InstanceTemplate(), "connect", Connection::v8Connect); + NODE_SET_METHOD(t->InstanceTemplate(), "close", Connection::v8Close); + NODE_SET_METHOD(t->InstanceTemplate(), "send", Connection::v8Send); + NODE_SET_METHOD(t->InstanceTemplate(), "sendEOF", Connection::v8SendEOF); } -static void on_read - ( oi_socket *socket - , const void *buf - , size_t count - ) -{ - Connection *connection = static_cast (socket->data); - if(count == 0) { - connection->Close(); - } else { - //write(1, buf, count); - connection->Parse(buf, count); - } -} - -static void on_close - ( oi_socket *socket - ) -{ - Connection *connection = static_cast (socket->data); - delete connection; -} - -HttpRequest::~HttpRequest () -{ - HandleScope scope; // needed? - // delete a reference c++ HttpRequest - js_object->SetInternalField(0, Undefined()); - js_object->Delete(respond_str); - // dispose of Persistent handle so that - // it can be GC'd normally. - js_object.Dispose(); -} - -HttpRequest::HttpRequest (Connection &c) : connection(c) -{ - ebb_request_init(&parser_info); - parser_info.on_path = on_path; - parser_info.on_query_string = on_query_string; - parser_info.on_uri = on_uri; - parser_info.on_fragment = on_fragment; - parser_info.on_header_field = on_header_field; - parser_info.on_header_value = on_header_value; - parser_info.on_headers_complete = on_headers_complete; - parser_info.on_body = on_body; - parser_info.on_complete = on_request_complete; - parser_info.data = this; - - done = false; -} - -void -HttpRequest::MakeBodyCallback (const char *base, size_t length) -{ - HandleScope handle_scope; - - Handle onbody_val = js_object->Get(on_body_str); - if (!onbody_val->IsFunction()) return; - Handle onbody = Handle::Cast(onbody_val); - - TryCatch try_catch; - const int argc = 1; - Handle argv[argc]; - - if(length) { - // TODO ByteArray? - // - - uint16_t expanded_base[length]; - for(int i = 0; i < length; i++) { - expanded_base[i] = base[i]; - } - - Handle chunk = String::New(expanded_base, length); - argv[0] = chunk; - } else { - argv[0] = Null(); - } - - Handle result = onbody->Call(js_object, argc, argv); - - if(try_catch.HasCaught()) - node::fatal_exception(try_catch); -} - -Local -HttpRequest::CreateJSObject () +Handle +HTTPClient::v8New (const Arguments& args) { HandleScope scope; - if (request_template.IsEmpty()) { - Handle raw_template = ObjectTemplate::New(); - raw_template->SetInternalFieldCount(1); - raw_template->Set(respond_str, FunctionTemplate::New(RespondCallback)); - - request_template = Persistent::New(raw_template); - } - - // Create an empty http request wrapper. - Handle result = request_template->NewInstance(); - - // Wrap the raw C++ pointer in an External so it can be referenced - // from within JavaScript. - Handle request_ptr = External::New(this); - - // Store the request pointer in the JavaScript wrapper. - result->SetInternalField(0, request_ptr); - - result->Set ( path_str - , String::New(path.c_str(), path.length()) - ); - - result->Set ( uri_str - , String::New(uri.c_str(), uri.length()) - ); + if (args[0]->IsFunction() == false) + return ThrowException(String::New("Must pass a class as the first argument.")); - result->Set ( query_string_str - , String::New(query_string.c_str(), query_string.length()) - ); - - result->Set ( fragment_str - , String::New(fragment.c_str(), fragment.length()) - ); - - result->Set ( method_str - , GetMethodString(parser_info.method) - ); - - char version[10]; - snprintf ( version - , 10 // big enough? :) - , "%d.%d" - , parser_info.version_major - , parser_info.version_minor - ); - result->Set ( http_version_str - , String::New(version) - ); + Handle protocol = Handle::Cast(args[0]); + int argc = args.Length(); + Handle argv[argc]; - Handle headers = Object::New(); - list::iterator field_iterator = header_fields.begin(); - list::iterator value_iterator = header_values.begin(); - while( value_iterator != header_values.end() ) { - string &f = *field_iterator; - string &v = *value_iterator; - - headers->Set( String::NewSymbol(f.c_str(), f.length()) - , String::New(v.c_str(), v.length() ) - ); - - field_iterator++; - value_iterator++; + argv[0] = args.This(); + for (int i = 1; i < args.Length(); i++) { + argv[i] = args[i]; } - result->Set(headers_str, headers); - - js_object = Persistent::New(result); - // XXX does the request's js_object need a MakeWeak callback? - // i dont think so because at some point the connection closes - // and we're going to delete the request. - - return scope.Close(result); -} - - -static oi_socket* -on_connection (oi_server *_server, struct sockaddr *addr, socklen_t len) -{ - HandleScope scope; - HttpServer *server = static_cast (_server->data); + Local protocol_instance = protocol->NewInstance(argc, argv); - Handle callback_v = server->Callback(); + new HTTPClient(args.This(), protocol_instance); - if(callback_v == Undefined()) - return NULL; - - Connection *connection = new Connection(); - - Handle f = Handle::Cast(callback_v); - connection->js_onrequest = Persistent::New(f); - - return &connection->socket; -} - -Connection::Connection () -{ - oi_socket_init (&socket, 30.0); // TODO make timeout adjustable - socket.on_read = on_read; - socket.on_error = NULL; - socket.on_close = on_close; - socket.on_timeout = NULL; - socket.on_drain = NULL; - socket.data = this; - - ebb_request_parser_init (&parser); - parser.new_request = on_request; - parser.data = this; -} - -Connection::~Connection () -{ - list::iterator it = requests.begin(); - - // delete all the requests - - for(it = requests.begin(); it != requests.end(); it++) - delete *it; - - for(it = finished_requests.begin(); it != finished_requests.end(); it++) - delete *it; -} - -void -Connection::Parse(const void *buf, size_t count) -{ - // FIXME change ebb_request_parser to have void* arg - ebb_request_parser_execute ( &parser - , static_cast (buf) - , count - ); - - if(ebb_request_parser_has_error(&parser)) { - fprintf(stderr, "parse error closing connection\n"); - oi_socket_close(&socket); - } -} - -void -Connection::AddRequest(HttpRequest *request) -{ - requests.push_back(request); -} - -void -Connection::Write ( ) -{ - if(requests.size() == 0) - return; - - HttpRequest *request = requests.front(); - - while(request->output.size() > 0) { - oi_buf *buf = request->output.front(); - oi_socket_write(&socket, buf); - request->output.pop_front(); - } - - if(request->done) { - if(!ebb_request_should_keep_alive(&request->parser_info)) { - socket.on_drain = oi_socket_close; - } - - requests.pop_front(); - finished_requests.push_back(request); - - Write(); - } -} - -void -Connection::Close ( ) -{ - oi_socket_close(&socket); -} - -static void -server_destroy (Persistent _, void *data) -{ - HttpServer *server = static_cast (data); - delete server; -} - -HttpServer::HttpServer (Handle _js_server) -{ - oi_server_init(&server, 1024); - server.on_connection = on_connection; - server.data = this; - HandleScope scope; - js_server = Persistent::New (_js_server); - // are we ever going to need this external? - js_server->SetInternalField (0, External::New(this)); - js_server.MakeWeak (this, server_destroy); -} - -HttpServer::~HttpServer () -{ - Stop(); - js_server.Dispose(); - js_server.Clear(); // necessary? -} - -int -HttpServer::Start(struct addrinfo *servinfo) -{ - int r = oi_server_listen(&server, servinfo); - if(r == 0) - oi_server_attach(EV_DEFAULT_UC_ &server); - return r; + return args.This(); } void -HttpServer::Stop() -{ - oi_server_close (&server); - oi_server_detach (&server); -} - -/* This constructor takes 2 arguments: host, port. */ -static Handle -newHTTPHttpServer (const Arguments& args) +HTTPClient::OnReceive (const void *buf, size_t len) { - if (args.Length() < 3) - return Undefined(); - - HandleScope scope; - - char *host = NULL; - String::AsciiValue host_v(args[0]->ToString()); - if(args[0]->IsString()) { - host = *host_v; - } - String::AsciiValue port(args[1]->ToString()); - - Handle onrequest = Handle::Cast(args[2]); - args.This()->Set(on_request_str, onrequest); - - // get addrinfo for localhost, PORT - struct addrinfo *servinfo; - struct addrinfo hints; - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; - // FIXME BLOCKING - int r = getaddrinfo(host, *port, &hints, &servinfo); - if (r != 0) - return Undefined(); // XXX raise error? - - // - // - // - // TODO host is ignored for now assumed localhost - // - // - // - // - - HttpServer *server = new HttpServer(args.This()); - if(server == NULL) - return Undefined(); // XXX raise error? - - r = server->Start(servinfo); - if (r != 0) - return Undefined(); // XXX raise error? - - return args.This(); + printf("http client got data!\n"); } -void -node::Init_http (Handle target) +HTTPClient::HTTPClient (Handle handle, Handle protocol) + : Connection(handle, protocol) { - HandleScope scope; - - Local server_t = FunctionTemplate::New(newHTTPHttpServer); - server_t->InstanceTemplate()->SetInternalFieldCount(1); - - server_t->Set("INVALID_STATE_ERR", Integer::New(INVALID_STATE_ERR)); - - target->Set(String::New("HTTPServer"), server_t->GetFunction()); - - path_str = Persistent::New( String::NewSymbol("path") ); - uri_str = Persistent::New( String::NewSymbol("uri") ); - query_string_str = Persistent::New( String::NewSymbol("query_string") ); - fragment_str = Persistent::New( String::NewSymbol("fragment") ); - method_str = Persistent::New( String::NewSymbol("method") ); - http_version_str = Persistent::New( String::NewSymbol("http_version") ); - headers_str = Persistent::New( String::NewSymbol("headers") ); - - on_request_str = Persistent::New( String::NewSymbol("onrequest") ); - on_body_str = Persistent::New( String::NewSymbol("onbody") ); - respond_str = Persistent::New( String::NewSymbol("respond") ); - - copy_str = Persistent::New( String::New("COPY") ); - delete_str = Persistent::New( String::New("DELETE") ); - get_str = Persistent::New( String::New("GET") ); - head_str = Persistent::New( String::New("HEAD") ); - lock_str = Persistent::New( String::New("LOCK") ); - mkcol_str = Persistent::New( String::New("MKCOL") ); - move_str = Persistent::New( String::New("MOVE") ); - options_str = Persistent::New( String::New("OPTIONS") ); - post_str = Persistent::New( String::New("POST") ); - propfind_str = Persistent::New( String::New("PROPFIND") ); - proppatch_str = Persistent::New( String::New("PROPPATCH") ); - put_str = Persistent::New( String::New("PUT") ); - trace_str = Persistent::New( String::New("TRACE") ); - unlock_str = Persistent::New( String::New("UNLOCK") ); -} +} diff --git a/src/http.h b/src/http.h index 69e5f09f6c..db9a6a992b 100644 --- a/src/http.h +++ b/src/http.h @@ -2,10 +2,21 @@ #define node_http_h #include +#include "net.h" namespace node { -void Init_http (v8::Handle target); +class HTTPClient : public node::Connection { +public: + static void Initialize (v8::Handle target); + + HTTPClient (v8::Handle handle, v8::Handle protocol); + + static v8::Handle v8New (const v8::Arguments& args); +protected: + void OnReceive (const void *buf, size_t len); + +}; } // namespace node #endif diff --git a/src/net.cc b/src/net.cc index 47b1aaa71b..dc81a61e3c 100644 --- a/src/net.cc +++ b/src/net.cc @@ -59,21 +59,12 @@ Connection::Initialize (v8::Handle target) NODE_SET_METHOD(t->InstanceTemplate(), "sendEOF", Connection::v8SendEOF); } -Local -Connection::NewServerSideInstance (Local protocol, Handle server) -{ - HandleScope scope; - Handle argv[] = { protocol, server }; - Local instance = tcp_connection_constructor->NewInstance(2, argv); - return scope.Close(instance); -} - -Connection::Connection (Handle handle) +Connection::Connection (Handle handle, Handle protocol) : ObjectWrap(handle) { HandleScope scope; - Local protocol = GetProtocol(); + handle_->Set(PROTOCOL_SYMBOL, protocol); encoding_ = RAW; Local encoding_v = protocol->Get(ENCODING_SYMBOL); @@ -136,9 +127,8 @@ Connection::v8New (const Arguments& args) } Local protocol_instance = protocol->NewInstance(argc, argv); - args.This()->Set(PROTOCOL_SYMBOL, protocol_instance); - new Connection(args.This()); + new Connection(args.This(), protocol_instance); return args.This(); } @@ -387,10 +377,11 @@ Acceptor::OnConnection (struct sockaddr *addr, socklen_t len) } Local protocol = Local::Cast(protocol_v); - Local connection_handle = - Connection::NewServerSideInstance(protocol, handle_); + Handle argv[] = { protocol, handle_ }; + Local connection_handle = tcp_connection_constructor->NewInstance(2, argv); + + Connection *connection = NODE_UNWRAP(Connection, connection_handle); - Connection *connection = new Connection(connection_handle); return connection; } diff --git a/src/net.h b/src/net.h index 45586971b5..60cad4ae64 100644 --- a/src/net.h +++ b/src/net.h @@ -11,10 +11,8 @@ class Connection : public ObjectWrap { public: static void Initialize (v8::Handle target); - Connection (v8::Handle handle); - ~Connection () { - Close(); - } + Connection (v8::Handle handle, v8::Handle protocol); + virtual ~Connection () { Close(); } int Connect (struct addrinfo *address) { return oi_socket_connect (&socket_, address); @@ -39,20 +37,17 @@ protected: static v8::Handle v8SendEOF (const v8::Arguments& args); static v8::Handle v8Close (const v8::Arguments& args); - void OnConnect (void); - void OnReceive (const void *buf, size_t len); - void OnDrain (void); - void OnEOF (void); - void OnDisconnect (void); - void OnError (oi_error e); - void OnTimeout (void); + virtual void OnConnect (void); + virtual void OnReceive (const void *buf, size_t len); + virtual void OnDrain (void); + virtual void OnEOF (void); + virtual void OnDisconnect (void); + virtual void OnError (oi_error e); + virtual void OnTimeout (void); v8::Local GetProtocol (void); - static v8::Local NewServerSideInstance ( - v8::Local protocol, - v8::Handle server); -private: +//private: /* liboi callbacks */ static void on_connect (oi_socket *s) { Connection *connection = static_cast (s->data); diff --git a/src/node.cc b/src/node.cc index b328737a1b..081ce0e6da 100644 --- a/src/node.cc +++ b/src/node.cc @@ -252,7 +252,7 @@ main (int argc, char *argv[]) Connection::Initialize(g); node::Init_timer(g); node::Init_file(g); - node::Init_http(g); + HTTPClient::Initialize(g); // NATIVE JAVASCRIPT MODULES TryCatch try_catch; diff --git a/src/node.h b/src/node.h index 959175253a..d7e79e9c9a 100644 --- a/src/node.h +++ b/src/node.h @@ -20,7 +20,7 @@ void eio_warmup (void); // call this before creating a new eio event. class ObjectWrap { public: ObjectWrap (v8::Handle handle); - ~ObjectWrap ( ); + virtual ~ObjectWrap ( ); protected: static void* Unwrap (v8::Handle handle); diff --git a/test/test-pingpong.js b/test/test-pingpong.js index 8ad2cf2500..8cc4654143 100644 --- a/test/test-pingpong.js +++ b/test/test-pingpong.js @@ -14,7 +14,7 @@ function Ponger (socket, server) { this.onReceive = function (data) { assertTrue(count <= N); - stdout.print ("-"); + stdout.print("-"); if (/PING/.exec(data)) { socket.send("PONG"); } diff --git a/wscript b/wscript index ccf20f9f9c..f1ec621aa8 100644 --- a/wscript +++ b/wscript @@ -18,7 +18,6 @@ def set_options(opt): # the gcc module provides a --debug-level option opt.tool_options('compiler_cxx') opt.tool_options('compiler_cc') - opt.tool_options('ragel', tdir=".") opt.add_option( '--debug' , action='store_true' , default=False @@ -29,10 +28,6 @@ def set_options(opt): def configure(conf): conf.check_tool('compiler_cxx') conf.check_tool('compiler_cc') - conf.check_tool('ragel', tooldir=".") - if not conf.env['RAGEL']: - fatal('ragel not found') - exit(1) conf.env["USE_DEBUG"] = Options.options.debug @@ -124,15 +119,15 @@ def build(bld): if bld.env["USE_DEBUG"]: oi.clone("debug") - ### ebb - ebb = bld.new_task_gen("cc", "staticlib") - ebb.source = "deps/libebb/ebb_request_parser.rl" - ebb.includes = "deps/libebb/" - ebb.name = "ebb" - ebb.target = "ebb" - ebb.install_path = None + ### http_parser + http_parser = bld.new_task_gen("cc", "staticlib") + http_parser.source = "deps/http_parser/http_parser.c" + http_parser.includes = "deps/http_parser/" + http_parser.name = "http_parser" + http_parser.target = "http_parser" + http_parser.install_path = None if bld.env["USE_DEBUG"]: - ebb.clone("debug") + http_parser.clone("debug") ### src/native.cc def javascript_in_c(task): @@ -167,9 +162,9 @@ def build(bld): deps/libev deps/libeio deps/liboi - deps/libebb + deps/http_parser """ - node.uselib_local = "oi ev eio ebb" + node.uselib_local = "oi ev eio http_parser" node.uselib = "V8 RT" node.install_path = '${PREFIX}/bin' node.chmod = 0755