From 73b3d680ca80f41c3cf7f725ebc60c3c9fc4b8a8 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 25 Jan 2021 20:55:52 +0100 Subject: [PATCH] Improve error reporting for missing/incorrect sets of payload/URI arguments Signed-off-by: DL6ER --- src/api/list.c | 276 ++++++++++++++++++++++-------------- src/api/routes.c | 1 + src/database/gravity-db.c | 158 ++++++++++----------- src/database/gravity-db.h | 5 +- src/webserver/http-common.c | 4 + src/webserver/http-common.h | 1 + 6 files changed, 254 insertions(+), 191 deletions(-) diff --git a/src/api/list.c b/src/api/list.c index 60d36842..8fd72ba6 100644 --- a/src/api/list.c +++ b/src/api/list.c @@ -20,15 +20,15 @@ static int api_list_read(struct ftl_conn *api, const int code, const enum gravity_list_type listtype, - const char *argument) + const char *item) { const char *sql_msg = NULL; - if(!gravityDB_readTable(listtype, argument, &sql_msg)) + if(!gravityDB_readTable(listtype, item, &sql_msg)) { cJSON *json = JSON_NEW_OBJ(); - // Add argument (may be NULL = not available) - JSON_OBJ_REF_STR(json, "argument", argument); + // Add item (may be NULL = not available) + JSON_OBJ_REF_STR(json, "item", item); // Add SQL message (may be NULL = not available) if (sql_msg != NULL) { @@ -43,100 +43,100 @@ static int api_list_read(struct ftl_conn *api, json); } - tablerow row; - cJSON *items = JSON_NEW_ARRAY(); - while(gravityDB_readTableGetRow(&row, &sql_msg)) + tablerow table; + cJSON *rows = JSON_NEW_ARRAY(); + while(gravityDB_readTableGetRow(&table, &sql_msg)) { - cJSON *item = JSON_NEW_OBJ(); + cJSON *row = JSON_NEW_OBJ(); // Special fields if(listtype == GRAVITY_GROUPS) { - JSON_OBJ_COPY_STR(item, "name", row.name); - if(row.description != NULL) { - JSON_OBJ_COPY_STR(item, "description", row.description); + JSON_OBJ_COPY_STR(row, "name", table.name); + if(table.comment != NULL) { + JSON_OBJ_COPY_STR(row, "comment", table.comment); } else { - JSON_OBJ_ADD_NULL(item, "description"); + JSON_OBJ_ADD_NULL(row, "comment"); } } else if(listtype == GRAVITY_ADLISTS) { - JSON_OBJ_COPY_STR(item, "address", row.address); - if(row.comment != NULL) { - JSON_OBJ_COPY_STR(item, "comment", row.comment); + JSON_OBJ_COPY_STR(row, "address", table.address); + if(table.comment != NULL) { + JSON_OBJ_COPY_STR(row, "comment", table.comment); } else { - JSON_OBJ_ADD_NULL(item, "comment"); + JSON_OBJ_ADD_NULL(row, "comment"); } } else if(listtype == GRAVITY_CLIENTS) { - if(row.ip != NULL) + if(table.client != NULL) { - JSON_OBJ_COPY_STR(item, "client", row.ip); - char *name = getNameFromIP(row.ip); + JSON_OBJ_COPY_STR(row, "client", table.client); + char *name = getNameFromIP(table.client); if(name != NULL) { - JSON_OBJ_COPY_STR(item, "name", name); + JSON_OBJ_COPY_STR(row, "name", name); free(name); } else { - JSON_OBJ_ADD_NULL(item, "name"); + JSON_OBJ_ADD_NULL(row, "name"); } } else { - JSON_OBJ_ADD_NULL(item, "ip"); - JSON_OBJ_ADD_NULL(item, "name"); + JSON_OBJ_ADD_NULL(row, "ip"); + JSON_OBJ_ADD_NULL(row, "name"); } - if(row.comment != NULL) { - JSON_OBJ_COPY_STR(item, "comment", row.comment); + if(table.comment != NULL) { + JSON_OBJ_COPY_STR(row, "comment", table.comment); } else { - JSON_OBJ_ADD_NULL(item, "comment"); + JSON_OBJ_ADD_NULL(row, "comment"); } } else // domainlists { - JSON_OBJ_COPY_STR(item, "domain", row.domain); - JSON_OBJ_REF_STR(item, "type", row.type); - JSON_OBJ_REF_STR(item, "kind", row.kind); - if(row.comment != NULL) { - JSON_OBJ_COPY_STR(item, "comment", row.comment); + JSON_OBJ_COPY_STR(row, "domain", table.domain); + JSON_OBJ_REF_STR(row, "type", table.type); + JSON_OBJ_REF_STR(row, "kind", table.kind); + if(table.comment != NULL) { + JSON_OBJ_COPY_STR(row, "comment", table.comment); } else { - JSON_OBJ_ADD_NULL(item, "comment"); + JSON_OBJ_ADD_NULL(row, "comment"); } } - if(row.group_ids != NULL) { + if(table.group_ids != NULL) { // Black magic at work here: We build a JSON array from // the group_concat result delivered from the database, - // parse it as valid array and append it as item to the + // parse it as valid array and append it as row to the // data - logg("row.group_ids = %p \"%s\"", row.group_ids, row.group_ids); - char group_ids_str[strlen(row.group_ids)+3u]; + logg("table.group_ids = %p \"%s\"", table.group_ids, table.group_ids); + char group_ids_str[strlen(table.group_ids)+3u]; group_ids_str[0] = '['; - strcpy(group_ids_str+1u , row.group_ids); + strcpy(group_ids_str+1u , table.group_ids); group_ids_str[sizeof(group_ids_str)-2u] = ']'; group_ids_str[sizeof(group_ids_str)-1u] = '\0'; cJSON * group_ids = cJSON_Parse(group_ids_str); - JSON_OBJ_ADD_ITEM(item, "groups", group_ids); + JSON_OBJ_ADD_ITEM(row, "groups", group_ids); } else { // Empty group set cJSON *group_ids = JSON_NEW_ARRAY(); - JSON_OBJ_ADD_ITEM(item, "groups", group_ids); + JSON_OBJ_ADD_ITEM(row, "groups", group_ids); } // Clients don't have the enabled property if(listtype != GRAVITY_CLIENTS) - JSON_OBJ_ADD_BOOL(item, "enabled", row.enabled); + JSON_OBJ_ADD_BOOL(row, "enabled", table.enabled); // Add read-only database parameters - JSON_OBJ_ADD_NUMBER(item, "id", row.id); - JSON_OBJ_ADD_NUMBER(item, "date_added", row.date_added); - JSON_OBJ_ADD_NUMBER(item, "date_modified", row.date_modified); + JSON_OBJ_ADD_NUMBER(row, "id", table.id); + JSON_OBJ_ADD_NUMBER(row, "date_added", table.date_added); + JSON_OBJ_ADD_NUMBER(row, "date_modified", table.date_modified); - JSON_ARRAY_ADD_ITEM(items, item); + JSON_ARRAY_ADD_ITEM(rows, row); } gravityDB_readTableFinalize(); @@ -153,16 +153,16 @@ static int api_list_read(struct ftl_conn *api, objname = "clients"; else // domainlists objname = "domains"; - JSON_OBJ_ADD_ITEM(json, objname, items); + JSON_OBJ_ADD_ITEM(json, objname, rows); JSON_SEND_OBJECT_CODE(json, code); } else { - JSON_DELETE(items); + JSON_DELETE(rows); cJSON *json = JSON_NEW_OBJ(); - // Add argument (may be NULL = not available) - JSON_OBJ_REF_STR(json, "argument", argument); + // Add item (may be NULL = not available) + JSON_OBJ_REF_STR(json, "item", item); // Add SQL message (may be NULL = not available) if (sql_msg != NULL) { @@ -180,14 +180,11 @@ static int api_list_read(struct ftl_conn *api, static int api_list_write(struct ftl_conn *api, const enum gravity_list_type listtype, - const char *argument, + const char *item, char payload[MAX_PAYLOAD_BYTES]) { tablerow row = { 0 }; - // Set argument - row.argument = argument; - // Check if valid JSON payload is available if (api->payload.json == NULL) { return send_json_error(api, 400, @@ -196,23 +193,97 @@ static int api_list_write(struct ftl_conn *api, NULL); } - // Clients don't have the enabled property - cJSON *json_enabled = cJSON_GetObjectItemCaseSensitive(api->payload.json, "enabled"); - if (cJSON_IsBool(json_enabled)) - row.enabled = cJSON_IsTrue(json_enabled); - else - row.enabled = true; // Default value - - cJSON *json_item = cJSON_GetObjectItemCaseSensitive(api->payload.json, "item"); - if(cJSON_IsString(json_item) && strlen(json_item->valuestring) > 0) - row.argument = json_item->valuestring; - else if (api->method != HTTP_PUT) // PUT uses the URI argument + if(api->method == HTTP_POST) { - return send_json_error(api, 400, - "bad_request", - "No \"item\" string in body data", - NULL); + // Extract domain/name/client/address from payload whe using POST, all + // others specify it as URI-component + cJSON *json_domain, *json_name, *json_address, *json_client; + switch(listtype) + { + case GRAVITY_DOMAINLIST_ALLOW_EXACT: + case GRAVITY_DOMAINLIST_ALLOW_REGEX: + case GRAVITY_DOMAINLIST_DENY_EXACT: + case GRAVITY_DOMAINLIST_DENY_REGEX: + json_domain = cJSON_GetObjectItemCaseSensitive(api->payload.json, "domain"); + if(cJSON_IsString(json_domain) && strlen(json_domain->valuestring) > 0) + { + row.item = json_domain->valuestring; + } + else + { + cJSON *uri = JSON_NEW_OBJ(); + JSON_OBJ_REF_STR(uri, "path", api->action_path); + JSON_OBJ_REF_STR(uri, "item", item); + return send_json_error(api, 400, + "uri_error", + "Invalid request: No item \"domain\" in payload", + uri); + } + break; + + case GRAVITY_GROUPS: + json_name = cJSON_GetObjectItemCaseSensitive(api->payload.json, "name"); + if(cJSON_IsString(json_name) && strlen(json_name->valuestring) > 0) + row.item = json_name->valuestring; + else + { + cJSON *uri = JSON_NEW_OBJ(); + JSON_OBJ_REF_STR(uri, "path", api->action_path); + JSON_OBJ_REF_STR(uri, "item", item); + return send_json_error(api, 400, + "uri_error", + "Invalid request: No item \"name\" in payload", + uri); + } + break; + + case GRAVITY_CLIENTS: + json_client = cJSON_GetObjectItemCaseSensitive(api->payload.json, "client"); + if(cJSON_IsString(json_client) && strlen(json_client->valuestring) > 0) + row.item = json_client->valuestring; + else + { + cJSON *uri = JSON_NEW_OBJ(); + JSON_OBJ_REF_STR(uri, "path", api->action_path); + JSON_OBJ_REF_STR(uri, "item", item); + return send_json_error(api, 400, + "uri_error", + "Invalid request: No item \"client\" in payload", + uri); + } + break; + + case GRAVITY_ADLISTS: + json_address = cJSON_GetObjectItemCaseSensitive(api->payload.json, "address"); + if(cJSON_IsString(json_address) && strlen(json_address->valuestring) > 0) + row.item = json_address->valuestring; + else + { + cJSON *uri = JSON_NEW_OBJ(); + JSON_OBJ_REF_STR(uri, "path", api->action_path); + JSON_OBJ_REF_STR(uri, "item", item); + return send_json_error(api, 400, + "uri_error", + "Invalid request: No item \"address\" in payload", + uri); + } + break; + + // Aggregate types are not handled by this routine + case GRAVITY_DOMAINLIST_ALL_ALL: + case GRAVITY_DOMAINLIST_ALL_EXACT: + case GRAVITY_DOMAINLIST_ALL_REGEX: + case GRAVITY_DOMAINLIST_ALLOW_ALL: + case GRAVITY_DOMAINLIST_DENY_ALL: + return 500; + } } + else + { + // PUT = Use URI item + row.item = item; + } + cJSON *json_comment = cJSON_GetObjectItemCaseSensitive(api->payload.json, "comment"); if(cJSON_IsString(json_comment) && strlen(json_comment->valuestring) > 0) @@ -220,12 +291,6 @@ static int api_list_write(struct ftl_conn *api, else row.comment = NULL; // Default value - cJSON *json_description = cJSON_GetObjectItemCaseSensitive(api->payload.json, "description"); - if(cJSON_IsString(json_description) && strlen(json_description->valuestring) > 0) - row.description = json_description->valuestring; - else - row.description = NULL; // Default value - cJSON *json_oldtype = cJSON_GetObjectItemCaseSensitive(api->payload.json, "oldtype"); if(cJSON_IsString(json_oldtype) && strlen(json_oldtype->valuestring) > 0) row.oldtype = json_oldtype->valuestring; @@ -238,13 +303,19 @@ static int api_list_write(struct ftl_conn *api, else row.oldkind = NULL; // Default value + cJSON *json_enabled = cJSON_GetObjectItemCaseSensitive(api->payload.json, "enabled"); + if (cJSON_IsBool(json_enabled)) + row.enabled = cJSON_IsTrue(json_enabled); + else + row.enabled = true; // Default value + bool okay = true; char *regex_msg = NULL; if(listtype == GRAVITY_DOMAINLIST_ALLOW_REGEX || listtype == GRAVITY_DOMAINLIST_DENY_REGEX) { // Test validity of this regex regexData regex = { 0 }; - okay = compile_regex(row.argument, ®ex, ®ex_msg); + okay = compile_regex(row.domain, ®ex, ®ex_msg); } // Try to add item to table @@ -271,12 +342,10 @@ static int api_list_write(struct ftl_conn *api, { // Error adding item, prepare error object cJSON *json = JSON_NEW_OBJ(); - JSON_OBJ_REF_STR(json, "item", row.argument); + JSON_OBJ_REF_STR(json, "item", item); JSON_OBJ_ADD_BOOL(json, "enabled", row.enabled); if(row.comment != NULL) JSON_OBJ_REF_STR(json, "comment", row.comment); - if(row.description != NULL) - JSON_OBJ_REF_STR(json, "description", row.description); if(row.name != NULL) JSON_OBJ_REF_STR(json, "name", row.name); if(row.oldtype != NULL) @@ -317,16 +386,16 @@ static int api_list_write(struct ftl_conn *api, if(api->method == HTTP_PUT) response_code = 200; // 200 - OK // Send GET style reply - return api_list_read(api, response_code, listtype, row.argument); + return api_list_read(api, response_code, listtype, row.item); } static int api_list_remove(struct ftl_conn *api, const enum gravity_list_type listtype, - const char *argument) + const char *item) { cJSON *json = JSON_NEW_OBJ(); const char *sql_msg = NULL; - if(gravityDB_delFromTable(listtype, argument, &sql_msg)) + if(gravityDB_delFromTable(listtype, item, &sql_msg)) { // Inform the resolver that it needs to reload the domainlists set_event(RELOAD_GRAVITY); @@ -336,8 +405,8 @@ static int api_list_remove(struct ftl_conn *api, } else { - // Add argument - JSON_OBJ_REF_STR(json, "argument", argument); + // Add item + JSON_OBJ_REF_STR(json, "item", item); // Add SQL message (may be NULL = not available) if (sql_msg != NULL) { @@ -365,59 +434,58 @@ int api_list(struct ftl_conn *api) enum gravity_list_type listtype; bool can_modify = false; - const char *argument = NULL; - if((argument = startsWith("/api/groups", api)) != NULL) + if((api->item = startsWith("/api/groups", api)) != NULL) { listtype = GRAVITY_GROUPS; can_modify = true; } - else if((argument = startsWith("/api/lists", api)) != NULL) + else if((api->item = startsWith("/api/lists", api)) != NULL) { listtype = GRAVITY_ADLISTS; can_modify = true; } - else if((argument = startsWith("/api/clients", api)) != NULL) + else if((api->item = startsWith("/api/clients", api)) != NULL) { listtype = GRAVITY_CLIENTS; can_modify = true; } - else if((argument = startsWith("/api/domains/allow/exact", api)) != NULL) + else if((api->item = startsWith("/api/domains/allow/exact", api)) != NULL) { listtype = GRAVITY_DOMAINLIST_ALLOW_EXACT; can_modify = true; } - else if((argument = startsWith("/api/domains/allow/regex", api)) != NULL) + else if((api->item = startsWith("/api/domains/allow/regex", api)) != NULL) { listtype = GRAVITY_DOMAINLIST_ALLOW_REGEX; can_modify = true; } - else if((argument = startsWith("/api/domains/allow", api)) != NULL) + else if((api->item = startsWith("/api/domains/allow", api)) != NULL) { listtype = GRAVITY_DOMAINLIST_ALLOW_ALL; } - else if((argument = startsWith("/api/domains/deny/exact", api)) != NULL) + else if((api->item = startsWith("/api/domains/deny/exact", api)) != NULL) { listtype = GRAVITY_DOMAINLIST_DENY_EXACT; can_modify = true; } - else if((argument = startsWith("/api/domains/deny/regex", api)) != NULL) + else if((api->item = startsWith("/api/domains/deny/regex", api)) != NULL) { listtype = GRAVITY_DOMAINLIST_DENY_REGEX; can_modify = true; } - else if((argument = startsWith("/api/domains/deny", api)) != NULL) + else if((api->item = startsWith("/api/domains/deny", api)) != NULL) { listtype = GRAVITY_DOMAINLIST_DENY_ALL; } - else if((argument = startsWith("/api/domains/exact", api)) != NULL) + else if((api->item = startsWith("/api/domains/exact", api)) != NULL) { listtype = GRAVITY_DOMAINLIST_ALL_EXACT; } - else if((argument = startsWith("/api/domains/regex", api)) != NULL) + else if((api->item = startsWith("/api/domains/regex", api)) != NULL) { listtype = GRAVITY_DOMAINLIST_ALL_REGEX; } - else if((argument = startsWith("/api/domains", api)) != NULL) + else if((api->item = startsWith("/api/domains", api)) != NULL) { listtype = GRAVITY_DOMAINLIST_ALL_ALL; } @@ -434,12 +502,12 @@ int api_list(struct ftl_conn *api) if(api->method == HTTP_GET) { // Read list item identified by URI (or read them all) - return api_list_read(api, 200, listtype, argument); + return api_list_read(api, 200, listtype, api->item); } else if(can_modify && api->method == HTTP_PUT) { // Add/update item identified by URI - if(strlen(argument) == 0) + if(api->item != NULL && strlen(api->item) == 0) { cJSON *uri = JSON_NEW_OBJ(); if(api->action_path != NULL) @@ -450,19 +518,19 @@ int api_list(struct ftl_conn *api) { JSON_OBJ_ADD_NULL(uri, "path"); } - JSON_OBJ_REF_STR(uri, "item", argument); + JSON_OBJ_REF_STR(uri, "item", api->item); return send_json_error(api, 400, "uri_error", "Invalid request: Specify item in URI", uri); } else - return api_list_write(api, listtype, argument, payload); + return api_list_write(api, listtype, api->item, payload); } else if(can_modify && api->method == HTTP_POST) { // Add item to list identified by payload - if(strlen(argument) != 0) + if(api->item != NULL && strlen(api->item) != 0) { cJSON *uri = JSON_NEW_OBJ(); if(api->action_path != NULL) @@ -473,19 +541,19 @@ int api_list(struct ftl_conn *api) { JSON_OBJ_ADD_NULL(uri, "path"); } - JSON_OBJ_REF_STR(uri, "item", argument); + JSON_OBJ_REF_STR(uri, "item", api->item); return send_json_error(api, 400, "uri_error", "Invalid request: Specify item in payload, not as URI parameter", uri); } else - return api_list_write(api, listtype, argument, payload); + return api_list_write(api, listtype, api->item, payload); } else if(can_modify && api->method == HTTP_DELETE) { // Delete item from list - return api_list_remove(api, listtype, argument); + return api_list_remove(api, listtype, api->item); } else if(!can_modify) { @@ -499,7 +567,7 @@ int api_list(struct ftl_conn *api) { JSON_OBJ_ADD_NULL(uri, "path"); } - JSON_OBJ_REF_STR(uri, "item", argument); + JSON_OBJ_REF_STR(uri, "item", api->item); return send_json_error(api, 400, "uri_error", "Invalid request: Specify list to modify more precisely", diff --git a/src/api/routes.c b/src/api/routes.c index d76905f3..6e78191c 100644 --- a/src/api/routes.c +++ b/src/api/routes.c @@ -30,6 +30,7 @@ int api_handler(struct mg_connection *conn, void *ignored) mg_get_request_info(conn), http_method(conn), NULL, + NULL, { 0 } }; read_and_parse_payload(&api); diff --git a/src/database/gravity-db.c b/src/database/gravity-db.c index 23afcc70..789c2f0f 100644 --- a/src/database/gravity-db.c +++ b/src/database/gravity-db.c @@ -1388,53 +1388,58 @@ bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row, return false; } - int type = -1; switch (listtype) { case GRAVITY_DOMAINLIST_ALLOW_EXACT: - type = 0; + row->type_int = 0; break; case GRAVITY_DOMAINLIST_DENY_EXACT: - type = 1; + row->type_int = 1; break; case GRAVITY_DOMAINLIST_ALLOW_REGEX: - type = 2; + row->type_int = 2; break; case GRAVITY_DOMAINLIST_DENY_REGEX: - type = 3; + row->type_int = 3; break; + // Nothing to be done for these tables case GRAVITY_GROUPS: case GRAVITY_ADLISTS: case GRAVITY_CLIENTS: - // No type required for these tables break; - // Aggregate types cannot be handled by this routine + // Aggregate types are not handled by this routine case GRAVITY_DOMAINLIST_ALLOW_ALL: case GRAVITY_DOMAINLIST_DENY_ALL: case GRAVITY_DOMAINLIST_ALL_EXACT: case GRAVITY_DOMAINLIST_ALL_REGEX: case GRAVITY_DOMAINLIST_ALL_ALL: - default: return false; } - row->type_int = type; // Prepare SQLite statement sqlite3_stmt* stmt = NULL; const char *querystr; if(method == HTTP_POST) // Create NEW entry, error if existing { - // The item is the argument for all POST requests + // The item is the item for all POST requests if(listtype == GRAVITY_GROUPS) - querystr = "INSERT INTO \"group\" (name,enabled,description) VALUES (:argument,:enabled,:description);"; + { + querystr = "INSERT INTO \"group\" (name,enabled,description) VALUES (:item,:enabled,:description);"; + } else if(listtype == GRAVITY_ADLISTS) - querystr = "INSERT INTO adlist (address,enabled,comment) VALUES (:argument,:enabled,:comment);"; + { + querystr = "INSERT INTO adlist (address,enabled,comment) VALUES (:item,:enabled,:comment);"; + } else if(listtype == GRAVITY_CLIENTS) - querystr = "INSERT INTO client (ip,comment) VALUES (:argument,:comment);"; - else // domainlist - querystr = "INSERT INTO domainlist (domain,type,enabled,comment) VALUES (:argument,:type,:enabled,:comment);"; + { + querystr = "INSERT INTO client (ip,comment) VALUES (:item,:comment);"; + } + else // domainlis + { + querystr = "INSERT INTO domainlist (domain,type,enabled,comment) VALUES (:item,:type,:enabled,:comment);"; + } } else { // Create new or replace existing entry, no error if existing @@ -1442,24 +1447,24 @@ bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row, // contraints (REPLACE recreates (= new ID) entries instead of updating them) if(listtype == GRAVITY_GROUPS) querystr = "REPLACE INTO \"group\" (name,enabled,description,id,date_added) " - "VALUES (:argument,:enabled,:description," - "(SELECT id FROM \"group\" WHERE name = :argument)," - "(SELECT date_added FROM \"group\" WHERE name = :argument));"; + "VALUES (:item,:enabled,:description," + "(SELECT id FROM \"group\" WHERE name = :item)," + "(SELECT date_added FROM \"group\" WHERE name = :item));"; else if(listtype == GRAVITY_ADLISTS) querystr = "REPLACE INTO adlist (address,enabled,comment,id,date_added) " - "VALUES (:argument,:enabled,:comment," - "(SELECT id FROM adlist WHERE address = :argument)," - "(SELECT date_added FROM adlist WHERE address = :argument));"; + "VALUES (:item,:enabled,:comment," + "(SELECT id FROM adlist WHERE address = :item)," + "(SELECT date_added FROM adlist WHERE address = :item));"; else if(listtype == GRAVITY_CLIENTS) querystr = "REPLACE INTO client (ip,comment,id,date_added) " - "VALUES (:argument,:comment," - "(SELECT id FROM client WHERE ip = :argument)," - "(SELECT date_added FROM client WHERE ip = :argument));"; + "VALUES (:item,:comment," + "(SELECT id FROM client WHERE ip = :item)," + "(SELECT date_added FROM client WHERE ip = :item));"; else // domainlist querystr = "REPLACE INTO domainlist (domain,type,enabled,comment,id,date_added) " - "VALUES (:argument,:type,:enabled,:comment," - "(SELECT id FROM domainlist WHERE domain = :argument AND type = :oldtype)," - "(SELECT date_added FROM domainlist WHERE domain = :argument AND type = :oldtype));"; + "VALUES (:item,:type,:enabled,:comment," + "(SELECT id FROM domainlist WHERE domain = :item AND type = :oldtype)," + "(SELECT date_added FROM domainlist WHERE domain = :item AND type = :oldtype));"; } int rc = sqlite3_prepare_v2(gravity_db, querystr, -1, &stmt, NULL); @@ -1467,17 +1472,17 @@ bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row, { *message = sqlite3_errmsg(gravity_db); logg("gravityDB_addToTable(%d, %s) - SQL error prepare (%i): %s", - type, row->domain, rc, *message); + row->type_int, row->domain, rc, *message); return false; } - // Bind argument to prepared statement (if requested) - int idx = sqlite3_bind_parameter_index(stmt, ":argument"); - if(idx > 0 && (rc = sqlite3_bind_text(stmt, idx, row->argument, -1, SQLITE_STATIC)) != SQLITE_OK) + // Bind item to prepared statement (if requested) + int idx = sqlite3_bind_parameter_index(stmt, ":item"); + if(idx > 0 && (rc = sqlite3_bind_text(stmt, idx, row->item, -1, SQLITE_STATIC)) != SQLITE_OK) { *message = sqlite3_errmsg(gravity_db); - logg("gravityDB_addToTable(%d, %s): Failed to bind argument (error %d) - %s", - type, row->argument, rc, *message); + logg("gravityDB_addToTable(%d, %s): Failed to bind item (error %d) - %s", + row->type_int, row->item, rc, *message); sqlite3_reset(stmt); sqlite3_finalize(stmt); return false; @@ -1485,11 +1490,11 @@ bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row, // Bind type to prepared statement (if requested) idx = sqlite3_bind_parameter_index(stmt, ":type"); - if(idx > 0 && (rc = sqlite3_bind_int(stmt, idx, type)) != SQLITE_OK) + if(idx > 0 && (rc = sqlite3_bind_int(stmt, idx, row->type_int)) != SQLITE_OK) { *message = sqlite3_errmsg(gravity_db); logg("gravityDB_addToTable(%d, %s): Failed to bind type (error %d) - %s", - type, row->domain, rc, *message); + row->type_int, row->domain, rc, *message); sqlite3_reset(stmt); sqlite3_finalize(stmt); return false; @@ -1503,14 +1508,14 @@ bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row, if(row->oldtype == NULL && row->oldkind == NULL) { // User didn't specify oldtype/oldkind, just replace without moving - oldtype = type; + oldtype = row->type_int; } else if(row->oldtype == NULL) { // Error, one is not meaningful without the other *message = "Field oldtype missing from request"; logg("gravityDB_addToTable(%d, %s): Oldtype missing", - type, row->domain); + row->type_int, row->domain); sqlite3_reset(stmt); sqlite3_finalize(stmt); return false; @@ -1520,7 +1525,7 @@ bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row, // Error, one is not meaningful without the other *message = "Field oldkind missing from request"; logg("gravityDB_addToTable(%d, %s): Oldkind missing", - type, row->domain); + row->type_int, row->domain); sqlite3_reset(stmt); sqlite3_finalize(stmt); return false; @@ -1543,7 +1548,7 @@ bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row, { *message = "Cannot interpret oldtype/oldkind"; logg("gravityDB_addToTable(%d, %s): Failed to identify oldtype=\"%s\", oldkind=\"%s\"", - type, row->domain, row->oldtype, row->oldkind); + row->type_int, row->domain, row->oldtype, row->oldkind); sqlite3_reset(stmt); sqlite3_finalize(stmt); return false; @@ -1555,7 +1560,7 @@ bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row, { *message = sqlite3_errmsg(gravity_db); logg("gravityDB_addToTable(%d, %s): Failed to bind oldtype (error %d) - %s", - type, row->domain, rc, *message); + row->type_int, row->domain, rc, *message); sqlite3_reset(stmt); sqlite3_finalize(stmt); return false; @@ -1568,7 +1573,7 @@ bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row, { *message = sqlite3_errmsg(gravity_db); logg("gravityDB_addToTable(%d, %s): Failed to bind enabled (error %d) - %s", - type, row->domain, rc, *message); + row->type_int, row->domain, rc, *message); sqlite3_reset(stmt); sqlite3_finalize(stmt); return false; @@ -1580,19 +1585,7 @@ bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row, { *message = sqlite3_errmsg(gravity_db); logg("gravityDB_addToTable(%d, %s): Failed to bind comment (error %d) - %s", - type, row->domain, rc, *message); - sqlite3_reset(stmt); - sqlite3_finalize(stmt); - return false; - } - - // Bind description string to prepared statement (if requested) - idx = sqlite3_bind_parameter_index(stmt, ":description"); - if(idx > 0 && (rc = sqlite3_bind_text(stmt, idx, row->description, -1, SQLITE_STATIC)) != SQLITE_OK) - { - *message = sqlite3_errmsg(gravity_db); - logg("gravityDB_addToTable(%d, %s): Failed to bind description (error %d) - %s", - type, row->domain, rc, *message); + row->type_int, row->domain, rc, *message); sqlite3_reset(stmt); sqlite3_finalize(stmt); return false; @@ -1799,7 +1792,7 @@ bool gravityDB_delFromTable(const enum gravity_list_type listtype, const char* a } static sqlite3_stmt* read_stmt = NULL; -bool gravityDB_readTable(const enum gravity_list_type listtype, const char *argument, const char **message) +bool gravityDB_readTable(const enum gravity_list_type listtype, const char *item, const char **message) { if(gravity_db == NULL) { @@ -1852,30 +1845,30 @@ bool gravityDB_readTable(const enum gravity_list_type listtype, const char *argu const char *extra = ""; if(listtype == GRAVITY_GROUPS) { - if(argument != NULL && argument[0] != '\0') - extra = " WHERE name = :argument;"; - sprintf(querystr, "SELECT id,name,enabled,date_added,date_modified,description FROM \"group\"%s;", extra); + if(item != NULL && item[0] != '\0') + extra = " WHERE name = :item;"; + sprintf(querystr, "SELECT id,name,enabled,date_added,date_modified,description AS comment FROM \"group\"%s;", extra); } else if(listtype == GRAVITY_ADLISTS) { - if(argument != NULL && argument[0] != '\0') - extra = " WHERE address = :argument;"; + if(item != NULL && item[0] != '\0') + extra = " WHERE address = :item;"; sprintf(querystr, "SELECT id,address,enabled,date_added,date_modified,comment," "(SELECT GROUP_CONCAT(group_id) FROM adlist_by_group g WHERE g.adlist_id = a.id) AS group_ids " "FROM adlist a%s;", extra); } else if(listtype == GRAVITY_CLIENTS) { - if(argument != NULL && argument[0] != '\0') - extra = " WHERE ip = :argument;"; - sprintf(querystr, "SELECT id,ip,date_added,date_modified,comment," + if(item != NULL && item[0] != '\0') + extra = " WHERE ip = :item;"; + sprintf(querystr, "SELECT id,ip AS client,date_added,date_modified,comment," "(SELECT GROUP_CONCAT(group_id) FROM client_by_group g WHERE g.client_id = c.id) AS group_ids " "FROM client c%s;", extra); } else // domainlist { - if(argument != NULL && argument[0] != '\0') - extra = " AND domain = :argument;"; + if(item != NULL && item[0] != '\0') + extra = " AND domain = :item;"; sprintf(querystr, "SELECT id,type,domain,enabled,date_added,date_modified,comment," "(SELECT GROUP_CONCAT(group_id) FROM domainlist_by_group g WHERE g.domainlist_id = d.id) AS group_ids " "FROM domainlist d WHERE d.type IN (%s)%s;", type, extra); @@ -1890,13 +1883,13 @@ bool gravityDB_readTable(const enum gravity_list_type listtype, const char *argu return false; } - // Bind argument to prepared statement (if requested) - int idx = sqlite3_bind_parameter_index(read_stmt, ":argument"); - if(idx > 0 && (rc = sqlite3_bind_text(read_stmt, idx, argument, -1, SQLITE_STATIC)) != SQLITE_OK) + // Bind item to prepared statement (if requested) + int idx = sqlite3_bind_parameter_index(read_stmt, ":item"); + if(idx > 0 && (rc = sqlite3_bind_text(read_stmt, idx, item, -1, SQLITE_STATIC)) != SQLITE_OK) { *message = sqlite3_errmsg(gravity_db); - logg("gravityDB_readTable(%d => (%s), %s): Failed to bind argument (error %d) - %s", - listtype, type, argument, rc, *message); + logg("gravityDB_readTable(%d => (%s), %s): Failed to bind item (error %d) - %s", + listtype, type, item, rc, *message); sqlite3_reset(read_stmt); sqlite3_finalize(read_stmt); return false; @@ -1906,7 +1899,7 @@ bool gravityDB_readTable(const enum gravity_list_type listtype, const char *argu if(config.debug & DEBUG_API) { logg("SQL: %s", querystr); - logg(" :argument = \"%s\"", argument); + logg(" :item = \"%s\"", item); } return true; @@ -1976,11 +1969,8 @@ bool gravityDB_readTableGetRow(tablerow *row, const char **message) else if(strcasecmp(cname, "name") == 0) row->name = (char*)sqlite3_column_text(read_stmt, c); - else if(strcasecmp(cname, "description") == 0) - row->description = (char*)sqlite3_column_text(read_stmt, c); - - else if(strcasecmp(cname, "ip") == 0) - row->ip = (char*)sqlite3_column_text(read_stmt, c); + else if(strcasecmp(cname, "client") == 0) + row->client = (char*)sqlite3_column_text(read_stmt, c); else logg("Internal API error: Encountered unknown column %s", cname); @@ -2025,19 +2015,19 @@ bool gravityDB_edit_groups(const enum gravity_list_type listtype, cJSON *groups, return false; else if(listtype == GRAVITY_CLIENTS) { - get_querystr = "SELECT id FROM client WHERE ip = :argument"; + get_querystr = "SELECT id FROM client WHERE ip = :item"; del_querystr = "DELETE FROM client_by_group WHERE client_id = :id;"; add_querystr = "INSERT INTO client_by_group (client_id,group_id) VALUES (:id,:gid);"; } else if(listtype == GRAVITY_ADLISTS) { - get_querystr = "SELECT id FROM adlist WHERE address = :argument"; + get_querystr = "SELECT id FROM adlist WHERE address = :item"; del_querystr = "DELETE FROM adlist_by_group WHERE adlist_id = :id;"; add_querystr = "INSERT INTO adlist_by_group (adlist_id,group_id) VALUES (:id,:gid);"; } else // domainlist { - get_querystr = "SELECT id FROM domainlist WHERE domain = :argument AND type = :type"; + get_querystr = "SELECT id FROM domainlist WHERE domain = :item AND type = :type"; del_querystr = "DELETE FROM domainlist_by_group WHERE domainlist_id = :id;"; add_querystr = "INSERT INTO domainlist_by_group (domainlist_id,group_id) VALUES (:id,:gid);"; } @@ -2053,12 +2043,12 @@ bool gravityDB_edit_groups(const enum gravity_list_type listtype, cJSON *groups, return false; } - // Bind argument string to prepared statement (if requested) - int idx = sqlite3_bind_parameter_index(stmt, ":argument"); - if(idx > 0 && (rc = sqlite3_bind_text(stmt, idx, row->argument, -1, SQLITE_STATIC)) != SQLITE_OK) + // Bind item string to prepared statement (if requested) + int idx = sqlite3_bind_parameter_index(stmt, ":item"); + if(idx > 0 && (rc = sqlite3_bind_text(stmt, idx, row->item, -1, SQLITE_STATIC)) != SQLITE_OK) { *message = sqlite3_errmsg(gravity_db); - logg("gravityDB_edit_groups(%d): Failed to bind argument SELECT (error %d) - %s", + logg("gravityDB_edit_groups(%d): Failed to bind item SELECT (error %d) - %s", listtype, rc, *message); sqlite3_reset(stmt); sqlite3_finalize(stmt); @@ -2095,7 +2085,7 @@ bool gravityDB_edit_groups(const enum gravity_list_type listtype, cJSON *groups, if(config.debug & DEBUG_API) { logg("SQL: %s", get_querystr); - logg(" :argument = \"%s\"", row->argument); + logg(" :item = \"%s\"", row->item); logg(" :type = \"%d\"", row->type_int); } diff --git a/src/database/gravity-db.h b/src/database/gravity-db.h index d5222e4d..25fe54ef 100644 --- a/src/database/gravity-db.h +++ b/src/database/gravity-db.h @@ -30,9 +30,8 @@ typedef struct { const char *oldkind; const char *comment; const char *group_ids; - const char *description; - const char *argument; - const char *ip; + const char *client; + const char *item; long id; time_t date_added; time_t date_modified; diff --git a/src/webserver/http-common.c b/src/webserver/http-common.c index f2c45607..96178a2c 100644 --- a/src/webserver/http-common.c +++ b/src/webserver/http-common.c @@ -146,6 +146,8 @@ const char* __attribute__((pure)) startsWith(const char *path, struct ftl_conn * if(api->request->local_uri[strlen(path)] == '/') { // Path match with argument after ".../" + if(api->action_path != NULL) + free(api->action_path); api->action_path = strdup(api->request->local_uri); api->action_path[strlen(path)] = '\0'; return api->request->local_uri + strlen(path) + 1u; @@ -153,6 +155,8 @@ const char* __attribute__((pure)) startsWith(const char *path, struct ftl_conn * else if(strlen(path) == strlen(api->request->local_uri)) { // Path match directly, no argument + if(api->action_path != NULL) + free(api->action_path); api->action_path = strdup(api->request->local_uri); return ""; } diff --git a/src/webserver/http-common.h b/src/webserver/http-common.h index 1451f963..8be641b1 100644 --- a/src/webserver/http-common.h +++ b/src/webserver/http-common.h @@ -25,6 +25,7 @@ struct ftl_conn { const struct mg_request_info *request; const enum http_method method; char *action_path; + const char *item; struct { bool avail :1; char raw[MAX_PAYLOAD_BYTES];