From: Michael Tremer Date: Wed, 1 Nov 2023 19:06:27 +0000 (+0000) Subject: xfer: Translate any errors into our own error codes X-Git-Tag: 0.9.30~1322 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6aed39be309398a26b08b4be3b082d1e00832e63;p=pakfire.git xfer: Translate any errors into our own error codes Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/httpclient.c b/src/libpakfire/httpclient.c index 7a97dcef9..fdc50016b 100644 --- a/src/libpakfire/httpclient.c +++ b/src/libpakfire/httpclient.c @@ -441,7 +441,7 @@ ERROR: TAILQ_REMOVE(&client->xfers_running, x, nodes); // Fail the transfer - pakfire_xfer_fail(x->xfer, 0); + pakfire_xfer_fail(x->xfer); } if (progress) diff --git a/src/libpakfire/include/pakfire/xfer.h b/src/libpakfire/include/pakfire/xfer.h index aff9e9063..da32b2f65 100644 --- a/src/libpakfire/include/pakfire/xfer.h +++ b/src/libpakfire/include/pakfire/xfer.h @@ -34,6 +34,43 @@ struct pakfire_xfer; #include #include +typedef enum pakfire_xfer_error_code { + PAKFIRE_XFER_OK = 0, + + // General/Unknown Failure + PAKFIRE_XFER_FAILED, + + // An unsupported protocol was requested + PAKFIRE_XFER_UNSUPPORTED, + + // Invalid URL + PAKFIRE_XFER_INVALID_URL, + + // The server responded with something weird + PAKFIRE_XFER_INVALID_RESPONSE, + + // DNS Problem + PAKFIRE_XFER_DNS_ERROR, + + // Authentication + PAKFIRE_XFER_AUTH_ERROR, + PAKFIRE_XFER_ACCESS_DENIED, + + // Some connection problem + PAKFIRE_XFER_TRANSPORT_ERROR, + + // Timeout + PAKFIRE_XFER_TIMEOUT, + + // Local operation errors + PAKFIRE_XFER_WRITE_ERROR, + PAKFIRE_XFER_READ_ERROR, + PAKFIRE_XFER_ABORTED, + + // Digest Mismatch + PAKFIRE_XFER_DIGEST_MISMATCH, +} pakfire_xfer_error_code_t; + typedef enum pakfire_xfer_flags { PAKFIRE_XFER_NO_PROGRESS = (1 << 0), } pakfire_xfer_flags_t; @@ -83,11 +120,12 @@ int pakfire_xfer_set_input(struct pakfire_xfer* xfer, FILE* f); int pakfire_xfer_auth(struct pakfire_xfer* xfer); int pakfire_xfer_prepare(struct pakfire_xfer* xfer, struct pakfire_progress* progress, int flags); -int pakfire_xfer_done(struct pakfire_xfer* xfer, int code); -int pakfire_xfer_fail(struct pakfire_xfer* xfer, int code); +pakfire_xfer_error_code_t pakfire_xfer_done(struct pakfire_xfer* xfer, int code); +int pakfire_xfer_fail(struct pakfire_xfer* xfer); -int pakfire_xfer_run(struct pakfire_xfer* xfer, int flags); -int pakfire_xfer_run_api_request(struct pakfire_xfer* xfer, struct json_object** response); +pakfire_xfer_error_code_t pakfire_xfer_run(struct pakfire_xfer* xfer, int flags); +pakfire_xfer_error_code_t pakfire_xfer_run_api_request( + struct pakfire_xfer* xfer, struct json_object** response); #endif /* PAKFIRE_PRIVATE */ #endif /* PAKFIRE_XFER_H */ diff --git a/src/libpakfire/xfer.c b/src/libpakfire/xfer.c index 975ab7c7c..0f849380a 100644 --- a/src/libpakfire/xfer.c +++ b/src/libpakfire/xfer.c @@ -738,7 +738,93 @@ static int pakfire_xfer_save(struct pakfire_xfer* xfer) { return 0; } -int pakfire_xfer_fail(struct pakfire_xfer* xfer, int code) { +/* + This function translates any cURL error codes into xfer codes +*/ +static pakfire_xfer_error_code_t pakfire_xfer_code(CURLcode code, int http_status) { + switch (code) { + case CURLE_OK: + return PAKFIRE_XFER_OK; + + // Unsupported requests + case CURLE_UNSUPPORTED_PROTOCOL: + case CURLE_NOT_BUILT_IN: + case CURLE_RANGE_ERROR: + return PAKFIRE_XFER_UNSUPPORTED; + + // Invalid requests + case CURLE_URL_MALFORMAT: + return PAKFIRE_XFER_INVALID_URL; + + // Invalid responses + case CURLE_TOO_MANY_REDIRECTS: + case CURLE_GOT_NOTHING: + case CURLE_BAD_CONTENT_ENCODING: + return PAKFIRE_XFER_INVALID_RESPONSE; + + // DNS Errors + case CURLE_COULDNT_RESOLVE_PROXY: + case CURLE_COULDNT_RESOLVE_HOST: + case CURLE_FTP_CANT_GET_HOST: + return PAKFIRE_XFER_DNS_ERROR; + + // Authentication + case CURLE_AUTH_ERROR: + return PAKFIRE_XFER_AUTH_ERROR; + + // Transport Errors + case CURLE_PROXY: + case CURLE_SSL_CONNECT_ERROR: + case CURLE_SSL_CERTPROBLEM: + case CURLE_SSL_CIPHER: + case CURLE_PEER_FAILED_VERIFICATION: + return PAKFIRE_XFER_TRANSPORT_ERROR; + + // Access Denied + case CURLE_REMOTE_ACCESS_DENIED: + return PAKFIRE_XFER_ACCESS_DENIED; + + // Timeout + case CURLE_FTP_ACCEPT_TIMEOUT: + case CURLE_OPERATION_TIMEDOUT: + return PAKFIRE_XFER_TIMEOUT; + + // Write error + case CURLE_WRITE_ERROR: + return PAKFIRE_XFER_WRITE_ERROR; + + // Read error + case CURLE_READ_ERROR: + case CURLE_FILE_COULDNT_READ_FILE: + return PAKFIRE_XFER_READ_ERROR; + + // Aborted + case CURLE_ABORTED_BY_CALLBACK: + return PAKFIRE_XFER_ABORTED; + + // HTTP Errors + case CURLE_HTTP_RETURNED_ERROR: + switch (http_status) { + // Proxy Error + case 502: + return PAKFIRE_XFER_TRANSPORT_ERROR; + + // Service Unavailable + case 503: + return PAKFIRE_XFER_TRANSPORT_ERROR; + + default: + return PAKFIRE_XFER_FAILED; + } + break; + + // Return "unknown error" for any other codes + default: + return PAKFIRE_XFER_FAILED; + } +} + +int pakfire_xfer_fail(struct pakfire_xfer* xfer) { int r; CTX_DEBUG(xfer->ctx, "Xfer failed\n"); @@ -764,16 +850,16 @@ int pakfire_xfer_fail(struct pakfire_xfer* xfer, int code) { pakfire_mirror_xfer_failed(xfer->mirror); // Try again with another mirror - return EAGAIN; + return -EAGAIN; } return 0; } -int pakfire_xfer_done(struct pakfire_xfer* xfer, int code) { +pakfire_xfer_error_code_t pakfire_xfer_done(struct pakfire_xfer* xfer, int code) { CURL* h = xfer->handle; int r; - char* scheme = NULL; + const char* scheme = NULL; long response_code; long http_version; double total_time; @@ -788,18 +874,10 @@ int pakfire_xfer_done(struct pakfire_xfer* xfer, int code) { if (r) return r; - CTX_DEBUG(xfer->ctx, "cURL xfer done: %d - %s\n", - code, curl_easy_strerror(code)); - - // Finish message digest computation - if (xfer->evp) { - r = EVP_DigestFinal_ex(xfer->evp, xfer->computed_digest, &xfer->computed_digest_length); - if (r != 1) { - CTX_ERROR(xfer->ctx, "Could not finish message digest computation: %s\n", - ERR_error_string(ERR_get_error(), NULL)); - return 1; - } - } + // Log the result + CTX_DEBUG(xfer->ctx, "cURL xfer done: %d - %s\n", code, curl_easy_strerror(code)); + if (*xfer->error) + CTX_DEBUG(xfer->ctx, " Error: %s\n", xfer->error); // Protocol curl_easy_getinfo(h, CURLINFO_SCHEME, &scheme); @@ -855,19 +933,27 @@ int pakfire_xfer_done(struct pakfire_xfer* xfer, int code) { if (upload_speed) CTX_DEBUG(xfer->ctx, " Upload Speed: %ld bps\n", upload_speed); - // Message Digest - char* hexdigest = __pakfire_hexlify(xfer->computed_digest, xfer->computed_digest_length); - if (hexdigest && *hexdigest) { - CTX_DEBUG(xfer->ctx, " Message Digest: %s\n", hexdigest); - free(hexdigest); - } - // Check if digests match if (xfer->evp) { + // Finish message digest computation + r = EVP_DigestFinal_ex(xfer->evp, xfer->computed_digest, &xfer->computed_digest_length); + if (r != 1) { + CTX_ERROR(xfer->ctx, "Could not finish message digest computation: %s\n", + ERR_error_string(ERR_get_error(), NULL)); + return 1; + } + + // Message Digest + char* hexdigest = __pakfire_hexlify(xfer->computed_digest, xfer->computed_digest_length); + if (hexdigest) { + CTX_DEBUG(xfer->ctx, " Message Digest: %s\n", hexdigest); + free(hexdigest); + } + r = CRYPTO_memcmp(xfer->computed_digest, xfer->expected_digest, xfer->computed_digest_length); - // If they don't match, log an error and try again + // If they don't match, log the error if (r) { char* computed_hexdigest = __pakfire_hexlify(xfer->computed_digest, xfer->computed_digest_length); @@ -884,60 +970,26 @@ int pakfire_xfer_done(struct pakfire_xfer* xfer, int code) { free(expected_hexdigest); // Make this download fail - r = pakfire_xfer_fail(xfer, 0); + r = pakfire_xfer_fail(xfer); if (r) return r; - return 1; + return PAKFIRE_XFER_DIGEST_MISMATCH; } } - // If we could not determine the scheme... - if (!scheme) - r = pakfire_xfer_fail(xfer, 0); - - // FILE - else if (strcmp(scheme, "FILE") == 0) { - // Handle any errors - if (code) - r = pakfire_xfer_fail(xfer, code); - else - r = pakfire_xfer_save(xfer); - - return r; - - // HTTPS + HTTP - } else if ((strcmp(scheme, "HTTPS") == 0) || (strcmp(scheme, "HTTP") == 0)) { - switch (response_code) { - // 200 - OK - case 200: - r = pakfire_xfer_save(xfer); - if (r) - return r; - break; - - // Treat all other response codes as an error - default: - r = pakfire_xfer_fail(xfer, code); - if (r) - return r; - - // Error - return 1; - } - - // FTP - } else if (strcmp(scheme, "FTP") == 0) { - if (response_code == 226) - r = pakfire_xfer_save(xfer); - else - r = pakfire_xfer_fail(xfer, code); + // Handle any errors + if (code) { + r = pakfire_xfer_fail(xfer); + if (r) + return r; - return r; + // Report that something went wrong + return pakfire_xfer_code(code, response_code); } - // Success - return 0; + // Otherwise save the file + return pakfire_xfer_save(xfer); } static int pakfire_xfer_update(void* data, @@ -1185,10 +1237,9 @@ int pakfire_xfer_prepare(struct pakfire_xfer* xfer, struct pakfire_progress* pro return 0; } -int pakfire_xfer_run(struct pakfire_xfer* xfer, int flags) { +pakfire_xfer_error_code_t pakfire_xfer_run(struct pakfire_xfer* xfer, int flags) { int r; -AGAIN: // Prepare the xfer r = pakfire_xfer_prepare(xfer, NULL, flags); if (r) { @@ -1203,14 +1254,9 @@ AGAIN: // Handle the result r = pakfire_xfer_done(xfer, r); - // Repeat the xfer if asked - switch (-r) { - case EAGAIN: - goto AGAIN; - - default: - break; - } + // Repeat if asked + if (r == -EAGAIN) + return pakfire_xfer_run(xfer, flags); return r; } @@ -1302,7 +1348,8 @@ ERROR: return r; } -static int pakfire_xfer_run_api_request_once(struct pakfire_xfer* xfer, struct json_object** response) { +static pakfire_xfer_error_code_t pakfire_xfer_run_api_request_once( + struct pakfire_xfer* xfer, struct json_object** response) { char* buffer = NULL; size_t length = 0; int r; @@ -1338,8 +1385,9 @@ ERROR: This function sends a request and automatically parses the response. The response might optionally be returned if response is not NULL. */ -int pakfire_xfer_run_api_request(struct pakfire_xfer* xfer, struct json_object** response) { - int r; +pakfire_xfer_error_code_t pakfire_xfer_run_api_request( + struct pakfire_xfer* xfer, struct json_object** response) { + pakfire_xfer_error_code_t r; // Loop indefinitely... for (;;) {