#include "http.h" #include #include #include struct http_client_t { CURL *curl; char *base_url; char *bearer_token; long timeout; long connect_timeout; }; static size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) { size_t total_size = size * nmemb; struct { char *data; size_t size; } *buffer = userp; char *ptr = realloc(buffer->data, buffer->size + total_size + 1); if (!ptr) return 0; buffer->data = ptr; memcpy(&(buffer->data[buffer->size]), contents, total_size); buffer->size += total_size; buffer->data[buffer->size] = '\0'; return total_size; } http_client_handle http_create(const char *base_url) { struct http_client_t *client = calloc(1, sizeof(struct http_client_t)); if (!client) return NULL; client->curl = curl_easy_init(); if (!client->curl) { free(client); return NULL; } client->base_url = base_url ? strdup(base_url) : NULL; client->bearer_token = NULL; client->timeout = 0; client->connect_timeout = 0; curl_easy_setopt(client->curl, CURLOPT_WRITEFUNCTION, write_callback); return client; } void http_destroy(http_client_handle client) { if (!client) return; if (client->curl) curl_easy_cleanup(client->curl); if (client->base_url) free(client->base_url); if (client->bearer_token) free(client->bearer_token); free(client); } void http_set_bearer_token(http_client_handle client, const char *token) { if (!client) return; if (client->bearer_token) free(client->bearer_token); client->bearer_token = token ? strdup(token) : NULL; } void http_set_timeout(http_client_handle client, long timeout_seconds) { if (!client) return; client->timeout = timeout_seconds; } void http_set_connect_timeout(http_client_handle client, long timeout_seconds) { if (!client) return; client->connect_timeout = timeout_seconds; } static const char *method_string(http_method_t method) { switch (method) { case HTTP_METHOD_GET: return "GET"; case HTTP_METHOD_POST: return "POST"; case HTTP_METHOD_PUT: return "PUT"; case HTTP_METHOD_DELETE: return "DELETE"; default: return "GET"; } } r_status_t http_request(http_client_handle client, http_method_t method, const char *path, const void *body, size_t body_size, char **response, int *response_code) { if (!client || !client->curl) return R_ERROR_INVALID_ARG; struct { char *data; size_t size; } buffer = {NULL, 0}; curl_easy_setopt(client->curl, CURLOPT_WRITEDATA, &buffer); char url[4096]; if (client->base_url) { snprintf(url, sizeof(url), "%s%s", client->base_url, path); } else { strncpy(url, path, sizeof(url) - 1); url[sizeof(url) - 1] = '\0'; } curl_easy_setopt(client->curl, CURLOPT_URL, url); curl_easy_setopt(client->curl, CURLOPT_CUSTOMREQUEST, method_string(method)); if (client->bearer_token) { char auth_header[512]; snprintf(auth_header, sizeof(auth_header), "Authorization: Bearer %s", client->bearer_token); struct curl_slist *headers = NULL; headers = curl_slist_append(headers, auth_header); curl_easy_setopt(client->curl, CURLOPT_HTTPHEADER, headers); } if (client->timeout > 0) { curl_easy_setopt(client->curl, CURLOPT_TIMEOUT, client->timeout); } if (client->connect_timeout > 0) { curl_easy_setopt(client->curl, CURLOPT_CONNECTTIMEOUT, client->connect_timeout); } if (body && body_size > 0) { curl_easy_setopt(client->curl, CURLOPT_POSTFIELDSIZE, (long)body_size); curl_easy_setopt(client->curl, CURLOPT_POSTFIELDS, body); } CURLcode res = curl_easy_perform(client->curl); if (res != CURLE_OK) { if (buffer.data) free(buffer.data); return R_ERROR_HTTP_CONNECTION; } long code; curl_easy_getinfo(client->curl, CURLINFO_RESPONSE_CODE, &code); if (response_code) *response_code = (int)code; if (response) { *response = buffer.data ? buffer.data : strdup(""); } else { if (buffer.data) free(buffer.data); } return R_SUCCESS; } r_status_t http_get(http_client_handle client, const char *path, char **response) { int code; return http_request(client, HTTP_METHOD_GET, path, NULL, 0, response, &code); } r_status_t http_post(http_client_handle client, const char *path, const char *body, char **response) { int code; size_t body_size = body ? strlen(body) : 0; return http_request(client, HTTP_METHOD_POST, path, body, body_size, response, &code); } r_status_t http_post_json(http_client_handle client, const char *path, const char *json, char **response) { return http_post(client, path, json, response); }