diff options
Diffstat (limited to 'src/ping903.c')
-rw-r--r-- | src/ping903.c | 276 |
1 files changed, 206 insertions, 70 deletions
diff --git a/src/ping903.c b/src/ping903.c index efc6246..47456a7 100644 --- a/src/ping903.c +++ b/src/ping903.c @@ -165,11 +165,10 @@ http_log(struct MHD_Connection *connection, user_agent ? user_agent : ""); free(ipstr); } - static int -http_error(struct MHD_Connection *conn, - char const *method, char const *url, int status) +http_response(struct MHD_Connection *conn, + char const *method, char const *url, int status) { int ret; struct MHD_Response *resp = @@ -233,6 +232,7 @@ json_to_str(struct json_value *obj) static int httpd_json_response(struct MHD_Connection *conn, char const *url, char const *method, + int status, struct json_value *val) { char *reply; @@ -242,24 +242,25 @@ httpd_json_response(struct MHD_Connection *conn, reply = json_to_str(val); json_value_free(val); if (!reply) - return http_error(conn, method, url, + return http_response(conn, method, url, MHD_HTTP_INTERNAL_SERVER_ERROR); resp = MHD_create_response_from_buffer(strlen(reply), reply, MHD_RESPMEM_MUST_COPY); - http_log(conn, method, url, MHD_HTTP_OK, reply); + http_log(conn, method, url, status, reply); free(reply); MHD_add_response_header(resp, MHD_HTTP_HEADER_CONTENT_TYPE, "application/json"); - ret = MHD_queue_response(conn, MHD_HTTP_OK, resp); + ret = MHD_queue_response(conn, status, resp); MHD_destroy_response(resp); return ret; } static int ept_config(struct MHD_Connection *conn, - const char *url, const char *method, const char *suffix) + const char *url, const char *method, const char *suffix, + struct json_value *unused) { struct json_value *val; @@ -268,7 +269,7 @@ ept_config(struct MHD_Connection *conn, val = config_to_json(); if (!val) - return http_error(conn, method, url, + return http_response(conn, method, url, MHD_HTTP_INTERNAL_SERVER_ERROR); if (*suffix) { @@ -276,7 +277,7 @@ ept_config(struct MHD_Connection *conn, int ret; if (json_object_get(val, suffix, &jv)) { - ret = http_error(conn, method, url, + ret = http_response(conn, method, url, (errno == ENOENT) ? MHD_HTTP_NOT_FOUND : MHD_HTTP_INTERNAL_SERVER_ERROR); @@ -285,7 +286,7 @@ ept_config(struct MHD_Connection *conn, } if (json_value_copy(jv, &cp)) { - ret = http_error(conn, method, url, + ret = http_response(conn, method, url, MHD_HTTP_INTERNAL_SERVER_ERROR); json_value_free(val); return ret; @@ -294,58 +295,86 @@ ept_config(struct MHD_Connection *conn, val = cp; } - return httpd_json_response(conn, url, method, val); + return httpd_json_response(conn, url, method, MHD_HTTP_OK, val); } static int ept_ip_delete(struct MHD_Connection *conn, - const char *url, const char *method, const char *suffix) + const char *url, const char *method, const char *suffix, + struct json_value *unused) { int ret; - struct MHD_Response *resp; - + while (*suffix == '/') suffix++; if (!*suffix) - return http_error(conn, method, url, MHD_HTTP_FORBIDDEN); - if (hostping_delete_by_name(suffix)) - return http_error(conn, method, url, MHD_HTTP_NOT_FOUND); - - resp = MHD_create_response_from_buffer(0, - NULL, - MHD_RESPMEM_PERSISTENT); - http_log(conn, method, url, MHD_HTTP_OK, NULL); - ret = MHD_queue_response(conn, MHD_HTTP_OK, resp); - MHD_destroy_response(resp); - return ret; + return http_response(conn, method, url, MHD_HTTP_FORBIDDEN); + if (pinger_host_delete_by_name(suffix)) + return http_response(conn, method, url, MHD_HTTP_NOT_FOUND); + return http_response(conn, method, url, MHD_HTTP_OK); } static int ept_ip_put(struct MHD_Connection *conn, - const char *url, const char *method, const char *suffix) + const char *url, const char *method, const char *suffix, + struct json_value *unused) { int ret; - struct MHD_Response *resp; while (*suffix == '/') suffix++; if (!*suffix) - return http_error(conn, method, url, MHD_HTTP_FORBIDDEN); - if (hostping_add_name(suffix)) + return http_response(conn, method, url, MHD_HTTP_FORBIDDEN); + if (pinger_host_add_name(suffix)) //FIXME - return http_error(conn, method, url, MHD_HTTP_FORBIDDEN); - resp = MHD_create_response_from_buffer(0, - NULL, - MHD_RESPMEM_PERSISTENT); - http_log(conn, method, url, MHD_HTTP_CREATED, NULL); - ret = MHD_queue_response(conn, MHD_HTTP_CREATED, resp); - MHD_destroy_response(resp); - return ret; + return http_response(conn, method, url, MHD_HTTP_FORBIDDEN); + return http_response(conn, method, url, MHD_HTTP_CREATED); +} + +static int +ept_ip_post(struct MHD_Connection *conn, + const char *url, const char *method, const char *suffix, + struct json_value *obj) +{ + char const *err_text; + int err_pos; + int status; + + status = pinger_hostlist_set(obj, &err_text, &err_pos); + if (!err_text && !err_pos) + return http_response(conn, method, url, status); + else { + struct json_value *jv, *err = json_new_object(); + char *str; + int rc; + + if (!err) + goto err; + if ((jv = json_new_string(err_text)) == NULL) + goto err; + if (json_object_set(err, "message", jv)) + goto err; + if (err_pos) { + if ((jv = json_new_number(err_pos)) == NULL) + goto err; + if (json_object_set(err, "index", jv)) + goto err; + } + str = json_to_str(err); + rc = httpd_json_response(conn, url, method, status, err); + json_value_free(err); + return rc; + err: + json_value_free(err); + return http_response(conn, method, url, + MHD_HTTP_INTERNAL_SERVER_ERROR); + } } static int ept_host_stat(struct MHD_Connection *conn, - const char *url, const char *method, const char *suffix) + const char *url, const char *method, const char *suffix, + struct json_value *unused) { struct json_value *val; int rc; @@ -359,15 +388,16 @@ ept_host_stat(struct MHD_Connection *conn, rc = get_hostname_stat(suffix, &val); } if (rc) - return http_error(conn, method, url, + return http_response(conn, method, url, MHD_HTTP_INTERNAL_SERVER_ERROR); - return httpd_json_response(conn, url, method, val); + return httpd_json_response(conn, url, method, MHD_HTTP_OK, val); } static int ept_ip_stat(struct MHD_Connection *conn, - const char *url, const char *method, const char *suffix) + const char *url, const char *method, const char *suffix, + struct json_value *unused) { struct json_value *val; int rc; @@ -376,7 +406,7 @@ ept_ip_stat(struct MHD_Connection *conn, suffix++; if (suffix[0] == 0) { - return http_error(conn, method, url, MHD_HTTP_FORBIDDEN); + return http_response(conn, method, url, MHD_HTTP_FORBIDDEN); } else { int ret; struct addrinfo hints, *res; @@ -385,16 +415,17 @@ ept_ip_stat(struct MHD_Connection *conn, hints.ai_protocol = IPPROTO_TCP; rc = getaddrinfo(suffix, NULL, &hints, &res); if (rc) - return http_error(conn, method, url, + return http_response(conn, method, url, MHD_HTTP_NOT_FOUND); rc = get_ipaddr_stat(res->ai_addr, res->ai_addrlen, &val); if (rc) - ret = http_error(conn, method, url, + ret = http_response(conn, method, url, MHD_HTTP_INTERNAL_SERVER_ERROR); else if (val) - ret = httpd_json_response(conn, url, method, val); + ret = httpd_json_response(conn, url, method, + MHD_HTTP_OK, val); else - ret = http_error(conn, method, url, MHD_HTTP_FORBIDDEN); + ret = http_response(conn, method, url, MHD_HTTP_FORBIDDEN); freeaddrinfo(res); return ret; } @@ -402,7 +433,8 @@ ept_ip_stat(struct MHD_Connection *conn, static int ept_ip_match(struct MHD_Connection *conn, - const char *url, const char *method, const char *suffix) + const char *url, const char *method, const char *suffix, + struct json_value *unused) { struct json_value *val; int rc; @@ -413,27 +445,28 @@ ept_ip_match(struct MHD_Connection *conn, suffix++; if (suffix[0] == 0) - return http_error(conn, method, url, MHD_HTTP_FORBIDDEN); + return http_response(conn, method, url, MHD_HTTP_FORBIDDEN); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_protocol = IPPROTO_TCP; rc = getaddrinfo(suffix, NULL, &hints, &res); if (rc) - return http_error(conn, method, url, MHD_HTTP_NOT_FOUND); + return http_response(conn, method, url, MHD_HTTP_NOT_FOUND); rc = get_host_matches(&res, &val); if (rc) - ret = http_error(conn, method, url, + ret = http_response(conn, method, url, MHD_HTTP_INTERNAL_SERVER_ERROR); else - ret = httpd_json_response(conn, url, method, val); + ret = httpd_json_response(conn, url, method, MHD_HTTP_OK, val); freeaddrinfo(res); return ret; } typedef int (*ENDPOINT_HANDLER)(struct MHD_Connection *, - const char *, const char *, const char *); + const char *, const char *, const char *, + struct json_value *); enum { EPT_EXACT = 0x01, @@ -449,6 +482,7 @@ struct endpoint { static struct endpoint endpoint[] = { { "/config/ip-list", EPT_PREFIX, MHD_HTTP_METHOD_PUT, ept_ip_put }, + { "/config/ip-list", EPT_PREFIX, MHD_HTTP_METHOD_POST, ept_ip_post }, { "/config/ip-list", EPT_PREFIX, MHD_HTTP_METHOD_DELETE, ept_ip_delete }, { "/config", EPT_PREFIX, MHD_HTTP_METHOD_GET, ept_config }, { "/host", EPT_PREFIX, MHD_HTTP_METHOD_GET, ept_host_stat }, @@ -457,28 +491,67 @@ static struct endpoint endpoint[] = { { NULL } }; -static ENDPOINT_HANDLER -find_endpoint_handler(char const *url, char const *method, char const **suffix) +static int +find_endpoint_handler(char const *url, char const *method, + ENDPOINT_HANDLER *ret_handler, char const **ret_suffix) { struct endpoint *ept; + int urlmatch = 0; for (ept = endpoint; ept->url; ept++) { - if (strcmp(ept->method, method)) - continue; if (ept->flags & EPT_EXACT) { if (strcmp(ept->url, url) == 0) { - *suffix = url + strlen(url); - return ept->handler; + if (strcmp(ept->method, method)) { + urlmatch++; + continue; + } + *ret_handler = ept->handler; + *ret_suffix = url + strlen(url); + return MHD_HTTP_OK; } } else { size_t len = strlen(ept->url); if (strncmp(url, ept->url, len) == 0 && (url[len] == '/' || url[len] == 0)) { - *suffix = url + len; - return ept->handler; + if (strcmp(ept->method, method)) { + urlmatch++; + continue; + } + *ret_handler = ept->handler; + *ret_suffix = url + len; + return MHD_HTTP_OK; } } } - return NULL; + return urlmatch ? MHD_HTTP_METHOD_NOT_ALLOWED : MHD_HTTP_NOT_FOUND; +} + +struct postbuf { + char *base; + size_t size; + size_t len; + ENDPOINT_HANDLER handler; + char suffix[1]; +}; + +static void +postbuf_free(struct postbuf *pb) +{ + free(pb->base); + free(pb); +} + +static int +postbuf_add(struct postbuf *pb, const char *str, size_t len) +{ + while (pb->len + len >= pb->size) { + char *np = json_2nrealloc(pb->base, &pb->size, 1); + if (!np) + return -1; + pb->base = np; + } + memcpy(pb->base + pb->len, str, len); + pb->len += len; + return 0; } static int @@ -491,15 +564,78 @@ p903_httpd_handler(void *cls, { ENDPOINT_HANDLER handler; char const *suffix; - - handler = find_endpoint_handler(url, method, &suffix); - if (handler) - return handler(conn, url, method, suffix); - - if (strcmp(method, MHD_HTTP_METHOD_GET)) - return http_error(conn, method, url, - MHD_HTTP_METHOD_NOT_ALLOWED); - return http_error(conn, method, url, MHD_HTTP_FORBIDDEN); + int status; + + if (strcmp(method, MHD_HTTP_METHOD_POST) == 0) { + struct postbuf *pb; + + if (*con_cls == NULL) { + char const *ctype; + + status = find_endpoint_handler(url, method, &handler, + &suffix); + if (status != MHD_HTTP_OK) + return http_response(conn, method, url, status); + + ctype = MHD_lookup_connection_value(conn, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_CONTENT_TYPE); + if (!ctype || strcmp(ctype, "application/json")) + return http_response(conn, method, url, + MHD_HTTP_NOT_ACCEPTABLE); + + pb = malloc(sizeof(*pb) + strlen(suffix)); + if (!pb) + return http_response(conn, method, url, + MHD_HTTP_INTERNAL_SERVER_ERROR); + pb->base = NULL; + pb->size = 0; + pb->len = 0; + pb->handler = handler; + strcpy(pb->suffix, suffix); + *con_cls = pb; + } else { + pb = *con_cls; + if (*upload_data_size != 0) { + if (postbuf_add(pb, upload_data, + *upload_data_size)) { + postbuf_free(pb); + return http_response(conn, method, url, + MHD_HTTP_INTERNAL_SERVER_ERROR); + } + *upload_data_size = 0; + } else { + char *endp; + int rc; + struct json_value *jv; + + if (postbuf_add(pb, "", 1)) { + postbuf_free(pb); + return http_response(conn, method, url, + MHD_HTTP_INTERNAL_SERVER_ERROR); + } + rc = json_parse_string(pb->base, &jv, &endp); + if (rc != JSON_E_NOERR) { + error("%s: %s near #%d", url, + json_strerror(rc), endp - pb->base); + return http_response(conn, method, url, + MHD_HTTP_BAD_REQUEST); + } + rc = pb->handler(conn, url, method, pb->suffix, + jv); + postbuf_free(pb); + json_value_free(jv); + return rc; + } + } + return MHD_YES; + } + + /* For all other methods */ + status = find_endpoint_handler(url, method, &handler, &suffix); + if (status != MHD_HTTP_OK) + return http_response(conn, method, url, status); + return handler(conn, url, method, suffix, NULL); } void |