diff --git a/components/query.c b/components/query.c new file mode 100644 index 0000000..55495c1 --- /dev/null +++ b/components/query.c @@ -0,0 +1,163 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file query.c + * @author Ilja Kartašov + * @brief HTTP POST/GET query stream parser source file + * + * @see https://lowenware.com/aisl/ + */ + +#include "query.h" + + +aisl_status_t +aislx_query_init( aislx_query_t query, + size_t total, + aislx_query_on_var on_var, + void * p_ctx ) +{ + query->on_var = on_var; + query->p_ctx = p_ctx; + query->data = NULL; + query->size = 0; + query->total = 0; + query->separator = 0; + + return AISL_SUCCESS; +} + + +void +aislx_query_release(aislx_query_t query) +{ + if (query->data) + free(query->data); +} + + +static void +aislx_query_notify(const char * key, uint32_t k_len, + const cahr * val, uint32_t v_len, + aislx_query_t query) +{ + if (query->on_var) + { + if (query->on_var(key, k_len, val, v_len, query->p_ctx) != 0) + query->on_var == NULL; + } +} + + +static int32_t +aislx_query_process(aislx_query_t query, const char * data, int32_t length) +{ + const char * i = data, + * key = data, + * val = NULL; + + uint32_t k_len = 0; + + size_t result; + + for (result=0; result < length; result++) + { + char c; + + switch( (c = *i) ) + { + case '=': + if (val) + return -1; + + k_len = i-key; + val = i+1; + break; + + case '&': + case ';' + if (!val) + return -1; + + if (!query->separator) + query->separator = c; + + if (query->separator == c) + { + aislx_query_notify(key, k_len, val, i-val, query); + /* reset parser */ + key = (c == ';') ? i+2 : i+1; + k_len = 0; + val = NULL; + break; + } + } + i++; + } + + if (query->total == result) + { + aislx_query_notify(key, k_len, val, i-val, query); + } + else + { + result = (key > i) ? i - data : key - data; + } + + query->total -= result; + + return result; +} + + +aisl_status_t +aislx_query_feed(aislx_query_t query, char * data, int32_t length) +{ + size_t processed; + char * source; + + if (query->data) + { + if (!(source = realloc(query->data, length + query->size))) + return AISL_MALLOC_ERROR; + + length += query->size; + query->data = source; + query->size = length; + + memcpy(&source[query->size], data, length); + } + else + source = data; + + processed = aislx_query_process(query, source, length); + + if (processed < 0) + return AISL_INPUT_ERROR; + + if (processed < length) + { + char * buffer; + + length -= processed; + if (!(buffer = malloc(length))) + return AISL_MALLOC_ERROR; + + memcpy(buffer, &source[processed], length); + + if (query->data) + free(query->data); + + query->data = buffer; + query->size = length; + } + + return AISL_SUCCESS; +} + + diff --git a/components/query.h b/components/query.h new file mode 100644 index 0000000..7c4d61c --- /dev/null +++ b/components/query.h @@ -0,0 +1,57 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file query.h + * @author Ilja Kartašov + * @brief HTTP POST/GET query stream parser header file + * + * @see https://lowenware.com/aisl + */ + +#ifndef AISLX_QUERY_H_9306EAEB_6DFC_4936_934A_6472F00E490C +#define AISLX_QUERY_H_9306EAEB_6DFC_4936_934A_6472F00E490C + +#include + + +typedef int +(*aislx_query_on_var)( const char * key, uint32_t k_len, + const char * val, uint32_t v_len, + void * p_ctx ); + + +struct aislx_query +{ + aislx_query_on_var on_var; + + void * p_ctx; + char * data; + size_t size; + size_t total; + char separator; +}; + +typedef struct aislx_query * aislx_query_t; + + +aisl_status_t +aislx_query_init( aislx_query_t query, + size_t total, + aislx_query_on_var on_var, + void * p_ctx ); + + +void +aislx_query_release(aislx_query_t query); + + +aisl_status_t +aislx_query_feed(aislx_query_t query, char * data, uint32_t length); + + +#endif /* !AISLX_QUERY_H */ diff --git a/mods/mod-feedback.c b/mods/mod-feedback.c index 5723447..60cadfa 100644 --- a/mods/mod-feedback.c +++ b/mods/mod-feedback.c @@ -12,17 +12,17 @@ * * @see https://lowenware.com/aisl/ */ -#include -#include -#include -#include +#include +#include +#include +#include #include "mod-feedback.h" struct context { struct aislx_mod_ctx root; - struct aislx_query_stream qs; + struct aislx_query qs; struct aislx_mail mail; char * email; @@ -35,7 +35,7 @@ typedef struct context * context_t; static void context_free(context_t ctx) { - aislx_query_stream_release(&ctx->qs); + aislx_query_release(&ctx->qs); aislx_mail_release(&ctx->mail); if (ctx->email) @@ -79,7 +79,7 @@ on_stream_open(aislx_mod_feedback_t mod, aisl_evt_stream_open_t const evt) aisl_stream_t s = (aisl_stream_t) (evt->evt.source); if (!(ctx = (context_t)aislx_mod_ctx_new(mod))) - goto e_malloc; + return AISL_MALLOC_ERROR; ctx->mail.from = mod->mail_from; ctx->mail.subject = mod->mail_subject; @@ -88,24 +88,25 @@ on_stream_open(aislx_mod_feedback_t mod, aisl_evt_stream_open_t const evt) ctx->mail.smtp_password = mod->smtp_password; ctx->mail.smtp_port = mod->smtp_port; - if(aislx_query_stream_init(&ctx->qs, on_input_var, NULL, (void*)ctx) != 0) - goto release; - aisl_set_context(s, ctx); return AISL_SUCCESS; - -release: - context_free(ctx); - -e_malloc: - return AISL_MALLOC_ERROR; } static aisl_status_t on_stream_header(aislx_mod_feedback_t mod, aisl_evt_stream_header_t const evt) { + if (strcmp(evt->key, "content-length")==0) + { + size_t total = strtoll(evt->value, NULL, 10); + + if(aislx_query_init(&ctx->qs, total, on_input_var, (void*)ctx) != 0) + { + aisl_stream_t s = (aisl_stream_source_t)evt->source; + aislx_quick_response(s, AISL_HTTP_INTERNAL_SERVER_ERROR); + } + } return AISL_SUCCESS; } @@ -115,7 +116,7 @@ on_stream_input(aislx_mod_feedback_t mod, aisl_evt_stream_input_t const evt) { context_t ctx = aisl_get_context((aisl_stream_t)evt->evt.source); - aislx_query_stream_feed(ctx->qs, evt->data, evt->size); + aislx_query_feed(ctx->qs, evt->data, evt->size); return AISL_SUCCESS; } @@ -128,7 +129,7 @@ on_stream_request(aislx_mod_feedback_t mod, aisl_evt_t const evt) aisl_stream_t s = (aisl_stream_t)evt->source; /* finalize input */ - aislx_query_stream_flush(ctx->qs); + aislx_query_flush(ctx->qs); /* verify input */ if (!ctx->email || !ctx->message || aislx_validate_email(ctx->email) != 0)