Files
r/src/impl/http_curl.c
T

165 lines
4.8 KiB
C
Raw Normal View History

#include "http.h"
#include <curl/curl.h>
#include <stdlib.h>
#include <string.h>
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);
}