libcurl

Most widely used HTTP client library for C/C++. Supports numerous protocols including HTTPS, FTP, SMTP. Proven track record as foundation technology for curl command-line tool. Cross-platform compatible and adopted by many applications and libraries.

HTTP ClientC/C++High PerformanceMulti-ProtocolSSL/TLSStandard Library

GitHub Overview

curl/curl

A command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features

Stars39,610
Watchers782
Forks6,913
Created:March 18, 2010
Language:C
License:Other

Topics

cclientcurlftpgopherhacktoberfesthttphttpsimapsldaplibcurllibrarymqttpop3scpsftptransfer-datatransferring-datauser-agentwebsocket

Star History

curl/curl Star History
Data as of: 10/22/2025, 09:55 AM

Library

libcurl

Overview

libcurl is "a high-performance multi-protocol transfer library for C/C++" developed as one of the most widely used HTTP client libraries in the world. Serving as the core of the cURL command-line tool, it supports over 30 protocols including HTTP/HTTPS, FTP, SFTP, SMTP, IMAP, and LDAP. Providing simple yet powerful C APIs, it's adopted across a wide range of applications from embedded systems to enterprise applications. With high reliability, rich features, and excellent performance, it serves as the foundation for HTTP libraries in various programming languages.

Details

libcurl 2025 edition maintains its solid position as a mature HTTP client library with over 20 years of development experience. Its C-based design achieves the highest level of performance with optimized memory usage and high-speed processing. It provides complete support for HTTP/1.1, HTTP/2, and HTTP/3, comprehensive SSL/TLS support, proxy server integration, cookie management, authentication systems, custom header control, and all professional-grade features. Cross-platform compatibility allows consistent use from embedded systems to cloud infrastructure.

Key Features

  • Multi-Protocol Support: Over 30 protocols including HTTP/HTTPS, FTP, SMTP
  • Latest HTTP Standards: Complete support for HTTP/3, HTTP/2, HTTP/1.1
  • High-Performance Design: Optimized C implementation with memory efficiency
  • Comprehensive Security: SSL/TLS, certificate verification, encrypted communication
  • Rich Authentication Methods: Basic, Digest, NTLM, OAuth authentication
  • Cross-Platform: Windows, Linux, macOS, embedded systems support

Pros and Cons

Pros

  • High-performance implementation in C delivers maximum processing speed and efficiency
  • Single library supports 30+ protocols for diverse communication requirements
  • Outstanding stability and maturity from 20+ years of development experience
  • Wide applicability from embedded systems to enterprise environments
  • Open source with minimal license constraints and free commercial use
  • High versatility through rich programming language bindings

Cons

  • C language API requires more code compared to higher-level language libraries
  • Manual memory management and error handling required
  • Callback-based design can complicate asynchronous processing
  • Rich features may lead to relatively large binary size
  • Debugging and troubleshooting requires more technical knowledge
  • Learning curve can be steep for beginners

Reference Pages

Code Examples

Installation and Basic Setup

# Installation on Ubuntu/Debian
sudo apt-get update
sudo apt-get install libcurl4-openssl-dev

# Installation on CentOS/RHEL
sudo yum install libcurl-devel

# Installation on macOS (Homebrew)
brew install curl

# Installation on Windows (vcpkg)
vcpkg install curl

# Build from source
curl -O https://curl.se/download/curl-8.x.x.tar.gz
tar -xzf curl-8.x.x.tar.gz
cd curl-8.x.x
./configure --with-ssl
make
sudo make install

# Usage in CMake projects
find_package(CURL REQUIRED)
target_link_libraries(your_target ${CURL_LIBRARIES})
target_include_directories(your_target PRIVATE ${CURL_INCLUDE_DIRS})

Basic HTTP Requests (GET/POST/PUT/DELETE)

#include <stdio.h>
#include <curl/curl.h>

// Callback function to receive response data
struct MemoryStruct {
    char *memory;
    size_t size;
};

static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
    size_t realsize = size * nmemb;
    struct MemoryStruct *mem = (struct MemoryStruct *)userp;
    
    char *ptr = realloc(mem->memory, mem->size + realsize + 1);
    if (!ptr) {
        printf("Out of memory! realloc returned NULL\n");
        return 0;
    }
    
    mem->memory = ptr;
    memcpy(&(mem->memory[mem->size]), contents, realsize);
    mem->size += realsize;
    mem->memory[mem->size] = 0;
    
    return realsize;
}

// Basic GET request
int perform_get_request() {
    CURL *curl;
    CURLcode res;
    struct MemoryStruct chunk;
    
    chunk.memory = malloc(1);
    chunk.size = 0;
    
    curl = curl_easy_init();
    if (curl) {
        // URL configuration
        curl_easy_setopt(curl, CURLOPT_URL, "https://api.example.com/users");
        
        // Response callback
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
        
        // User agent configuration
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "MyApp/1.0 (libcurl)");
        
        // Enable SSL certificate verification
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
        
        // Execute request
        res = curl_easy_perform(curl);
        
        if (res != CURLE_OK) {
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                    curl_easy_strerror(res));
        } else {
            printf("Response: %s\n", chunk.memory);
            
            // Get HTTP status code
            long response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
            printf("HTTP Status: %ld\n", response_code);
        }
        
        curl_easy_cleanup(curl);
    }
    
    if (chunk.memory) {
        free(chunk.memory);
    }
    
    return 0;
}

// POST request (sending JSON)
int perform_post_request() {
    CURL *curl;
    CURLcode res;
    struct curl_slist *headers = NULL;
    
    curl = curl_easy_init();
    if (curl) {
        // URL configuration
        curl_easy_setopt(curl, CURLOPT_URL, "https://api.example.com/users");
        
        // POST data
        const char *json_data = "{\"name\":\"John Doe\",\"email\":\"[email protected]\",\"age\":30}";
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data);
        
        // Header configuration
        headers = curl_slist_append(headers, "Content-Type: application/json");
        headers = curl_slist_append(headers, "Authorization: Bearer your-token");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        
        // Response handling setup
        struct MemoryStruct chunk;
        chunk.memory = malloc(1);
        chunk.size = 0;
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
        
        // Execute request
        res = curl_easy_perform(curl);
        
        if (res != CURLE_OK) {
            fprintf(stderr, "POST failed: %s\n", curl_easy_strerror(res));
        } else {
            long response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
            printf("POST response (%ld): %s\n", response_code, chunk.memory);
        }
        
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        if (chunk.memory) free(chunk.memory);
    }
    
    return 0;
}

// PUT request (data update)
int perform_put_request() {
    CURL *curl;
    CURLcode res;
    struct curl_slist *headers = NULL;
    
    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "https://api.example.com/users/123");
        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
        
        const char *json_data = "{\"name\":\"Jane Doe\",\"email\":\"[email protected]\"}";
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data);
        
        headers = curl_slist_append(headers, "Content-Type: application/json");
        headers = curl_slist_append(headers, "Authorization: Bearer your-token");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        
        res = curl_easy_perform(curl);
        
        if (res == CURLE_OK) {
            long response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
            printf("PUT completed with status: %ld\n", response_code);
        }
        
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
    }
    
    return 0;
}

// DELETE request
int perform_delete_request() {
    CURL *curl;
    CURLcode res;
    struct curl_slist *headers = NULL;
    
    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "https://api.example.com/users/123");
        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
        
        headers = curl_slist_append(headers, "Authorization: Bearer your-token");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        
        res = curl_easy_perform(curl);
        
        if (res == CURLE_OK) {
            long response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
            if (response_code == 204) {
                printf("User deletion completed\n");
            }
        }
        
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
    }
    
    return 0;
}

int main() {
    // Initialize libcurl
    curl_global_init(CURL_GLOBAL_DEFAULT);
    
    perform_get_request();
    perform_post_request();
    perform_put_request();
    perform_delete_request();
    
    // Cleanup libcurl
    curl_global_cleanup();
    
    return 0;
}

Advanced Configuration and Customization (Authentication, SSL, Proxy, etc.)

#include <curl/curl.h>

// Request with Basic authentication
int authenticated_request() {
    CURL *curl;
    CURLcode res;
    
    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "https://api.example.com/private");
        
        // Basic authentication
        curl_easy_setopt(curl, CURLOPT_USERNAME, "username");
        curl_easy_setopt(curl, CURLOPT_PASSWORD, "password");
        curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
        
        // Or specify authentication string directly
        // curl_easy_setopt(curl, CURLOPT_USERPWD, "username:password");
        
        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
    }
    
    return 0;
}

// Custom headers and timeout configuration
int custom_headers_and_timeout() {
    CURL *curl;
    CURLcode res;
    struct curl_slist *headers = NULL;
    
    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "https://api.example.com/data");
        
        // Custom header configuration
        headers = curl_slist_append(headers, "User-Agent: MyApp/1.0 (libcurl)");
        headers = curl_slist_append(headers, "Accept: application/json");
        headers = curl_slist_append(headers, "Accept-Language: en-US,ja-JP");
        headers = curl_slist_append(headers, "X-API-Version: v2");
        headers = curl_slist_append(headers, "X-Request-ID: req-12345");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        
        // Timeout configuration
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);  // Connection timeout 10 seconds
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L);         // Overall timeout 30 seconds
        
        // DNS resolution timeout
        curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, 60L);
        
        res = curl_easy_perform(curl);
        
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
    }
    
    return 0;
}

// SSL/TLS configuration and client certificates
int ssl_configuration() {
    CURL *curl;
    CURLcode res;
    
    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "https://secure-api.example.com/data");
        
        // SSL certificate verification settings
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
        
        // CA certificate bundle specification
        curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/ca-bundle.crt");
        
        // Client certificate configuration
        curl_easy_setopt(curl, CURLOPT_SSLCERT, "/path/to/client.pem");
        curl_easy_setopt(curl, CURLOPT_SSLKEY, "/path/to/client.key");
        curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "certificate-password");
        
        // SSL certificate type specification
        curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
        curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
        
        // SSL encryption settings
        curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, "HIGH:!aNULL:!MD5");
        
        // Disable certificate verification for development (not recommended for production)
        // curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
        
        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
    }
    
    return 0;
}

// Proxy server configuration
int proxy_configuration() {
    CURL *curl;
    CURLcode res;
    
    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "https://api.example.com/data");
        
        // Proxy server configuration
        curl_easy_setopt(curl, CURLOPT_PROXY, "http://proxy.example.com:8080");
        
        // Proxy authentication
        curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, "proxy_user");
        curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, "proxy_pass");
        curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
        
        // Proxy type specification
        curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
        
        // HTTPS proxy tunneling
        curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L);
        
        // SOCKS proxy example
        // curl_easy_setopt(curl, CURLOPT_PROXY, "socks5://proxy.example.com:1080");
        // curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
        
        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
    }
    
    return 0;
}

// Cookie management
int cookie_management() {
    CURL *curl;
    CURLcode res;
    
    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "https://api.example.com/login");
        
        // Loading from cookie file
        curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/tmp/cookies.txt");
        
        // Saving to cookie file
        curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "/tmp/cookies.txt");
        
        // In-memory cookie management
        curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
        
        // Custom cookie configuration
        curl_easy_setopt(curl, CURLOPT_COOKIE, "session_id=abc123; user_pref=dark_mode");
        
        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
    }
    
    return 0;
}

Error Handling and Debugging Features

#include <curl/curl.h>

// Comprehensive error handling
int comprehensive_error_handling() {
    CURL *curl;
    CURLcode res;
    char errbuf[CURL_ERROR_SIZE];
    
    curl = curl_easy_init();
    if (!curl) {
        fprintf(stderr, "cURL initialization failed\n");
        return 1;
    }
    
    // Error buffer configuration
    curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
    errbuf[0] = 0; // Clear error buffer
    
    curl_easy_setopt(curl, CURLOPT_URL, "https://api.example.com/data");
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
    
    res = curl_easy_perform(curl);
    
    if (res != CURLE_OK) {
        size_t len = strlen(errbuf);
        fprintf(stderr, "libcurl error (%d): ", res);
        
        if (len) {
            fprintf(stderr, "%s%s", errbuf,
                    ((errbuf[len - 1] != '\n') ? "\n" : ""));
        } else {
            fprintf(stderr, "%s\n", curl_easy_strerror(res));
        }
        
        // Error type-specific handling
        switch (res) {
            case CURLE_COULDNT_CONNECT:
                fprintf(stderr, "Connection error: Cannot connect to server\n");
                break;
            case CURLE_OPERATION_TIMEDOUT:
                fprintf(stderr, "Timeout error: Request timed out\n");
                break;
            case CURLE_SSL_CONNECT_ERROR:
                fprintf(stderr, "SSL connection error: SSL/TLS connection failed\n");
                break;
            case CURLE_HTTP_RETURNED_ERROR:
                fprintf(stderr, "HTTP error: Server returned an error\n");
                break;
            default:
                fprintf(stderr, "Other error: %s\n", curl_easy_strerror(res));
                break;
        }
    } else {
        // Get detailed information on success
        long response_code;
        double total_time, connect_time, download_time;
        char *content_type = NULL;
        
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
        curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);
        curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &connect_time);
        curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &download_time);
        curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &content_type);
        
        printf("=== Request Successful ===\n");
        printf("HTTP Status: %ld\n", response_code);
        printf("Total Time: %.3f seconds\n", total_time);
        printf("Connect Time: %.3f seconds\n", connect_time);
        printf("Download Start Time: %.3f seconds\n", download_time);
        printf("Content Type: %s\n", content_type ? content_type : "unknown");
        
        // HTTP status code-specific handling
        if (response_code >= 200 && response_code < 300) {
            printf("Success: Request processed successfully\n");
        } else if (response_code >= 400 && response_code < 500) {
            fprintf(stderr, "Client error (%ld): There's an issue with the request\n", response_code);
        } else if (response_code >= 500) {
            fprintf(stderr, "Server error (%ld): Problem occurred on server side\n", response_code);
        }
    }
    
    curl_easy_cleanup(curl);
    return (res == CURLE_OK) ? 0 : 1;
}

// Request with debug functionality
static int debug_callback(CURL *handle, curl_infotype type, char *data, size_t size, void *userptr)
{
    const char *text;
    (void)handle; // Suppress unused parameter warning
    (void)userptr;
    
    switch (type) {
        case CURLINFO_TEXT:
            text = "== Info";
            break;
        case CURLINFO_HEADER_OUT:
            text = "=> Send header";
            break;
        case CURLINFO_DATA_OUT:
            text = "=> Send data";
            break;
        case CURLINFO_SSL_DATA_OUT:
            text = "=> Send SSL data";
            break;
        case CURLINFO_HEADER_IN:
            text = "< Recv header";
            break;
        case CURLINFO_DATA_IN:
            text = "< Recv data";
            break;
        case CURLINFO_SSL_DATA_IN:
            text = "< Recv SSL data";
            break;
        default:
            return 0;
    }
    
    printf("%s: %.*s", text, (int)size, data);
    return 0;
}

int debug_enabled_request() {
    CURL *curl;
    CURLcode res;
    
    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "https://api.example.com/debug");
        
        // Enable debug functionality
        curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, debug_callback);
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
        
        // Display progress information
        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
        
        res = curl_easy_perform(curl);
        
        if (res != CURLE_OK) {
            fprintf(stderr, "Debug request failed: %s\n", curl_easy_strerror(res));
        }
        
        curl_easy_cleanup(curl);
    }
    
    return 0;
}

// Request with retry functionality
int request_with_retry(const char *url, int max_retries) {
    CURL *curl;
    CURLcode res;
    int attempt;
    
    curl = curl_easy_init();
    if (!curl) {
        return -1;
    }
    
    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
    
    for (attempt = 0; attempt <= max_retries; attempt++) {
        printf("Attempt %d/%d: %s\n", attempt + 1, max_retries + 1, url);
        
        res = curl_easy_perform(curl);
        
        if (res == CURLE_OK) {
            long response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
            
            if (response_code == 200) {
                printf("Success: Request completed\n");
                break;
            } else if (response_code >= 500 && attempt < max_retries) {
                printf("Server error (%ld): Retrying in %d seconds\n", response_code, (attempt + 1) * 2);
                sleep((attempt + 1) * 2); // Exponential backoff
            } else {
                printf("HTTP error (%ld): Stopping retry\n", response_code);
                break;
            }
        } else if (attempt < max_retries) {
            printf("Connection error (%s): Retrying in %d seconds\n", curl_easy_strerror(res), (attempt + 1) * 2);
            sleep((attempt + 1) * 2);
        } else {
            printf("Maximum attempts reached: %s\n", curl_easy_strerror(res));
        }
    }
    
    curl_easy_cleanup(curl);
    return (res == CURLE_OK) ? 0 : -1;
}

Multi-Handle for Concurrent Processing

#include <curl/curl.h>

// Concurrent fetching of multiple URLs
struct url_data {
    char *url;
    char *data;
    size_t size;
};

int parallel_requests() {
    CURLM *multi_handle;
    CURLMcode mc;
    int still_running = 1;
    int msgs_left;
    CURLMsg *msg;
    
    const char *urls[] = {
        "https://api.example.com/users",
        "https://api.example.com/posts",
        "https://api.example.com/comments",
        NULL
    };
    
    struct url_data url_data[3];
    CURL *curl_handles[3];
    
    // Initialize multi handle
    multi_handle = curl_multi_init();
    
    // Create handles for each URL
    for (int i = 0; urls[i]; i++) {
        curl_handles[i] = curl_easy_init();
        
        url_data[i].url = (char*)urls[i];
        url_data[i].data = malloc(1);
        url_data[i].size = 0;
        
        curl_easy_setopt(curl_handles[i], CURLOPT_URL, urls[i]);
        curl_easy_setopt(curl_handles[i], CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
        curl_easy_setopt(curl_handles[i], CURLOPT_WRITEDATA, &url_data[i]);
        curl_easy_setopt(curl_handles[i], CURLOPT_PRIVATE, &url_data[i]);
        
        // Add to multi handle
        curl_multi_add_handle(multi_handle, curl_handles[i]);
    }
    
    // Start concurrent execution
    curl_multi_perform(multi_handle, &still_running);
    
    // Wait until completion
    while (still_running) {
        fd_set fdread, fdwrite, fdexcep;
        int maxfd = -1;
        long curl_timeo = -1;
        
        FD_ZERO(&fdread);
        FD_ZERO(&fdwrite);
        FD_ZERO(&fdexcep);
        
        // Get timeout
        curl_multi_timeout(multi_handle, &curl_timeo);
        if (curl_timeo < 0)
            curl_timeo = 1000;
        
        // Get file descriptors
        mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
        
        if (mc != CURLM_OK) {
            fprintf(stderr, "curl_multi_fdset failed: %s\n", curl_multi_strerror(mc));
            break;
        }
        
        if (maxfd == -1) {
            usleep(100000); // Wait 100ms
        } else {
            struct timeval timeout;
            timeout.tv_sec = curl_timeo / 1000;
            timeout.tv_usec = (curl_timeo % 1000) * 1000;
            
            int rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);
            if (rc < 0) {
                perror("select");
                break;
            }
        }
        
        curl_multi_perform(multi_handle, &still_running);
    }
    
    // Process results
    while ((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
        if (msg->msg == CURLMSG_DONE) {
            CURL *easy_handle = msg->easy_handle;
            CURLcode result = msg->data.result;
            struct url_data *data;
            
            curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, &data);
            
            if (result == CURLE_OK) {
                long response_code;
                curl_easy_getinfo(easy_handle, CURLINFO_RESPONSE_CODE, &response_code);
                printf("URL: %s (Status: %ld)\n", data->url, response_code);
                printf("Data: %.100s...\n", data->data); // Display first 100 characters
            } else {
                fprintf(stderr, "Error for %s: %s\n", data->url, curl_easy_strerror(result));
            }
            
            curl_multi_remove_handle(multi_handle, easy_handle);
            curl_easy_cleanup(easy_handle);
        }
    }
    
    // Cleanup
    curl_multi_cleanup(multi_handle);
    
    for (int i = 0; urls[i]; i++) {
        if (url_data[i].data) {
            free(url_data[i].data);
        }
    }
    
    return 0;
}

int main() {
    curl_global_init(CURL_GLOBAL_DEFAULT);
    
    comprehensive_error_handling();
    debug_enabled_request();
    request_with_retry("https://api.example.com/test", 3);
    parallel_requests();
    
    curl_global_cleanup();
    return 0;
}

File Upload and Download Features

#include <curl/curl.h>

// File upload
int upload_file(const char *url, const char *file_path) {
    CURL *curl;
    CURLcode res;
    FILE *file;
    curl_mime *mime;
    curl_mimepart *part;
    
    curl = curl_easy_init();
    if (!curl) {
        return -1;
    }
    
    file = fopen(file_path, "rb");
    if (!file) {
        curl_easy_cleanup(curl);
        return -1;
    }
    
    // File upload in MIME format
    mime = curl_mime_init(curl);
    part = curl_mime_addpart(mime);
    curl_mime_name(part, "file");
    curl_mime_filedata(part, file_path);
    
    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
    
    res = curl_easy_perform(curl);
    
    fclose(file);
    curl_mime_free(mime);
    curl_easy_cleanup(curl);
    
    return (res == CURLE_OK) ? 0 : -1;
}

// File download
static size_t write_file_callback(void *contents, size_t size, size_t nmemb, FILE *stream) {
    return fwrite(contents, size, nmemb, stream);
}

int download_file(const char *url, const char *output_path) {
    CURL *curl;
    CURLcode res;
    FILE *fp;
    
    curl = curl_easy_init();
    if (!curl) {
        return -1;
    }
    
    fp = fopen(output_path, "wb");
    if (!fp) {
        curl_easy_cleanup(curl);
        return -1;
    }
    
    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_file_callback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    
    res = curl_easy_perform(curl);
    
    fclose(fp);
    curl_easy_cleanup(curl);
    
    return (res == CURLE_OK) ? 0 : -1;
}