Mercurial > libjeffpc
changeset 298:289a8ac515f2
qstring: turn a encoded query string into a nvlist entries
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Mon, 31 Jul 2017 21:22:20 +0300 |
parents | d7967afe6c56 |
children | 8c1ea2cc67a2 |
files | .hgignore CMakeLists.txt include/jeffpc/qstring.h jeffpc.mapfile-vers qstring.c test_qstring.c tests/CMakeLists.txt tests/qstring-basic/CMakeLists.txt tests/qstring-basic/comment-body.qs tests/qstring-basic/empty.qs tests/qstring-basic/multi-char.qs tests/qstring-basic/no-value-long.qs tests/qstring-basic/no-value.qs tests/qstring-basic/one.qs tests/qstring-basic/two.qs |
diffstat | 14 files changed, 295 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Mon Jul 31 20:23:43 2017 +0300 +++ b/.hgignore Mon Jul 31 21:22:20 2017 +0300 @@ -28,6 +28,7 @@ test_nvl test_nvl_pack test_padding +test_qstring test_sexpr_parser test_sexpr_eval test_urldecode
--- a/CMakeLists.txt Mon Jul 31 20:23:43 2017 +0300 +++ b/CMakeLists.txt Mon Jul 31 21:22:20 2017 +0300 @@ -100,6 +100,7 @@ nvl_pack.c nvl_unpack.c padding.c + qstring.c rand.c sexpr.c sexpr_eval.c @@ -150,6 +151,7 @@ include/jeffpc/mem.h include/jeffpc/nvl.h include/jeffpc/padding.h + include/jeffpc/qstring.h include/jeffpc/rand.h include/jeffpc/refcnt.h include/jeffpc/scgi.h @@ -201,6 +203,7 @@ # build_test_bin(sexpr_parser) +build_test_bin(qstring) build_test_bin_and_run(array) build_test_bin_and_run(atomic-single-thread) build_test_bin_and_run(bswap)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/jeffpc/qstring.h Mon Jul 31 21:22:20 2017 +0300 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014-2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __JEFFPC_QSTRING_H +#define __JEFFPC_QSTRING_H + +#include <string.h> + +#include <jeffpc/nvl.h> + +extern int qstring_parse_len(struct nvlist *vars, const char *qs, size_t len); + +static inline int qstring_parse(struct nvlist *vars, const char *qs) +{ + size_t len; + + if (qs) + len = strlen(qs); + else + len = 0; + + return qstring_parse_len(vars, qs, len); +} + +#endif
--- a/jeffpc.mapfile-vers Mon Jul 31 20:23:43 2017 +0300 +++ b/jeffpc.mapfile-vers Mon Jul 31 21:22:20 2017 +0300 @@ -121,6 +121,9 @@ # padding check_padding; + # qstring + qstring_parse_len; + # rand rand32; rand64;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qstring.c Mon Jul 31 21:22:20 2017 +0300 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2014-2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <jeffpc/qstring.h> +#include <jeffpc/urldecode.h> +#include <jeffpc/error.h> + +/* + * The query string is a sequence of name-value pairs. Each name is + * separated from the value with a '=', and each pair is separated by '&'. + * We parse the input string, and produce a nvlist key-value pair for each + * of the input pairs. We map each input pair based on these rules: + * + * foo=bar -> { "foo" : "bar" } + * foo= -> { "foo" : "" } + * foo -> { "foo" : null } + * =bar -> { "" : "bar" } + */ + +enum qs_state { + QS_STATE_NAME, + QS_STATE_VAL, +}; + +static int insert(struct nvlist *nvl, const char *namestart, size_t namelen, + const char *valstart, size_t vallen) +{ + char name[namelen + 1]; + ssize_t newlen; + + /* decode & nul-terminate the name */ + newlen = urldecode(namestart, namelen, name); + if (newlen < 0) + return newlen; + + name[newlen] = '\0'; + + if (!valstart) { + /* we want a null value */ + return nvl_set_null(nvl, name); + } else { + /* we want a string value (possibly empty string) */ + struct str *val; + + if (!vallen) + val = str_dup(NULL); + else + val = urldecode_str(valstart, vallen); + + if (IS_ERR(val)) + return PTR_ERR(val); + + return nvl_set_str(nvl, name, val); + } +} + +int qstring_parse_len(struct nvlist *nvl, const char *qs, size_t len) +{ + const char *cur, *end; + const char *name; + const char *val; + size_t name_len; + enum qs_state state; + + if (!nvl) + return -EINVAL; + + if (!len && !qs) + return 0; + + if (!qs) + return -EINVAL; + + end = qs + len; + cur = qs; + + state = QS_STATE_NAME; + + name = qs; + name_len = 0; + val = NULL; + + for (; end > cur; cur++) { + char c = *cur; + + if (state == QS_STATE_NAME) { + if (c == '=') { + /* end of name */ + name_len = cur - name; + val = cur + 1; + state = QS_STATE_VAL; + } else if (c == '&') { + /* end of name; no value */ + insert(nvl, name, cur - name, NULL, 0); + + name = cur + 1; + state = QS_STATE_NAME; /* no change */ + } + } else if (state == QS_STATE_VAL) { + if (c == '&') { + /* end of value */ + insert(nvl, name, name_len, val, cur - val); + + name = cur + 1; + state = QS_STATE_NAME; + } else if (c == '=') { + /* value contains = */ + return -EILSEQ; + } + } + } + + /* qs ends with a name without a '=' (e.g., abc=def&ghi) */ + if ((state == QS_STATE_NAME) && (name < end)) + insert(nvl, name, end - name, NULL, 0); + /* qs ends with an empty value (e.g., abc=def&ghi=) */ + if ((state == QS_STATE_VAL) && (val == end)) + insert(nvl, name, name_len, val, 0); + /* qs ends with a value (e.g., abc=def&ghi=jkl) */ + if ((state == QS_STATE_VAL) && (val < end)) + insert(nvl, name, name_len, val, end - val); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test_qstring.c Mon Jul 31 21:22:20 2017 +0300 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014-2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <stdlib.h> + +#include <jeffpc/qstring.h> +#include <jeffpc/io.h> + +static int onefile(char *ibuf, size_t len) +{ + struct nvlist *vars; + int ret; + + vars = nvl_alloc(); + if (!vars) + return -ENOMEM; + + ret = qstring_parse_len(vars, ibuf, len); + if (!ret) + nvl_dump_file(stderr, vars); + + nvl_putref(vars); + + return 0; +} + +int main(int argc, char **argv) +{ + char *in; + int i; + int result; + + result = 0; + + ASSERT0(putenv("UMEM_DEBUG=default,verbose")); + + for (i = 1; i < argc; i++) { + in = read_file(argv[i]); + ASSERT(!IS_ERR(in)); + + if (onefile(in, strlen(in))) + result = 1; + + free(in); + } + + return result; +}
--- a/tests/CMakeLists.txt Mon Jul 31 20:23:43 2017 +0300 +++ b/tests/CMakeLists.txt Mon Jul 31 21:22:20 2017 +0300 @@ -1,5 +1,5 @@ # -# Copyright (c) 2016 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> +# Copyright (c) 2016-2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -20,4 +20,5 @@ # SOFTWARE. # +add_subdirectory(qstring-basic) add_subdirectory(sexpr-parser)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/qstring-basic/CMakeLists.txt Mon Jul 31 21:22:20 2017 +0300 @@ -0,0 +1,26 @@ +# +# Copyright (c) 2014-2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +file(GLOB TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qs) +foreach(TEST ${TESTS}) + simple_c_test(qstring basic qstring ${TEST}) +endforeach()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/qstring-basic/comment-body.qs Mon Jul 31 21:22:20 2017 +0300 @@ -0,0 +1,1 @@ +i=535&d=1448913859968688486&s=Submit+Comment&a=seo&e=dsqbketcxa@example.com&u=http%3a%2f%2fwww.example.com%2f&x=seo&v=seo&c=Hello+Web+Admin%2c+I+noticed+that
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/qstring-basic/multi-char.qs Mon Jul 31 21:22:20 2017 +0300 @@ -0,0 +1,1 @@ +preview=1234&p=5 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/qstring-basic/no-value-long.qs Mon Jul 31 21:22:20 2017 +0300 @@ -0,0 +1,1 @@ +just-a-very-long-string---longer-than-most-variable-names-would-be-because-we-want-to-make-sure-that-nothing-blows-up-when-there-is-no-value-and-just-a-long-name \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/qstring-basic/no-value.qs Mon Jul 31 21:22:20 2017 +0300 @@ -0,0 +1,1 @@ +abc \ No newline at end of file