Mercurial > libjeffpc
view qstring.c @ 806:12a3139a2baf
sock: use atomic_cas_ptr correctly
This bug was caused by incorrect documentation (already fixed). It resulted
in us freeing the name on successful CAS and caching the freed pointer.
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Fri, 10 Apr 2020 12:27:10 -0400 |
parents | 158cd10d5616 |
children |
line wrap: on
line source
/* * Copyright (c) 2014-2018 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_empty_string(); 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; }