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.
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
Topics
Star History
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;
}