diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2016-12-12 13:44:08 +0000 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2016-12-12 13:44:08 +0000 |
commit | 1d95f1678637f30b6bf453f781b5938d64354228 (patch) | |
tree | 2ee99ae2bc79323bd96dad52157e6e6be67ba45a /src/ragel | |
parent | 55467ed90c19bc82506433f8f7d274b5bfb8d10f (diff) | |
download | rspamd-1d95f1678637f30b6bf453f781b5938d64354228.tar.gz rspamd-1d95f1678637f30b6bf453f781b5938d64354228.zip |
[Rework] Implement content type parser for mime
Diffstat (limited to 'src/ragel')
-rw-r--r-- | src/ragel/content_type.rl | 40 | ||||
-rw-r--r-- | src/ragel/content_type_parser.rl | 152 |
2 files changed, 192 insertions, 0 deletions
diff --git a/src/ragel/content_type.rl b/src/ragel/content_type.rl new file mode 100644 index 000000000..d9c222e5c --- /dev/null +++ b/src/ragel/content_type.rl @@ -0,0 +1,40 @@ +%%{ + machine content_type; + include smtp_whitespace "smtp_whitespace.rl"; + + # https://tools.ietf.org/html/rfc2045#section-5.1 + + ccontent = ctext | FWS | '(' @{ fcall balanced_ccontent; }; + balanced_ccontent := ccontent* ')' @{ fret; }; + comment = "(" (FWS? ccontent)* FWS? ")"; + CFWS = ((FWS? comment)+ FWS?) | FWS; + qcontent = qtextSMTP | quoted_pairSMTP; + quoted_string = CFWS? + (DQUOTE + (((FWS? qcontent)* FWS?) >Quoted_Str_Start %Quoted_Str_End) + DQUOTE) CFWS?; + token = 0x21..0x27 | 0x2a..0x2b | 0x2c..0x2e | 0x30..0x39 | 0x41..0x5a | 0x5e..0x7e; + value = (quoted_string | (token -- '"' | 0x3d)+) >Param_Value_Start %Param_Value_End; + attribute = (token+) >Param_Name_Start %Param_Name_End; + parameter = CFWS? attribute "=" value CFWS?; + + ietf_token = token+; + custom_x_token = 'x'i "-" token+; + extension_token = ietf_token | custom_x_token; + discrete_type = 'text'i | 'image'i | 'audio'i | 'video'i | + 'application'i | extension_token; + composite_type = 'message'i | 'multipart'i | extension_token; + iana_token = token+; + main_type = (discrete_type | composite_type) >Type_Start %Type_End; + sub_type = (extension_token | iana_token) >Subtype_Start %Subtype_End; + content_type = main_type ("/" sub_type)? (((CFWS? ";"+) | CFWS) parameter CFWS?)*; + + prepush { + if (top >= st_storage.size) { + st_storage.size = (top + 1) * 2; + st_storage.data = realloc (st_storage.data, st_storage.size * sizeof (int)); + g_assert (st_storage.data != NULL); + stack = st_storage.data; + } + } +}%%
\ No newline at end of file diff --git a/src/ragel/content_type_parser.rl b/src/ragel/content_type_parser.rl new file mode 100644 index 000000000..aec3db287 --- /dev/null +++ b/src/ragel/content_type_parser.rl @@ -0,0 +1,152 @@ +%%{ + machine content_type_parser; + + action Type_Start { + qstart = NULL; + qend = NULL; + ct->type.begin = p; + } + + action Type_End { + if (qstart) { + ct->type.begin = qstart; + } + if (qend && qend >= qstart) { + ct->type.len = qend - qstart; + } + else if (p >= ct->type.begin) { + ct->type.len = p - ct->type.begin; + } + qstart = NULL; + qend = NULL; + } + + action Subtype_Start { + qstart = NULL; + qend = NULL; + ct->subtype.begin = p; + } + + action Subtype_End { + if (qstart) { + ct->subtype.begin = qstart; + } + if (qend && qend >= qstart) { + ct->subtype.len = qend - qstart; + } + else if (p >= ct->subtype.begin) { + ct->subtype.len = p - ct->subtype.begin; + } + qstart = NULL; + qend = NULL; + } + + action Param_Name_Start { + qstart = NULL; + qend = NULL; + pname_start = p; + pname_end = NULL; + } + + + action Param_Name_End { + if (qstart) { + pname_start = qstart; + } + if (qend && qend >= qstart) { + pname_end = qend; + } + else if (p >= pname_start) { + pname_end = p; + } + qstart = NULL; + qend = NULL; + } + + + action Param_Value_Start { + qstart = NULL; + qend = NULL; + + if (pname_end) { + pvalue_start = p; + pvalue_end = NULL; + } + } + + + action Param_Value_End { + if (pname_end) { + if (qstart) { + pvalue_start = qstart; + } + if (qend && qend >= qstart) { + pvalue_end = qend; + } + else if (p >= pvalue_start) { + pvalue_end = p; + } + qstart = NULL; + qend = NULL; + + if (pvalue_end && pvalue_end > pvalue_start && pname_end > pname_start) { + rspamd_content_type_add_param (pool, ct, pname_start, pname_end, pvalue_start, pvalue_end); + } + } + + pname_start = NULL; + pname_end = NULL; + pvalue_start = NULL; + pvalue_end = NULL; + qend = NULL; + qstart = NULL; + } + + action Quoted_Str_Start { + qstart = p; + qend = NULL; + } + + action Quoted_Str_End { + if (qstart) { + qend = p; + } + } + + + include content_type "content_type.rl"; + + main := content_type; + +}%% + +#include "smtp_parsers.h" +#include "content_type.h" + +%% write data; + +gboolean +rspamd_content_type_parser (const char *data, size_t len, struct rspamd_content_type *ct, rspamd_mempool_t *pool) +{ + const char *p = data, *pe = data + len, *eof, *qstart = NULL, *qend = NULL, + *pname_start = NULL, *pname_end = NULL, *pvalue_start, *pvalue_end; + int cs, *stack = NULL; + gsize top = 0; + struct _ragel_st_storage { + int *data; + gsize size; + } st_storage; + + memset (&st_storage, 0, sizeof (st_storage)); + memset (ct, 0, sizeof (*ct)); + eof = pe; + + %% write init; + %% write exec; + + if (st_storage.data) { + free (st_storage.data); + } + + return ct->type.len > 0; +} |