#define _POSIX_C_SOURCE 200809L #include "libweb/form.h" #include "libweb/http.h" #include #include #include #include #include struct pair { char *key, *value; }; struct form { struct pair *pairs; size_t n; }; void form_free(struct form *const f) { if (!f) return; for (size_t i = 0; i < f->n; i++) { struct pair *const p = &f->pairs[i]; free(p->key); free(p->value); } free(f->pairs); free(f); } const char *form_value(const struct form *const f, const char *const key) { for (size_t i = 0; i < f->n; i++) { const struct pair *const p = &f->pairs[i]; if (!strcmp(p->key, key)) return p->value; } return NULL; } static char *alloc_form_data(const char *const s, const char **const end) { const char *const next = strchr(s, '&'); char *const data = next ? strndup(s, next - s) : strdup(s); if (!data) { fprintf(stderr, "%s: strndup/strdup(3): %s\n", __func__, strerror(errno)); return NULL; } *end = next ? next + 1 : s + strlen(s); return data; } static int append(struct form *const forms, const char **const s) { int ret = -1; const char *end; char *const data = alloc_form_data(*s, &end), *enckey = NULL, *encvalue = NULL, *key = NULL, *value = NULL; struct pair *p; if (!data) { fprintf(stderr, "%s: alloc_form_data failed\n", __func__); goto end; } const char *const sep = strchr(data, '='); if (!sep) { ret = 1; goto end; } else if (!data || !*(sep + 1)) { ret = 1; goto end; } const size_t keylen = sep - data; if (!(enckey = strndup(data, keylen))) { fprintf(stderr, "%s: strndup(3) enckey: %s\n", __func__, strerror(errno)); goto end; } else if (!(encvalue = strdup(sep + 1))) { fprintf(stderr, "%s: strdup(3) encvalue: %s\n", __func__, strerror(errno)); goto end; } /* HTML input forms use '+' for whitespace, rather than %20. */ else if ((ret = http_decode_url(enckey, true, &key))) { fprintf(stderr, "%s: http_decode_url enckey failed\n", __func__); goto end; } else if ((ret = http_decode_url(encvalue, true, &value))) { fprintf(stderr, "%s: http_decode_url encvalue failed\n", __func__); goto end; } else if (!(p = realloc(forms->pairs, (forms->n + 1) * sizeof *p))) { fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno)); goto end; } forms->pairs = p; p[forms->n++] = (const struct pair) { .key = key, .value = value }; *s = end; ret = 0; end: if (ret) { free(key); free(value); } free(enckey); free(encvalue); free(data); return ret; } int form_foreach(const struct form *const f, const form_iter it, void *const user) { for (size_t i = 0; i < f->n; i++) { const struct pair *const p = &f->pairs[i]; const int ret = it(p->key, p->value, user); if (ret) return ret; } return 0; } int form_alloc(const char *data, struct form **const out) { int ret = -1; struct form *const f = malloc(sizeof *f); if (!f) { fprintf(stderr, "%s: malloc(3): %s\n", __func__, strerror(errno)); goto failure; } *f = (const struct form){0}; while (*data) if ((ret = append(f, &data))) { if (ret < 0) fprintf(stderr, "%s: append_form failed\n", __func__); goto failure; } *out = f; return 0; failure: form_free(f); return ret; }