From: Michael Tremer Date: Sat, 21 Jun 2025 16:16:55 +0000 (+0000) Subject: json: Cleanup the JSON parsing interfaces X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d1d1c3482e45cc9acdd9fc47c87fe9ed4ef872d7;p=pakfire.git json: Cleanup the JSON parsing interfaces We should not always require the context to have some basic logging. Instead we can return the error as a string. Signed-off-by: Michael Tremer --- diff --git a/src/pakfire/daemon.c b/src/pakfire/daemon.c index 2b562d5a..567ab3ab 100644 --- a/src/pakfire/daemon.c +++ b/src/pakfire/daemon.c @@ -533,14 +533,15 @@ static int pakfire_daemon_recv(struct pakfire_xfer* xfer, struct pakfire_daemon* daemon = data; struct json_object* type = NULL; struct json_object* m = NULL; + char* error = NULL; int r; const char* job_id = NULL; // Parse the JSON message - m = pakfire_json_parse(daemon->ctx, message, size); - if (!m) { - r = -errno; + r = pakfire_json_parse(&m, &error, message, size); + if (r < 0) { + ERROR(daemon->ctx, "Failed to parse JSON message: %s\n", error); goto ERROR; } @@ -592,6 +593,8 @@ static int pakfire_daemon_recv(struct pakfire_xfer* xfer, ERROR: if (m) json_object_put(m); + if (error) + free(error); return r; } diff --git a/src/pakfire/json.c b/src/pakfire/json.c index 0eee8228..116e7910 100644 --- a/src/pakfire/json.c +++ b/src/pakfire/json.c @@ -32,67 +32,87 @@ const char* pakfire_json_to_string(struct json_object* json) { return json_object_to_json_string_ext(json, flags); } -struct json_object* pakfire_json_parse( - struct pakfire_ctx* ctx, const char* buffer, const size_t length) { +int pakfire_json_parse(struct json_object** json, char** error, + const char* buffer, const size_t length) { struct json_tokener* tokener = NULL; - struct json_object* json = NULL; + struct json_object* object = NULL; + enum json_tokener_error e; + int r; // Create tokener tokener = json_tokener_new(); - if (!tokener) { - ERROR(ctx, "Could not allocate JSON tokener: %m\n"); - goto ERROR; - } + if (!tokener) + return -ENOMEM; // Parse JSON from buffer - json = json_tokener_parse_ex(tokener, buffer, length); - if (!json) { - enum json_tokener_error error = json_tokener_get_error(tokener); - - ERROR(ctx, "JSON parsing error: %s\n", json_tokener_error_desc(error)); - goto ERROR; + object = json_tokener_parse_ex(tokener, buffer, length); + if (!object) { + // Fetch the error code + e = json_tokener_get_error(tokener); + + // Format the error string + if (error) { + r = asprintf(error, "JSON parsing error: %s\n", json_tokener_error_desc(e)); + if (r < 0) + goto ERROR; + } + + // Assume that the input was invalid + r = -EBADMSG; } - // Log what we have parsed - DEBUG(ctx, "Parsed JSON:\n%s\n", pakfire_json_to_string(json)); + // Return the object + *json = object; + r = 0; ERROR: if (tokener) json_tokener_free(tokener); - return json; + return r; } -static struct json_object* pakfire_json_parse_file(struct pakfire_ctx* ctx, FILE* f) { - struct json_object* json = NULL; +static int pakfire_json_parse_file(struct json_object** json, char** error, FILE* f) { char* buffer = NULL; size_t length = 0; int r; // Map everything into memory r = pakfire_mmap(fileno(f), &buffer, &length); - if (r) + if (r < 0) goto ERROR; // Parse - json = pakfire_json_parse(ctx, buffer, length); + r = pakfire_json_parse(json, error, buffer, length); ERROR: if (buffer) munmap(buffer, length); - return json; + return r; } -struct json_object* pakfire_json_parse_from_file(struct pakfire_ctx* ctx, const char* path) { - FILE* f = fopen(path, "r"); - if (!f) - return NULL; +int pakfire_json_parse_from_file(struct json_object** json, char** error, const char* path) { + FILE* f = NULL; + int r; + + // Open the file + f = fopen(path, "r"); + if (!f) { + r = -errno; + goto ERROR; + } + + // Parse the payload + r = pakfire_json_parse_file(json, error, f); + if (r < 0) + goto ERROR; - struct json_object* json = pakfire_json_parse_file(ctx, f); - fclose(f); +ERROR: + if (f) + fclose(f); - return json; + return r; } struct json_object* pakfire_json_new_object(void) { diff --git a/src/pakfire/json.h b/src/pakfire/json.h index 2023ccd1..b6a2d3ef 100644 --- a/src/pakfire/json.h +++ b/src/pakfire/json.h @@ -31,11 +31,11 @@ const char* pakfire_json_to_string(struct json_object* json); // Parse -struct json_object* pakfire_json_parse(struct pakfire_ctx* ctx, +int pakfire_json_parse(struct json_object** json, char** error, const char* buffer, const size_t length); // Parse from file -struct json_object* pakfire_json_parse_from_file(struct pakfire_ctx* ctx, const char* path); +int pakfire_json_parse_from_file(struct json_object** json, char** error, const char* path); struct json_object* pakfire_json_new_object(void); diff --git a/src/pakfire/jwt.c b/src/pakfire/jwt.c index 4474104e..0682650d 100644 --- a/src/pakfire/jwt.c +++ b/src/pakfire/jwt.c @@ -89,6 +89,7 @@ ERROR: } int pakfire_jwt_payload(struct pakfire_ctx* ctx, const char* token, struct json_object** payload) { + char* error = NULL; char* p = NULL; size_t l = 0; int r; @@ -97,13 +98,19 @@ int pakfire_jwt_payload(struct pakfire_ctx* ctx, const char* token, struct json_ r = pakfire_jwt_decode_payload(&p, &l, token); if (r < 0) { ERROR(ctx, "Failed to decode the JWT payload: %s\n", strerror(-r)); - return r; + goto ERROR; } // Parse the JSON - *payload = pakfire_json_parse(ctx, p, l); - if (!*payload) - return -EINVAL; + r = pakfire_json_parse(payload, &error, p, l); + if (r < 0) { + ERROR(ctx, "Failed to parse JSON payload: %s\n", error); + goto ERROR; + } + +ERROR: + if (error) + free(error); return 0; } diff --git a/src/pakfire/mirrorlist.c b/src/pakfire/mirrorlist.c index 801061c5..10016b39 100644 --- a/src/pakfire/mirrorlist.c +++ b/src/pakfire/mirrorlist.c @@ -140,6 +140,8 @@ ERROR: } int pakfire_mirrorlist_read(struct pakfire_mirrorlist* list, const char* path) { + struct json_object* json = NULL; + char* error = NULL; int r; if (!path || !*path) { @@ -149,13 +151,14 @@ int pakfire_mirrorlist_read(struct pakfire_mirrorlist* list, const char* path) { DEBUG(list->ctx, "Reading mirrorlist from %s\n", path); - struct json_object* json = pakfire_json_parse_from_file(list->ctx, path); - if (!json) { + // Parse the file + r = pakfire_json_parse_from_file(&json, &error, path); + if (r < 0) { // Ignore if path does not exist if (errno == ENOENT) return 0; - ERROR(list->ctx, "Could not parse mirrorlist from %s: %m\n", path); + ERROR(list->ctx, "Could not parse mirrorlist from %s: %s\n", path, error); return 1; } @@ -206,6 +209,8 @@ int pakfire_mirrorlist_read(struct pakfire_mirrorlist* list, const char* path) { ERROR: if (json) json_object_put(json); + if (error) + free(error); return r; } diff --git a/src/pakfire/repo.c b/src/pakfire/repo.c index c0b18fb2..ac627e06 100644 --- a/src/pakfire/repo.c +++ b/src/pakfire/repo.c @@ -1055,14 +1055,15 @@ ERROR: static int pakfire_repo_read_metadata(struct pakfire_repo* repo, const char* path) { struct json_object* json = NULL; + char* error = NULL; int r; DEBUG(repo->ctx, "Reading repository metadata from %s...\n", path); // Parse the existing metadata - json = pakfire_json_parse_from_file(repo->ctx, path); - if (!json) { - switch (errno) { + r = pakfire_json_parse_from_file(&json, &error, path); + if (r < 0) { + switch (-r) { case ENOENT: // Log some message DEBUG(repo->ctx, "Repository metadata is not available\n"); @@ -1071,8 +1072,7 @@ static int pakfire_repo_read_metadata(struct pakfire_repo* repo, const char* pat return 0; default: - ERROR(repo->ctx, "Could not parse metadata from %s: %m\n", path); - r = -errno; + ERROR(repo->ctx, "Could not parse metadata from %s: %s\n", path, error); goto ERROR; } } @@ -1098,6 +1098,8 @@ ERROR: // Free the parsed JSON object if (json) json_object_put(json); + if (error) + free(error); return r; } @@ -1262,6 +1264,7 @@ static int pakfire_repo_download_metadata(struct pakfire_repo* repo, const char* struct pakfire_buffer buffer = {}; struct pakfire_xfer* xfer = NULL; struct json_object* json = NULL; + char* error = NULL; int r; // Local repositories don't need to download metadata @@ -1320,9 +1323,9 @@ static int pakfire_repo_download_metadata(struct pakfire_repo* repo, const char* } // Parse JSON from buffer - json = pakfire_json_parse(repo->ctx, buffer.data, buffer.length); - if (!json) { - r = -EBADMSG; + r = pakfire_json_parse(&json, &error, buffer.data, buffer.length); + if (r < 0) { + ERROR(repo->ctx, "Failed to parse JSON data: %s\n", error); goto ERROR; } @@ -1361,6 +1364,8 @@ ERROR: json_object_put(json); if (buffer.data) free(buffer.data); + if (error) + free(error); return r; } diff --git a/src/pakfire/xfer.c b/src/pakfire/xfer.c index 583cab29..21d9c10c 100644 --- a/src/pakfire/xfer.c +++ b/src/pakfire/xfer.c @@ -1875,6 +1875,7 @@ static int pakfire_xfer_parse_api_response(struct pakfire_xfer* xfer, const char* buffer, const size_t length, struct json_object** object) { struct json_object* error = NULL; struct json_object* o = NULL; + char* e = NULL; int r; // Check if we received any data @@ -1891,10 +1892,9 @@ static int pakfire_xfer_parse_api_response(struct pakfire_xfer* xfer, // XXX Maybe fetch the parser's error message here?! // Parse the buffer - o = pakfire_json_parse(xfer->ctx, buffer, length); - if (!o) { - ERROR(xfer->ctx, "Could not parse the response\n"); - r = -EBADMSG; + r = pakfire_json_parse(&o, &e, buffer, length); + if (r < 0) { + ERROR(xfer->ctx, "Could not parse the response: %s\n", e); goto ERROR; } @@ -1919,6 +1919,8 @@ static int pakfire_xfer_parse_api_response(struct pakfire_xfer* xfer, ERROR: if (o) json_object_put(o); + if (e) + free(e); return r; }