ext/kcar/kcar.c in kcar-0.6.0 vs ext/kcar/kcar.c in kcar-0.7.0

- old
+ new

@@ -10,14 +10,24 @@ #include "ext_help.h" #include <assert.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> +#include <limits.h> #include "c_util.h" static VALUE eParserError; -static ID id_sq, id_sq_set; +static ID id_uminus, id_sq, id_sq_set; +static VALUE g_rack_url_scheme, + g_80, g_443, g_http, g_https, + g_HTTP_HOST, g_HTTP_CONNECTION, g_HTTP_TRAILER, g_HTTP_TRANSFER_ENCODING, + g_HTTP_VERSION, + g_CONTENT_LENGTH, g_CONTENT_TYPE, g_FRAGMENT, + g_PATH_INFO, g_QUERY_STRING, + g_REQUEST_METHOD, g_REQUEST_PATH, g_REQUEST_URI, + g_SERVER_NAME, g_SERVER_PORT, g_SERVER_PROTOCOL; +static VALUE e413, e414; /** Defines common length and error messages for input length validation. */ #define DEF_MAX_LENGTH(N, length) \ static const size_t MAX_##N##_LENGTH = length; \ static const char MAX_##N##_LENGTH_ERR[] = \ @@ -30,75 +40,180 @@ #define VALIDATE_MAX_LENGTH(len, N) do { \ if (len > MAX_##N##_LENGTH) \ rb_raise(eParserError, MAX_##N##_LENGTH_ERR); \ } while (0) +#define VALIDATE_MAX_URI_LENGTH(len, N) do { \ + if (len > MAX_##N##_LENGTH) \ + rb_raise(e414, MAX_##N##_LENGTH_ERR); \ +} while (0) + /* Defines the maximum allowed lengths for various input elements.*/ DEF_MAX_LENGTH(FIELD_NAME, 256); DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024); DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32))); +DEF_MAX_LENGTH(REQUEST_URI, 1024 * 15); +DEF_MAX_LENGTH(REQUEST_PATH, 4096); /* common PATH_MAX on modern systems */ +DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10)); -#define UH_FL_CHUNKED 0x1 -#define UH_FL_HASBODY 0x2 -#define UH_FL_INBODY 0x4 -#define UH_FL_HASTRAILER 0x8 -#define UH_FL_INTRAILER 0x10 -#define UH_FL_INCHUNK 0x20 -#define UH_FL_KEEPALIVE 0x40 -#define UH_FL_HASHEADER 0x80 - struct http_parser { int cs; /* Ragel internal state */ - unsigned int flags; - size_t mark; - size_t offset; + unsigned int is_request:1; + unsigned int has_query:1; + unsigned int has_scheme:1; + unsigned int chunked:1; + unsigned int has_body:1; + unsigned int in_body:1; + unsigned int has_trailer:1; + unsigned int in_trailer:1; + unsigned int in_chunk:1; + unsigned int persistent:1; + unsigned int has_header:1; + unsigned int body_eof_seen:1; + unsigned int is_https:1; + unsigned int padding:19; + unsigned int mark; + unsigned int offset; union { /* these 2 fields don't nest */ - size_t field; - size_t query; + unsigned int field; + unsigned int query; } start; union { - size_t field_len; /* only used during header processing */ - size_t dest_offset; /* only used during body processing */ + unsigned int field_len; /* only used during header processing */ + unsigned int dest_offset; /* only used during body processing */ } s; VALUE cont; /* Qfalse: unset, Qnil: ignored header, T_STRING: append */ - VALUE status; /* String or Qnil */ union { + /* String or Qnil */ + VALUE status; /* status string for responses */ + VALUE host; /* Host: header for requests */ + } v; + union { off_t content; off_t chunk; } len; }; +static unsigned int ulong2uint(unsigned long n) +{ + unsigned int i = (unsigned int)n; + + if (sizeof(unsigned int) != sizeof(unsigned long)) { + if ((unsigned long)i != n) { + rb_raise(rb_eRangeError, "too large to be 32-bit uint: %lu", n); + } + } + return i; +} + #define REMAINING (unsigned long)(pe - p) -#define LEN(AT, FPC) (FPC - buffer - hp->AT) -#define MARK(M,FPC) (hp->M = (FPC) - buffer) +#define LEN(AT, FPC) (ulong2uint(FPC - buffer) - hp->AT) +#define MARK(M,FPC) (hp->M = ulong2uint((FPC) - buffer)) #define PTR_TO(F) (buffer + hp->F) #define STR_NEW(M,FPC) rb_str_new(PTR_TO(M), LEN(M, FPC)) #define STRIPPED_STR_NEW(M,FPC) stripped_str_new(PTR_TO(M), LEN(M, FPC)) -#define HP_FL_TEST(hp,fl) ((hp)->flags & (UH_FL_##fl)) -#define HP_FL_SET(hp,fl) ((hp)->flags |= (UH_FL_##fl)) -#define HP_FL_UNSET(hp,fl) ((hp)->flags &= ~(UH_FL_##fl)) -#define HP_FL_ALL(hp,fl) (HP_FL_TEST(hp, fl) == (UH_FL_##fl)) +/* Downcases a single ASCII character. Locale-agnostic. */ +static void downcase_char(char *c) +{ + if (*c >= 'A' && *c <= 'Z') + *c |= 0x20; +} static int is_lws(char c) { return (c == ' ' || c == '\t'); } +/* this will dedupe under Ruby 2.5+ (December 2017) */ +static VALUE str_dd_freeze(VALUE str) +{ + if (STR_UMINUS_DEDUPE) + return rb_funcall(str, id_uminus, 0); + + /* freeze,since it speeds up MRI slightly */ + OBJ_FREEZE(str); + return str; +} + +static VALUE str_new_dd_freeze(const char *ptr, long len) +{ + return str_dd_freeze(rb_str_new(ptr, len)); +} + static VALUE stripped_str_new(const char *str, long len) { long end; for (end = len - 1; end >= 0 && is_lws(str[end]); end--); return rb_str_new(str, end + 1); } -static void finalize_header(struct http_parser *hp) +static VALUE request_host_val(struct http_parser *hp) { - if ((HP_FL_TEST(hp, HASTRAILER) && ! HP_FL_TEST(hp, CHUNKED))) + assert(hp->is_request == 1 && "not a request"); + return NIL_P(hp->v.host) ? Qfalse : hp->v.host; +} + +static void set_server_vars(struct http_parser *hp, VALUE env, VALUE host) +{ + char *host_ptr = RSTRING_PTR(host); + long host_len = RSTRING_LEN(host); + char *colon; + VALUE server_name = host; + VALUE server_port = hp->has_scheme ? (hp->is_https ? g_443 : g_80) : Qfalse; + + if (*host_ptr == '[') { /* ipv6 address format */ + char *rbracket = memchr(host_ptr + 1, ']', host_len - 1); + + if (rbracket) + colon = (rbracket[1] == ':') ? rbracket + 1 : NULL; + else + colon = memchr(host_ptr + 1, ':', host_len - 1); + } else { + colon = memchr(host_ptr, ':', host_len); + } + + if (colon) { + long port_start = colon - host_ptr + 1; + long port_len = host_len - port_start; + + server_name = rb_str_substr(host, 0, colon - host_ptr); + server_name = str_dd_freeze(server_name); + if (port_len > 0) { + server_port = rb_str_substr(host, port_start, port_len); + server_port = str_dd_freeze(server_port); + } + } + rb_hash_aset(env, g_SERVER_NAME, server_name); + if (server_port != Qfalse) + rb_hash_aset(env, g_SERVER_PORT, server_port); +} + +static void finalize_header(struct http_parser *hp, VALUE hdr) +{ + if (hp->has_trailer && !hp->chunked) rb_raise(eParserError, "trailer but not chunked"); + if (hp->is_request) { + if (hp->chunked) { + if (hp->len.chunk >= 0) + rb_raise(eParserError, "Content-Length set with chunked encoding"); + else + hp->len.chunk = 0; + } else if (hp->len.content < 0) { + hp->len.content = 0; + } + + if (!hp->has_query) + rb_hash_aset(hdr, g_QUERY_STRING, rb_str_new(NULL, 0)); + if (hp->has_header) { + VALUE host = request_host_val(hp); + if (host != Qfalse) + set_server_vars(hp, hdr, host); + } + } } /* * handles values of the "Connection:" header, keepalive is implied * for HTTP/1.1 but needs to be explicitly enabled with HTTP/1.0 @@ -107,55 +222,143 @@ static void hp_keepalive_connection(struct http_parser *hp, VALUE val) { /* REQUEST_METHOD is always set before any headers */ if (STR_CSTR_CASE_EQ(val, "keep-alive")) { /* basically have HTTP/1.0 masquerade as HTTP/1.1+ */ - HP_FL_SET(hp, KEEPALIVE); + hp->persistent = 1; } else if (STR_CSTR_CASE_EQ(val, "close")) { /* * it doesn't matter what HTTP version or request method we have, * if a server says "Connection: close", we disable keepalive */ - HP_FL_UNSET(hp, KEEPALIVE); + hp->persistent = 0; } else { /* * server could've sent anything, ignore it for now. Maybe - * "HP_FL_UNSET(hp, KEEPALIVE);" just in case? + * "hp->persistent = 0;" just in case? * Raising an exception might be too mean... */ } } static void -http_version(struct http_parser *hp, VALUE hdr, const char *ptr, size_t len) +request_method(VALUE env, const char *ptr, size_t len) { + rb_hash_aset(env, g_REQUEST_METHOD, str_new_dd_freeze(ptr, len)); +} + +static void +url_scheme(struct http_parser *hp, VALUE env, const char *ptr, size_t len) +{ + VALUE val; + + hp->has_scheme = 1; + /* Ragel machine downcases and enforces this as "http" or "https" */ + if (len == 5) { + hp->is_https = 1; + assert(CONST_MEM_EQ("https", ptr, len) && "len == 5 but not 'https'"); + val = g_https; + } else { + assert(CONST_MEM_EQ("http", ptr, len) && "len != 4 but not 'http'"); + val = g_http; + } + rb_hash_aset(env, g_rack_url_scheme, val); +} + +static void +request_host(struct http_parser *hp, VALUE env, const char *ptr, size_t len) +{ + VALUE val = rb_str_new(ptr, len); + + rb_hash_aset(env, g_HTTP_HOST, val); + hp->v.host = val; +} + +static void +set_fragment(VALUE env, const char *ptr, size_t len) +{ + VALUE val = rb_str_new(ptr, len); + rb_hash_aset(env, g_FRAGMENT, val); +} + +static void +request_uri(VALUE env, const char *ptr, size_t len) +{ + VALUE val; + + VALIDATE_MAX_URI_LENGTH(len, REQUEST_URI); + val = rb_str_new(ptr, len); + rb_hash_aset(env, g_REQUEST_URI, val); + + /* + * rack says PATH_INFO must start with "/" or be empty, + * but "OPTIONS *" is a valid request + */ + if (CONST_MEM_EQ("*", ptr, len)) { + val = rb_str_new(NULL, 0); + rb_hash_aset(env, g_PATH_INFO, val); + rb_hash_aset(env, g_REQUEST_PATH, val); + } +} + +static void +query_string(struct http_parser *hp, VALUE env, const char *ptr, size_t len) +{ + VALIDATE_MAX_URI_LENGTH(len, QUERY_STRING); + + hp->has_query = 1; + rb_hash_aset(env, g_QUERY_STRING, rb_str_new(ptr, len)); +} + +static void +request_path(VALUE env, const char *ptr, size_t len) +{ + VALUE val; + + VALIDATE_MAX_URI_LENGTH(len, REQUEST_PATH); + val = rb_str_new(ptr, len); + + rb_hash_aset(env, g_REQUEST_PATH, val); + rb_hash_aset(env, g_PATH_INFO, val); +} + +static void +http_version(struct http_parser *hp, VALUE env, const char *ptr, size_t len) +{ if (CONST_MEM_EQ("HTTP/1.1", ptr, len)) { /* HTTP/1.1 implies keepalive unless "Connection: close" is set */ - HP_FL_SET(hp, KEEPALIVE); + hp->persistent = 1; } + if (hp->is_request) { + VALUE v = str_new_dd_freeze(ptr, len); + hp->has_header = 1; + + rb_hash_aset(env, g_SERVER_PROTOCOL, v); + rb_hash_aset(env, g_HTTP_VERSION, v); + } } static void status_phrase(struct http_parser *hp, VALUE hdr, const char *ptr, size_t len) { long nr; - hp->status = rb_str_new(ptr, len); + hp->v.status = str_new_dd_freeze(ptr, len); /* RSTRING_PTR is null terminated, ptr is not */ - nr = strtol(RSTRING_PTR(hp->status), NULL, 10); + nr = strtol(RSTRING_PTR(hp->v.status), NULL, 10); if (nr < 100 || nr > 999) - rb_raise(eParserError, "invalid status: %s", RSTRING_PTR(hp->status)); + rb_raise(eParserError, "invalid status: %s", RSTRING_PTR(hp->v.status)); if ( !((nr >= 100 && nr <= 199) || nr == 204 || nr == 304) ) - HP_FL_SET(hp, HASBODY); + hp->has_body = 1; } static inline void invalid_if_trailer(struct http_parser *hp) { - if (HP_FL_TEST(hp, INTRAILER)) + if (hp->in_trailer) rb_raise(eParserError, "invalid Trailer"); } static void write_cont_value(struct http_parser *hp, char *buffer, const char *p) @@ -185,28 +388,28 @@ vptr = PTR_TO(mark); /* normalize tab to space */ if (cont_len > 0) { - assert((' ' == *vptr || '\t' == *vptr) && "invalid leading white space"); + assert(is_lws(*vptr) && "invalid leading white space"); *vptr = ' '; } for (end = len - 1; end >= 0 && is_lws(vptr[end]); end--); rb_str_buf_cat(hp->cont, vptr, end + 1); } -static void write_value(VALUE hdr, struct http_parser *hp, - const char *buffer, const char *p) +static void write_response_value(struct http_parser *hp, VALUE hdr, + const char *buffer, const char *p) { VALUE f, v; VALUE hclass; const char *fptr = PTR_TO(start.field); size_t flen = hp->s.field_len; const char *vptr; size_t vlen; - HP_FL_SET(hp, HASHEADER); + hp->has_header = 1; /* Rack does not like Status headers, so we never send them */ if (CSTR_CASE_EQ(fptr, flen, "status")) { hp->cont = Qnil; return; @@ -214,11 +417,11 @@ vptr = PTR_TO(mark); vlen = LEN(mark, p); VALIDATE_MAX_LENGTH(vlen, FIELD_VALUE); VALIDATE_MAX_LENGTH(flen, FIELD_NAME); - f = rb_str_new(fptr, (long)flen); + f = str_new_dd_freeze(fptr, (long)flen); v = stripped_str_new(vptr, (long)vlen); /* needs more tests for error-checking here */ /* * TODO: @@ -226,38 +429,38 @@ * report real-world examples as we find them: */ if (STR_CSTR_CASE_EQ(f, "connection")) { hp_keepalive_connection(hp, v); } else if (STR_CSTR_CASE_EQ(f, "content-length")) { - if (! HP_FL_TEST(hp, HASBODY)) + if (!hp->has_body) rb_raise(eParserError, "Content-Length with no body expected"); - if (HP_FL_TEST(hp, CHUNKED)) + if (hp->chunked) rb_raise(eParserError, "Content-Length when chunked Transfer-Encoding is set"); hp->len.content = parse_length(vptr, vlen); if (hp->len.content < 0) rb_raise(eParserError, "invalid Content-Length"); invalid_if_trailer(hp); } else if (STR_CSTR_CASE_EQ(f, "transfer-encoding")) { if (STR_CSTR_CASE_EQ(v, "chunked")) { - if (! HP_FL_TEST(hp, HASBODY)) + if (!hp->has_body) rb_raise(eParserError, "chunked Transfer-Encoding with no body expected"); if (hp->len.content >= 0) rb_raise(eParserError, "chunked Transfer-Encoding when Content-Length is set"); hp->len.chunk = 0; - HP_FL_SET(hp, CHUNKED); + hp->chunked = 1; } invalid_if_trailer(hp); } else if (STR_CSTR_CASE_EQ(f, "trailer")) { - if (! HP_FL_TEST(hp, HASBODY)) + if (!hp->has_body) rb_raise(eParserError, "trailer with no body"); - HP_FL_SET(hp, HASTRAILER); + hp->has_trailer = 1; invalid_if_trailer(hp); } hclass = CLASS_OF(hdr); if (hclass == rb_cArray) { @@ -272,13 +475,10 @@ e = rb_hash_aref(hdr, f); else e = rb_funcall(hdr, id_sq, 1, f); if (NIL_P(e)) { - /* new value, freeze it since it speeds up MRI slightly */ - OBJ_FREEZE(f); - if (hclass == rb_cHash) rb_hash_aset(hdr, f, v); else rb_funcall(hdr, id_sq_set, 2, f, v); @@ -295,45 +495,151 @@ hp->cont = rb_str_buf_append(e, v); } } } +static VALUE req_field(const char *ptr, size_t len) +{ + size_t pfxlen = sizeof("HTTP_") - 1; + VALUE str = rb_str_new(NULL, pfxlen + len); + char *dst = RSTRING_PTR(str); + + memcpy(dst, "HTTP_", pfxlen); + memcpy(dst + pfxlen, ptr, len); + assert(*(dst + RSTRING_LEN(str)) == '\0' && + "string didn't end with \\0"); /* paranoia */ + + return str; +} + +static void snake_upcase(char *ptr, size_t len) +{ + char *c; + + for (c = ptr; len--; c++) { + if (*c >= 'a' && *c <= 'z') + *c &= ~0x20; + else if (*c == '-') + *c = '_'; + } +} + +static void write_request_value(struct http_parser *hp, VALUE env, + char *buffer, const char *p) +{ + char *fptr = PTR_TO(start.field); + size_t flen = hp->s.field_len; + char *vptr = PTR_TO(mark); + size_t vlen = LEN(mark, p); + VALUE key, val; + VALUE existing; + + VALIDATE_MAX_LENGTH(flen, FIELD_NAME); + VALIDATE_MAX_LENGTH(LEN(mark, p), FIELD_VALUE); + snake_upcase(fptr, flen); + + /* + * ignore "Version" headers since they conflict with the HTTP_VERSION + * rack env variable. + */ + if (CONST_MEM_EQ("VERSION", fptr, flen)) { + hp->cont = Qnil; + return; + } + val = vlen == 0 ? rb_str_new(0, 0) : stripped_str_new(vptr, vlen); + + if (CONST_MEM_EQ("CONNECTION", fptr, flen)) { + key = g_HTTP_CONNECTION; + hp_keepalive_connection(hp, val); + } else if (CONST_MEM_EQ("CONTENT_LENGTH", fptr, flen)) { + key = g_CONTENT_LENGTH; + hp->len.content = parse_length(vptr, vlen); + if (hp->len.content < 0) + rb_raise(eParserError, "invalid Content-Length"); + if (hp->len.content != 0) + hp->has_body = 1; + invalid_if_trailer(hp); + } else if (CONST_MEM_EQ("CONTENT_TYPE", fptr, flen)) { + key = g_CONTENT_TYPE; + } else if (CONST_MEM_EQ("TRANSFER_ENCODING", fptr, flen)) { + key = g_HTTP_TRANSFER_ENCODING; + if (STR_CSTR_CASE_EQ(val, "chunked")) { + hp->chunked = 1; + hp->has_body = 1; + } + invalid_if_trailer(hp); + } else if (CONST_MEM_EQ("TRAILER", fptr, flen)) { + key = g_HTTP_TRAILER; + hp->has_trailer = 1; + invalid_if_trailer(hp); + } else if (CONST_MEM_EQ("HOST", fptr, flen)) { + key = g_HTTP_HOST; + if (NIL_P(hp->v.host)) + hp->v.host = val; + } else { + key = req_field(fptr, flen); + if (!HASH_ASET_DEDUPE) + key = str_dd_freeze(key); + } + existing = rb_hash_aref(env, key); + if (NIL_P(existing)) { + hp->cont = rb_hash_aset(env, key, val); + /* + * Ignore repeated Host headers and favor host set by absolute URIs. + * absoluteURI Request-URI takes precedence over + * the Host: header (ref: rfc 2616, section 5.2.1) + */ + } else if (key == g_HTTP_HOST) { + hp->cont = Qnil; + } else { + rb_str_buf_cat(existing, ",", 1); + hp->cont = rb_str_buf_append(existing, val); + } +} + +static void write_value(struct http_parser *hp, VALUE hdr, + char *buf, const char *p) +{ + hp->is_request ? write_request_value(hp, hdr, buf, p) : + write_response_value(hp, hdr, buf, p); +} + /** Machine **/ -#line 363 "kcar.rl" +#line 681 "kcar.rl" /** Data **/ -#line 309 "kcar.c" +#line 615 "kcar.c" static const int http_parser_start = 1; -static const int http_parser_first_final = 44; +static const int http_parser_first_final = 134; static const int http_parser_error = 0; -static const int http_parser_en_ChunkedBody = 22; -static const int http_parser_en_ChunkedBody_chunk_chunk_end = 27; -static const int http_parser_en_Trailers = 36; +static const int http_parser_en_ChunkedBody = 112; +static const int http_parser_en_ChunkedBody_chunk_chunk_end = 117; +static const int http_parser_en_Trailers = 126; static const int http_parser_en_main = 1; -#line 367 "kcar.rl" +#line 685 "kcar.rl" static void http_parser_init(struct http_parser *hp) { int cs = 0; memset(hp, 0, sizeof(struct http_parser)); hp->cont = Qfalse; /* zero on MRI, should be optimized away by above */ - hp->status = Qnil; + hp->v.status = Qnil; hp->len.content = -1; -#line 330 "kcar.c" +#line 636 "kcar.c" { cs = http_parser_start; } -#line 376 "kcar.rl" +#line 694 "kcar.rl" hp->cs = cs; } /** exec **/ static void http_parser_execute(struct http_parser *hp, @@ -352,878 +658,3048 @@ pe = buffer+len; assert((void *)(pe - p) == (void *)(len - off) && "pointers aren't same distance"); - if (HP_FL_TEST(hp, INCHUNK)) { - HP_FL_UNSET(hp, INCHUNK); + if (hp->in_chunk) { + hp->in_chunk = 0; goto skip_chunk_data_hack; } -#line 363 "kcar.c" +#line 669 "kcar.c" { if ( p == pe ) goto _test_eof; switch ( cs ) { case 1: - if ( (*p) == 72 ) + switch( (*p) ) { + case 33: goto tr0; + case 71: goto tr2; + case 72: goto tr3; + case 124: goto tr0; + case 126: goto tr0; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto tr0; + } else if ( (*p) >= 35 ) + goto tr0; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr0; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto tr0; + } else + goto tr0; + } else goto tr0; goto st0; st0: cs = 0; goto _out; tr0: -#line 303 "kcar.rl" +#line 609 "kcar.rl" {MARK(mark, p); } goto st2; st2: if ( ++p == pe ) goto _test_eof2; case 2: -#line 384 "kcar.c" - if ( (*p) == 84 ) - goto st3; +#line 712 "kcar.c" + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st49; + case 124: goto st49; + case 126: goto st49; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st49; + } else if ( (*p) >= 35 ) + goto st49; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st49; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st49; + } else + goto st49; + } else + goto st49; goto st0; +tr4: +#line 613 "kcar.rl" + { request_method(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st3; st3: if ( ++p == pe ) goto _test_eof3; case 3: - if ( (*p) == 84 ) - goto st4; +#line 745 "kcar.c" + switch( (*p) ) { + case 42: goto tr6; + case 47: goto tr7; + case 72: goto tr8; + case 104: goto tr8; + } goto st0; +tr6: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st4; st4: if ( ++p == pe ) goto _test_eof4; case 4: - if ( (*p) == 80 ) - goto st5; +#line 761 "kcar.c" + switch( (*p) ) { + case 32: goto tr9; + case 35: goto tr10; + } goto st0; +tr9: +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st5; +tr43: +#line 609 "kcar.rl" + {MARK(mark, p); } +#line 617 "kcar.rl" + { set_fragment(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st5; +tr46: +#line 617 "kcar.rl" + { set_fragment(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st5; +tr50: +#line 622 "kcar.rl" + { request_path(hdr, PTR_TO(mark), LEN(mark, p)); } +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st5; +tr56: +#line 618 "kcar.rl" + { MARK(start.query, p); } +#line 619 "kcar.rl" + { + query_string(hp, hdr, PTR_TO(start.query), LEN(start.query, p)); + } +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st5; +tr60: +#line 619 "kcar.rl" + { + query_string(hp, hdr, PTR_TO(start.query), LEN(start.query, p)); + } +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st5; st5: if ( ++p == pe ) goto _test_eof5; case 5: - if ( (*p) == 47 ) - goto st6; +#line 809 "kcar.c" + if ( (*p) == 72 ) + goto tr11; goto st0; +tr11: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st6; st6: if ( ++p == pe ) goto _test_eof6; case 6: - if ( 48 <= (*p) && (*p) <= 57 ) +#line 821 "kcar.c" + if ( (*p) == 84 ) goto st7; goto st0; st7: if ( ++p == pe ) goto _test_eof7; case 7: - if ( (*p) == 46 ) + if ( (*p) == 84 ) goto st8; - if ( 48 <= (*p) && (*p) <= 57 ) - goto st7; goto st0; st8: if ( ++p == pe ) goto _test_eof8; case 8: - if ( 48 <= (*p) && (*p) <= 57 ) + if ( (*p) == 80 ) goto st9; goto st0; st9: if ( ++p == pe ) goto _test_eof9; case 9: - if ( (*p) == 32 ) - goto tr9; - if ( 48 <= (*p) && (*p) <= 57 ) - goto st9; + if ( (*p) == 47 ) + goto st10; goto st0; -tr9: -#line 310 "kcar.rl" - { http_version(hp, hdr, PTR_TO(mark), LEN(mark, p)); } - goto st10; st10: if ( ++p == pe ) goto _test_eof10; case 10: -#line 449 "kcar.c" - if ( (*p) == 32 ) - goto st10; if ( 48 <= (*p) && (*p) <= 57 ) - goto tr11; + goto st11; goto st0; -tr11: -#line 303 "kcar.rl" - {MARK(mark, p); } - goto st11; st11: if ( ++p == pe ) goto _test_eof11; case 11: -#line 463 "kcar.c" + if ( (*p) == 46 ) + goto st12; + if ( 48 <= (*p) && (*p) <= 57 ) + goto st11; + goto st0; +st12: + if ( ++p == pe ) + goto _test_eof12; +case 12: + if ( 48 <= (*p) && (*p) <= 57 ) + goto st13; + goto st0; +st13: + if ( ++p == pe ) + goto _test_eof13; +case 13: switch( (*p) ) { - case 10: goto tr12; - case 13: goto tr13; - case 32: goto st20; + case 10: goto tr19; + case 13: goto tr20; } if ( 48 <= (*p) && (*p) <= 57 ) - goto st11; + goto st13; goto st0; -tr12: -#line 311 "kcar.rl" - { status_phrase(hp, hdr, PTR_TO(mark), LEN(mark, p)); } - goto st12; -tr22: -#line 307 "kcar.rl" +tr19: +#line 628 "kcar.rl" + { http_version(hp, hdr, PTR_TO(mark), LEN(mark, p)); } + goto st14; +tr27: +#line 625 "kcar.rl" { MARK(mark, p); } -#line 309 "kcar.rl" +#line 627 "kcar.rl" { write_cont_value(hp, buffer, p); } - goto st12; -tr25: -#line 309 "kcar.rl" + goto st14; +tr30: +#line 627 "kcar.rl" { write_cont_value(hp, buffer, p); } - goto st12; -tr32: -#line 307 "kcar.rl" + goto st14; +tr37: +#line 625 "kcar.rl" { MARK(mark, p); } -#line 308 "kcar.rl" - { write_value(hdr, hp, buffer, p); } - goto st12; -tr35: -#line 308 "kcar.rl" - { write_value(hdr, hp, buffer, p); } - goto st12; -st12: +#line 626 "kcar.rl" + { write_value(hp, hdr, buffer, p); } + goto st14; +tr40: +#line 626 "kcar.rl" + { write_value(hp, hdr, buffer, p); } + goto st14; +tr162: +#line 629 "kcar.rl" + { status_phrase(hp, hdr, PTR_TO(mark), LEN(mark, p)); } + goto st14; +st14: if ( ++p == pe ) - goto _test_eof12; -case 12: -#line 500 "kcar.c" + goto _test_eof14; +case 14: +#line 912 "kcar.c" switch( (*p) ) { - case 9: goto st13; - case 10: goto tr17; - case 13: goto st16; - case 32: goto st13; - case 33: goto tr19; - case 124: goto tr19; - case 126: goto tr19; + case 9: goto st15; + case 10: goto tr22; + case 13: goto st18; + case 32: goto st15; + case 33: goto tr24; + case 124: goto tr24; + case 126: goto tr24; } if ( (*p) < 45 ) { if ( (*p) > 39 ) { if ( 42 <= (*p) && (*p) <= 43 ) - goto tr19; + goto tr24; } else if ( (*p) >= 35 ) - goto tr19; + goto tr24; } else if ( (*p) > 46 ) { if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) - goto tr19; + goto tr24; } else if ( (*p) > 90 ) { if ( 94 <= (*p) && (*p) <= 122 ) - goto tr19; + goto tr24; } else - goto tr19; + goto tr24; } else - goto tr19; + goto tr24; goto st0; -tr21: -#line 307 "kcar.rl" +tr26: +#line 625 "kcar.rl" { MARK(mark, p); } - goto st13; -st13: + goto st15; +st15: if ( ++p == pe ) - goto _test_eof13; -case 13: -#line 536 "kcar.c" + goto _test_eof15; +case 15: +#line 948 "kcar.c" switch( (*p) ) { - case 9: goto tr21; - case 10: goto tr22; - case 13: goto tr23; - case 32: goto tr21; + case 9: goto tr26; + case 10: goto tr27; + case 13: goto tr28; + case 32: goto tr26; + case 127: goto st0; } - goto tr20; -tr20: -#line 307 "kcar.rl" + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto tr25; +tr25: +#line 625 "kcar.rl" { MARK(mark, p); } - goto st14; -st14: + goto st16; +st16: if ( ++p == pe ) - goto _test_eof14; -case 14: -#line 552 "kcar.c" + goto _test_eof16; +case 16: +#line 967 "kcar.c" switch( (*p) ) { - case 10: goto tr25; - case 13: goto tr26; + case 10: goto tr30; + case 13: goto tr31; + case 127: goto st0; } - goto st14; -tr13: -#line 311 "kcar.rl" - { status_phrase(hp, hdr, PTR_TO(mark), LEN(mark, p)); } - goto st15; -tr23: -#line 307 "kcar.rl" + if ( (*p) > 8 ) { + if ( 11 <= (*p) && (*p) <= 31 ) + goto st0; + } else if ( (*p) >= 0 ) + goto st0; + goto st16; +tr20: +#line 628 "kcar.rl" + { http_version(hp, hdr, PTR_TO(mark), LEN(mark, p)); } + goto st17; +tr28: +#line 625 "kcar.rl" { MARK(mark, p); } -#line 309 "kcar.rl" +#line 627 "kcar.rl" { write_cont_value(hp, buffer, p); } - goto st15; -tr26: -#line 309 "kcar.rl" + goto st17; +tr31: +#line 627 "kcar.rl" { write_cont_value(hp, buffer, p); } - goto st15; -tr33: -#line 307 "kcar.rl" + goto st17; +tr38: +#line 625 "kcar.rl" { MARK(mark, p); } -#line 308 "kcar.rl" - { write_value(hdr, hp, buffer, p); } - goto st15; -tr36: -#line 308 "kcar.rl" - { write_value(hdr, hp, buffer, p); } - goto st15; -st15: +#line 626 "kcar.rl" + { write_value(hp, hdr, buffer, p); } + goto st17; +tr41: +#line 626 "kcar.rl" + { write_value(hp, hdr, buffer, p); } + goto st17; +tr163: +#line 629 "kcar.rl" + { status_phrase(hp, hdr, PTR_TO(mark), LEN(mark, p)); } + goto st17; +st17: if ( ++p == pe ) - goto _test_eof15; -case 15: -#line 586 "kcar.c" + goto _test_eof17; +case 17: +#line 1011 "kcar.c" if ( (*p) == 10 ) - goto st12; + goto st14; goto st0; -tr17: -#line 318 "kcar.rl" +tr22: +#line 636 "kcar.rl" { - finalize_header(hp); + finalize_header(hp, hdr); cs = http_parser_first_final; - if (HP_FL_TEST(hp, CHUNKED)) + if (hp->chunked) cs = http_parser_en_ChunkedBody; /* * go back to Ruby so we can call the Rack application, we'll reenter * the parser iff the body needs to be processed. */ goto post_exec; } - goto st44; -st44: + goto st134; +tr105: +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } +#line 636 "kcar.rl" + { + finalize_header(hp, hdr); + cs = http_parser_first_final; + + if (hp->chunked) + cs = http_parser_en_ChunkedBody; + + /* + * go back to Ruby so we can call the Rack application, we'll reenter + * the parser iff the body needs to be processed. + */ + goto post_exec; + } + goto st134; +tr109: +#line 609 "kcar.rl" + {MARK(mark, p); } +#line 617 "kcar.rl" + { set_fragment(hdr, PTR_TO(mark), LEN(mark, p)); } +#line 636 "kcar.rl" + { + finalize_header(hp, hdr); + cs = http_parser_first_final; + + if (hp->chunked) + cs = http_parser_en_ChunkedBody; + + /* + * go back to Ruby so we can call the Rack application, we'll reenter + * the parser iff the body needs to be processed. + */ + goto post_exec; + } + goto st134; +tr113: +#line 617 "kcar.rl" + { set_fragment(hdr, PTR_TO(mark), LEN(mark, p)); } +#line 636 "kcar.rl" + { + finalize_header(hp, hdr); + cs = http_parser_first_final; + + if (hp->chunked) + cs = http_parser_en_ChunkedBody; + + /* + * go back to Ruby so we can call the Rack application, we'll reenter + * the parser iff the body needs to be processed. + */ + goto post_exec; + } + goto st134; +tr118: +#line 622 "kcar.rl" + { request_path(hdr, PTR_TO(mark), LEN(mark, p)); } +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } +#line 636 "kcar.rl" + { + finalize_header(hp, hdr); + cs = http_parser_first_final; + + if (hp->chunked) + cs = http_parser_en_ChunkedBody; + + /* + * go back to Ruby so we can call the Rack application, we'll reenter + * the parser iff the body needs to be processed. + */ + goto post_exec; + } + goto st134; +tr125: +#line 618 "kcar.rl" + { MARK(start.query, p); } +#line 619 "kcar.rl" + { + query_string(hp, hdr, PTR_TO(start.query), LEN(start.query, p)); + } +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } +#line 636 "kcar.rl" + { + finalize_header(hp, hdr); + cs = http_parser_first_final; + + if (hp->chunked) + cs = http_parser_en_ChunkedBody; + + /* + * go back to Ruby so we can call the Rack application, we'll reenter + * the parser iff the body needs to be processed. + */ + goto post_exec; + } + goto st134; +tr130: +#line 619 "kcar.rl" + { + query_string(hp, hdr, PTR_TO(start.query), LEN(start.query, p)); + } +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } +#line 636 "kcar.rl" + { + finalize_header(hp, hdr); + cs = http_parser_first_final; + + if (hp->chunked) + cs = http_parser_en_ChunkedBody; + + /* + * go back to Ruby so we can call the Rack application, we'll reenter + * the parser iff the body needs to be processed. + */ + goto post_exec; + } + goto st134; +st134: if ( ++p == pe ) - goto _test_eof44; -case 44: -#line 610 "kcar.c" + goto _test_eof134; +case 134: +#line 1157 "kcar.c" goto st0; -st16: +tr106: +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st18; +tr110: +#line 609 "kcar.rl" + {MARK(mark, p); } +#line 617 "kcar.rl" + { set_fragment(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st18; +tr114: +#line 617 "kcar.rl" + { set_fragment(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st18; +tr119: +#line 622 "kcar.rl" + { request_path(hdr, PTR_TO(mark), LEN(mark, p)); } +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st18; +tr126: +#line 618 "kcar.rl" + { MARK(start.query, p); } +#line 619 "kcar.rl" + { + query_string(hp, hdr, PTR_TO(start.query), LEN(start.query, p)); + } +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st18; +tr131: +#line 619 "kcar.rl" + { + query_string(hp, hdr, PTR_TO(start.query), LEN(start.query, p)); + } +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st18; +st18: if ( ++p == pe ) - goto _test_eof16; -case 16: + goto _test_eof18; +case 18: +#line 1201 "kcar.c" if ( (*p) == 10 ) - goto tr17; + goto tr22; goto st0; -tr19: -#line 305 "kcar.rl" +tr24: +#line 623 "kcar.rl" { MARK(start.field, p); } - goto st17; -st17: + goto st19; +st19: if ( ++p == pe ) - goto _test_eof17; -case 17: -#line 627 "kcar.c" + goto _test_eof19; +case 19: +#line 1213 "kcar.c" switch( (*p) ) { - case 33: goto st17; - case 58: goto tr29; - case 124: goto st17; - case 126: goto st17; + case 33: goto st19; + case 58: goto tr34; + case 124: goto st19; + case 126: goto st19; } if ( (*p) < 45 ) { if ( (*p) > 39 ) { if ( 42 <= (*p) && (*p) <= 43 ) - goto st17; + goto st19; } else if ( (*p) >= 35 ) - goto st17; + goto st19; } else if ( (*p) > 46 ) { if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) - goto st17; + goto st19; } else if ( (*p) > 90 ) { if ( 94 <= (*p) && (*p) <= 122 ) - goto st17; + goto st19; } else - goto st17; + goto st19; } else - goto st17; + goto st19; goto st0; -tr31: -#line 307 "kcar.rl" +tr36: +#line 625 "kcar.rl" { MARK(mark, p); } - goto st18; -tr29: -#line 306 "kcar.rl" + goto st20; +tr34: +#line 624 "kcar.rl" { hp->s.field_len = LEN(start.field, p); } - goto st18; -st18: - if ( ++p == pe ) - goto _test_eof18; -case 18: -#line 664 "kcar.c" - switch( (*p) ) { - case 9: goto tr31; - case 10: goto tr32; - case 13: goto tr33; - case 32: goto tr31; - } - goto tr30; -tr30: -#line 307 "kcar.rl" - { MARK(mark, p); } - goto st19; -st19: - if ( ++p == pe ) - goto _test_eof19; -case 19: -#line 680 "kcar.c" - switch( (*p) ) { - case 10: goto tr35; - case 13: goto tr36; - } - goto st19; + goto st20; st20: if ( ++p == pe ) goto _test_eof20; case 20: - if ( (*p) == 10 ) +#line 1250 "kcar.c" + switch( (*p) ) { + case 9: goto tr36; + case 10: goto tr37; + case 13: goto tr38; + case 32: goto tr36; + case 127: goto st0; + } + if ( 0 <= (*p) && (*p) <= 31 ) goto st0; + goto tr35; +tr35: +#line 625 "kcar.rl" + { MARK(mark, p); } goto st21; st21: if ( ++p == pe ) goto _test_eof21; case 21: +#line 1269 "kcar.c" switch( (*p) ) { - case 10: goto tr12; - case 13: goto tr13; + case 10: goto tr40; + case 13: goto tr41; + case 127: goto st0; } + if ( (*p) > 8 ) { + if ( 11 <= (*p) && (*p) <= 31 ) + goto st0; + } else if ( (*p) >= 0 ) + goto st0; goto st21; +tr10: +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st22; +tr51: +#line 622 "kcar.rl" + { request_path(hdr, PTR_TO(mark), LEN(mark, p)); } +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st22; +tr57: +#line 618 "kcar.rl" + { MARK(start.query, p); } +#line 619 "kcar.rl" + { + query_string(hp, hdr, PTR_TO(start.query), LEN(start.query, p)); + } +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st22; +tr61: +#line 619 "kcar.rl" + { + query_string(hp, hdr, PTR_TO(start.query), LEN(start.query, p)); + } +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st22; st22: if ( ++p == pe ) goto _test_eof22; case 22: +#line 1313 "kcar.c" + switch( (*p) ) { + case 32: goto tr43; + case 35: goto st0; + case 37: goto tr44; + case 127: goto st0; + } + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto tr42; +tr42: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st23; +st23: + if ( ++p == pe ) + goto _test_eof23; +case 23: +#line 1331 "kcar.c" + switch( (*p) ) { + case 32: goto tr46; + case 35: goto st0; + case 37: goto st24; + case 127: goto st0; + } + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto st23; +tr44: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st24; +st24: + if ( ++p == pe ) + goto _test_eof24; +case 24: +#line 1349 "kcar.c" + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st25; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st25; + } else + goto st25; + goto st0; +st25: + if ( ++p == pe ) + goto _test_eof25; +case 25: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st23; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st23; + } else + goto st23; + goto st0; +tr7: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st26; +tr77: +#line 615 "kcar.rl" + { request_host(hp, hdr, PTR_TO(mark), LEN(mark, p)); } +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st26; +st26: + if ( ++p == pe ) + goto _test_eof26; +case 26: +#line 1386 "kcar.c" + switch( (*p) ) { + case 32: goto tr50; + case 35: goto tr51; + case 37: goto st27; + case 63: goto tr53; + case 127: goto st0; + } + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto st26; +st27: + if ( ++p == pe ) + goto _test_eof27; +case 27: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st28; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st28; + } else + goto st28; + goto st0; +st28: + if ( ++p == pe ) + goto _test_eof28; +case 28: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st26; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st26; + } else + goto st26; + goto st0; +tr53: +#line 622 "kcar.rl" + { request_path(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st29; +st29: + if ( ++p == pe ) + goto _test_eof29; +case 29: +#line 1431 "kcar.c" + switch( (*p) ) { + case 32: goto tr56; + case 35: goto tr57; + case 37: goto tr58; + case 127: goto st0; + } + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto tr55; +tr55: +#line 618 "kcar.rl" + { MARK(start.query, p); } + goto st30; +st30: + if ( ++p == pe ) + goto _test_eof30; +case 30: +#line 1449 "kcar.c" + switch( (*p) ) { + case 32: goto tr60; + case 35: goto tr61; + case 37: goto st31; + case 127: goto st0; + } + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto st30; +tr58: +#line 618 "kcar.rl" + { MARK(start.query, p); } + goto st31; +st31: + if ( ++p == pe ) + goto _test_eof31; +case 31: +#line 1467 "kcar.c" + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st32; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st32; + } else + goto st32; + goto st0; +st32: + if ( ++p == pe ) + goto _test_eof32; +case 32: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st30; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st30; + } else + goto st30; + goto st0; +tr8: +#line 609 "kcar.rl" + {MARK(mark, p); } +#line 612 "kcar.rl" + { downcase_char(deconst(p)); } + goto st33; +st33: + if ( ++p == pe ) + goto _test_eof33; +case 33: +#line 1500 "kcar.c" + switch( (*p) ) { + case 84: goto tr64; + case 116: goto tr64; + } + goto st0; +tr64: +#line 612 "kcar.rl" + { downcase_char(deconst(p)); } + goto st34; +st34: + if ( ++p == pe ) + goto _test_eof34; +case 34: +#line 1514 "kcar.c" + switch( (*p) ) { + case 84: goto tr65; + case 116: goto tr65; + } + goto st0; +tr65: +#line 612 "kcar.rl" + { downcase_char(deconst(p)); } + goto st35; +st35: + if ( ++p == pe ) + goto _test_eof35; +case 35: +#line 1528 "kcar.c" + switch( (*p) ) { + case 80: goto tr66; + case 112: goto tr66; + } + goto st0; +tr66: +#line 612 "kcar.rl" + { downcase_char(deconst(p)); } + goto st36; +st36: + if ( ++p == pe ) + goto _test_eof36; +case 36: +#line 1542 "kcar.c" + switch( (*p) ) { + case 58: goto tr67; + case 83: goto tr68; + case 115: goto tr68; + } + goto st0; +tr67: +#line 614 "kcar.rl" + { url_scheme(hp, hdr, PTR_TO(mark), LEN(mark, p)); } + goto st37; +st37: + if ( ++p == pe ) + goto _test_eof37; +case 37: +#line 1557 "kcar.c" + if ( (*p) == 47 ) + goto st38; + goto st0; +st38: + if ( ++p == pe ) + goto _test_eof38; +case 38: + if ( (*p) == 47 ) + goto st39; + goto st0; +st39: + if ( ++p == pe ) + goto _test_eof39; +case 39: + switch( (*p) ) { + case 37: goto st41; + case 47: goto st0; + case 60: goto st0; + case 91: goto tr74; + case 95: goto tr73; + case 127: goto st0; + } + if ( (*p) < 45 ) { + if ( (*p) > 32 ) { + if ( 34 <= (*p) && (*p) <= 35 ) + goto st0; + } else if ( (*p) >= 0 ) + goto st0; + } else if ( (*p) > 57 ) { + if ( (*p) < 65 ) { + if ( 62 <= (*p) && (*p) <= 64 ) + goto st0; + } else if ( (*p) > 90 ) { + if ( 97 <= (*p) && (*p) <= 122 ) + goto tr73; + } else + goto tr73; + } else + goto tr73; + goto st40; +st40: + if ( ++p == pe ) + goto _test_eof40; +case 40: + switch( (*p) ) { + case 37: goto st41; + case 47: goto st0; + case 60: goto st0; + case 64: goto st39; + case 127: goto st0; + } + if ( (*p) < 34 ) { + if ( 0 <= (*p) && (*p) <= 32 ) + goto st0; + } else if ( (*p) > 35 ) { + if ( 62 <= (*p) && (*p) <= 63 ) + goto st0; + } else + goto st0; + goto st40; +st41: + if ( ++p == pe ) + goto _test_eof41; +case 41: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st42; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st42; + } else + goto st42; + goto st0; +st42: + if ( ++p == pe ) + goto _test_eof42; +case 42: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st40; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st40; + } else + goto st40; + goto st0; +tr73: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st43; +st43: + if ( ++p == pe ) + goto _test_eof43; +case 43: +#line 1652 "kcar.c" + switch( (*p) ) { + case 37: goto st41; + case 47: goto tr77; + case 58: goto st44; + case 60: goto st0; + case 64: goto st39; + case 95: goto st43; + case 127: goto st0; + } + if ( (*p) < 45 ) { + if ( (*p) > 32 ) { + if ( 34 <= (*p) && (*p) <= 35 ) + goto st0; + } else if ( (*p) >= 0 ) + goto st0; + } else if ( (*p) > 57 ) { + if ( (*p) < 65 ) { + if ( 62 <= (*p) && (*p) <= 63 ) + goto st0; + } else if ( (*p) > 90 ) { + if ( 97 <= (*p) && (*p) <= 122 ) + goto st43; + } else + goto st43; + } else + goto st43; + goto st40; +st44: + if ( ++p == pe ) + goto _test_eof44; +case 44: + switch( (*p) ) { + case 37: goto st41; + case 47: goto tr77; + case 60: goto st0; + case 64: goto st39; + case 127: goto st0; + } + if ( (*p) < 34 ) { + if ( 0 <= (*p) && (*p) <= 32 ) + goto st0; + } else if ( (*p) > 35 ) { + if ( (*p) > 57 ) { + if ( 62 <= (*p) && (*p) <= 63 ) + goto st0; + } else if ( (*p) >= 48 ) + goto st44; + } else + goto st0; + goto st40; +tr74: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st45; +st45: + if ( ++p == pe ) + goto _test_eof45; +case 45: +#line 1711 "kcar.c" + switch( (*p) ) { + case 37: goto st41; + case 47: goto st0; + case 60: goto st0; + case 64: goto st39; + case 127: goto st0; + } + if ( (*p) < 48 ) { + if ( (*p) > 32 ) { + if ( 34 <= (*p) && (*p) <= 35 ) + goto st0; + } else if ( (*p) >= 0 ) + goto st0; + } else if ( (*p) > 58 ) { + if ( (*p) < 65 ) { + if ( 62 <= (*p) && (*p) <= 63 ) + goto st0; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st46; + } else + goto st46; + } else + goto st46; + goto st40; +st46: + if ( ++p == pe ) + goto _test_eof46; +case 46: + switch( (*p) ) { + case 37: goto st41; + case 47: goto st0; + case 60: goto st0; + case 64: goto st39; + case 93: goto st47; + case 127: goto st0; + } + if ( (*p) < 48 ) { + if ( (*p) > 32 ) { + if ( 34 <= (*p) && (*p) <= 35 ) + goto st0; + } else if ( (*p) >= 0 ) + goto st0; + } else if ( (*p) > 58 ) { + if ( (*p) < 65 ) { + if ( 62 <= (*p) && (*p) <= 63 ) + goto st0; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st46; + } else + goto st46; + } else + goto st46; + goto st40; +st47: + if ( ++p == pe ) + goto _test_eof47; +case 47: + switch( (*p) ) { + case 37: goto st41; + case 47: goto tr77; + case 58: goto st44; + case 60: goto st0; + case 64: goto st39; + case 127: goto st0; + } + if ( (*p) < 34 ) { + if ( 0 <= (*p) && (*p) <= 32 ) + goto st0; + } else if ( (*p) > 35 ) { + if ( 62 <= (*p) && (*p) <= 63 ) + goto st0; + } else + goto st0; + goto st40; +tr68: +#line 612 "kcar.rl" + { downcase_char(deconst(p)); } + goto st48; +st48: + if ( ++p == pe ) + goto _test_eof48; +case 48: +#line 1796 "kcar.c" + if ( (*p) == 58 ) + goto tr67; + goto st0; +st49: + if ( ++p == pe ) + goto _test_eof49; +case 49: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st50; + case 124: goto st50; + case 126: goto st50; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st50; + } else if ( (*p) >= 35 ) + goto st50; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st50; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st50; + } else + goto st50; + } else + goto st50; + goto st0; +st50: + if ( ++p == pe ) + goto _test_eof50; +case 50: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st51; + case 124: goto st51; + case 126: goto st51; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st51; + } else if ( (*p) >= 35 ) + goto st51; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st51; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st51; + } else + goto st51; + } else + goto st51; + goto st0; +st51: + if ( ++p == pe ) + goto _test_eof51; +case 51: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st52; + case 124: goto st52; + case 126: goto st52; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st52; + } else if ( (*p) >= 35 ) + goto st52; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st52; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st52; + } else + goto st52; + } else + goto st52; + goto st0; +st52: + if ( ++p == pe ) + goto _test_eof52; +case 52: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st53; + case 124: goto st53; + case 126: goto st53; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st53; + } else if ( (*p) >= 35 ) + goto st53; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st53; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st53; + } else + goto st53; + } else + goto st53; + goto st0; +st53: + if ( ++p == pe ) + goto _test_eof53; +case 53: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st54; + case 124: goto st54; + case 126: goto st54; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st54; + } else if ( (*p) >= 35 ) + goto st54; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st54; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st54; + } else + goto st54; + } else + goto st54; + goto st0; +st54: + if ( ++p == pe ) + goto _test_eof54; +case 54: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st55; + case 124: goto st55; + case 126: goto st55; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st55; + } else if ( (*p) >= 35 ) + goto st55; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st55; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st55; + } else + goto st55; + } else + goto st55; + goto st0; +st55: + if ( ++p == pe ) + goto _test_eof55; +case 55: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st56; + case 124: goto st56; + case 126: goto st56; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st56; + } else if ( (*p) >= 35 ) + goto st56; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st56; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st56; + } else + goto st56; + } else + goto st56; + goto st0; +st56: + if ( ++p == pe ) + goto _test_eof56; +case 56: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st57; + case 124: goto st57; + case 126: goto st57; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st57; + } else if ( (*p) >= 35 ) + goto st57; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st57; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st57; + } else + goto st57; + } else + goto st57; + goto st0; +st57: + if ( ++p == pe ) + goto _test_eof57; +case 57: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st58; + case 124: goto st58; + case 126: goto st58; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st58; + } else if ( (*p) >= 35 ) + goto st58; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st58; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st58; + } else + goto st58; + } else + goto st58; + goto st0; +st58: + if ( ++p == pe ) + goto _test_eof58; +case 58: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st59; + case 124: goto st59; + case 126: goto st59; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st59; + } else if ( (*p) >= 35 ) + goto st59; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st59; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st59; + } else + goto st59; + } else + goto st59; + goto st0; +st59: + if ( ++p == pe ) + goto _test_eof59; +case 59: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st60; + case 124: goto st60; + case 126: goto st60; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st60; + } else if ( (*p) >= 35 ) + goto st60; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st60; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st60; + } else + goto st60; + } else + goto st60; + goto st0; +st60: + if ( ++p == pe ) + goto _test_eof60; +case 60: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st61; + case 124: goto st61; + case 126: goto st61; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st61; + } else if ( (*p) >= 35 ) + goto st61; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st61; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st61; + } else + goto st61; + } else + goto st61; + goto st0; +st61: + if ( ++p == pe ) + goto _test_eof61; +case 61: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st62; + case 124: goto st62; + case 126: goto st62; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st62; + } else if ( (*p) >= 35 ) + goto st62; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st62; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st62; + } else + goto st62; + } else + goto st62; + goto st0; +st62: + if ( ++p == pe ) + goto _test_eof62; +case 62: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st63; + case 124: goto st63; + case 126: goto st63; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st63; + } else if ( (*p) >= 35 ) + goto st63; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st63; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st63; + } else + goto st63; + } else + goto st63; + goto st0; +st63: + if ( ++p == pe ) + goto _test_eof63; +case 63: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st64; + case 124: goto st64; + case 126: goto st64; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st64; + } else if ( (*p) >= 35 ) + goto st64; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st64; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st64; + } else + goto st64; + } else + goto st64; + goto st0; +st64: + if ( ++p == pe ) + goto _test_eof64; +case 64: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st65; + case 124: goto st65; + case 126: goto st65; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st65; + } else if ( (*p) >= 35 ) + goto st65; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st65; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st65; + } else + goto st65; + } else + goto st65; + goto st0; +st65: + if ( ++p == pe ) + goto _test_eof65; +case 65: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st66; + case 124: goto st66; + case 126: goto st66; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st66; + } else if ( (*p) >= 35 ) + goto st66; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st66; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st66; + } else + goto st66; + } else + goto st66; + goto st0; +st66: + if ( ++p == pe ) + goto _test_eof66; +case 66: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st67; + case 124: goto st67; + case 126: goto st67; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st67; + } else if ( (*p) >= 35 ) + goto st67; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st67; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st67; + } else + goto st67; + } else + goto st67; + goto st0; +st67: + if ( ++p == pe ) + goto _test_eof67; +case 67: + if ( (*p) == 32 ) + goto tr4; + goto st0; +tr2: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st68; +st68: + if ( ++p == pe ) + goto _test_eof68; +case 68: +#line 2319 "kcar.c" + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st49; + case 69: goto st69; + case 124: goto st49; + case 126: goto st49; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st49; + } else if ( (*p) >= 35 ) + goto st49; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st49; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st49; + } else + goto st49; + } else + goto st49; + goto st0; +st69: + if ( ++p == pe ) + goto _test_eof69; +case 69: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st50; + case 84: goto st70; + case 124: goto st50; + case 126: goto st50; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st50; + } else if ( (*p) >= 35 ) + goto st50; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st50; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st50; + } else + goto st50; + } else + goto st50; + goto st0; +st70: + if ( ++p == pe ) + goto _test_eof70; +case 70: + switch( (*p) ) { + case 32: goto tr101; + case 33: goto st51; + case 124: goto st51; + case 126: goto st51; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st51; + } else if ( (*p) >= 35 ) + goto st51; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st51; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st51; + } else + goto st51; + } else + goto st51; + goto st0; +tr101: +#line 613 "kcar.rl" + { request_method(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st71; +st71: + if ( ++p == pe ) + goto _test_eof71; +case 71: +#line 2410 "kcar.c" + switch( (*p) ) { + case 42: goto tr102; + case 47: goto tr103; + case 72: goto tr104; + case 104: goto tr104; + } + goto st0; +tr102: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st72; +st72: + if ( ++p == pe ) + goto _test_eof72; +case 72: +#line 2426 "kcar.c" + switch( (*p) ) { + case 10: goto tr105; + case 13: goto tr106; + case 32: goto tr9; + case 35: goto tr107; + } + goto st0; +tr107: +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st73; +tr120: +#line 622 "kcar.rl" + { request_path(hdr, PTR_TO(mark), LEN(mark, p)); } +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st73; +tr127: +#line 618 "kcar.rl" + { MARK(start.query, p); } +#line 619 "kcar.rl" + { + query_string(hp, hdr, PTR_TO(start.query), LEN(start.query, p)); + } +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st73; +tr132: +#line 619 "kcar.rl" + { + query_string(hp, hdr, PTR_TO(start.query), LEN(start.query, p)); + } +#line 616 "kcar.rl" + { request_uri(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st73; +st73: + if ( ++p == pe ) + goto _test_eof73; +case 73: +#line 2466 "kcar.c" + switch( (*p) ) { + case 10: goto tr109; + case 13: goto tr110; + case 32: goto tr43; + case 35: goto st0; + case 37: goto tr111; + case 127: goto st0; + } + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto tr108; +tr108: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st74; +st74: + if ( ++p == pe ) + goto _test_eof74; +case 74: +#line 2486 "kcar.c" + switch( (*p) ) { + case 10: goto tr113; + case 13: goto tr114; + case 32: goto tr46; + case 35: goto st0; + case 37: goto st75; + case 127: goto st0; + } + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto st74; +tr111: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st75; +st75: + if ( ++p == pe ) + goto _test_eof75; +case 75: +#line 2506 "kcar.c" + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st76; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st76; + } else + goto st76; + goto st0; +st76: + if ( ++p == pe ) + goto _test_eof76; +case 76: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st74; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st74; + } else + goto st74; + goto st0; +tr103: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st77; +tr148: +#line 615 "kcar.rl" + { request_host(hp, hdr, PTR_TO(mark), LEN(mark, p)); } +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st77; +st77: + if ( ++p == pe ) + goto _test_eof77; +case 77: +#line 2543 "kcar.c" + switch( (*p) ) { + case 10: goto tr118; + case 13: goto tr119; + case 32: goto tr50; + case 35: goto tr120; + case 37: goto st78; + case 63: goto tr122; + case 127: goto st0; + } + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto st77; +st78: + if ( ++p == pe ) + goto _test_eof78; +case 78: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st79; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st79; + } else + goto st79; + goto st0; +st79: + if ( ++p == pe ) + goto _test_eof79; +case 79: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st77; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st77; + } else + goto st77; + goto st0; +tr122: +#line 622 "kcar.rl" + { request_path(hdr, PTR_TO(mark), LEN(mark, p)); } + goto st80; +st80: + if ( ++p == pe ) + goto _test_eof80; +case 80: +#line 2590 "kcar.c" + switch( (*p) ) { + case 10: goto tr125; + case 13: goto tr126; + case 32: goto tr56; + case 35: goto tr127; + case 37: goto tr128; + case 127: goto st0; + } + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto tr124; +tr124: +#line 618 "kcar.rl" + { MARK(start.query, p); } + goto st81; +st81: + if ( ++p == pe ) + goto _test_eof81; +case 81: +#line 2610 "kcar.c" + switch( (*p) ) { + case 10: goto tr130; + case 13: goto tr131; + case 32: goto tr60; + case 35: goto tr132; + case 37: goto st82; + case 127: goto st0; + } + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto st81; +tr128: +#line 618 "kcar.rl" + { MARK(start.query, p); } + goto st82; +st82: + if ( ++p == pe ) + goto _test_eof82; +case 82: +#line 2630 "kcar.c" + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st83; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st83; + } else + goto st83; + goto st0; +st83: + if ( ++p == pe ) + goto _test_eof83; +case 83: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st81; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st81; + } else + goto st81; + goto st0; +tr104: +#line 609 "kcar.rl" + {MARK(mark, p); } +#line 612 "kcar.rl" + { downcase_char(deconst(p)); } + goto st84; +st84: + if ( ++p == pe ) + goto _test_eof84; +case 84: +#line 2663 "kcar.c" + switch( (*p) ) { + case 84: goto tr135; + case 116: goto tr135; + } + goto st0; +tr135: +#line 612 "kcar.rl" + { downcase_char(deconst(p)); } + goto st85; +st85: + if ( ++p == pe ) + goto _test_eof85; +case 85: +#line 2677 "kcar.c" + switch( (*p) ) { + case 84: goto tr136; + case 116: goto tr136; + } + goto st0; +tr136: +#line 612 "kcar.rl" + { downcase_char(deconst(p)); } + goto st86; +st86: + if ( ++p == pe ) + goto _test_eof86; +case 86: +#line 2691 "kcar.c" + switch( (*p) ) { + case 80: goto tr137; + case 112: goto tr137; + } + goto st0; +tr137: +#line 612 "kcar.rl" + { downcase_char(deconst(p)); } + goto st87; +st87: + if ( ++p == pe ) + goto _test_eof87; +case 87: +#line 2705 "kcar.c" + switch( (*p) ) { + case 58: goto tr138; + case 83: goto tr139; + case 115: goto tr139; + } + goto st0; +tr138: +#line 614 "kcar.rl" + { url_scheme(hp, hdr, PTR_TO(mark), LEN(mark, p)); } + goto st88; +st88: + if ( ++p == pe ) + goto _test_eof88; +case 88: +#line 2720 "kcar.c" + if ( (*p) == 47 ) + goto st89; + goto st0; +st89: + if ( ++p == pe ) + goto _test_eof89; +case 89: + if ( (*p) == 47 ) + goto st90; + goto st0; +st90: + if ( ++p == pe ) + goto _test_eof90; +case 90: + switch( (*p) ) { + case 37: goto st92; + case 47: goto st0; + case 60: goto st0; + case 91: goto tr145; + case 95: goto tr144; + case 127: goto st0; + } + if ( (*p) < 45 ) { + if ( (*p) > 32 ) { + if ( 34 <= (*p) && (*p) <= 35 ) + goto st0; + } else if ( (*p) >= 0 ) + goto st0; + } else if ( (*p) > 57 ) { + if ( (*p) < 65 ) { + if ( 62 <= (*p) && (*p) <= 64 ) + goto st0; + } else if ( (*p) > 90 ) { + if ( 97 <= (*p) && (*p) <= 122 ) + goto tr144; + } else + goto tr144; + } else + goto tr144; + goto st91; +st91: + if ( ++p == pe ) + goto _test_eof91; +case 91: + switch( (*p) ) { + case 37: goto st92; + case 47: goto st0; + case 60: goto st0; + case 64: goto st90; + case 127: goto st0; + } + if ( (*p) < 34 ) { + if ( 0 <= (*p) && (*p) <= 32 ) + goto st0; + } else if ( (*p) > 35 ) { + if ( 62 <= (*p) && (*p) <= 63 ) + goto st0; + } else + goto st0; + goto st91; +st92: + if ( ++p == pe ) + goto _test_eof92; +case 92: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st93; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st93; + } else + goto st93; + goto st0; +st93: + if ( ++p == pe ) + goto _test_eof93; +case 93: + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st91; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st91; + } else + goto st91; + goto st0; +tr144: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st94; +st94: + if ( ++p == pe ) + goto _test_eof94; +case 94: +#line 2815 "kcar.c" + switch( (*p) ) { + case 37: goto st92; + case 47: goto tr148; + case 58: goto st95; + case 60: goto st0; + case 64: goto st90; + case 95: goto st94; + case 127: goto st0; + } + if ( (*p) < 45 ) { + if ( (*p) > 32 ) { + if ( 34 <= (*p) && (*p) <= 35 ) + goto st0; + } else if ( (*p) >= 0 ) + goto st0; + } else if ( (*p) > 57 ) { + if ( (*p) < 65 ) { + if ( 62 <= (*p) && (*p) <= 63 ) + goto st0; + } else if ( (*p) > 90 ) { + if ( 97 <= (*p) && (*p) <= 122 ) + goto st94; + } else + goto st94; + } else + goto st94; + goto st91; +st95: + if ( ++p == pe ) + goto _test_eof95; +case 95: + switch( (*p) ) { + case 37: goto st92; + case 47: goto tr148; + case 60: goto st0; + case 64: goto st90; + case 127: goto st0; + } + if ( (*p) < 34 ) { + if ( 0 <= (*p) && (*p) <= 32 ) + goto st0; + } else if ( (*p) > 35 ) { + if ( (*p) > 57 ) { + if ( 62 <= (*p) && (*p) <= 63 ) + goto st0; + } else if ( (*p) >= 48 ) + goto st95; + } else + goto st0; + goto st91; +tr145: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st96; +st96: + if ( ++p == pe ) + goto _test_eof96; +case 96: +#line 2874 "kcar.c" + switch( (*p) ) { + case 37: goto st92; + case 47: goto st0; + case 60: goto st0; + case 64: goto st90; + case 127: goto st0; + } + if ( (*p) < 48 ) { + if ( (*p) > 32 ) { + if ( 34 <= (*p) && (*p) <= 35 ) + goto st0; + } else if ( (*p) >= 0 ) + goto st0; + } else if ( (*p) > 58 ) { + if ( (*p) < 65 ) { + if ( 62 <= (*p) && (*p) <= 63 ) + goto st0; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st97; + } else + goto st97; + } else + goto st97; + goto st91; +st97: + if ( ++p == pe ) + goto _test_eof97; +case 97: + switch( (*p) ) { + case 37: goto st92; + case 47: goto st0; + case 60: goto st0; + case 64: goto st90; + case 93: goto st98; + case 127: goto st0; + } + if ( (*p) < 48 ) { + if ( (*p) > 32 ) { + if ( 34 <= (*p) && (*p) <= 35 ) + goto st0; + } else if ( (*p) >= 0 ) + goto st0; + } else if ( (*p) > 58 ) { + if ( (*p) < 65 ) { + if ( 62 <= (*p) && (*p) <= 63 ) + goto st0; + } else if ( (*p) > 70 ) { + if ( 97 <= (*p) && (*p) <= 102 ) + goto st97; + } else + goto st97; + } else + goto st97; + goto st91; +st98: + if ( ++p == pe ) + goto _test_eof98; +case 98: + switch( (*p) ) { + case 37: goto st92; + case 47: goto tr148; + case 58: goto st95; + case 60: goto st0; + case 64: goto st90; + case 127: goto st0; + } + if ( (*p) < 34 ) { + if ( 0 <= (*p) && (*p) <= 32 ) + goto st0; + } else if ( (*p) > 35 ) { + if ( 62 <= (*p) && (*p) <= 63 ) + goto st0; + } else + goto st0; + goto st91; +tr139: +#line 612 "kcar.rl" + { downcase_char(deconst(p)); } + goto st99; +st99: + if ( ++p == pe ) + goto _test_eof99; +case 99: +#line 2959 "kcar.c" + if ( (*p) == 58 ) + goto tr138; + goto st0; +tr3: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st100; +st100: + if ( ++p == pe ) + goto _test_eof100; +case 100: +#line 2971 "kcar.c" + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st49; + case 84: goto st101; + case 124: goto st49; + case 126: goto st49; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st49; + } else if ( (*p) >= 35 ) + goto st49; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st49; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st49; + } else + goto st49; + } else + goto st49; + goto st0; +st101: + if ( ++p == pe ) + goto _test_eof101; +case 101: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st50; + case 84: goto st102; + case 124: goto st50; + case 126: goto st50; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st50; + } else if ( (*p) >= 35 ) + goto st50; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st50; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st50; + } else + goto st50; + } else + goto st50; + goto st0; +st102: + if ( ++p == pe ) + goto _test_eof102; +case 102: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st51; + case 80: goto st103; + case 124: goto st51; + case 126: goto st51; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st51; + } else if ( (*p) >= 35 ) + goto st51; + } else if ( (*p) > 46 ) { + if ( (*p) < 65 ) { + if ( 48 <= (*p) && (*p) <= 57 ) + goto st51; + } else if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st51; + } else + goto st51; + } else + goto st51; + goto st0; +st103: + if ( ++p == pe ) + goto _test_eof103; +case 103: + switch( (*p) ) { + case 32: goto tr4; + case 33: goto st52; + case 47: goto st104; + case 124: goto st52; + case 126: goto st52; + } + if ( (*p) < 45 ) { + if ( (*p) > 39 ) { + if ( 42 <= (*p) && (*p) <= 43 ) + goto st52; + } else if ( (*p) >= 35 ) + goto st52; + } else if ( (*p) > 57 ) { + if ( (*p) > 90 ) { + if ( 94 <= (*p) && (*p) <= 122 ) + goto st52; + } else if ( (*p) >= 65 ) + goto st52; + } else + goto st52; + goto st0; +st104: + if ( ++p == pe ) + goto _test_eof104; +case 104: + if ( 48 <= (*p) && (*p) <= 57 ) + goto st105; + goto st0; +st105: + if ( ++p == pe ) + goto _test_eof105; +case 105: + if ( (*p) == 46 ) + goto st106; + if ( 48 <= (*p) && (*p) <= 57 ) + goto st105; + goto st0; +st106: + if ( ++p == pe ) + goto _test_eof106; +case 106: + if ( 48 <= (*p) && (*p) <= 57 ) + goto st107; + goto st0; +st107: + if ( ++p == pe ) + goto _test_eof107; +case 107: + if ( (*p) == 32 ) + goto tr159; + if ( 48 <= (*p) && (*p) <= 57 ) + goto st107; + goto st0; +tr159: +#line 628 "kcar.rl" + { http_version(hp, hdr, PTR_TO(mark), LEN(mark, p)); } + goto st108; +st108: + if ( ++p == pe ) + goto _test_eof108; +case 108: +#line 3121 "kcar.c" + if ( (*p) == 32 ) + goto st108; + if ( 48 <= (*p) && (*p) <= 57 ) + goto tr161; + goto st0; +tr161: +#line 609 "kcar.rl" + {MARK(mark, p); } + goto st109; +st109: + if ( ++p == pe ) + goto _test_eof109; +case 109: +#line 3135 "kcar.c" + switch( (*p) ) { + case 10: goto tr162; + case 13: goto tr163; + case 32: goto st110; + } + if ( 48 <= (*p) && (*p) <= 57 ) + goto st109; + goto st0; +st110: + if ( ++p == pe ) + goto _test_eof110; +case 110: + if ( (*p) == 10 ) + goto st0; + goto st111; +st111: + if ( ++p == pe ) + goto _test_eof111; +case 111: + switch( (*p) ) { + case 10: goto tr162; + case 13: goto tr163; + } + goto st111; +st112: + if ( ++p == pe ) + goto _test_eof112; +case 112: if ( (*p) == 48 ) - goto tr38; + goto tr167; if ( (*p) < 65 ) { if ( 49 <= (*p) && (*p) <= 57 ) - goto tr39; + goto tr168; } else if ( (*p) > 70 ) { if ( 97 <= (*p) && (*p) <= 102 ) - goto tr39; + goto tr168; } else - goto tr39; + goto tr168; goto st0; -tr38: -#line 313 "kcar.rl" +tr167: +#line 631 "kcar.rl" { hp->len.chunk = step_incr(hp->len.chunk, (*p), 16); if (hp->len.chunk < 0) rb_raise(eParserError, "invalid chunk size"); } - goto st23; -st23: + goto st113; +st113: if ( ++p == pe ) - goto _test_eof23; -case 23: -#line 729 "kcar.c" + goto _test_eof113; +case 113: +#line 3187 "kcar.c" switch( (*p) ) { - case 10: goto tr40; - case 13: goto st24; - case 48: goto tr38; - case 59: goto st33; + case 10: goto tr169; + case 13: goto st114; + case 48: goto tr167; + case 59: goto st123; } if ( (*p) < 65 ) { if ( 49 <= (*p) && (*p) <= 57 ) - goto tr39; + goto tr168; } else if ( (*p) > 70 ) { if ( 97 <= (*p) && (*p) <= 102 ) - goto tr39; + goto tr168; } else - goto tr39; + goto tr168; goto st0; -tr40: -#line 337 "kcar.rl" +tr169: +#line 655 "kcar.rl" { - HP_FL_SET(hp, INTRAILER); + hp->in_trailer = 1; cs = http_parser_en_Trailers; ++p; assert(p <= pe && "buffer overflow after chunked body"); goto post_exec; } - goto st45; -st45: + goto st135; +st135: if ( ++p == pe ) - goto _test_eof45; -case 45: -#line 759 "kcar.c" + goto _test_eof135; +case 135: +#line 3217 "kcar.c" goto st0; -st24: +st114: if ( ++p == pe ) - goto _test_eof24; -case 24: + goto _test_eof114; +case 114: if ( (*p) == 10 ) - goto tr40; + goto tr169; goto st0; -tr39: -#line 313 "kcar.rl" +tr168: +#line 631 "kcar.rl" { hp->len.chunk = step_incr(hp->len.chunk, (*p), 16); if (hp->len.chunk < 0) rb_raise(eParserError, "invalid chunk size"); } - goto st25; -st25: + goto st115; +st115: if ( ++p == pe ) - goto _test_eof25; -case 25: -#line 780 "kcar.c" + goto _test_eof115; +case 115: +#line 3238 "kcar.c" switch( (*p) ) { - case 10: goto st26; - case 13: goto st29; - case 59: goto st30; + case 10: goto st116; + case 13: goto st119; + case 59: goto st120; } if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) - goto tr39; + goto tr168; } else if ( (*p) > 70 ) { if ( 97 <= (*p) && (*p) <= 102 ) - goto tr39; + goto tr168; } else - goto tr39; + goto tr168; goto st0; -st26: +st116: if ( ++p == pe ) - goto _test_eof26; -case 26: - goto tr46; -tr46: -#line 345 "kcar.rl" + goto _test_eof116; +case 116: + goto tr175; +tr175: +#line 663 "kcar.rl" { skip_chunk_data_hack: { size_t nr = MIN((size_t)hp->len.chunk, REMAINING); memcpy(RSTRING_PTR(hdr) + hp->s.dest_offset, p, nr); hp->s.dest_offset += nr; hp->len.chunk -= nr; p += nr; assert(hp->len.chunk >= 0 && "negative chunk length"); if ((size_t)hp->len.chunk > REMAINING) { - HP_FL_SET(hp, INCHUNK); + hp->in_chunk = 1; goto post_exec; } else { p--; - {goto st27;} + {goto st117;} } }} - goto st27; -st27: + goto st117; +st117: if ( ++p == pe ) - goto _test_eof27; -case 27: -#line 823 "kcar.c" + goto _test_eof117; +case 117: +#line 3281 "kcar.c" switch( (*p) ) { - case 10: goto st22; - case 13: goto st28; + case 10: goto st112; + case 13: goto st118; } goto st0; -st28: +st118: if ( ++p == pe ) - goto _test_eof28; -case 28: + goto _test_eof118; +case 118: if ( (*p) == 10 ) - goto st22; + goto st112; goto st0; -st29: +st119: if ( ++p == pe ) - goto _test_eof29; -case 29: + goto _test_eof119; +case 119: if ( (*p) == 10 ) - goto st26; + goto st116; goto st0; -st30: +st120: if ( ++p == pe ) - goto _test_eof30; -case 30: + goto _test_eof120; +case 120: switch( (*p) ) { - case 10: goto st26; - case 13: goto st29; - case 32: goto st30; - case 33: goto st31; - case 59: goto st30; - case 61: goto st32; - case 124: goto st31; - case 126: goto st31; + case 10: goto st116; + case 13: goto st119; + case 32: goto st120; + case 33: goto st121; + case 59: goto st120; + case 61: goto st122; + case 124: goto st121; + case 126: goto st121; } if ( (*p) < 45 ) { if ( (*p) > 39 ) { if ( 42 <= (*p) && (*p) <= 43 ) - goto st31; + goto st121; } else if ( (*p) >= 35 ) - goto st31; + goto st121; } else if ( (*p) > 46 ) { if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) - goto st31; + goto st121; } else if ( (*p) > 90 ) { if ( 94 <= (*p) && (*p) <= 122 ) - goto st31; + goto st121; } else - goto st31; + goto st121; } else - goto st31; + goto st121; goto st0; -st31: +st121: if ( ++p == pe ) - goto _test_eof31; -case 31: + goto _test_eof121; +case 121: switch( (*p) ) { - case 10: goto st26; - case 13: goto st29; - case 33: goto st31; - case 59: goto st30; - case 61: goto st32; - case 124: goto st31; - case 126: goto st31; + case 10: goto st116; + case 13: goto st119; + case 33: goto st121; + case 59: goto st120; + case 61: goto st122; + case 124: goto st121; + case 126: goto st121; } if ( (*p) < 45 ) { if ( (*p) > 39 ) { if ( 42 <= (*p) && (*p) <= 43 ) - goto st31; + goto st121; } else if ( (*p) >= 35 ) - goto st31; + goto st121; } else if ( (*p) > 46 ) { if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) - goto st31; + goto st121; } else if ( (*p) > 90 ) { if ( 94 <= (*p) && (*p) <= 122 ) - goto st31; + goto st121; } else - goto st31; + goto st121; } else - goto st31; + goto st121; goto st0; -st32: +st122: if ( ++p == pe ) - goto _test_eof32; -case 32: + goto _test_eof122; +case 122: switch( (*p) ) { - case 10: goto st26; - case 13: goto st29; - case 33: goto st32; - case 59: goto st30; - case 124: goto st32; - case 126: goto st32; + case 10: goto st116; + case 13: goto st119; + case 33: goto st122; + case 59: goto st120; + case 124: goto st122; + case 126: goto st122; } if ( (*p) < 45 ) { if ( (*p) > 39 ) { if ( 42 <= (*p) && (*p) <= 43 ) - goto st32; + goto st122; } else if ( (*p) >= 35 ) - goto st32; + goto st122; } else if ( (*p) > 46 ) { if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) - goto st32; + goto st122; } else if ( (*p) > 90 ) { if ( 94 <= (*p) && (*p) <= 122 ) - goto st32; + goto st122; } else - goto st32; + goto st122; } else - goto st32; + goto st122; goto st0; -st33: +st123: if ( ++p == pe ) - goto _test_eof33; -case 33: + goto _test_eof123; +case 123: switch( (*p) ) { - case 10: goto tr40; - case 13: goto st24; - case 32: goto st33; - case 33: goto st34; - case 59: goto st33; - case 61: goto st35; - case 124: goto st34; - case 126: goto st34; + case 10: goto tr169; + case 13: goto st114; + case 32: goto st123; + case 33: goto st124; + case 59: goto st123; + case 61: goto st125; + case 124: goto st124; + case 126: goto st124; } if ( (*p) < 45 ) { if ( (*p) > 39 ) { if ( 42 <= (*p) && (*p) <= 43 ) - goto st34; + goto st124; } else if ( (*p) >= 35 ) - goto st34; + goto st124; } else if ( (*p) > 46 ) { if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) - goto st34; + goto st124; } else if ( (*p) > 90 ) { if ( 94 <= (*p) && (*p) <= 122 ) - goto st34; + goto st124; } else - goto st34; + goto st124; } else - goto st34; + goto st124; goto st0; -st34: +st124: if ( ++p == pe ) - goto _test_eof34; -case 34: + goto _test_eof124; +case 124: switch( (*p) ) { - case 10: goto tr40; - case 13: goto st24; - case 33: goto st34; - case 59: goto st33; - case 61: goto st35; - case 124: goto st34; - case 126: goto st34; + case 10: goto tr169; + case 13: goto st114; + case 33: goto st124; + case 59: goto st123; + case 61: goto st125; + case 124: goto st124; + case 126: goto st124; } if ( (*p) < 45 ) { if ( (*p) > 39 ) { if ( 42 <= (*p) && (*p) <= 43 ) - goto st34; + goto st124; } else if ( (*p) >= 35 ) - goto st34; + goto st124; } else if ( (*p) > 46 ) { if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) - goto st34; + goto st124; } else if ( (*p) > 90 ) { if ( 94 <= (*p) && (*p) <= 122 ) - goto st34; + goto st124; } else - goto st34; + goto st124; } else - goto st34; + goto st124; goto st0; -st35: +st125: if ( ++p == pe ) - goto _test_eof35; -case 35: + goto _test_eof125; +case 125: switch( (*p) ) { - case 10: goto tr40; - case 13: goto st24; - case 33: goto st35; - case 59: goto st33; - case 124: goto st35; - case 126: goto st35; + case 10: goto tr169; + case 13: goto st114; + case 33: goto st125; + case 59: goto st123; + case 124: goto st125; + case 126: goto st125; } if ( (*p) < 45 ) { if ( (*p) > 39 ) { if ( 42 <= (*p) && (*p) <= 43 ) - goto st35; + goto st125; } else if ( (*p) >= 35 ) - goto st35; + goto st125; } else if ( (*p) > 46 ) { if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) - goto st35; + goto st125; } else if ( (*p) > 90 ) { if ( 94 <= (*p) && (*p) <= 122 ) - goto st35; + goto st125; } else - goto st35; + goto st125; } else - goto st35; + goto st125; goto st0; -tr59: -#line 307 "kcar.rl" +tr188: +#line 625 "kcar.rl" { MARK(mark, p); } -#line 309 "kcar.rl" +#line 627 "kcar.rl" { write_cont_value(hp, buffer, p); } - goto st36; -tr62: -#line 309 "kcar.rl" + goto st126; +tr191: +#line 627 "kcar.rl" { write_cont_value(hp, buffer, p); } - goto st36; -tr69: -#line 307 "kcar.rl" + goto st126; +tr198: +#line 625 "kcar.rl" { MARK(mark, p); } -#line 308 "kcar.rl" - { write_value(hdr, hp, buffer, p); } - goto st36; -tr72: -#line 308 "kcar.rl" - { write_value(hdr, hp, buffer, p); } - goto st36; -st36: +#line 626 "kcar.rl" + { write_value(hp, hdr, buffer, p); } + goto st126; +tr201: +#line 626 "kcar.rl" + { write_value(hp, hdr, buffer, p); } + goto st126; +st126: if ( ++p == pe ) - goto _test_eof36; -case 36: -#line 1053 "kcar.c" + goto _test_eof126; +case 126: +#line 3511 "kcar.c" switch( (*p) ) { - case 9: goto st37; - case 10: goto tr54; - case 13: goto st40; - case 32: goto st37; - case 33: goto tr56; - case 124: goto tr56; - case 126: goto tr56; + case 9: goto st127; + case 10: goto tr183; + case 13: goto st130; + case 32: goto st127; + case 33: goto tr185; + case 124: goto tr185; + case 126: goto tr185; } if ( (*p) < 45 ) { if ( (*p) > 39 ) { if ( 42 <= (*p) && (*p) <= 43 ) - goto tr56; + goto tr185; } else if ( (*p) >= 35 ) - goto tr56; + goto tr185; } else if ( (*p) > 46 ) { if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) - goto tr56; + goto tr185; } else if ( (*p) > 90 ) { if ( 94 <= (*p) && (*p) <= 122 ) - goto tr56; + goto tr185; } else - goto tr56; + goto tr185; } else - goto tr56; + goto tr185; goto st0; -tr58: -#line 307 "kcar.rl" +tr187: +#line 625 "kcar.rl" { MARK(mark, p); } - goto st37; -st37: + goto st127; +st127: if ( ++p == pe ) - goto _test_eof37; -case 37: -#line 1089 "kcar.c" + goto _test_eof127; +case 127: +#line 3547 "kcar.c" switch( (*p) ) { - case 9: goto tr58; - case 10: goto tr59; - case 13: goto tr60; - case 32: goto tr58; + case 9: goto tr187; + case 10: goto tr188; + case 13: goto tr189; + case 32: goto tr187; + case 127: goto st0; } - goto tr57; -tr57: -#line 307 "kcar.rl" + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto tr186; +tr186: +#line 625 "kcar.rl" { MARK(mark, p); } - goto st38; -st38: + goto st128; +st128: if ( ++p == pe ) - goto _test_eof38; -case 38: -#line 1105 "kcar.c" + goto _test_eof128; +case 128: +#line 3566 "kcar.c" switch( (*p) ) { - case 10: goto tr62; - case 13: goto tr63; + case 10: goto tr191; + case 13: goto tr192; + case 127: goto st0; } - goto st38; -tr60: -#line 307 "kcar.rl" + if ( (*p) > 8 ) { + if ( 11 <= (*p) && (*p) <= 31 ) + goto st0; + } else if ( (*p) >= 0 ) + goto st0; + goto st128; +tr189: +#line 625 "kcar.rl" { MARK(mark, p); } -#line 309 "kcar.rl" +#line 627 "kcar.rl" { write_cont_value(hp, buffer, p); } - goto st39; -tr63: -#line 309 "kcar.rl" + goto st129; +tr192: +#line 627 "kcar.rl" { write_cont_value(hp, buffer, p); } - goto st39; -tr70: -#line 307 "kcar.rl" + goto st129; +tr199: +#line 625 "kcar.rl" { MARK(mark, p); } -#line 308 "kcar.rl" - { write_value(hdr, hp, buffer, p); } - goto st39; -tr73: -#line 308 "kcar.rl" - { write_value(hdr, hp, buffer, p); } - goto st39; -st39: +#line 626 "kcar.rl" + { write_value(hp, hdr, buffer, p); } + goto st129; +tr202: +#line 626 "kcar.rl" + { write_value(hp, hdr, buffer, p); } + goto st129; +st129: if ( ++p == pe ) - goto _test_eof39; -case 39: -#line 1135 "kcar.c" + goto _test_eof129; +case 129: +#line 3602 "kcar.c" if ( (*p) == 10 ) - goto st36; + goto st126; goto st0; -tr54: -#line 332 "kcar.rl" +tr183: +#line 650 "kcar.rl" { cs = http_parser_first_final; goto post_exec; } - goto st46; -st46: + goto st136; +st136: if ( ++p == pe ) - goto _test_eof46; -case 46: -#line 1150 "kcar.c" + goto _test_eof136; +case 136: +#line 3617 "kcar.c" goto st0; -st40: +st130: if ( ++p == pe ) - goto _test_eof40; -case 40: + goto _test_eof130; +case 130: if ( (*p) == 10 ) - goto tr54; + goto tr183; goto st0; -tr56: -#line 305 "kcar.rl" +tr185: +#line 623 "kcar.rl" { MARK(start.field, p); } - goto st41; -st41: + goto st131; +st131: if ( ++p == pe ) - goto _test_eof41; -case 41: -#line 1167 "kcar.c" + goto _test_eof131; +case 131: +#line 3634 "kcar.c" switch( (*p) ) { - case 33: goto st41; - case 58: goto tr66; - case 124: goto st41; - case 126: goto st41; + case 33: goto st131; + case 58: goto tr195; + case 124: goto st131; + case 126: goto st131; } if ( (*p) < 45 ) { if ( (*p) > 39 ) { if ( 42 <= (*p) && (*p) <= 43 ) - goto st41; + goto st131; } else if ( (*p) >= 35 ) - goto st41; + goto st131; } else if ( (*p) > 46 ) { if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) - goto st41; + goto st131; } else if ( (*p) > 90 ) { if ( 94 <= (*p) && (*p) <= 122 ) - goto st41; + goto st131; } else - goto st41; + goto st131; } else - goto st41; + goto st131; goto st0; -tr68: -#line 307 "kcar.rl" +tr197: +#line 625 "kcar.rl" { MARK(mark, p); } - goto st42; -tr66: -#line 306 "kcar.rl" + goto st132; +tr195: +#line 624 "kcar.rl" { hp->s.field_len = LEN(start.field, p); } - goto st42; -st42: + goto st132; +st132: if ( ++p == pe ) - goto _test_eof42; -case 42: -#line 1204 "kcar.c" + goto _test_eof132; +case 132: +#line 3671 "kcar.c" switch( (*p) ) { - case 9: goto tr68; - case 10: goto tr69; - case 13: goto tr70; - case 32: goto tr68; + case 9: goto tr197; + case 10: goto tr198; + case 13: goto tr199; + case 32: goto tr197; + case 127: goto st0; } - goto tr67; -tr67: -#line 307 "kcar.rl" + if ( 0 <= (*p) && (*p) <= 31 ) + goto st0; + goto tr196; +tr196: +#line 625 "kcar.rl" { MARK(mark, p); } - goto st43; -st43: + goto st133; +st133: if ( ++p == pe ) - goto _test_eof43; -case 43: -#line 1220 "kcar.c" + goto _test_eof133; +case 133: +#line 3690 "kcar.c" switch( (*p) ) { - case 10: goto tr72; - case 13: goto tr73; + case 10: goto tr201; + case 13: goto tr202; + case 127: goto st0; } - goto st43; + if ( (*p) > 8 ) { + if ( 11 <= (*p) && (*p) <= 31 ) + goto st0; + } else if ( (*p) >= 0 ) + goto st0; + goto st133; } _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; @@ -1235,20 +3711,19 @@ _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_eof44: cs = 44; goto _test_eof; _test_eof16: cs = 16; goto _test_eof; _test_eof17: cs = 17; goto _test_eof; + _test_eof134: cs = 134; goto _test_eof; _test_eof18: cs = 18; goto _test_eof; _test_eof19: cs = 19; 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_eof45: cs = 45; 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; @@ -1261,53 +3736,156 @@ _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_eof46: cs = 46; 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_eof135: cs = 135; 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_eof136: cs = 136; 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_eof: {} _out: {} } -#line 403 "kcar.rl" +#line 721 "kcar.rl" post_exec: /* "_out:" also goes here */ if (hp->cs != http_parser_error) hp->cs = cs; - hp->offset = p - buffer; + hp->offset = ulong2uint(p - buffer); assert(p <= pe && "buffer overflow after parsing execute"); assert(hp->offset <= len && "offset longer than length"); } -static struct http_parser *data_get(VALUE self) +static void kcar_mark(void *ptr) { - struct http_parser *hp; + struct http_parser *hp = ptr; - Data_Get_Struct(self, struct http_parser, hp); - assert(hp && "failed to extract http_parser struct"); - return hp; + rb_gc_mark(hp->cont); + rb_gc_mark(hp->v.status); } -static void mark(void *ptr) +static size_t kcar_memsize(const void *ptr) { - struct http_parser *hp = ptr; + return sizeof(struct http_parser); +} - rb_gc_mark(hp->cont); - rb_gc_mark(hp->status); +static const rb_data_type_t kcar_type = { + "kcar_parser", + { kcar_mark, RUBY_TYPED_DEFAULT_FREE, kcar_memsize, /* reserved */ }, + /* parent, data, [ flags ] */ +}; + +static VALUE kcar_alloc(VALUE klass) +{ + struct http_parser *hp; + return TypedData_Make_Struct(klass, struct http_parser, &kcar_type, hp); } -static VALUE alloc(VALUE klass) +static struct http_parser *data_get(VALUE self) { struct http_parser *hp; - return Data_Make_Struct(klass, struct http_parser, mark, -1, hp); + + TypedData_Get_Struct(self, struct http_parser, &kcar_type, hp); + assert(hp && "failed to extract http_parser struct"); + return hp; } + /** * call-seq: * Kcar::Parser.new => parser * * Creates a new parser. @@ -1357,11 +3935,11 @@ */ static VALUE body_bytes_left(VALUE self) { struct http_parser *hp = data_get(self); - if (HP_FL_TEST(hp, CHUNKED)) + if (hp->chunked) return Qnil; if (hp->len.content >= 0) return OFFT2NUM(hp->len.content); return Qnil; @@ -1377,13 +3955,15 @@ */ static VALUE body_bytes_left_set(VALUE self, VALUE bytes) { struct http_parser *hp = data_get(self); - if (HP_FL_TEST(hp, CHUNKED)) + if (hp->chunked) rb_raise(rb_eRuntimeError, "body_bytes_left= is not for chunked bodies"); hp->len.content = NUM2OFFT(bytes); + if (hp->len.content == 0) + hp->body_eof_seen = 1; return bytes; } /** * Document-method: chunked @@ -1394,13 +3974,36 @@ */ static VALUE chunked(VALUE self) { struct http_parser *hp = data_get(self); - return HP_FL_TEST(hp, CHUNKED) ? Qtrue : Qfalse; + return hp->chunked ? Qtrue : Qfalse; } +static void check_buffer_size(long dlen) +{ + if ((uint64_t)dlen > UINT_MAX) + rb_raise(rb_eRangeError, "headers too large to process (%ld bytes)", dlen); +} + +static void parser_execute(struct http_parser *hp, VALUE hdr, VALUE buf) +{ + char *ptr; + long len; + + Check_Type(buf, T_STRING); + rb_str_modify(buf); + ptr = RSTRING_PTR(buf); + len = RSTRING_LEN(buf); + check_buffer_size(len); + + http_parser_execute(hp, hdr, ptr, len); + + if (hp->cs == http_parser_error) + rb_raise(eParserError, "Invalid HTTP format, parsing fails."); +} + /** * Document-method: headers * call-seq: * parser.headers(hdr, data) => hdr or nil * @@ -1413,32 +4016,53 @@ */ static VALUE headers(VALUE self, VALUE hdr, VALUE data) { struct http_parser *hp = data_get(self); - http_parser_execute(hp, hdr, RSTRING_PTR(data), RSTRING_LEN(data)); + if (hp->is_request) + rb_raise(rb_eRuntimeError, "parser is handling a request, not response"); + + parser_execute(hp, hdr, data); VALIDATE_MAX_LENGTH(hp->offset, HEADER); if (hp->cs == http_parser_first_final || hp->cs == http_parser_en_ChunkedBody) { advance_str(data, hp->offset + 1); hp->offset = 0; - if (HP_FL_TEST(hp, INTRAILER)) + if (hp->in_trailer) return hdr; else - return rb_ary_new3(2, hp->status, hdr); + return rb_ary_new3(2, hp->v.status, hdr); } - if (hp->cs == http_parser_error) - rb_raise(eParserError, "Invalid HTTP format, parsing fails."); - return Qnil; } +static VALUE request(VALUE self, VALUE env, VALUE buf) +{ + struct http_parser *hp = data_get(self); + + hp->is_request = 1; + Check_Type(buf, T_STRING); + parser_execute(hp, env, buf); + + if (hp->cs == http_parser_first_final || + hp->cs == http_parser_en_ChunkedBody) { + advance_str(buf, hp->offset + 1); + hp->offset = 0; + if (hp->in_trailer) + hp->body_eof_seen = 1; + + return env; + } + return Qnil; /* incomplete */ +} + + static int chunked_eof(struct http_parser *hp) { - return ((hp->cs == http_parser_first_final) || HP_FL_TEST(hp, INTRAILER)); + return ((hp->cs == http_parser_first_final) || hp->in_trailer); } /** * call-seq: * parser.body_eof? => true or false @@ -1448,17 +4072,17 @@ */ static VALUE body_eof(VALUE self) { struct http_parser *hp = data_get(self); - if (!HP_FL_TEST(hp, HASHEADER) && HP_FL_ALL(hp, KEEPALIVE)) + if (!hp->has_header && hp->persistent) return Qtrue; - if (HP_FL_TEST(hp, CHUNKED)) + if (hp->chunked) return chunked_eof(hp) ? Qtrue : Qfalse; - if (! HP_FL_TEST(hp, HASBODY)) + if (!hp->has_body) return Qtrue; return hp->len.content == 0 ? Qtrue : Qfalse; } @@ -1476,14 +4100,18 @@ */ static VALUE keepalive(VALUE self) { struct http_parser *hp = data_get(self); - if (HP_FL_ALL(hp, KEEPALIVE)) { - if (HP_FL_TEST(hp, HASHEADER) && HP_FL_TEST(hp, HASBODY) ) { - if (HP_FL_TEST(hp, CHUNKED) || (hp->len.content >= 0)) - return Qtrue; + if (hp->persistent) { + if (hp->has_header && hp->has_body) { + if (hp->chunked || (hp->len.content >= 0)) { + if (!hp->is_request) + return Qtrue; + else + return hp->body_eof_seen ? Qtrue : Qfalse; + } /* unknown Content-Length and not chunked, we must assume close */ return Qfalse; } else { /* 100 Continue, 304 Not Modified, etc... */ @@ -1493,70 +4121,103 @@ return Qfalse; } /** * call-seq: - * parser.filter_body(buf, data) => nil/data + * parser.filter_body(dst, src) => nil/dst * - * Takes a String of +data+, will modify data if dechunking is done. - * Returns +nil+ if there is more data left to process. Returns - * +data+ if body processing is complete. When returning +data+, - * it may modify +data+ so the start of the string points to where + * Takes a String of +src+, will modify src if dechunking is done. + * Returns +nil+ if there is more +src+ left to process. Returns + * +dst+ if body processing is complete. When returning +dst+, + * it may modify +src+ so the start of the string points to where * the body ended so that trailer processing can begin. * * Raises ParserError if there are dechunking errors. - * Basically this is a glorified memcpy(3) that copies +data+ - * into +buf+ while filtering it through the dechunker. + * Basically this is a glorified memcpy(3) that copies +src+ + * into +dst+ while filtering it through the dechunker. */ -static VALUE filter_body(VALUE self, VALUE buf, VALUE data) +static VALUE filter_body(VALUE self, VALUE dst, VALUE src) { struct http_parser *hp = data_get(self); - char *dptr; - long dlen; + char *sptr; + long slen; - dptr = RSTRING_PTR(data); - dlen = RSTRING_LEN(data); + sptr = RSTRING_PTR(src); + slen = RSTRING_LEN(src); + check_buffer_size(slen); - StringValue(buf); - rb_str_modify(buf); - rb_str_resize(buf, dlen); /* we can never copy more than dlen bytes */ - OBJ_TAINT(buf); /* keep weirdo $SAFE users happy */ + StringValue(dst); + rb_str_modify(dst); + OBJ_TAINT(dst); /* keep weirdo $SAFE users happy */ - if (!HP_FL_TEST(hp, CHUNKED)) + /* + * for now, only support filter_body for identity requests, + * not responses; it's rather inefficient to blindly memcpy + * giant request bodies; on the other hand, it simplifies + * server-side code. + */ + if (hp->is_request && !hp->chunked) { + /* no need to enter the Ragel machine for unchunked transfers */ + assert(hp->len.content >= 0 && "negative Content-Length"); + if (hp->len.content > 0) { + long nr = MIN(slen, hp->len.content); + + rb_str_resize(dst, nr); + memcpy(RSTRING_PTR(dst), sptr, nr); + hp->len.content -= nr; + if (hp->len.content == 0) + hp->body_eof_seen = 1; + advance_str(src, nr); + } + return dst; + } + + if (!hp->chunked) rb_raise(rb_eRuntimeError, "filter_body is only for chunked bodies"); + rb_str_resize(dst, slen); /* we can never copy more than slen bytes */ if (!chunked_eof(hp)) { hp->s.dest_offset = 0; - http_parser_execute(hp, buf, dptr, dlen); + http_parser_execute(hp, dst, sptr, slen); if (hp->cs == http_parser_error) rb_raise(eParserError, "Invalid HTTP format, parsing fails."); assert(hp->s.dest_offset <= hp->offset && "destination buffer overflow"); - advance_str(data, hp->offset); - rb_str_set_len(buf, hp->s.dest_offset); + advance_str(src, hp->offset); + rb_str_set_len(dst, hp->s.dest_offset); - if (RSTRING_LEN(buf) == 0 && chunked_eof(hp)) { + if (RSTRING_LEN(dst) == 0 && chunked_eof(hp)) { assert(hp->len.chunk == 0 && "chunk at EOF but more to parse"); } else { - data = Qnil; + dst = Qnil; } } hp->offset = 0; /* for trailer parsing */ - return data; + return dst; } void Init_kcar_ext(void) { VALUE mKcar = rb_define_module("Kcar"); VALUE cParser = rb_define_class_under(mKcar, "Parser", rb_cObject); + /* + * Document-class: Kcar::ParserError + * + * This is raised if there are parsing errors. + */ eParserError = rb_define_class_under(mKcar, "ParserError", rb_eIOError); + e413 = rb_define_class_under(mKcar, "RequestEntityTooLargeError", + eParserError); + e414 = rb_define_class_under(mKcar, "RequestURITooLongError", + eParserError); - rb_define_alloc_func(cParser, alloc); + rb_define_alloc_func(cParser, kcar_alloc); rb_define_method(cParser, "initialize", initialize, 0); rb_define_method(cParser, "reset", initialize, 0); + rb_define_method(cParser, "request", request, 2); rb_define_method(cParser, "headers", headers, 2); rb_define_method(cParser, "trailers", headers, 2); rb_define_method(cParser, "filter_body", filter_body, 2); rb_define_method(cParser, "body_bytes_left", body_bytes_left, 0); rb_define_method(cParser, "body_bytes_left=", body_bytes_left_set, 1); @@ -1578,6 +4239,36 @@ * to the limits of the file system used for +Dir.tmpdir+. */ rb_define_const(cParser, "LENGTH_MAX", OFFT2NUM(UH_OFF_T_MAX)); id_sq = rb_intern("[]"); id_sq_set = rb_intern("[]="); + id_uminus = rb_intern("-@"); + + /* TODO: gperf to make a perfect hash of common strings */ +#define C(var, cstr) do { \ + var = str_new_dd_freeze((cstr), sizeof(cstr) - 1); \ + rb_gc_register_mark_object((var)); \ +} while (0); + + C(g_CONTENT_LENGTH, "CONTENT_LENGTH"); + C(g_CONTENT_TYPE, "CONTENT_TYPE"); + C(g_FRAGMENT, "FRAGMENT"); + C(g_HTTP_HOST, "HTTP_HOST"); + C(g_HTTP_CONNECTION, "HTTP_CONNECTION"); + C(g_HTTP_TRAILER, "HTTP_TRAILER"); + C(g_HTTP_TRANSFER_ENCODING, "HTTP_TRANSFER_ENCODING"); + C(g_HTTP_VERSION, "HTTP_VERSION"); + C(g_PATH_INFO, "PATH_INFO"); + C(g_QUERY_STRING, "QUERY_STRING"); + C(g_REQUEST_METHOD, "REQUEST_METHOD"); + C(g_REQUEST_PATH, "REQUEST_PATH"); + C(g_REQUEST_URI, "REQUEST_URI"); + C(g_SERVER_NAME, "SERVER_NAME"); + C(g_SERVER_PORT, "SERVER_PORT"); + C(g_SERVER_PROTOCOL, "SERVER_PROTOCOL"); + C(g_rack_url_scheme, "rack.url_scheme"); + C(g_http, "http"); + C(g_https, "https"); + C(g_80, "80"); + C(g_443, "443"); +#undef C }