aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ctl.c147
-rw-r--r--src/piesctl.c13
2 files changed, 100 insertions, 60 deletions
diff --git a/src/ctl.c b/src/ctl.c
index 676f93b..d26bf45 100644
--- a/src/ctl.c
+++ b/src/ctl.c
@@ -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:

Return to:

Send suggestions and report system problems to the System administrator.