]> git.ipfire.org Git - pakfire.git/commitdiff
xfer: Translate any errors into our own error codes
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 1 Nov 2023 19:06:27 +0000 (19:06 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 1 Nov 2023 19:06:27 +0000 (19:06 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/httpclient.c
src/libpakfire/include/pakfire/xfer.h
src/libpakfire/xfer.c

index 7a97dcef91910368bc00fb044c67828cffff08af..fdc50016b7dbc388783dbe61dcc5238941706c6c 100644 (file)
@@ -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)
index aff9e90638fb77e9e9458f978080d11a8e9d32b7..da32b2f65fdfffcc55cb980f8ef32293d6f6e075 100644 (file)
@@ -34,6 +34,43 @@ struct pakfire_xfer;
 #include <pakfire/mirrorlist.h>
 #include <pakfire/progress.h>
 
+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 */
index 975ab7c7cccdf1f92fd9d28fd643a3bca7b85f9d..0f849380a7906007d5d9c922efa2fde04b964dde 100644 (file)
@@ -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 (;;) {