diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-01-04 14:08:29 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-01-04 14:08:29 +0200 |
commit | 2c03055b8ed023e7d8d65f2dbd51cd128040fcfb (patch) | |
tree | 7792b90c2a99e1910ffbdd2f277b68f63190f0c0 /src/ctl.c | |
parent | 2782ae034e51d5e9c74a9b1f2c6e6c452bd83243 (diff) | |
download | pies-2c03055b8ed023e7d8d65f2dbd51cd128040fcfb.tar.gz pies-2c03055b8ed023e7d8d65f2dbd51cd128040fcfb.tar.bz2 |
Redo URI handling.
* src/ctl.c (res_instance)
(res_programs): Take partial URI as argument (instead of full
URI split on path delimiter)
(ctlio_resource): New member uri_len; Change signature of handler.
(find_resource): Compare URI prefix.
(ctlio_do_command): Redo URI parsing. Improve error checking.
* src/piesctl.c (shttp_print_error): New function.
(shttp_fatal): Print error on 404 and 409 responses.
Diffstat (limited to 'src/ctl.c')
-rw-r--r-- | src/ctl.c | 147 |
1 files changed, 89 insertions, 58 deletions
@@ -886,44 +886,78 @@ method_decode (char const *method) return METH_INVALID; } -static void res_instance (struct ctlio *, enum http_method, size_t, char **, +static void res_instance (struct ctlio *, enum http_method, char const *, struct json_value *); -static void res_programs (struct ctlio *, enum http_method, size_t, char **, +static void res_programs (struct ctlio *, enum http_method, char const *, struct json_value *); struct ctlio_resource { - char *uri; + char const *uri; + size_t uri_len; int states; void (*handler) (struct ctlio *, enum http_method, - size_t pathc, char **pathv, - struct json_value *); + char const *uri, struct json_value *); }; static struct ctlio_resource restab[] = { - { "instance", CTL_ADMIN_STATE, res_instance }, - { "programs", CTL_ADMIN_STATE|CTL_USER_STATE, res_programs }, +#define S(s) #s, (sizeof (#s)-1) + { S(/instance), CTL_ADMIN_STATE, res_instance }, + { S(/programs), CTL_ADMIN_STATE|CTL_USER_STATE, res_programs }, { NULL } +#undef S }; static struct ctlio_resource * find_resource (struct ctlio *io, const char *endpoint) { struct ctlio_resource *p; + size_t len = strlen (endpoint); + + if (len == 0) + return NULL; + + if (endpoint[len-1] == '/') + --len; for (p = restab; p->uri; p++) - if (strcmp (p->uri, endpoint) == 0) + if (len >= p->uri_len && memcmp (p->uri, endpoint, p->uri_len) == 0 + && (endpoint[p->uri_len] == 0 || endpoint[p->uri_len] == '/')) + return p; + return NULL; +} + +static char * +json_extract (char *uri) +{ + char *p = strrchr (uri, '/'); + if (p && strchr ("\"{[", p[1])) + { + *p++ = 0; return p; + } return NULL; } +static size_t +delim_count (char const *str, int delim) +{ + size_t i = 0; + for (; *str; str++) + if (*str == delim) + ++i; + return i; +} + static void -ctlio_do_command (struct ctlio *io, struct wordsplit *uri) +ctlio_do_command (struct ctlio *io) { const char *val; struct ctlio_resource *res; enum http_method method; struct json_value *json; + char *uri = io->input.input_uri; + char *json_query = NULL; if (strcmp (io->input.input_proto, "HTTP/1.1")) { @@ -958,18 +992,24 @@ ctlio_do_command (struct ctlio *io, struct wordsplit *uri) return; } - if (uri->ws_wordc < 1) - { - ctlio_reply (io, 404, NULL); - return; - } - - res = find_resource (io, uri->ws_wordv[0]); + res = find_resource (io, uri); if (!res) { ctlio_reply (io, 404, "resource not found"); return; } + uri += res->uri_len; + if (uri[0]) + { + json_query = json_extract (uri); + if (delim_count (uri, '/') > 1) + { + ctlio_reply (io, 404, "resource not found"); + return; + } + } + if (!uri[0]) + uri = NULL; if (!(io->state & res->states)) { @@ -984,30 +1024,42 @@ ctlio_do_command (struct ctlio *io, struct wordsplit *uri) if (io->input.input_content_length) { + if (json_query) + { + ctlio_reply (io, 400, "JSON query supplied twice"); + return; + } + json = json_parse_string (ctlbuf_peek (&io->input.ibuf), ctlbuf_rdsize (&io->input.ibuf)); if (!json) { - ctlio_reply (io, 400, NULL); + ctlio_reply (io, 400, "JSON error: %s", json_err_diag); //FIXME: Reply json + return; } } - else if (method != METH_POST - && uri->ws_wordc > 1 - && strchr ("\"{[", uri->ws_wordv[uri->ws_wordc-1][0])) + else if (json_query) { - json = json_parse_string (uri->ws_wordv[uri->ws_wordc-1], - strlen (uri->ws_wordv[uri->ws_wordc-1])); - if (!json) - ctlio_reply (io, 400, NULL); - free (uri->ws_wordv[uri->ws_wordc-1]); - uri->ws_wordv[uri->ws_wordc-1] = NULL; - uri->ws_wordc--; + if (method == METH_POST) + { + ctlio_reply (io, 400, NULL); + return; + } + else + { + json = json_parse_string (json_query, strlen (json_query)); + if (!json) + { + ctlio_reply (io, 400, "JSON error: %s", json_err_diag); + return; + } + } } else json = json_new_bool (1); - res->handler (io, method, uri->ws_wordc, uri->ws_wordv, json); + res->handler (io, method, uri, json); json_value_free (json); } @@ -1034,20 +1086,7 @@ ctlrd (int fd, void *data) return 0; if (rc == 200) - { - struct wordsplit ws; - - ws.ws_delim = "/"; - if (wordsplit (io->input.input_uri, &ws, - WRDSF_DELIM | WRDSF_SQUEEZE_DELIMS - | WRDSF_NOVAR | WRDSF_NOCMD)) - ctlio_reply (io, 500, NULL); - else - { - ctlio_do_command (io, &ws); - wordsplit_free (&ws); - } - } + ctlio_do_command (io); else ctlio_reply (io, rc, NULL); @@ -1204,8 +1243,7 @@ idfmt_pid (struct ctlio *io, char const *name, void *ptr) static void res_instance (struct ctlio *io, enum http_method meth, - size_t pathc, char **pathv, - struct json_value *req) + char const *uri, struct json_value *req) { static struct idparam { char *name; @@ -1223,19 +1261,14 @@ res_instance (struct ctlio *io, enum http_method meth, }; struct idparam *p; - if (pathc > 2) - { - ctlio_reply (io, 404, NULL); - return; - } - io->output.reply = json_reply_create (); - if (pathc == 2) + if (uri) { + ++uri; /* skip leading / */ if (meth == METH_GET) { for (p = idparam; p->name; p++) - if (strcmp (p->name, pathv[1]) == 0) + if (strcmp (p->name, uri) == 0) break; if (p->name) { @@ -1245,8 +1278,7 @@ res_instance (struct ctlio *io, enum http_method meth, else ctlio_reply (io, 404, NULL); } - else if (strcmp (pathv[1], "PID") == 0 - || strcmp (pathv[1], "instance") == 0) + else if (strcmp (uri, "PID") == 0 || strcmp (uri, "instance") == 0) { if (meth == METH_DELETE) { @@ -1740,8 +1772,7 @@ component_start (struct ctlio *io, struct prog *prog) static void res_programs (struct ctlio *io, enum http_method meth, - size_t pathc, char **pathv, - struct json_value *json) + char const *uri, struct json_value *json) { if (meth == METH_GET) { @@ -1758,11 +1789,11 @@ res_programs (struct ctlio *io, enum http_method meth, } else if (meth == METH_DELETE || meth == METH_PUT) { - if (pathc != 2) + if (!uri) ctlio_reply (io, 404, NULL); else { - struct prog *prog = progman_locate (pathv[1]); + struct prog *prog = progman_locate (uri); if (!prog) ctlio_reply (io, 404, NULL); else if (auth_prog (prog, io) & CTL_ADMIN_STATE) |