diff options
-rw-r--r-- | src/ctl.c | 147 | ||||
-rw-r--r-- | src/piesctl.c | 13 |
2 files changed, 100 insertions, 60 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) diff --git a/src/piesctl.c b/src/piesctl.c index 4319946..8c4e2e1 100644 --- a/src/piesctl.c +++ b/src/piesctl.c @@ -813,10 +813,9 @@ shttp_format_result (struct shttp_connection *conn, FILE *fp) } static void -shttp_fatal (struct shttp_connection *conn) +shttp_print_error (struct shttp_connection *conn) { struct json_value *jv; - int status; if (conn->result && (jv = json_value_lookup (conn->result, "error_message"))) { @@ -827,11 +826,20 @@ shttp_fatal (struct shttp_connection *conn) } else grecs_error (NULL, 0, "%s", conn->status_line[2]); +} + +static void +shttp_fatal (struct shttp_connection *conn) +{ + int status; + + shttp_print_error (conn); switch (conn->resp.code) { case 400: case 405: + case 406: case 501: case 505: grecs_error (NULL, 0, _("please report")); @@ -975,6 +983,7 @@ shttp_process (struct shttp_connection *conn, int method, char const *uri) case 404: /* Not found */ case 409: /* Conflict */ + shttp_print_error (conn); return; default: |