/****************************************************************************** * * 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 #include #include #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 char * 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, const char *data, int32_t length) { size_t processed; const char *source; if (query->data) { if (!(source = realloc(query->data, length + query->size))) return AISL_MALLOC_ERROR; length += query->size; query->data = (char*)source; query->size = length; memcpy((char*)&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; }