From 83cd2267b309fa7411acaed356f88101196bb2ad Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Thu, 6 Feb 2020 19:43:57 +0300 Subject: [magi] Broken to become better. --- src/urlencoded.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 src/urlencoded.c (limited to 'src/urlencoded.c') diff --git a/src/urlencoded.c b/src/urlencoded.c new file mode 100644 index 0000000..e3ea56a --- /dev/null +++ b/src/urlencoded.c @@ -0,0 +1,144 @@ +#include "inner_urlencoded.h" + +#include "inner_tools.h" +#include +#include +#include + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Local Shortcuts + */ +/* Call only if is_hex(c). */ +static int from_hex(char c) +{ + if (isdigit(c)) { + return c - '0'; + } else { + return toupper(c) - 'A' + 10; + } +} + +static int is_hex(char c) +{ + return isdigit(c) || strchr("ABCDEF", toupper(c)); +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * URL Decoding + */ +static int deurl(char ** data) +{ + char * val = *data; + int ti; + int ci; + if (!val) { + *data = malloc(1); + **data = 0; + return 1; + } + for (ti = 0, ci = 0; val[ci]; ++ti, ++ci) { + if (val[ci] == '%') { + if (is_hex(val[ci + 1]) && is_hex(val[ci + 2])) { + /* Since chars can be signed, arithmetics are not safe. */ + val[ti] = from_hex(val[ci + 2]); /* 0000xxxx */ + val[ti] |= from_hex(val[ci + 1]) << 4; /* XXXXxxxx */ + ci += 2; /* Two extra characters are readed from code. */ + } else { + return 0; + } + } else if (val[ci] == '+') { + val[ti] = ' '; + } else { + val[ti] = val[ci]; + } + } + val[ti] = 0; + return 1; +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Urlencoded Automata + */ +enum st { st_error = 0, st_name, st_data }; + +struct automata { + struct magi_param_list ** list; + struct magi_param param; + int size; + int len; +}; + + +static enum st parse_name(struct automata * a, char c) +{ + if (c == '&' || c == ';') { /* Impossible character means error. */ + return st_error; + } + if (c == '=') { /* Separator ends name. */ + a->size = 1; + a->len = 0; + return st_data; + } + + if (!magi_str_add(&a->param.name, &a->len, &a->size, c)) { + return st_error; + } + return st_name; +} + +static enum st end_data(struct automata * a) +{ + if (deurl(&a->param.name) && deurl(&a->param.data)) { + if (magi_param_list_add(a->list, &a->param)) { + a->size = 1; + a->len = 0; + a->param.name = 0; + a->param.data = 0; + return st_name; + } + } + return st_error; +} + +static enum st parse_data(struct automata * a, char c) +{ + if (c == '=') { /* Impossible character means error. */ + return st_error; + } + if (c == '&' || c == ';') { /* Separator ends data. */ + return end_data(a); + } + + if (!magi_str_add(&a->param.data, &a->len, &a->size, c)) { + return st_error; + } + return st_data; +} + +void magi_urlencoded(struct magi_param_list ** list, + struct magi_request * request, + const char * encoded) +{ + enum st state; + struct automata a = { 0, { 0, 0 }, 1, 0 }; + a.list = list; + *list = 0; + if (!encoded || !*encoded) { + return; + } + for (state = st_name; state && *encoded; ++encoded) { + if (state == st_name) { + state = parse_name(&a, *encoded); + } else { + state = parse_data(&a, *encoded); + } + } + if (state == st_name || !state || !end_data(&a)) { + free(a.param.name); + free(a.param.data); + request->error = magi_error_urlenc; + } +} -- cgit v1.2.3