/****************************************************************************** * * 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 "log.h" #include "query.h" AislStatus ax_query_init(AxQuery query, size_t total, AxQueryHandler on_var, void *p_ctx) { query->on_var = on_var; query->p_ctx = p_ctx; query->data = NULL; query->size = 0; query->total = total; query->separator = 0; return AISL_SUCCESS; } void ax_query_release(AxQuery query) { if (query->data) free(query->data); } static void ax_query_notify(const char *key, uint32_t k_len, const char *val, uint32_t v_len, AxQuery 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 ax_query_process(AxQuery 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) { ax_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) { ax_query_notify(key, k_len, val, i-val, query); } else { result = (key > i) ? i - data : key - data; } query->total -= result; return result; } AislStatus ax_query_feed(AxQuery 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 = ax_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; } void ax_query__decode(char *e_str) { char *p = e_str, hex[3] = {0,0,0}; do { switch(*e_str) { case '%': hex[0] = *(++e_str); hex[1] = *(++e_str); *p++ = (char)strtol(hex, NULL, 16); break; case '+': *p++ = ' '; break; default: *p++ = *e_str; } } while(*e_str++ != 0); }