Mercurial > projects > dreactor
view 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 source
/** * 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; } }