Mercurial > projects > dreactor
diff asyncdreactor/protocol/http11_parser.rl @ 11:5836613d16ac
reorg! reorg!
author | rick@minifunk |
---|---|
date | Tue, 12 Aug 2008 16:59:56 -0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/asyncdreactor/protocol/http11_parser.rl Tue Aug 12 16:59:56 2008 -0400 @@ -0,0 +1,192 @@ +/** + * Copyright (c) 2005 Zed A. Shaw, + * Modified for D/DReactor by Rick Richardson, 2008 + * You can redistribute it and/or modify it under the same terms as Ruby. + */ + +alias void delegate (void *data, const char *at, size_t length) element_cb; +alias void delegate (void *data, const char *field, size_t flen, const char *value, size_t vlen) field_cb; + +class Http11Parser +{ + int cs; + size_t body_start; + int content_len; + size_t nread; + size_t mark; + size_t field_start; + size_t field_len; + size_t query_start; + + void *data; + + field_cb http_field; + element_cb request_method; + element_cb request_uri; + element_cb fragment; + element_cb request_path; + element_cb query_string; + element_cb http_version; + element_cb header_done; + +/* + * capitalizes all lower-case ASCII characters, + * converts dashes to underscores. + */ +private void snake_upcase_char(char *c) +{ + if (*c >= 'a' && *c <= 'z') + *c &= ~0x20; + else if (*c == '-') + *c = '_'; +} + +//#define LEN(AT, FPC) (FPC - buffer - parser->AT) +private int LEN(char* at, char* fpc) +{ + return (fpc - buffer.ptr - at); +} + +//#define MARK(M,FPC) (parser->M = (FPC) - buffer) +private void MARK(size_t* item, char* fpc) +{ + *item = fpc - buffer.ptr; +} + +//#define PTR_TO(F) (buffer + parser->F) +private char* PTR_TO(size_t F) +{ + return (buffer.ptr + F); +} +/** Machine **/ + +%%{ + + machine http_parser; + + action mark {MARK(mark, fpc); } + + + action start_field { MARK(field_start, fpc); } + action snake_upcase_field { snake_upcase_char((char *)fpc); } + action write_field { + field_len = LEN(field_start, fpc); + } + + action start_value { MARK(mark, fpc); } + action write_value { + if(http_field) + http_field(data, + PTR_TO(field_start), + field_len, + PTR_TO(mark), + LEN(mark, fpc)); + } + action request_method { + if(request_method) + request_method(data, PTR_TO(mark), LEN(mark, fpc)); + } + + action request_uri { + if(request_uri) + request_uri(data, PTR_TO(mark), LEN(mark, fpc)); + } + + action fragment { + if(fragment) + fragment(data, PTR_TO(mark), LEN(mark, fpc)); + } + + action start_query {MARK(query_start, fpc); } + + action query_string { + if(query_string) + query_string(data, PTR_TO(query_start), LEN(query_start, fpc)); + } + + action http_version { + if(http_version) + http_version(data, PTR_TO(mark), LEN(mark, fpc)); + } + + action request_path { + if(request_path) + request_path(data, PTR_TO(mark), LEN(mark,fpc)); + } + + action done { + body_start = fpc - buffer + 1; + if(header_done) + header_done(data, fpc + 1, pe - fpc - 1); + fbreak; + } + + include http_parser_common "http11_parser_common.rl"; + +}%% + +/** Data **/ +%% write data; + +this () +{ + cs = 0; + %% write init; + + body_start = 0; + content_len = 0; + mark = 0; + nread = 0; + field_len = 0; + field_start = 0; +} + + +/** exec **/ +size_t execute(const char[] buffer, size_t off) { + const char *p, *pe; + int len = buffer.length; + + assert(off <= len && "offset past end of buffer"); + + p = buffer.ptr+off; + pe = buffer.ptr+len; + + /* assert(*pe == '\0' && "pointer does not end on NUL"); */ + assert(pe - p == len - off && "pointers aren't same distance"); + + %% write exec; + + //parser->cs = cs; + nread += p - (buffer.ptr + off); + + assert(p <= pe && "buffer overflow after parsing execute"); + assert(nread <= len && "nread longer than length"); + assert(body_start <= len && "body starts after buffer end"); + assert(mark < len && "mark is after buffer end"); + assert(field_len <= len && "field has length longer than whole buffer"); + assert(field_start < len && "field starts after buffer end"); + + return(nread); +} + +int finish() +{ + if (has_error() ) { + return -1; + } else if (is_finished() ) { + return 1; + } else { + return 0; + } +} + +bool has_error() { + return cs == http_parser_error; +} + +bool is_finished() { + return cs >= http_parser_first_final; +} + +}