Introduce new ftl_conn struct that makes it easier to share stuff across processing subroutines in the same thread.
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
parent
15ba45e50f
commit
f67becc3e1
155
src/api/auth.c
155
src/api/auth.c
|
@ -75,14 +75,11 @@ static void sha256_hex(uint8_t *data, char *buffer)
|
|||
// Returns >= 0 for any valid authentication
|
||||
#define LOCALHOSTv4 "127.0.0.1"
|
||||
#define LOCALHOSTv6 "::1"
|
||||
int check_client_auth(struct mg_connection *conn, char payload[MAX_PAYLOAD_BYTES])
|
||||
int check_client_auth(struct ftl_conn *api)
|
||||
{
|
||||
int user_id = -1;
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
|
||||
// Is the user requesting from localhost?
|
||||
if(!httpsettings.api_auth_for_localhost && (strcmp(request->remote_addr, LOCALHOSTv4) == 0 ||
|
||||
strcmp(request->remote_addr, LOCALHOSTv6) == 0))
|
||||
if(!httpsettings.api_auth_for_localhost && (strcmp(api->request->remote_addr, LOCALHOSTv4) == 0 ||
|
||||
strcmp(api->request->remote_addr, LOCALHOSTv6) == 0))
|
||||
{
|
||||
return API_AUTH_LOCALHOST;
|
||||
}
|
||||
|
@ -97,15 +94,13 @@ int check_client_auth(struct mg_connection *conn, char payload[MAX_PAYLOAD_BYTES
|
|||
// Does the client provide a session cookie?
|
||||
char sid[SID_SIZE];
|
||||
const char *sid_source = "cookie";
|
||||
bool sid_avail = http_get_cookie_str(conn, "sid", sid, SID_SIZE);
|
||||
bool sid_avail = http_get_cookie_str(api, "sid", sid, SID_SIZE);
|
||||
|
||||
// If not, does the client provide a session ID via GET/POST?
|
||||
bool sid_raw_payload = false, sid_json_payload = false;
|
||||
cJSON *json;
|
||||
if(!sid_avail && http_get_payload(conn, payload))
|
||||
if(!sid_avail && api->payload.avail)
|
||||
{
|
||||
// Try to extract SID from form-encoded payload
|
||||
if(GET_VAR("sid", sid, payload) > 0)
|
||||
if(GET_VAR("sid", sid, api->payload.raw) > 0)
|
||||
{
|
||||
// "+" may have been replaced by " ", undo this here
|
||||
for(unsigned int i = 0; i < SID_SIZE; i++)
|
||||
|
@ -118,70 +113,73 @@ int check_client_auth(struct mg_connection *conn, char payload[MAX_PAYLOAD_BYTES
|
|||
sid_avail = true;
|
||||
}
|
||||
// Try to extract SID from root of a possibly included JSON payload
|
||||
else if((json = cJSON_Parse(payload)) != NULL)
|
||||
else if(api->payload.json != NULL)
|
||||
{
|
||||
cJSON *sid_obj = cJSON_GetObjectItem(json, "sid");
|
||||
cJSON *sid_obj = cJSON_GetObjectItem(api->payload.json, "sid");
|
||||
if(cJSON_IsString(sid_obj))
|
||||
{
|
||||
strncpy(sid, sid_obj->valuestring, SID_SIZE - 1u);
|
||||
sid[SID_SIZE-1] = '\0';
|
||||
sid_source = "payload (JSON)";
|
||||
sid_avail = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logg("payload: \"%s\"", payload);
|
||||
logg("sid: \"%s\"", sid);
|
||||
|
||||
if(sid_avail || sid_raw_payload || sid_json_payload)
|
||||
if(!sid_avail)
|
||||
{
|
||||
const time_t now = time(NULL);
|
||||
if(config.debug & DEBUG_API)
|
||||
logg("API: Read sid=\"%s\" from %s", sid, sid_source);
|
||||
logg("API Authentification: FAIL (no SID provided)");
|
||||
|
||||
for(unsigned int i = 0; i < API_MAX_CLIENTS; i++)
|
||||
return API_AUTH_UNAUTHORIZED;
|
||||
}
|
||||
|
||||
// else: Analyze SID
|
||||
int user_id = API_AUTH_UNAUTHORIZED;
|
||||
const time_t now = time(NULL);
|
||||
if(config.debug & DEBUG_API)
|
||||
logg("API: Read sid=\"%s\" from %s", sid, sid_source);
|
||||
|
||||
for(unsigned int i = 0; i < API_MAX_CLIENTS; i++)
|
||||
{
|
||||
if(auth_data[i].used &&
|
||||
auth_data[i].valid_until >= now &&
|
||||
strcmp(auth_data[i].remote_addr, api->request->remote_addr) == 0 &&
|
||||
strcmp(auth_data[i].sid, sid) == 0)
|
||||
{
|
||||
if(auth_data[i].used &&
|
||||
auth_data[i].valid_until >= now &&
|
||||
strcmp(auth_data[i].remote_addr, request->remote_addr) == 0 &&
|
||||
strcmp(auth_data[i].sid, sid) == 0)
|
||||
{
|
||||
user_id = i;
|
||||
break;
|
||||
}
|
||||
user_id = i;
|
||||
break;
|
||||
}
|
||||
if(user_id > API_AUTH_UNAUTHORIZED)
|
||||
}
|
||||
if(user_id > API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
// Authentication succesful:
|
||||
// - We know this client
|
||||
// - The session is (still) valid
|
||||
// - The IP matches the one we know for this SID
|
||||
|
||||
// Update timestamp of this client to extend
|
||||
// the validity of their API authentication
|
||||
auth_data[user_id].valid_until = now + httpsettings.session_timeout;
|
||||
|
||||
// Update user cookie
|
||||
if(snprintf(pi_hole_extra_headers, sizeof(pi_hole_extra_headers),
|
||||
FTL_SET_COOKIE,
|
||||
auth_data[user_id].sid, httpsettings.session_timeout) < 0)
|
||||
{
|
||||
// Authentication succesful:
|
||||
// - We know this client
|
||||
// - The session is (still) valid
|
||||
// - The IP matches the one we know for this SID
|
||||
|
||||
// Update timestamp of this client to extend
|
||||
// the validity of their API authentication
|
||||
auth_data[user_id].valid_until = now + httpsettings.session_timeout;
|
||||
|
||||
// Update user cookie
|
||||
if(snprintf(pi_hole_extra_headers, sizeof(pi_hole_extra_headers),
|
||||
FTL_SET_COOKIE,
|
||||
auth_data[user_id].sid, httpsettings.session_timeout) < 0)
|
||||
{
|
||||
return send_json_error(conn, 500, "internal_error", "Internal server error", NULL);
|
||||
}
|
||||
|
||||
if(config.debug & DEBUG_API)
|
||||
{
|
||||
char timestr[128];
|
||||
get_timestr(timestr, auth_data[user_id].valid_until);
|
||||
logg("API: Recognized known user: user_id %i valid_until: %s remote_addr %s",
|
||||
user_id, timestr, auth_data[user_id].remote_addr);
|
||||
}
|
||||
return send_json_error(api, 500, "internal_error", "Internal server error", NULL);
|
||||
}
|
||||
|
||||
if(config.debug & DEBUG_API)
|
||||
{
|
||||
char timestr[128];
|
||||
get_timestr(timestr, auth_data[user_id].valid_until);
|
||||
logg("API: Recognized known user: user_id %i valid_until: %s remote_addr %s",
|
||||
user_id, timestr, auth_data[user_id].remote_addr);
|
||||
}
|
||||
else if(config.debug & DEBUG_API)
|
||||
logg("API Authentification: FAIL (SID invalid/expired)");
|
||||
}
|
||||
else if(config.debug & DEBUG_API)
|
||||
logg("API Authentification: FAIL (no SID provided)");
|
||||
logg("API Authentification: FAIL (SID invalid/expired)");
|
||||
|
||||
return user_id;
|
||||
}
|
||||
|
@ -209,7 +207,7 @@ static bool check_response(const char *response, const time_t now)
|
|||
return false;
|
||||
}
|
||||
|
||||
static int get_session_object(struct mg_connection *conn, cJSON *json, const int user_id, const time_t now)
|
||||
static int get_session_object(struct ftl_conn *api, cJSON *json, const int user_id, const time_t now)
|
||||
{
|
||||
// Authentication not needed
|
||||
if(user_id == API_AUTH_LOCALHOST || user_id == API_AUTH_EMPTYPASS)
|
||||
|
@ -254,7 +252,7 @@ static void delete_session(const int user_id)
|
|||
memset(auth_data[user_id].remote_addr, 0, sizeof(auth_data[user_id].remote_addr));
|
||||
}
|
||||
|
||||
static int send_api_auth_status(struct mg_connection *conn, const int user_id, const int method, const time_t now)
|
||||
static int send_api_auth_status(struct ftl_conn *api, const int user_id, const time_t now)
|
||||
{
|
||||
if(user_id == API_AUTH_LOCALHOST)
|
||||
{
|
||||
|
@ -262,7 +260,7 @@ static int send_api_auth_status(struct mg_connection *conn, const int user_id, c
|
|||
logg("API Auth status: OK (localhost does not need auth)");
|
||||
|
||||
cJSON *json = JSON_NEW_OBJ();
|
||||
get_session_object(conn, json, user_id, now);
|
||||
get_session_object(api, json, user_id, now);
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
|
@ -272,11 +270,11 @@ static int send_api_auth_status(struct mg_connection *conn, const int user_id, c
|
|||
logg("API Auth status: OK (empty password)");
|
||||
|
||||
cJSON *json = JSON_NEW_OBJ();
|
||||
get_session_object(conn, json, user_id, now);
|
||||
get_session_object(api, json, user_id, now);
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
if(user_id > API_AUTH_UNAUTHORIZED && (method == HTTP_GET || method == HTTP_POST))
|
||||
if(user_id > API_AUTH_UNAUTHORIZED && (api->method == HTTP_GET || api->method == HTTP_POST))
|
||||
{
|
||||
if(config.debug & DEBUG_API)
|
||||
logg("API Auth status: OK");
|
||||
|
@ -286,14 +284,14 @@ static int send_api_auth_status(struct mg_connection *conn, const int user_id, c
|
|||
FTL_SET_COOKIE,
|
||||
auth_data[user_id].sid, API_SESSION_EXPIRE) < 0)
|
||||
{
|
||||
return send_json_error(conn, 500, "internal_error", "Internal server error", NULL);
|
||||
return send_json_error(api, 500, "internal_error", "Internal server error", NULL);
|
||||
}
|
||||
|
||||
cJSON *json = JSON_NEW_OBJ();
|
||||
get_session_object(conn, json, user_id, now);
|
||||
get_session_object(api, json, user_id, now);
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
else if(user_id > API_AUTH_UNAUTHORIZED && method == HTTP_DELETE)
|
||||
else if(user_id > API_AUTH_UNAUTHORIZED && api->method == HTTP_DELETE)
|
||||
{
|
||||
if(config.debug & DEBUG_API)
|
||||
logg("API Auth status: Logout, asking to delete cookie");
|
||||
|
@ -303,7 +301,7 @@ static int send_api_auth_status(struct mg_connection *conn, const int user_id, c
|
|||
|
||||
strncpy(pi_hole_extra_headers, FTL_DELETE_COOKIE, sizeof(pi_hole_extra_headers));
|
||||
cJSON *json = JSON_NEW_OBJ();
|
||||
get_session_object(conn, json, user_id, now);
|
||||
get_session_object(api, json, user_id, now);
|
||||
JSON_SEND_OBJECT_CODE(json, 410); // 410 Gone
|
||||
}
|
||||
else
|
||||
|
@ -313,7 +311,7 @@ static int send_api_auth_status(struct mg_connection *conn, const int user_id, c
|
|||
|
||||
strncpy(pi_hole_extra_headers, FTL_DELETE_COOKIE, sizeof(pi_hole_extra_headers));
|
||||
cJSON *json = JSON_NEW_OBJ();
|
||||
get_session_object(conn, json, user_id, now);
|
||||
get_session_object(api, json, user_id, now);
|
||||
JSON_SEND_OBJECT_CODE(json, 401); // 401 Unauthorized
|
||||
}
|
||||
}
|
||||
|
@ -378,40 +376,37 @@ static void generateSID(char *sid)
|
|||
// GET: Check authentication and obtain a challenge
|
||||
// POST: Login
|
||||
// DELETE: Logout
|
||||
int api_auth(struct mg_connection *conn)
|
||||
int api_auth(struct ftl_conn *api)
|
||||
{
|
||||
// Check HTTP method
|
||||
const enum http_method method = http_method(conn);
|
||||
const time_t now = time(NULL);
|
||||
|
||||
char *password_hash = get_password_hash();
|
||||
const bool empty_password = (strlen(password_hash) == 0u);
|
||||
|
||||
int user_id = API_AUTH_UNAUTHORIZED;
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
|
||||
bool reponse_set = false;
|
||||
char response[256] = { 0 };
|
||||
char payload[MAX_PAYLOAD_BYTES];
|
||||
|
||||
// Did the client authenticate before and we can validate this?
|
||||
user_id = check_client_auth(conn, payload);
|
||||
user_id = check_client_auth(api);
|
||||
|
||||
// If this is a valid session, we can exit early at this point
|
||||
if(user_id != API_AUTH_UNAUTHORIZED)
|
||||
return send_api_auth_status(conn, user_id, method, now);
|
||||
return send_api_auth_status(api, user_id, now);
|
||||
|
||||
// Login attempt, extract response
|
||||
if(method == HTTP_POST)
|
||||
if(api->method == HTTP_POST)
|
||||
{
|
||||
// Try to extract response from payload
|
||||
int len = 0;
|
||||
if((len = GET_VAR("response", response, payload)) != CHALLENGE_SIZE)
|
||||
if((len = GET_VAR("response", response, api->payload.raw)) != CHALLENGE_SIZE)
|
||||
{
|
||||
const char *message = len < 0 ? "No response found" : "Invalid response length";
|
||||
if(config.debug & DEBUG_API)
|
||||
logg("API auth error: %s", message);
|
||||
return send_json_error(conn, 400,
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
message,
|
||||
NULL);
|
||||
|
@ -420,11 +415,11 @@ int api_auth(struct mg_connection *conn)
|
|||
}
|
||||
|
||||
// Logout attempt
|
||||
if(method == HTTP_DELETE)
|
||||
if(api->method == HTTP_DELETE)
|
||||
{
|
||||
if(config.debug & DEBUG_API)
|
||||
logg("API Auth: User with ID %i wants to log out", user_id);
|
||||
return send_api_auth_status(conn, user_id, method, now);
|
||||
return send_api_auth_status(api, user_id, now);
|
||||
}
|
||||
|
||||
// Login attempt and/or auth check
|
||||
|
@ -455,7 +450,7 @@ int api_auth(struct mg_connection *conn)
|
|||
{
|
||||
auth_data[i].used = true;
|
||||
auth_data[i].valid_until = now + httpsettings.session_timeout;
|
||||
strncpy(auth_data[i].remote_addr, request->remote_addr, sizeof(auth_data[i].remote_addr));
|
||||
strncpy(auth_data[i].remote_addr, api->request->remote_addr, sizeof(auth_data[i].remote_addr));
|
||||
auth_data[i].remote_addr[sizeof(auth_data[i].remote_addr)-1] = '\0';
|
||||
generateSID(auth_data[i].sid);
|
||||
|
||||
|
@ -486,7 +481,7 @@ int api_auth(struct mg_connection *conn)
|
|||
// Free allocated memory
|
||||
free(password_hash);
|
||||
password_hash = NULL;
|
||||
return send_api_auth_status(conn, user_id, method, now);
|
||||
return send_api_auth_status(api, user_id, now);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -534,7 +529,7 @@ int api_auth(struct mg_connection *conn)
|
|||
// Return to user
|
||||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_REF_STR(json, "challenge", challenges[i].challenge);
|
||||
get_session_object(conn, json, -1, now);
|
||||
get_session_object(api, json, -1, now);
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
// set_blockingmode_timer()
|
||||
#include "../timers.h"
|
||||
|
||||
static int get_blocking(struct mg_connection *conn)
|
||||
static int get_blocking(struct ftl_conn *api)
|
||||
{
|
||||
// Return current status
|
||||
cJSON *json = JSON_NEW_OBJ();
|
||||
|
@ -45,35 +45,24 @@ static int get_blocking(struct mg_connection *conn)
|
|||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
static int set_blocking(struct mg_connection *conn)
|
||||
static int set_blocking(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to access this ressource
|
||||
if(check_client_auth(conn, NULL) == API_AUTH_UNAUTHORIZED)
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(conn);
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
char buffer[1024] = { 0 };
|
||||
const int data_len = mg_read(conn, buffer, sizeof(buffer) - 1);
|
||||
if ((data_len < 1) || (data_len >= (int)sizeof(buffer))) {
|
||||
return send_json_error(conn, 400,
|
||||
"bad_request", "No request body data",
|
||||
NULL);
|
||||
}
|
||||
buffer[data_len] = '\0';
|
||||
|
||||
cJSON *obj = cJSON_Parse(buffer);
|
||||
if (obj == NULL) {
|
||||
return send_json_error(conn, 400,
|
||||
if (api->payload.json == NULL) {
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"Invalid request body data",
|
||||
NULL);
|
||||
}
|
||||
|
||||
cJSON *elem = cJSON_GetObjectItemCaseSensitive(obj, "blocking");
|
||||
cJSON *elem = cJSON_GetObjectItemCaseSensitive(api->payload.json, "blocking");
|
||||
if (!cJSON_IsBool(elem)) {
|
||||
cJSON_Delete(obj);
|
||||
return send_json_error(conn, 400,
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"No \"blocking\" boolean in body data",
|
||||
NULL);
|
||||
|
@ -82,13 +71,10 @@ static int set_blocking(struct mg_connection *conn)
|
|||
|
||||
// Get (optional) delay
|
||||
int delay = -1;
|
||||
elem = cJSON_GetObjectItemCaseSensitive(obj, "delay");
|
||||
elem = cJSON_GetObjectItemCaseSensitive(api->payload.json, "delay");
|
||||
if (cJSON_IsNumber(elem) && elem->valuedouble > 0.0)
|
||||
delay = elem->valueint;
|
||||
|
||||
// Free memory not needed any longer
|
||||
cJSON_Delete(obj);
|
||||
|
||||
if(target_status == get_blockingstatus())
|
||||
{
|
||||
// The blocking status does not need to be changed
|
||||
|
@ -107,19 +93,18 @@ static int set_blocking(struct mg_connection *conn)
|
|||
|
||||
// Return GET property as result of POST/PUT/PATCH action
|
||||
// if no error happened above
|
||||
return get_blocking(conn);
|
||||
return get_blocking(api);
|
||||
}
|
||||
|
||||
int api_dns_blockingstatus(struct mg_connection *conn)
|
||||
int api_dns_blockingstatus(struct ftl_conn *api)
|
||||
{
|
||||
int method = http_method(conn);
|
||||
if(method == HTTP_GET)
|
||||
if(api->method == HTTP_GET)
|
||||
{
|
||||
return get_blocking(conn);
|
||||
return get_blocking(api);
|
||||
}
|
||||
else if(method == HTTP_PUT)
|
||||
else if(api->method == HTTP_PUT)
|
||||
{
|
||||
return set_blocking(conn);
|
||||
return set_blocking(api);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -128,12 +113,12 @@ int api_dns_blockingstatus(struct mg_connection *conn)
|
|||
}
|
||||
}
|
||||
|
||||
int api_dns_cacheinfo(struct mg_connection *conn)
|
||||
int api_dns_cacheinfo(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to access this ressource
|
||||
if(check_client_auth(conn, NULL) == API_AUTH_UNAUTHORIZED)
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(conn);
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
cacheinforecord cacheinfo;
|
||||
|
|
|
@ -29,28 +29,26 @@
|
|||
// counters
|
||||
#include "../shmem.h"
|
||||
|
||||
int api_ftl_client(struct mg_connection *conn)
|
||||
int api_ftl_client(struct ftl_conn *api)
|
||||
{
|
||||
cJSON *json = JSON_NEW_OBJ();
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
|
||||
// Add client's IP address
|
||||
JSON_OBJ_REF_STR(json, "remote_addr", request->remote_addr);
|
||||
JSON_OBJ_REF_STR(json, "remote_addr", api->request->remote_addr);
|
||||
|
||||
// Add HTTP version
|
||||
JSON_OBJ_REF_STR(json, "http_version", request->http_version);
|
||||
JSON_OBJ_REF_STR(json, "http_version", api->request->http_version);
|
||||
|
||||
// Add request method
|
||||
JSON_OBJ_REF_STR(json, "method", request->request_method);
|
||||
JSON_OBJ_REF_STR(json, "method", api->request->request_method);
|
||||
|
||||
// Add HTTP headers
|
||||
cJSON *headers = JSON_NEW_ARRAY();
|
||||
for(int i = 0; i < request->num_headers; i++)
|
||||
for(int i = 0; i < api->request->num_headers; i++)
|
||||
{
|
||||
// Add headers
|
||||
cJSON *header = JSON_NEW_OBJ();
|
||||
JSON_OBJ_REF_STR(header, "name", request->http_headers[i].name);
|
||||
JSON_OBJ_REF_STR(header, "value", request->http_headers[i].value);
|
||||
JSON_OBJ_REF_STR(header, "name", api->request->http_headers[i].name);
|
||||
JSON_OBJ_REF_STR(header, "value", api->request->http_headers[i].value);
|
||||
JSON_ARRAY_ADD_ITEM(headers, header);
|
||||
}
|
||||
JSON_OBJ_ADD_ITEM(json, "headers", headers);
|
||||
|
@ -60,21 +58,20 @@ int api_ftl_client(struct mg_connection *conn)
|
|||
|
||||
// fifologData is allocated in shared memory for cross-fork compatibility
|
||||
fifologData *fifo_log = NULL;
|
||||
int api_ftl_dnsmasq_log(struct mg_connection *conn)
|
||||
int api_ftl_dnsmasq_log(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(conn, NULL) == API_AUTH_UNAUTHORIZED)
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(conn);
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
unsigned int start = 0u;
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
if(request->query_string != NULL)
|
||||
if(api->request->query_string != NULL)
|
||||
{
|
||||
// Does the user request an ID to sent from?
|
||||
unsigned int nextID;
|
||||
if(get_uint_var(request->query_string, "nextID", &nextID))
|
||||
if(get_uint_var(api->request->query_string, "nextID", &nextID))
|
||||
{
|
||||
if(nextID >= fifo_log->next_id)
|
||||
{
|
||||
|
@ -125,12 +122,12 @@ int api_ftl_dnsmasq_log(struct mg_connection *conn)
|
|||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_ftl_database(struct mg_connection *conn)
|
||||
int api_ftl_database(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(conn, NULL) == API_AUTH_UNAUTHORIZED)
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
send_json_unauthorized(conn);
|
||||
send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
cJSON *json = JSON_NEW_OBJ();
|
||||
|
@ -200,7 +197,7 @@ int api_ftl_database(struct mg_connection *conn)
|
|||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
static int read_temp_sensor(struct mg_connection *conn,
|
||||
static int read_temp_sensor(struct ftl_conn *api,
|
||||
const char *label_path,
|
||||
const char *value_path,
|
||||
const char *fallback_label,
|
||||
|
@ -276,12 +273,12 @@ static bool GetRamInKB(long *mem_total, long *mem_used, long *mem_free, long *me
|
|||
return true;
|
||||
}
|
||||
|
||||
int get_system_obj(struct mg_connection *conn, cJSON *system)
|
||||
int get_system_obj(struct ftl_conn *api, cJSON *system)
|
||||
{
|
||||
const int nprocs = get_nprocs();
|
||||
struct sysinfo info;
|
||||
if(sysinfo(&info) != 0)
|
||||
return send_json_error(conn, 500, "error", strerror(errno), NULL);
|
||||
return send_json_error(api, 500, "error", strerror(errno), NULL);
|
||||
|
||||
// Seconds since boot
|
||||
JSON_OBJ_ADD_NUMBER(system, "uptime", info.uptime);
|
||||
|
@ -362,7 +359,7 @@ int get_system_obj(struct mg_connection *conn, cJSON *system)
|
|||
sprintf(label_path, "/sys/class/thermal/thermal_zone%d/type", i);
|
||||
sprintf(value_path, "/sys/class/thermal/thermal_zone%d/temp", i);
|
||||
sprintf(fallback_label, "thermal_zone%d/temp", i);
|
||||
ret = read_temp_sensor(conn, label_path, value_path, fallback_label, sensors);
|
||||
ret = read_temp_sensor(api, label_path, value_path, fallback_label, sensors);
|
||||
// Error handling
|
||||
if(ret != 0)
|
||||
return ret;
|
||||
|
@ -371,7 +368,7 @@ int get_system_obj(struct mg_connection *conn, cJSON *system)
|
|||
sprintf(label_path, "/sys/class/hwmon/hwmon0/temp%d_label", i);
|
||||
sprintf(value_path, "/sys/class/hwmon/hwmon0/temp%d_input", i);
|
||||
sprintf(fallback_label, "hwmon0/temp%d", i);
|
||||
ret = read_temp_sensor(conn, label_path, value_path, fallback_label, sensors);
|
||||
ret = read_temp_sensor(api, label_path, value_path, fallback_label, sensors);
|
||||
// Error handling
|
||||
if(ret != 0)
|
||||
return ret;
|
||||
|
@ -387,13 +384,13 @@ int get_system_obj(struct mg_connection *conn, cJSON *system)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int api_ftl_system(struct mg_connection *conn)
|
||||
int api_ftl_system(struct ftl_conn *api)
|
||||
{
|
||||
cJSON *json = JSON_NEW_OBJ();
|
||||
cJSON *system = JSON_NEW_OBJ();
|
||||
|
||||
// Get system object
|
||||
const int ret = get_system_obj(conn, system);
|
||||
const int ret = get_system_obj(api, system);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
|
|
112
src/api/list.c
112
src/api/list.c
|
@ -14,7 +14,7 @@
|
|||
#include "routes.h"
|
||||
#include "../database/gravity-db.h"
|
||||
|
||||
static int api_list_read(struct mg_connection *conn,
|
||||
static int api_list_read(struct ftl_conn *api,
|
||||
const int code,
|
||||
const enum gravity_list_type listtype,
|
||||
const char *argument)
|
||||
|
@ -34,7 +34,7 @@ static int api_list_read(struct mg_connection *conn,
|
|||
JSON_OBJ_ADD_NULL(json, "sql_msg");
|
||||
}
|
||||
|
||||
return send_json_error(conn, 400, // 400 Bad Request
|
||||
return send_json_error(api, 400, // 400 Bad Request
|
||||
"database_error",
|
||||
"Could not read domains from database table",
|
||||
json);
|
||||
|
@ -46,7 +46,6 @@ static int api_list_read(struct mg_connection *conn,
|
|||
{
|
||||
cJSON *item = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(item, "id", row.id);
|
||||
JSON_OBJ_ADD_BOOL(item, "enabled", row.enabled);
|
||||
|
||||
// Special fields
|
||||
if(listtype == GRAVITY_GROUPS)
|
||||
|
@ -69,8 +68,8 @@ static int api_list_read(struct mg_connection *conn,
|
|||
}
|
||||
else // domainlists
|
||||
{
|
||||
JSON_OBJ_REF_STR(item, "type", row.type);
|
||||
JSON_OBJ_COPY_STR(item, "domain", row.domain);
|
||||
JSON_OBJ_REF_STR(item, "type", row.type);
|
||||
if(row.comment != NULL) {
|
||||
JSON_OBJ_COPY_STR(item, "comment", row.comment);
|
||||
} else {
|
||||
|
@ -87,14 +86,15 @@ static int api_list_read(struct mg_connection *conn,
|
|||
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, "group_ids", group_ids);
|
||||
JSON_OBJ_ADD_ITEM(item, "groups", group_ids);
|
||||
} else {
|
||||
// Empty group set
|
||||
cJSON *group_ids = JSON_NEW_ARRAY();
|
||||
JSON_OBJ_ADD_ITEM(item, "group_ids", group_ids);
|
||||
JSON_OBJ_ADD_ITEM(item, "groups", group_ids);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JSON_OBJ_ADD_BOOL(item, "enabled", row.enabled);
|
||||
JSON_OBJ_ADD_NUMBER(item, "date_added", row.date_added);
|
||||
JSON_OBJ_ADD_NUMBER(item, "date_modified", row.date_modified);
|
||||
|
||||
|
@ -131,16 +131,15 @@ static int api_list_read(struct mg_connection *conn,
|
|||
JSON_OBJ_ADD_NULL(json, "sql_msg");
|
||||
}
|
||||
|
||||
return send_json_error(conn, 400, // 400 Bad Request
|
||||
return send_json_error(api, 400, // 400 Bad Request
|
||||
"database_error",
|
||||
"Could not read from gravity database",
|
||||
json);
|
||||
}
|
||||
}
|
||||
|
||||
static int api_list_write(struct mg_connection *conn,
|
||||
static int api_list_write(struct ftl_conn *api,
|
||||
const enum gravity_list_type listtype,
|
||||
const enum http_method method,
|
||||
const char *argument,
|
||||
char payload[MAX_PAYLOAD_BYTES])
|
||||
{
|
||||
|
@ -149,44 +148,36 @@ static int api_list_write(struct mg_connection *conn,
|
|||
// Set argument
|
||||
row.argument = argument;
|
||||
|
||||
// Extract payload
|
||||
cJSON *obj = cJSON_Parse(payload);
|
||||
if (obj == NULL) {
|
||||
return send_json_error(conn, 400,
|
||||
// Check if valid JSON payload is available
|
||||
if (api->payload.json == NULL) {
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"Invalid request body data",
|
||||
NULL);
|
||||
}
|
||||
|
||||
cJSON *json_enabled = cJSON_GetObjectItemCaseSensitive(obj, "enabled");
|
||||
cJSON *json_enabled = cJSON_GetObjectItemCaseSensitive(api->payload.json, "enabled");
|
||||
if (!cJSON_IsBool(json_enabled)) {
|
||||
cJSON_Delete(obj);
|
||||
return send_json_error(conn, 400,
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"No \"enabled\" boolean in body data",
|
||||
NULL);
|
||||
}
|
||||
row.enabled = cJSON_IsTrue(json_enabled);
|
||||
|
||||
cJSON *json_comment = cJSON_GetObjectItemCaseSensitive(obj, "comment");
|
||||
cJSON *json_comment = cJSON_GetObjectItemCaseSensitive(api->payload.json, "comment");
|
||||
if(cJSON_IsString(json_comment) && strlen(json_comment->valuestring) > 0)
|
||||
row.comment = json_comment->valuestring;
|
||||
else
|
||||
row.comment = NULL;
|
||||
|
||||
cJSON *json_description = cJSON_GetObjectItemCaseSensitive(obj, "description");
|
||||
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;
|
||||
|
||||
cJSON *json_name = cJSON_GetObjectItemCaseSensitive(obj, "name");
|
||||
if(cJSON_IsString(json_name) && strlen(json_name->valuestring) > 0)
|
||||
row.name = json_name->valuestring;
|
||||
else
|
||||
row.name = NULL;
|
||||
|
||||
cJSON *json_oldtype = cJSON_GetObjectItemCaseSensitive(obj, "oldtype");
|
||||
cJSON *json_oldtype = cJSON_GetObjectItemCaseSensitive(api->payload.json, "oldtype");
|
||||
if(cJSON_IsString(json_oldtype) && strlen(json_oldtype->valuestring) > 0)
|
||||
row.oldtype = json_oldtype->valuestring;
|
||||
else
|
||||
|
@ -195,9 +186,9 @@ static int api_list_write(struct mg_connection *conn,
|
|||
// Try to add domain to table
|
||||
const char *sql_msg = NULL;
|
||||
bool okay = false;
|
||||
if(gravityDB_addToTable(listtype, &row, &sql_msg, method))
|
||||
if(gravityDB_addToTable(listtype, &row, &sql_msg, api->method))
|
||||
{
|
||||
cJSON *groups = cJSON_GetObjectItemCaseSensitive(obj, "groups");
|
||||
cJSON *groups = cJSON_GetObjectItemCaseSensitive(api->payload.json, "groups");
|
||||
if(groups != NULL)
|
||||
okay = gravityDB_edit_groups(listtype, groups, &row, &sql_msg);
|
||||
else
|
||||
|
@ -227,25 +218,22 @@ static int api_list_write(struct mg_connection *conn,
|
|||
JSON_OBJ_ADD_NULL(json, "sql_msg");
|
||||
}
|
||||
|
||||
// Free memory not needed any longer
|
||||
cJSON_Delete(obj);
|
||||
|
||||
// Send error reply
|
||||
return send_json_error(conn, 400, // 400 Bad Request
|
||||
return send_json_error(api, 400, // 400 Bad Request
|
||||
"database_error",
|
||||
"Could not add to gravity database",
|
||||
json);
|
||||
}
|
||||
// else: everything is okay
|
||||
|
||||
// Free memory not needed any longer
|
||||
cJSON_Delete(obj);
|
||||
|
||||
// Send GET style reply with code 201 Created
|
||||
return api_list_read(conn, 201, listtype, argument);
|
||||
int response_code = 201; // 201 - Created
|
||||
if(api->method == HTTP_PUT)
|
||||
response_code = 200; // 200 - OK
|
||||
// Send GET style reply
|
||||
return api_list_read(api, response_code, listtype, argument);
|
||||
}
|
||||
|
||||
static int api_list_remove(struct mg_connection *conn,
|
||||
static int api_list_remove(struct ftl_conn *api,
|
||||
const enum gravity_list_type listtype,
|
||||
const char *argument)
|
||||
{
|
||||
|
@ -269,49 +257,48 @@ static int api_list_remove(struct mg_connection *conn,
|
|||
}
|
||||
|
||||
// Send error reply
|
||||
return send_json_error(conn, 400,
|
||||
return send_json_error(api, 400,
|
||||
"database_error",
|
||||
"Could not remove domain from database table",
|
||||
json);
|
||||
}
|
||||
}
|
||||
|
||||
int api_list(struct mg_connection *conn)
|
||||
int api_list(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
char payload[MAX_PAYLOAD_BYTES] = { 0 };
|
||||
if(check_client_auth(conn, payload) == API_AUTH_UNAUTHORIZED)
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(conn);
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
enum gravity_list_type listtype;
|
||||
bool can_modify = false;
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
const char *argument = NULL;
|
||||
if((argument = startsWith("/api/groups", request->local_uri)) != NULL)
|
||||
if((argument = startsWith("/api/groups", api)) != NULL)
|
||||
{
|
||||
listtype = GRAVITY_GROUPS;
|
||||
can_modify = true;
|
||||
}
|
||||
else if((argument = startsWith("/api/adlists", request->local_uri)) != NULL)
|
||||
else if((argument = startsWith("/api/adlists", api)) != NULL)
|
||||
{
|
||||
listtype = GRAVITY_ADLISTS;
|
||||
can_modify = true;
|
||||
}
|
||||
else if((argument = startsWith("/api/clients", request->local_uri)) != NULL)
|
||||
else if((argument = startsWith("/api/clients", api)) != NULL)
|
||||
{
|
||||
listtype = GRAVITY_CLIENTS;
|
||||
can_modify = true;
|
||||
}
|
||||
else if((argument = startsWith("/api/domains/allow", request->local_uri)) != NULL)
|
||||
else if((argument = startsWith("/api/domains/allow", api)) != NULL)
|
||||
{
|
||||
if((argument = startsWith("/api/domains/allow/exact", request->local_uri)) != NULL)
|
||||
if((argument = startsWith("/api/domains/allow/exact", api)) != NULL)
|
||||
{
|
||||
listtype = GRAVITY_DOMAINLIST_ALLOW_EXACT;
|
||||
can_modify = true;
|
||||
}
|
||||
else if((argument = startsWith("/api/domains/allow/regex", request->local_uri)) != NULL)
|
||||
else if((argument = startsWith("/api/domains/allow/regex", api)) != NULL)
|
||||
{
|
||||
listtype = GRAVITY_DOMAINLIST_ALLOW_REGEX;
|
||||
can_modify = true;
|
||||
|
@ -319,14 +306,14 @@ int api_list(struct mg_connection *conn)
|
|||
else
|
||||
listtype = GRAVITY_DOMAINLIST_ALLOW_ALL;
|
||||
}
|
||||
else if((argument = startsWith("/api/domains/deny", request->local_uri)) != NULL)
|
||||
else if((argument = startsWith("/api/domains/deny", api)) != NULL)
|
||||
{
|
||||
if((argument = startsWith("/api/domains/deny/exact", request->local_uri)) != NULL)
|
||||
if((argument = startsWith("/api/domains/deny/exact", api)) != NULL)
|
||||
{
|
||||
listtype = GRAVITY_DOMAINLIST_DENY_EXACT;
|
||||
can_modify = true;
|
||||
}
|
||||
else if((argument = startsWith("/api/domains/deny/regex", request->local_uri)) != NULL)
|
||||
else if((argument = startsWith("/api/domains/deny/regex", api)) != NULL)
|
||||
{
|
||||
listtype = GRAVITY_DOMAINLIST_DENY_REGEX;
|
||||
can_modify = true;
|
||||
|
@ -336,36 +323,35 @@ int api_list(struct mg_connection *conn)
|
|||
}
|
||||
else
|
||||
{
|
||||
if((argument = startsWith("/api/domains/exact", request->local_uri)) != NULL)
|
||||
if((argument = startsWith("/api/domains/exact", api)) != NULL)
|
||||
listtype = GRAVITY_DOMAINLIST_ALL_EXACT;
|
||||
else if((argument = startsWith("/api/domains/regex", request->local_uri)) != NULL)
|
||||
else if((argument = startsWith("/api/domains/regex", api)) != NULL)
|
||||
listtype = GRAVITY_DOMAINLIST_ALL_REGEX;
|
||||
else
|
||||
{
|
||||
argument = startsWith("/api/domains", request->local_uri);
|
||||
argument = startsWith("/api/domains", api);
|
||||
listtype = GRAVITY_DOMAINLIST_ALL_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
const enum http_method method = http_method(conn);
|
||||
if(method == HTTP_GET)
|
||||
if(api->method == HTTP_GET)
|
||||
{
|
||||
return api_list_read(conn, 200, listtype, argument);
|
||||
return api_list_read(api, 200, listtype, argument);
|
||||
}
|
||||
else if(can_modify && (method == HTTP_POST || method == HTTP_PUT))
|
||||
else if(can_modify && (api->method == HTTP_POST || api->method == HTTP_PUT))
|
||||
{
|
||||
// Add item from list
|
||||
return api_list_write(conn, listtype, method, argument, payload);
|
||||
return api_list_write(api, listtype, argument, payload);
|
||||
}
|
||||
else if(can_modify && method == HTTP_DELETE)
|
||||
else if(can_modify && api->method == HTTP_DELETE)
|
||||
{
|
||||
// Delete item from list
|
||||
return api_list_remove(conn, listtype, argument);
|
||||
return api_list_remove(api, listtype, argument);
|
||||
}
|
||||
else if(!can_modify)
|
||||
{
|
||||
// This list type cannot be modified (e.g., ALL_ALL)
|
||||
return send_json_error(conn, 400,
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"Invalid request: Specify list to modify",
|
||||
NULL);
|
||||
|
|
|
@ -15,15 +15,15 @@
|
|||
// networkrecord
|
||||
#include "../database/network-table.h"
|
||||
|
||||
int api_network(struct mg_connection *conn)
|
||||
int api_network(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(conn, NULL) == API_AUTH_UNAUTHORIZED)
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(conn);
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
// Connect to database
|
||||
// apiect to database
|
||||
const char *sql_msg = NULL;
|
||||
if(!networkTable_readDevices(&sql_msg))
|
||||
{
|
||||
|
@ -34,7 +34,7 @@ int api_network(struct mg_connection *conn)
|
|||
} else {
|
||||
JSON_OBJ_ADD_NULL(json, "sql_msg");
|
||||
}
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"database_error",
|
||||
"Could not read network details from database table",
|
||||
json);
|
||||
|
@ -73,7 +73,7 @@ int api_network(struct mg_connection *conn)
|
|||
JSON_OBJ_ADD_ITEM(json, "last_item", item);
|
||||
// Add SQL message
|
||||
JSON_OBJ_REF_STR(json, "sql_msg", sql_msg);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"database_error",
|
||||
"Could not read network details from database table (getting IP records)",
|
||||
json);
|
||||
|
@ -96,7 +96,7 @@ int api_network(struct mg_connection *conn)
|
|||
json = JSON_NEW_OBJ();
|
||||
// Add SQL message
|
||||
JSON_OBJ_REF_STR(json, "sql_msg", sql_msg);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"database_error",
|
||||
"Could not read network details from database table (step)",
|
||||
json);
|
||||
|
|
156
src/api/routes.c
156
src/api/routes.c
|
@ -24,161 +24,177 @@ int api_handler(struct mg_connection *conn, void *ignored)
|
|||
|
||||
int ret = 0;
|
||||
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
// Prepare API info struct
|
||||
struct ftl_conn api = {
|
||||
conn,
|
||||
mg_get_request_info(conn),
|
||||
http_method(conn),
|
||||
{ 0 }
|
||||
};
|
||||
read_and_parse_payload(&api);
|
||||
|
||||
if(config.debug & DEBUG_API)
|
||||
logg("Requested API URI: %s %s", request->request_method, request->local_uri);
|
||||
logg("Requested API URI: %s %s", api.request->request_method, api.request->local_uri);
|
||||
|
||||
/******************************** /api/dns ********************************/
|
||||
if(startsWith("/api/dns/blocking", request->local_uri))
|
||||
if(startsWith("/api/dns/blocking", &api))
|
||||
{
|
||||
ret = api_dns_blockingstatus(conn);
|
||||
ret = api_dns_blockingstatus(&api);
|
||||
}
|
||||
else if(startsWith("/api/dns/cacheinfo", request->local_uri))
|
||||
else if(startsWith("/api/dns/cacheinfo", &api))
|
||||
{
|
||||
ret = api_dns_cacheinfo(conn);
|
||||
ret = api_dns_cacheinfo(&api);
|
||||
}
|
||||
/*********** /api/domains, /api/groups, /api/adlists, /api/clients *******/
|
||||
else if(startsWith("/api/domains", request->local_uri))
|
||||
else if(startsWith("/api/domains", &api))
|
||||
{
|
||||
ret = api_list(conn);
|
||||
ret = api_list(&api);
|
||||
}
|
||||
else if(startsWith("/api/groups", request->local_uri))
|
||||
else if(startsWith("/api/groups", &api))
|
||||
{
|
||||
ret = api_list(conn);
|
||||
ret = api_list(&api);
|
||||
}
|
||||
else if(startsWith("/api/adlists", request->local_uri))
|
||||
else if(startsWith("/api/adlists", &api))
|
||||
{
|
||||
ret = api_list(conn);
|
||||
ret = api_list(&api);
|
||||
}
|
||||
else if(startsWith("/api/clients", request->local_uri))
|
||||
else if(startsWith("/api/clients", &api))
|
||||
{
|
||||
ret = api_list(conn);
|
||||
ret = api_list(&api);
|
||||
}
|
||||
/******************************** /api/ftl ****************************/
|
||||
else if(startsWith("/api/ftl/client", request->local_uri))
|
||||
else if(startsWith("/api/ftl/client", &api))
|
||||
{
|
||||
ret = api_ftl_client(conn);
|
||||
ret = api_ftl_client(&api);
|
||||
}
|
||||
else if(startsWith("/api/ftl/dnsmasq_log", request->local_uri))
|
||||
else if(startsWith("/api/ftl/dnsmasq_log", &api))
|
||||
{
|
||||
ret = api_ftl_dnsmasq_log(conn);
|
||||
ret = api_ftl_dnsmasq_log(&api);
|
||||
}
|
||||
else if(startsWith("/api/ftl/database", request->local_uri))
|
||||
else if(startsWith("/api/ftl/database", &api))
|
||||
{
|
||||
ret = api_ftl_database(conn);
|
||||
ret = api_ftl_database(&api);
|
||||
}
|
||||
else if(startsWith("/api/ftl/system", request->local_uri))
|
||||
else if(startsWith("/api/ftl/system", &api))
|
||||
{
|
||||
ret = api_ftl_system(conn);
|
||||
ret = api_ftl_system(&api);
|
||||
}
|
||||
/******************************** /api/network ****************************/
|
||||
else if(startsWith("/api/network", request->local_uri))
|
||||
else if(startsWith("/api/network", &api))
|
||||
{
|
||||
ret = api_network(conn);
|
||||
ret = api_network(&api);
|
||||
}
|
||||
/******************************** /api/stats **************************/
|
||||
else if(startsWith("/api/stats/summary", request->local_uri))
|
||||
else if(startsWith("/api/stats/summary", &api))
|
||||
{
|
||||
ret = api_stats_summary(conn);
|
||||
ret = api_stats_summary(&api);
|
||||
}
|
||||
else if(startsWith("/api/stats/overTime/history", request->local_uri))
|
||||
else if(startsWith("/api/stats/overTime/history", &api))
|
||||
{
|
||||
ret = api_stats_overTime_history(conn);
|
||||
ret = api_stats_overTime_history(&api);
|
||||
}
|
||||
else if(startsWith("/api/stats/overTime/clients", request->local_uri))
|
||||
else if(startsWith("/api/stats/overTime/clients", &api))
|
||||
{
|
||||
ret = api_stats_overTime_clients(conn);
|
||||
ret = api_stats_overTime_clients(&api);
|
||||
}
|
||||
else if(startsWith("/api/stats/query_types", request->local_uri))
|
||||
else if(startsWith("/api/stats/query_types", &api))
|
||||
{
|
||||
ret = api_stats_query_types(conn);
|
||||
ret = api_stats_query_types(&api);
|
||||
}
|
||||
else if(startsWith("/api/stats/upstreams", request->local_uri))
|
||||
else if(startsWith("/api/stats/upstreams", &api))
|
||||
{
|
||||
ret = api_stats_upstreams(conn);
|
||||
ret = api_stats_upstreams(&api);
|
||||
}
|
||||
else if(startsWith("/api/stats/top_domains", request->local_uri))
|
||||
else if(startsWith("/api/stats/top_domains", &api))
|
||||
{
|
||||
ret = api_stats_top_domains(false, conn);
|
||||
ret = api_stats_top_domains(false, &api);
|
||||
}
|
||||
else if(startsWith("/api/stats/top_blocked", request->local_uri))
|
||||
else if(startsWith("/api/stats/top_blocked", &api))
|
||||
{
|
||||
ret = api_stats_top_domains(true, conn);
|
||||
ret = api_stats_top_domains(true, &api);
|
||||
}
|
||||
else if(startsWith("/api/stats/top_clients", request->local_uri))
|
||||
else if(startsWith("/api/stats/top_clients", &api))
|
||||
{
|
||||
ret = api_stats_top_clients(false, conn);
|
||||
ret = api_stats_top_clients(false, &api);
|
||||
}
|
||||
else if(startsWith("/api/stats/top_blocked_clients", request->local_uri))
|
||||
else if(startsWith("/api/stats/top_blocked_clients", &api))
|
||||
{
|
||||
ret = api_stats_top_clients(true, conn);
|
||||
ret = api_stats_top_clients(true, &api);
|
||||
}
|
||||
else if(startsWith("/api/stats/history", request->local_uri))
|
||||
else if(startsWith("/api/stats/history", &api))
|
||||
{
|
||||
ret = api_stats_history(conn);
|
||||
ret = api_stats_history(&api);
|
||||
}
|
||||
else if(startsWith("/api/stats/recent_blocked", request->local_uri))
|
||||
else if(startsWith("/api/stats/recent_blocked", &api))
|
||||
{
|
||||
ret = api_stats_recentblocked(conn);
|
||||
ret = api_stats_recentblocked(&api);
|
||||
}
|
||||
else if(startsWith("/api/stats/database/overTime/history", request->local_uri))
|
||||
else if(startsWith("/api/stats/database/overTime/history", &api))
|
||||
{
|
||||
ret = api_stats_database_overTime_history(conn);
|
||||
ret = api_stats_database_overTime_history(&api);
|
||||
}
|
||||
else if(startsWith("/api/stats/database/top_domains", request->local_uri))
|
||||
else if(startsWith("/api/stats/database/top_domains", &api))
|
||||
{
|
||||
ret = api_stats_database_top_items(false, true, conn);
|
||||
ret = api_stats_database_top_items(false, true, &api);
|
||||
}
|
||||
else if(startsWith("/api/stats/database/top_blocked", request->local_uri))
|
||||
else if(startsWith("/api/stats/database/top_blocked", &api))
|
||||
{
|
||||
ret = api_stats_database_top_items(true, true, conn);
|
||||
ret = api_stats_database_top_items(true, true, &api);
|
||||
}
|
||||
else if(startsWith("/api/stats/database/top_clients", request->local_uri))
|
||||
else if(startsWith("/api/stats/database/top_clients", &api))
|
||||
{
|
||||
ret = api_stats_database_top_items(false, false, conn);
|
||||
ret = api_stats_database_top_items(false, false, &api);
|
||||
}
|
||||
else if(startsWith("/api/stats/database/summary", request->local_uri))
|
||||
else if(startsWith("/api/stats/database/summary", &api))
|
||||
{
|
||||
ret = api_stats_database_summary(conn);
|
||||
ret = api_stats_database_summary(&api);
|
||||
}
|
||||
else if(startsWith("/api/stats/database/overTime/clients", request->local_uri))
|
||||
else if(startsWith("/api/stats/database/overTime/clients", &api))
|
||||
{
|
||||
ret = api_stats_database_overTime_clients(conn);
|
||||
ret = api_stats_database_overTime_clients(&api);
|
||||
}
|
||||
else if(startsWith("/api/stats/database/query_types", request->local_uri))
|
||||
else if(startsWith("/api/stats/database/query_types", &api))
|
||||
{
|
||||
ret = api_stats_database_query_types(conn);
|
||||
ret = api_stats_database_query_types(&api);
|
||||
}
|
||||
else if(startsWith("/api/stats/database/upstreams", request->local_uri))
|
||||
else if(startsWith("/api/stats/database/upstreams", &api))
|
||||
{
|
||||
ret = api_stats_database_upstreams(conn);
|
||||
ret = api_stats_database_upstreams(&api);
|
||||
}
|
||||
/******************************** /api/version ****************************/
|
||||
else if(startsWith("/api/version", request->local_uri))
|
||||
else if(startsWith("/api/version", &api))
|
||||
{
|
||||
ret = api_version(conn);
|
||||
ret = api_version(&api);
|
||||
}
|
||||
/******************************** /api/auth ****************************/
|
||||
else if(startsWith("/api/auth", request->local_uri))
|
||||
else if(startsWith("/api/auth", &api))
|
||||
{
|
||||
ret = api_auth(conn);
|
||||
ret = api_auth(&api);
|
||||
}
|
||||
/******************************** /api/settings ****************************/
|
||||
else if(startsWith("/api/settings/web", request->local_uri))
|
||||
else if(startsWith("/api/settings/web", &api))
|
||||
{
|
||||
ret = api_settings_web(conn);
|
||||
ret = api_settings_web(&api);
|
||||
}
|
||||
/******************************** not found or invalid request**************/
|
||||
if(ret == 0)
|
||||
{
|
||||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_REF_STR(json, "path", request->local_uri);
|
||||
ret = send_json_error(conn, 404,
|
||||
cJSON *string_item = cJSON_CreateStringReference((const char*)api.request->local_uri);
|
||||
cJSON_AddItemToObject(json, "path", string_item);
|
||||
ret = send_json_error(&api, 404,
|
||||
"not_found",
|
||||
"Not found",
|
||||
json);
|
||||
}
|
||||
|
||||
// Free JSON-parsed payload memory (if allocated)
|
||||
if(api.payload.json != NULL)
|
||||
{
|
||||
cJSON_Delete(api.payload.json);
|
||||
api.payload.json = NULL;
|
||||
}
|
||||
|
||||
// Unlock after API access
|
||||
unlock_shm();
|
||||
|
||||
|
|
|
@ -19,51 +19,52 @@
|
|||
// API router
|
||||
int api_handler(struct mg_connection *conn, void *ignored);
|
||||
|
||||
|
||||
// Statistic methods
|
||||
int api_stats_summary(struct mg_connection *conn);
|
||||
int api_stats_overTime_history(struct mg_connection *conn);
|
||||
int api_stats_overTime_clients(struct mg_connection *conn);
|
||||
int api_stats_query_types(struct mg_connection *conn);
|
||||
int api_stats_upstreams(struct mg_connection *conn);
|
||||
int api_stats_top_domains(bool blocked, struct mg_connection *conn);
|
||||
int api_stats_top_clients(bool blocked, struct mg_connection *conn);
|
||||
int api_stats_history(struct mg_connection *conn);
|
||||
int api_stats_recentblocked(struct mg_connection *conn);
|
||||
int api_stats_summary(struct ftl_conn *api);
|
||||
int api_stats_overTime_history(struct ftl_conn *api);
|
||||
int api_stats_overTime_clients(struct ftl_conn *api);
|
||||
int api_stats_query_types(struct ftl_conn *api);
|
||||
int api_stats_upstreams(struct ftl_conn *api);
|
||||
int api_stats_top_domains(bool blocked, struct ftl_conn *api);
|
||||
int api_stats_top_clients(bool blocked, struct ftl_conn *api);
|
||||
int api_stats_history(struct ftl_conn *api);
|
||||
int api_stats_recentblocked(struct ftl_conn *api);
|
||||
|
||||
// Statistics methods (database)
|
||||
int api_stats_database_overTime_history(struct mg_connection *conn);
|
||||
int api_stats_database_top_items(bool blocked, bool domains, struct mg_connection *conn);
|
||||
int api_stats_database_summary(struct mg_connection *conn);
|
||||
int api_stats_database_overTime_clients(struct mg_connection *conn);
|
||||
int api_stats_database_query_types(struct mg_connection *conn);
|
||||
int api_stats_database_upstreams(struct mg_connection *conn);
|
||||
int api_stats_database_overTime_history(struct ftl_conn *api);
|
||||
int api_stats_database_top_items(bool blocked, bool domains, struct ftl_conn *api);
|
||||
int api_stats_database_summary(struct ftl_conn *api);
|
||||
int api_stats_database_overTime_clients(struct ftl_conn *api);
|
||||
int api_stats_database_query_types(struct ftl_conn *api);
|
||||
int api_stats_database_upstreams(struct ftl_conn *api);
|
||||
|
||||
// FTL methods
|
||||
int api_ftl_client(struct mg_connection *conn);
|
||||
int api_ftl_dnsmasq_log(struct mg_connection *conn);
|
||||
int api_ftl_database(struct mg_connection *conn);
|
||||
int api_ftl_system(struct mg_connection *conn);
|
||||
int get_system_obj(struct mg_connection *conn, cJSON *system);
|
||||
int api_ftl_client(struct ftl_conn *api);
|
||||
int api_ftl_dnsmasq_log(struct ftl_conn *api);
|
||||
int api_ftl_database(struct ftl_conn *api);
|
||||
int api_ftl_system(struct ftl_conn *api);
|
||||
int get_system_obj(struct ftl_conn *api, cJSON *system);
|
||||
|
||||
// Network methods
|
||||
int api_network(struct mg_connection *conn);
|
||||
int api_network(struct ftl_conn *api);
|
||||
|
||||
// DNS methods
|
||||
int api_dns_blockingstatus(struct mg_connection *conn);
|
||||
int api_dns_cacheinfo(struct mg_connection *conn);
|
||||
int api_dns_blockingstatus(struct ftl_conn *api);
|
||||
int api_dns_cacheinfo(struct ftl_conn *api);
|
||||
|
||||
// List methods
|
||||
int api_list(struct mg_connection *conn);
|
||||
int api_group(struct mg_connection *conn);
|
||||
int api_list(struct ftl_conn *api);
|
||||
int api_group(struct ftl_conn *api);
|
||||
|
||||
// Version method
|
||||
int api_version(struct mg_connection *conn);
|
||||
int api_version(struct ftl_conn *api);
|
||||
|
||||
// Auth method
|
||||
int check_client_auth(struct mg_connection *conn, char payload[MAX_PAYLOAD_BYTES]);
|
||||
int api_auth(struct mg_connection *conn);
|
||||
int check_client_auth(struct ftl_conn *api);
|
||||
int api_auth(struct ftl_conn *api);
|
||||
|
||||
// Settings methods
|
||||
int api_settings_web(struct mg_connection *conn);
|
||||
int api_settings_web(struct ftl_conn *api);
|
||||
|
||||
#endif // ROUTES_H
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "../webserver/json_macros.h"
|
||||
#include "routes.h"
|
||||
|
||||
int api_settings_web(struct mg_connection *conn)
|
||||
int api_settings_web(struct ftl_conn *api)
|
||||
{
|
||||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_REF_STR(json, "layout", "boxed");
|
||||
|
|
|
@ -59,7 +59,7 @@ static int __attribute__((pure)) cmpdesc(const void *a, const void *b)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int api_stats_summary(struct mg_connection *conn)
|
||||
int api_stats_summary(struct ftl_conn *api)
|
||||
{
|
||||
const int blocked = counters->blocked;
|
||||
const int total = counters->queries;
|
||||
|
@ -118,14 +118,14 @@ int api_stats_summary(struct mg_connection *conn)
|
|||
JSON_OBJ_ADD_ITEM(json, "reply_types", reply_types);
|
||||
|
||||
cJSON *system = JSON_NEW_OBJ();
|
||||
const int ret = get_system_obj(conn, system);
|
||||
const int ret = get_system_obj(api, system);
|
||||
if(ret != 0) return ret;
|
||||
JSON_OBJ_ADD_ITEM(json, "system", system);
|
||||
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_stats_overTime_history(struct mg_connection *conn)
|
||||
int api_stats_overTime_history(struct ftl_conn *api)
|
||||
{
|
||||
int from = 0, until = OVERTIME_SLOTS;
|
||||
bool found = false;
|
||||
|
@ -179,15 +179,15 @@ int api_stats_overTime_history(struct mg_connection *conn)
|
|||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_stats_top_domains(bool blocked, struct mg_connection *conn)
|
||||
int api_stats_top_domains(bool blocked, struct ftl_conn *api)
|
||||
{
|
||||
int temparray[counters->domains][2], show = 10;
|
||||
bool audit = false;
|
||||
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(conn, NULL) == API_AUTH_UNAUTHORIZED)
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(conn);
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
// Exit before processing any data if requested via config setting
|
||||
|
@ -207,18 +207,17 @@ int api_stats_top_domains(bool blocked, struct mg_connection *conn)
|
|||
}
|
||||
|
||||
// /api/stats/top_domains?blocked=true is allowed as well
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
if(request->query_string != NULL)
|
||||
if(api->request->query_string != NULL)
|
||||
{
|
||||
// Should blocked clients be shown?
|
||||
get_bool_var(request->query_string, "blocked", &blocked);
|
||||
get_bool_var(api->request->query_string, "blocked", &blocked);
|
||||
|
||||
// Does the user request a non-default number of replies?
|
||||
// Note: We do not accept zero query requests here
|
||||
get_int_var(request->query_string, "show", &show);
|
||||
get_int_var(api->request->query_string, "show", &show);
|
||||
|
||||
// Apply Audit Log filtering?
|
||||
get_bool_var(request->query_string, "audit", &audit);
|
||||
get_bool_var(api->request->query_string, "audit", &audit);
|
||||
}
|
||||
|
||||
for(int domainID=0; domainID < counters->domains; domainID++)
|
||||
|
@ -337,15 +336,15 @@ int api_stats_top_domains(bool blocked, struct mg_connection *conn)
|
|||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_stats_top_clients(bool blocked, struct mg_connection *conn)
|
||||
int api_stats_top_clients(bool blocked, struct ftl_conn *api)
|
||||
{
|
||||
int temparray[counters->clients][2], show = 10;
|
||||
bool includezeroclients = false;
|
||||
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(conn, NULL) == API_AUTH_UNAUTHORIZED)
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(conn);
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
// Exit before processing any data if requested via config setting
|
||||
|
@ -365,18 +364,17 @@ int api_stats_top_clients(bool blocked, struct mg_connection *conn)
|
|||
}
|
||||
|
||||
// /api/stats/top_clients9?blocked=true is allowed as well
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
if(request->query_string != NULL)
|
||||
if(api->request->query_string != NULL)
|
||||
{
|
||||
// Should blocked clients be shown?
|
||||
get_bool_var(request->query_string, "blocked", &blocked);
|
||||
get_bool_var(api->request->query_string, "blocked", &blocked);
|
||||
|
||||
// Does the user request a non-default number of replies?
|
||||
// Note: We do not accept zero query requests here
|
||||
get_int_var(request->query_string, "show", &show);
|
||||
get_int_var(api->request->query_string, "show", &show);
|
||||
|
||||
// Show also clients which have not been active recently?
|
||||
get_bool_var(request->query_string, "withzero", &includezeroclients);
|
||||
get_bool_var(api->request->query_string, "withzero", &includezeroclients);
|
||||
}
|
||||
|
||||
for(int clientID = 0; clientID < counters->clients; clientID++)
|
||||
|
@ -465,14 +463,14 @@ int api_stats_top_clients(bool blocked, struct mg_connection *conn)
|
|||
}
|
||||
|
||||
|
||||
int api_stats_upstreams(struct mg_connection *conn)
|
||||
int api_stats_upstreams(struct ftl_conn *api)
|
||||
{
|
||||
int temparray[counters->forwarded][2];
|
||||
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(conn, NULL) == API_AUTH_UNAUTHORIZED)
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(conn);
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
for(int upstreamID = 0; upstreamID < counters->upstreams; upstreamID++)
|
||||
{
|
||||
|
@ -568,12 +566,12 @@ int api_stats_upstreams(struct mg_connection *conn)
|
|||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_stats_query_types(struct mg_connection *conn)
|
||||
int api_stats_query_types(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(conn, NULL) == API_AUTH_UNAUTHORIZED)
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(conn);
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
// Send response
|
||||
|
@ -588,7 +586,7 @@ int api_stats_query_types(struct mg_connection *conn)
|
|||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_stats_history(struct mg_connection *conn)
|
||||
int api_stats_history(struct ftl_conn *api)
|
||||
{
|
||||
// Exit before processing any data if requested via config setting
|
||||
get_privacy_level(NULL);
|
||||
|
@ -607,9 +605,9 @@ int api_stats_history(struct mg_connection *conn)
|
|||
}
|
||||
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(conn, NULL) == API_AUTH_UNAUTHORIZED)
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(conn);
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
// Do we want a more specific version of this command (domain/client/time interval filtered)?
|
||||
|
@ -635,25 +633,24 @@ int api_stats_history(struct mg_connection *conn)
|
|||
// We send 200 queries (until the API is asked for a different limit)
|
||||
unsigned int show = 200u;
|
||||
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
if(request->query_string != NULL)
|
||||
if(api->request->query_string != NULL)
|
||||
{
|
||||
// Time filtering?
|
||||
get_uint_var(request->query_string, "from", &from);
|
||||
get_uint_var(request->query_string, "until", &until);
|
||||
get_uint_var(api->request->query_string, "from", &from);
|
||||
get_uint_var(api->request->query_string, "until", &until);
|
||||
|
||||
// Query type filtering?
|
||||
int num;
|
||||
if(get_int_var(request->query_string, "querytype", &num) && num < TYPE_MAX)
|
||||
if(get_int_var(api->request->query_string, "querytype", &num) && num < TYPE_MAX)
|
||||
querytype = num;
|
||||
|
||||
// Does the user request a non-default number of replies?
|
||||
// Note: We do not accept zero query requests here
|
||||
get_uint_var(request->query_string, "show", &show);
|
||||
get_uint_var(api->request->query_string, "show", &show);
|
||||
|
||||
// Forward destination filtering?
|
||||
char buffer[256] = { 0 };
|
||||
if(GET_VAR("forward", buffer, request->query_string) > 0)
|
||||
if(GET_VAR("forward", buffer, api->request->query_string) > 0)
|
||||
{
|
||||
forwarddest = calloc(256, sizeof(char));
|
||||
if(forwarddest == NULL)
|
||||
|
@ -712,7 +709,7 @@ int api_stats_history(struct mg_connection *conn)
|
|||
JSON_OBJ_COPY_STR(json, "upstream", forwarddest);
|
||||
free(forwarddest);
|
||||
|
||||
return send_json_error(conn, 400,
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"Requested upstream not found",
|
||||
json);
|
||||
|
@ -721,7 +718,7 @@ int api_stats_history(struct mg_connection *conn)
|
|||
}
|
||||
|
||||
// Domain filtering?
|
||||
if(GET_VAR("domain", buffer, request->query_string) > 0)
|
||||
if(GET_VAR("domain", buffer, api->request->query_string) > 0)
|
||||
{
|
||||
domainname = calloc(512, sizeof(char));
|
||||
if(domainname == NULL)
|
||||
|
@ -755,7 +752,7 @@ int api_stats_history(struct mg_connection *conn)
|
|||
JSON_OBJ_COPY_STR(json, "domain", domainname);
|
||||
free(domainname);
|
||||
|
||||
return send_json_error(conn, 400,
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"Requested domain not found",
|
||||
json);
|
||||
|
@ -763,7 +760,7 @@ int api_stats_history(struct mg_connection *conn)
|
|||
}
|
||||
|
||||
// Client filtering?
|
||||
if(GET_VAR("client", buffer, request->query_string) > 0)
|
||||
if(GET_VAR("client", buffer, api->request->query_string) > 0)
|
||||
{
|
||||
clientname = calloc(512, sizeof(char));
|
||||
if(clientname == NULL)
|
||||
|
@ -805,7 +802,7 @@ int api_stats_history(struct mg_connection *conn)
|
|||
JSON_OBJ_COPY_STR(json, "client", clientname);
|
||||
free(clientname);
|
||||
|
||||
return send_json_error(conn, 400,
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"Requested client not found",
|
||||
json);
|
||||
|
@ -813,7 +810,7 @@ int api_stats_history(struct mg_connection *conn)
|
|||
}
|
||||
|
||||
unsigned int unum = 0u;
|
||||
if(GET_VAR("cursor", buffer, request->query_string) > 0 &&
|
||||
if(GET_VAR("cursor", buffer, api->request->query_string) > 0 &&
|
||||
sscanf(buffer, "%u", &unum) > 0)
|
||||
{
|
||||
// Do not start at the most recent, but at an older query
|
||||
|
@ -830,7 +827,7 @@ int api_stats_history(struct mg_connection *conn)
|
|||
JSON_OBJ_ADD_NUMBER(json, "maxval", counters->queries);
|
||||
free(clientname);
|
||||
|
||||
return send_json_error(conn, 400,
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"Requested cursor larger than number of queries",
|
||||
json);
|
||||
|
@ -1060,14 +1057,14 @@ int api_stats_history(struct mg_connection *conn)
|
|||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_stats_recentblocked(struct mg_connection *conn)
|
||||
int api_stats_recentblocked(struct ftl_conn *api)
|
||||
{
|
||||
unsigned int show = 1;
|
||||
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(conn, NULL) == API_AUTH_UNAUTHORIZED)
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(conn);
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
// Exit before processing any data if requested via config setting
|
||||
|
@ -1081,12 +1078,11 @@ int api_stats_recentblocked(struct mg_connection *conn)
|
|||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
if(request->query_string != NULL)
|
||||
if(api->request->query_string != NULL)
|
||||
{
|
||||
// Does the user request a non-default number of replies?
|
||||
// Note: We do not accept zero query requests here
|
||||
get_uint_var(request->query_string, "show", &show);
|
||||
get_uint_var(api->request->query_string, "show", &show);
|
||||
}
|
||||
|
||||
// Find most recently blocked query
|
||||
|
@ -1124,14 +1120,14 @@ int api_stats_recentblocked(struct mg_connection *conn)
|
|||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_stats_overTime_clients(struct mg_connection *conn)
|
||||
int api_stats_overTime_clients(struct ftl_conn *api)
|
||||
{
|
||||
int sendit = -1, until = OVERTIME_SLOTS;
|
||||
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(conn, NULL) == API_AUTH_UNAUTHORIZED)
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(conn);
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
// Find minimum ID to send
|
||||
|
|
|
@ -20,15 +20,14 @@
|
|||
// FTL_db
|
||||
#include "../database/common.h"
|
||||
|
||||
int api_stats_database_overTime_history(struct mg_connection *conn)
|
||||
int api_stats_database_overTime_history(struct ftl_conn *api)
|
||||
{
|
||||
unsigned int from = 0, until = 0;
|
||||
const int interval = 600;
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
if(request->query_string != NULL)
|
||||
if(api->request->query_string != NULL)
|
||||
{
|
||||
get_uint_var(request->query_string, "from", &from);
|
||||
get_uint_var(request->query_string, "until", &until);
|
||||
get_uint_var(api->request->query_string, "from", &from);
|
||||
get_uint_var(api->request->query_string, "until", &until);
|
||||
}
|
||||
|
||||
// Check if we received the required information
|
||||
|
@ -37,7 +36,7 @@ int api_stats_database_overTime_history(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 400,
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"You need to specify \"until\" in the request.",
|
||||
json);
|
||||
|
@ -79,7 +78,7 @@ int api_stats_database_overTime_history(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to bind interval",
|
||||
json);
|
||||
|
@ -100,7 +99,7 @@ int api_stats_database_overTime_history(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to bind from",
|
||||
json);
|
||||
|
@ -121,7 +120,7 @@ int api_stats_database_overTime_history(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to bind until",
|
||||
json);
|
||||
|
@ -182,23 +181,22 @@ int api_stats_database_overTime_history(struct mg_connection *conn)
|
|||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_stats_database_top_items(bool blocked, bool domains, struct mg_connection *conn)
|
||||
int api_stats_database_top_items(bool blocked, bool domains, struct ftl_conn *api)
|
||||
{
|
||||
unsigned int from = 0, until = 0, show = 10;
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
if(request->query_string != NULL)
|
||||
if(api->request->query_string != NULL)
|
||||
{
|
||||
get_uint_var(request->query_string, "from", &from);
|
||||
get_uint_var(request->query_string, "until", &until);
|
||||
get_uint_var(api->request->query_string, "from", &from);
|
||||
get_uint_var(api->request->query_string, "until", &until);
|
||||
|
||||
// Get blocked queries not only for .../top_blocked
|
||||
// but also for .../top_domains?blocked=true
|
||||
// Note: this may overwrite the blocked propery from the URL
|
||||
get_bool_var(request->query_string, "blocked", &blocked);
|
||||
get_bool_var(api->request->query_string, "blocked", &blocked);
|
||||
|
||||
// Does the user request a non-default number of replies?
|
||||
// Note: We do not accept zero query requests here
|
||||
get_uint_var(request->query_string, "show", &show);
|
||||
get_uint_var(api->request->query_string, "show", &show);
|
||||
}
|
||||
|
||||
// Check if we received the required information
|
||||
|
@ -207,7 +205,7 @@ int api_stats_database_top_items(bool blocked, bool domains, struct mg_connectio
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 400,
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"You need to specify both \"from\" and \"until\" in the request.",
|
||||
json);
|
||||
|
@ -277,7 +275,7 @@ int api_stats_database_top_items(bool blocked, bool domains, struct mg_connectio
|
|||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
JSON_OBJ_REF_STR(json, "querystr", querystr);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to prepare query string",
|
||||
json);
|
||||
|
@ -298,7 +296,7 @@ int api_stats_database_top_items(bool blocked, bool domains, struct mg_connectio
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to bind from",
|
||||
json);
|
||||
|
@ -319,7 +317,7 @@ int api_stats_database_top_items(bool blocked, bool domains, struct mg_connectio
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to bind until",
|
||||
json);
|
||||
|
@ -340,7 +338,7 @@ int api_stats_database_top_items(bool blocked, bool domains, struct mg_connectio
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to bind show",
|
||||
json);
|
||||
|
@ -378,14 +376,13 @@ int api_stats_database_top_items(bool blocked, bool domains, struct mg_connectio
|
|||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_stats_database_summary(struct mg_connection *conn)
|
||||
int api_stats_database_summary(struct ftl_conn *api)
|
||||
{
|
||||
unsigned int from = 0, until = 0;
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
if(request->query_string != NULL)
|
||||
if(api->request->query_string != NULL)
|
||||
{
|
||||
get_uint_var(request->query_string, "from", &from);
|
||||
get_uint_var(request->query_string, "until", &until);
|
||||
get_uint_var(api->request->query_string, "from", &from);
|
||||
get_uint_var(api->request->query_string, "until", &until);
|
||||
}
|
||||
|
||||
// Check if we received the required information
|
||||
|
@ -394,7 +391,7 @@ int api_stats_database_summary(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 400,
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"You need to specify both \"from\" and \"until\" in the request.",
|
||||
json);
|
||||
|
@ -435,7 +432,7 @@ int api_stats_database_summary(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Internal server error",
|
||||
json);
|
||||
|
@ -459,15 +456,14 @@ int api_stats_database_summary(struct mg_connection *conn)
|
|||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_stats_database_overTime_clients(struct mg_connection *conn)
|
||||
int api_stats_database_overTime_clients(struct ftl_conn *api)
|
||||
{
|
||||
unsigned int from = 0, until = 0;
|
||||
const int interval = 600;
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
if(request->query_string != NULL)
|
||||
if(api->request->query_string != NULL)
|
||||
{
|
||||
get_uint_var(request->query_string, "from", &from);
|
||||
get_uint_var(request->query_string, "until", &until);
|
||||
get_uint_var(api->request->query_string, "from", &from);
|
||||
get_uint_var(api->request->query_string, "until", &until);
|
||||
}
|
||||
|
||||
// Check if we received the required information
|
||||
|
@ -476,7 +472,7 @@ int api_stats_database_overTime_clients(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 400,
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"You need to specify both \"from\" and \"until\" in the request.",
|
||||
json);
|
||||
|
@ -505,7 +501,7 @@ int api_stats_database_overTime_clients(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to prepare outer statement",
|
||||
json);
|
||||
|
@ -526,7 +522,7 @@ int api_stats_database_overTime_clients(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to bind from",
|
||||
json);
|
||||
|
@ -547,7 +543,7 @@ int api_stats_database_overTime_clients(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to bind until",
|
||||
json);
|
||||
|
@ -584,7 +580,7 @@ int api_stats_database_overTime_clients(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to prepare inner statement",
|
||||
json);
|
||||
|
@ -605,7 +601,7 @@ int api_stats_database_overTime_clients(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to bind interval",
|
||||
json);
|
||||
|
@ -626,7 +622,7 @@ int api_stats_database_overTime_clients(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to bind from",
|
||||
json);
|
||||
|
@ -647,7 +643,7 @@ int api_stats_database_overTime_clients(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to bind until",
|
||||
json);
|
||||
|
@ -722,14 +718,13 @@ int api_stats_database_overTime_clients(struct mg_connection *conn)
|
|||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_stats_database_query_types(struct mg_connection *conn)
|
||||
int api_stats_database_query_types(struct ftl_conn *api)
|
||||
{
|
||||
unsigned int from = 0, until = 0;
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
if(request->query_string != NULL)
|
||||
if(api->request->query_string != NULL)
|
||||
{
|
||||
get_uint_var(request->query_string, "from", &from);
|
||||
get_uint_var(request->query_string, "until", &until);
|
||||
get_uint_var(api->request->query_string, "from", &from);
|
||||
get_uint_var(api->request->query_string, "until", &until);
|
||||
}
|
||||
|
||||
// Check if we received the required information
|
||||
|
@ -738,7 +733,7 @@ int api_stats_database_query_types(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 400,
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"You need to specify both \"from\" and \"until\" in the request.",
|
||||
json);
|
||||
|
@ -777,14 +772,13 @@ int api_stats_database_query_types(struct mg_connection *conn)
|
|||
}
|
||||
|
||||
|
||||
int api_stats_database_upstreams(struct mg_connection *conn)
|
||||
int api_stats_database_upstreams(struct ftl_conn *api)
|
||||
{
|
||||
unsigned int from = 0, until = 0;
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
if(request->query_string != NULL)
|
||||
if(api->request->query_string != NULL)
|
||||
{
|
||||
get_uint_var(request->query_string, "from", &from);
|
||||
get_uint_var(request->query_string, "until", &until);
|
||||
get_uint_var(api->request->query_string, "from", &from);
|
||||
get_uint_var(api->request->query_string, "until", &until);
|
||||
}
|
||||
|
||||
// Check if we received the required information
|
||||
|
@ -793,7 +787,7 @@ int api_stats_database_upstreams(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 400,
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"You need to specify both \"from\" and \"until\" in the request.",
|
||||
json);
|
||||
|
@ -838,7 +832,7 @@ int api_stats_database_upstreams(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to prepare statement",
|
||||
json);
|
||||
|
@ -859,7 +853,7 @@ int api_stats_database_upstreams(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to bind from",
|
||||
json);
|
||||
|
@ -880,7 +874,7 @@ int api_stats_database_upstreams(struct mg_connection *conn)
|
|||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_ADD_NUMBER(json, "from", from);
|
||||
JSON_OBJ_ADD_NUMBER(json, "until", until);
|
||||
return send_json_error(conn, 500,
|
||||
return send_json_error(api, 500,
|
||||
"internal_error",
|
||||
"Failed to bind until",
|
||||
json);
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "../log.h"
|
||||
#include "../version.h"
|
||||
|
||||
int api_version(struct mg_connection *conn)
|
||||
int api_version(struct ftl_conn *api)
|
||||
{
|
||||
cJSON *json = JSON_NEW_OBJ();
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ typedef struct {
|
|||
const char *description;
|
||||
const char *argument;
|
||||
const char *oldtype;
|
||||
const char *ip;
|
||||
long id;
|
||||
time_t date_added;
|
||||
time_t date_modified;
|
||||
|
|
|
@ -41,35 +41,35 @@ const char* json_formatter(const cJSON *object)
|
|||
}
|
||||
}
|
||||
|
||||
int send_http(struct mg_connection *conn, const char *mime_type,
|
||||
int send_http(struct ftl_conn *api, const char *mime_type,
|
||||
const char *msg)
|
||||
{
|
||||
mg_send_http_ok(conn, mime_type, NULL, strlen(msg));
|
||||
return mg_write(conn, msg, strlen(msg));
|
||||
mg_send_http_ok(api->conn, mime_type, NULL, strlen(msg));
|
||||
return mg_write(api->conn, msg, strlen(msg));
|
||||
}
|
||||
|
||||
int send_http_code(struct mg_connection *conn, const char *mime_type,
|
||||
int send_http_code(struct ftl_conn *api, const char *mime_type,
|
||||
int code, const char *msg)
|
||||
{
|
||||
// Payload will be sent with text/plain encoding due to
|
||||
// the first line being "Error <code>" by definition
|
||||
//return mg_send_http_error(conn, code, "%s", msg);
|
||||
my_send_http_error_headers(conn, code,
|
||||
my_send_http_error_headers(api->conn, code,
|
||||
mime_type,
|
||||
strlen(msg));
|
||||
|
||||
return mg_write(conn, msg, strlen(msg));
|
||||
return mg_write(api->conn, msg, strlen(msg));
|
||||
}
|
||||
|
||||
int send_json_unauthorized(struct mg_connection *conn)
|
||||
int send_json_unauthorized(struct ftl_conn *api)
|
||||
{
|
||||
return send_json_error(conn, 401,
|
||||
return send_json_error(api, 401,
|
||||
"unauthorized",
|
||||
"Unauthorized",
|
||||
NULL);
|
||||
}
|
||||
|
||||
int send_json_error(struct mg_connection *conn, const int code,
|
||||
int send_json_error(struct ftl_conn *api, const int code,
|
||||
const char *key, const char* message,
|
||||
cJSON *data)
|
||||
{
|
||||
|
@ -93,16 +93,16 @@ int send_json_error(struct mg_connection *conn, const int code,
|
|||
JSON_SEND_OBJECT_CODE(json, code);
|
||||
}
|
||||
|
||||
int send_json_success(struct mg_connection *conn)
|
||||
int send_json_success(struct ftl_conn *api)
|
||||
{
|
||||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_REF_STR(json, "status", "success");
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int send_http_internal_error(struct mg_connection *conn)
|
||||
int send_http_internal_error(struct ftl_conn *api)
|
||||
{
|
||||
return mg_send_http_error(conn, 500, "Internal server error");
|
||||
return mg_send_http_error(api->conn, 500, "Internal server error");
|
||||
}
|
||||
|
||||
bool get_bool_var(const char *source, const char *var, bool *boolean)
|
||||
|
@ -140,40 +140,12 @@ bool get_uint_var(const char *source, const char *var, unsigned int *num)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Extract payload either from GET or POST data
|
||||
bool http_get_payload(struct mg_connection *conn, char *payload)
|
||||
const char* __attribute__((pure)) startsWith(const char *path, const struct ftl_conn *api)
|
||||
{
|
||||
// We do not want to extract any payload here
|
||||
if(payload == NULL)
|
||||
return false;
|
||||
|
||||
const enum http_method method = http_method(conn);
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
if(method == HTTP_GET && request->query_string != NULL)
|
||||
{
|
||||
strncpy(payload, request->query_string, MAX_PAYLOAD_BYTES-1);
|
||||
return true;
|
||||
}
|
||||
else // POST, PUT, PATCH
|
||||
{
|
||||
int data_len = mg_read(conn, payload, MAX_PAYLOAD_BYTES - 1);
|
||||
if ((data_len < 1) || (data_len >= MAX_PAYLOAD_BYTES))
|
||||
return false;
|
||||
|
||||
payload[data_len] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
// Everything else
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* __attribute__((pure)) startsWith(const char *path, const char *uri)
|
||||
{
|
||||
if(strncmp(path, uri, strlen(path)) == 0)
|
||||
if(uri[strlen(path)] == '/')
|
||||
if(strncmp(path, api->request->local_uri, strlen(path)) == 0)
|
||||
if(api->request->local_uri[strlen(path)] == '/')
|
||||
// Path match with argument after ".../"
|
||||
return uri + strlen(path) + 1u;
|
||||
return api->request->local_uri + strlen(path) + 1u;
|
||||
else
|
||||
// Path match without argument
|
||||
return "";
|
||||
|
@ -182,11 +154,11 @@ const char* __attribute__((pure)) startsWith(const char *path, const char *uri)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
bool http_get_cookie_int(struct mg_connection *conn, const char *cookieName, int *i)
|
||||
bool http_get_cookie_int(struct ftl_conn *api, const char *cookieName, int *i)
|
||||
{
|
||||
// Maximum cookie length is 4KB
|
||||
char cookieValue[4096];
|
||||
const char *cookie = mg_get_header(conn, "Cookie");
|
||||
const char *cookie = mg_get_header(api->conn, "Cookie");
|
||||
if(mg_get_cookie(cookie, cookieName, cookieValue, sizeof(cookieValue)) > 0)
|
||||
{
|
||||
*i = atoi(cookieValue);
|
||||
|
@ -195,9 +167,9 @@ bool http_get_cookie_int(struct mg_connection *conn, const char *cookieName, int
|
|||
return false;
|
||||
}
|
||||
|
||||
bool http_get_cookie_str(struct mg_connection *conn, const char *cookieName, char *str, size_t str_size)
|
||||
bool http_get_cookie_str(struct ftl_conn *api, const char *cookieName, char *str, size_t str_size)
|
||||
{
|
||||
const char *cookie = mg_get_header(conn, "Cookie");
|
||||
const char *cookie = mg_get_header(api->conn, "Cookie");
|
||||
if(mg_get_cookie(cookie, cookieName, str, str_size) > 0)
|
||||
{
|
||||
return true;
|
||||
|
@ -205,7 +177,7 @@ bool http_get_cookie_str(struct mg_connection *conn, const char *cookieName, cha
|
|||
return false;
|
||||
}
|
||||
|
||||
int http_method(struct mg_connection *conn)
|
||||
enum http_method __attribute__((pure)) http_method(struct mg_connection *conn)
|
||||
{
|
||||
const struct mg_request_info *request = mg_get_request_info(conn);
|
||||
if(strcmp(request->request_method, "GET") == 0)
|
||||
|
@ -220,17 +192,25 @@ int http_method(struct mg_connection *conn)
|
|||
return HTTP_UNKNOWN;
|
||||
}
|
||||
|
||||
cJSON *get_POST_JSON(struct mg_connection *conn)
|
||||
void read_and_parse_payload(struct ftl_conn *api)
|
||||
{
|
||||
// Extract payload
|
||||
char buffer[1024] = { 0 };
|
||||
int data_len = mg_read(conn, buffer, sizeof(buffer) - 1);
|
||||
if ((data_len < 1) || (data_len >= (int)sizeof(buffer)))
|
||||
return NULL;
|
||||
// Try to extract payload from GET request
|
||||
if(api->method == HTTP_GET && api->request->query_string != NULL)
|
||||
{
|
||||
strncpy(api->payload.raw, api->request->query_string, MAX_PAYLOAD_BYTES-1);
|
||||
api->payload.avail = true;
|
||||
}
|
||||
else // POST, PUT
|
||||
{
|
||||
int data_len = mg_read(api->conn, api->payload.raw, MAX_PAYLOAD_BYTES - 1);
|
||||
logg("Received payload with size: %d", data_len);
|
||||
if ((data_len < 1) || (data_len >= MAX_PAYLOAD_BYTES))
|
||||
return;
|
||||
|
||||
buffer[data_len] = '\0';
|
||||
api->payload.raw[data_len] = '\0';
|
||||
api->payload.avail = true;
|
||||
|
||||
// Parse JSON
|
||||
cJSON *obj = cJSON_Parse(buffer);
|
||||
return obj;
|
||||
// Try to parse possibly existing JSON payload
|
||||
api->payload.json = cJSON_Parse(api->payload.raw);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,40 +17,49 @@
|
|||
// strlen()
|
||||
#include <string.h>
|
||||
|
||||
// API-internal definitions
|
||||
#define MAX_PAYLOAD_BYTES 2048
|
||||
enum http_method { HTTP_UNKNOWN, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_DELETE };
|
||||
struct ftl_conn {
|
||||
struct mg_connection *conn;
|
||||
const struct mg_request_info *request;
|
||||
const enum http_method method;
|
||||
struct {
|
||||
bool avail :1;
|
||||
char raw[MAX_PAYLOAD_BYTES];
|
||||
cJSON *json;
|
||||
} payload;
|
||||
};
|
||||
|
||||
|
||||
const char* json_formatter(const cJSON *object);
|
||||
|
||||
int send_http(struct mg_connection *conn, const char *mime_type, const char *msg);
|
||||
int send_http_code(struct mg_connection *conn, const char *mime_type, int code, const char *msg);
|
||||
int send_http_internal_error(struct mg_connection *conn);
|
||||
int send_json_unauthorized(struct mg_connection *conn);
|
||||
int send_json_error(struct mg_connection *conn, const int code,
|
||||
int send_http(struct ftl_conn *api, const char *mime_type, const char *msg);
|
||||
int send_http_code(struct ftl_conn *api, const char *mime_type, int code, const char *msg);
|
||||
int send_http_internal_error(struct ftl_conn *api);
|
||||
int send_json_unauthorized(struct ftl_conn *api);
|
||||
int send_json_error(struct ftl_conn *api, const int code,
|
||||
const char *key, const char* message,
|
||||
cJSON *data);
|
||||
int send_json_success(struct mg_connection *conn);
|
||||
int send_json_success(struct ftl_conn *api);
|
||||
|
||||
void http_reread_index_html(void);
|
||||
|
||||
// Cookie routines
|
||||
bool http_get_cookie_int(struct mg_connection *conn, const char *cookieName, int *i);
|
||||
bool http_get_cookie_str(struct mg_connection *conn, const char *cookieName, char *str, size_t str_size);
|
||||
bool http_get_cookie_int(struct ftl_conn *api, const char *cookieName, int *i);
|
||||
bool http_get_cookie_str(struct ftl_conn *api, const char *cookieName, char *str, size_t str_size);
|
||||
|
||||
// HTTP parameter routines
|
||||
bool get_bool_var(const char *source, const char *var, bool *boolean);
|
||||
bool get_uint_var(const char *source, const char *var, unsigned int *num);
|
||||
bool get_int_var(const char *source, const char *var, int *num);
|
||||
bool http_get_payload(struct mg_connection *conn, char *payload);
|
||||
cJSON *get_POST_JSON(struct mg_connection *conn);
|
||||
|
||||
// HTTP macros
|
||||
#define GET_VAR(variable, destination, source) mg_get_var(source, strlen(source), variable, destination, sizeof(destination))
|
||||
|
||||
// Method routines
|
||||
enum http_method { HTTP_UNKNOWN, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_DELETE };
|
||||
int http_method(struct mg_connection *conn);
|
||||
|
||||
// Utils
|
||||
const char *startsWith(const char *path, const char *uri) __attribute__((pure));
|
||||
enum http_method __attribute__((pure)) http_method(struct mg_connection *conn);
|
||||
const char* __attribute__((pure)) startsWith(const char *path, const struct ftl_conn *api);
|
||||
void read_and_parse_payload(struct ftl_conn *api);
|
||||
|
||||
#endif // HTTP_H
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
if(string_item == NULL) \
|
||||
{ \
|
||||
cJSON_Delete(object); \
|
||||
send_http_internal_error(conn); \
|
||||
send_http_internal_error(api); \
|
||||
logg("JSON_OBJ_COPY_STR FAILED (key: \"%s\", string: \"%s\")!", key, string); \
|
||||
return 500; \
|
||||
} \
|
||||
|
@ -50,7 +50,7 @@
|
|||
if(string_item == NULL) \
|
||||
{ \
|
||||
cJSON_Delete(object); \
|
||||
send_http_internal_error(conn); \
|
||||
send_http_internal_error(api); \
|
||||
logg("JSON_OBJ_REF_STR FAILED (key: \"%s\", string: \"%s\")!", key, string); \
|
||||
return 500; \
|
||||
} \
|
||||
|
@ -61,7 +61,7 @@
|
|||
if(cJSON_AddNumberToObject(object, key, (double)(number)) == NULL) \
|
||||
{ \
|
||||
cJSON_Delete(object); \
|
||||
send_http_internal_error(conn); \
|
||||
send_http_internal_error(api); \
|
||||
logg("JSON_OBJ_ADD_NUMBER FAILED!"); \
|
||||
return 500; \
|
||||
} \
|
||||
|
@ -72,7 +72,7 @@
|
|||
if(null_item == NULL) \
|
||||
{ \
|
||||
cJSON_Delete(object); \
|
||||
send_http_internal_error(conn); \
|
||||
send_http_internal_error(api); \
|
||||
logg("JSON_OBJ_ADD_NULL FAILED!"); \
|
||||
return 500; \
|
||||
} \
|
||||
|
@ -84,7 +84,7 @@
|
|||
if(bool_item == NULL) \
|
||||
{ \
|
||||
cJSON_Delete(object); \
|
||||
send_http_internal_error(conn); \
|
||||
send_http_internal_error(api); \
|
||||
logg("JSON_OBJ_ADD_BOOL FAILED!"); \
|
||||
return 500; \
|
||||
} \
|
||||
|
@ -114,7 +114,7 @@
|
|||
if(string_item == NULL) \
|
||||
{ \
|
||||
cJSON_Delete(array); \
|
||||
send_http_internal_error(conn); \
|
||||
send_http_internal_error(api); \
|
||||
logg("JSON_ARRAY_REF_STR FAILED!"); \
|
||||
return 500; \
|
||||
} \
|
||||
|
@ -134,7 +134,7 @@
|
|||
if(string_item == NULL) \
|
||||
{ \
|
||||
cJSON_Delete(array); \
|
||||
send_http_internal_error(conn); \
|
||||
send_http_internal_error(api); \
|
||||
logg("JSON_ARRAY_COPY_STR FAILED!"); \
|
||||
return 500; \
|
||||
} \
|
||||
|
@ -153,11 +153,11 @@
|
|||
if(msg == NULL) \
|
||||
{ \
|
||||
cJSON_Delete(object); \
|
||||
send_http_internal_error(conn); \
|
||||
send_http_internal_error(api); \
|
||||
logg("JSON_SEND_OBJECT FAILED!"); \
|
||||
return 500; \
|
||||
} \
|
||||
send_http(conn, "application/json; charset=utf-8", msg); \
|
||||
send_http(api, "application/json; charset=utf-8", msg); \
|
||||
cJSON_Delete(object); \
|
||||
return 200; \
|
||||
}
|
||||
|
@ -167,11 +167,11 @@
|
|||
if(msg == NULL) \
|
||||
{ \
|
||||
cJSON_Delete(object); \
|
||||
send_http_internal_error(conn); \
|
||||
send_http_internal_error(api); \
|
||||
logg("JSON_SEND_OBJECT_CODE FAILED!"); \
|
||||
return 500; \
|
||||
} \
|
||||
send_http_code(conn, "application/json; charset=utf-8", code, msg); \
|
||||
send_http_code(api, "application/json; charset=utf-8", code, msg); \
|
||||
cJSON_Delete(object); \
|
||||
return code; \
|
||||
}
|
||||
|
@ -181,11 +181,11 @@
|
|||
if(msg == NULL) \
|
||||
{ \
|
||||
cJSON_Delete(object); \
|
||||
send_http_internal_error(conn); \
|
||||
send_http_internal_error(api); \
|
||||
logg("JSON_SEND_OBJECT_AND_HEADERS FAILED!"); \
|
||||
return 500; \
|
||||
} \
|
||||
send_http(conn, "application/json; charset=utf-8", additional_headers, msg); \
|
||||
send_http(api, "application/json; charset=utf-8", additional_headers, msg); \
|
||||
cJSON_Delete(object); \
|
||||
free(additional_headers); \
|
||||
return 200; \
|
||||
|
@ -196,11 +196,11 @@
|
|||
if(msg == NULL) \
|
||||
{ \
|
||||
cJSON_Delete(object); \
|
||||
send_http_internal_error(conn); \
|
||||
send_http_internal_error(api); \
|
||||
logg("JSON_SEND_OBJECT_AND_HEADERS_CODE FAILED!"); \
|
||||
return 500; \
|
||||
} \
|
||||
send_http_code(conn, "application/json; charset=utf-8", additional_headers, code, msg); \
|
||||
send_http_code(api, "application/json; charset=utf-8", additional_headers, code, msg); \
|
||||
cJSON_Delete(object); \
|
||||
free(additional_headers); \
|
||||
return code; \
|
||||
|
|
|
@ -22,12 +22,6 @@
|
|||
// Server context handle
|
||||
static struct mg_context *ctx = NULL;
|
||||
|
||||
// Print passed string directly
|
||||
static int print_simple(struct mg_connection *conn, void *input)
|
||||
{
|
||||
return send_http(conn, "text/plain", input);
|
||||
}
|
||||
|
||||
static int redirect_root_handler(struct mg_connection *conn, void *input)
|
||||
{
|
||||
// Get requested host
|
||||
|
@ -142,7 +136,7 @@ void http_init(void)
|
|||
const char *options[] = {
|
||||
"document_root", httpsettings.webroot,
|
||||
"listening_ports", httpsettings.port,
|
||||
"decode_url", "no",
|
||||
"decode_url", "yes",
|
||||
"enable_directory_listing", "no",
|
||||
"num_threads", "16",
|
||||
"access_control_list", httpsettings.acl,
|
||||
|
@ -171,9 +165,6 @@ void http_init(void)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Add simple demonstration callbacks */
|
||||
mg_set_request_handler(ctx, "/ping", print_simple, (char*)"pong\n");
|
||||
|
||||
// Register API handler
|
||||
mg_set_request_handler(ctx, "/api", api_handler, NULL);
|
||||
|
||||
|
|
Loading…
Reference in New Issue