165 lines
4.8 KiB
C
165 lines
4.8 KiB
C
#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);
|
||
|
|
}
|