slimpack/lib/http.c
2025-03-08 23:22:10 +02:00

102 lines
2.0 KiB
C

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <curl/curl.h>
#include <stdlib.h>
#include <string.h>
#include "lib.h"
typedef struct {
char **segments;
size_t *sizes;
size_t n, cap;
} http_body_buff_t;
static size_t body_writer(char *ptr, size_t _, size_t size, void *pbuff) {
http_body_buff_t *buff = pbuff;
size_t new_cap = buff->cap;
while (buff->n >= new_cap) {
new_cap *= 2;
}
if (new_cap > buff->cap) {
buff->segments = realloc(buff->segments, sizeof(*buff->segments) * new_cap);
buff->sizes = realloc(buff->sizes, sizeof(*buff->sizes) * new_cap);
buff->cap = new_cap;
}
buff->segments[buff->n] = malloc(size);
memcpy(buff->segments[buff->n], ptr, size);
buff->sizes[buff->n] = size;
buff->n++;
return size;
}
static char *body_compress(http_body_buff_t buff, size_t *psize) {
size_t size = 0;
for (size_t i = 0; i < buff.n; i++) {
size += buff.sizes[i];
}
char *res = malloc(size + 1);
res[size] = 0;
size_t offset = 0;
for (size_t i = 0; i < buff.n; i++) {
memcpy(res + offset, buff.segments[i], buff.sizes[i]);
offset += buff.sizes[i];
free(buff.segments[i]);
}
free(buff.segments);
free(buff.sizes);
*psize = size;
return res;
}
static int lib_http_get(lua_State *ctx) {
const char *url = luaL_checkstring(ctx, 1);
http_body_buff_t buff = {
.segments = malloc(sizeof *buff.segments * 16),
.sizes = malloc(sizeof *buff.sizes * 16),
.n = 0,
.cap = 16,
};
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, body_writer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buff);
CURLcode code = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if (code != CURLE_OK) {
return luaL_error(ctx, "HTTP GET failed: %s", curl_easy_strerror(code));
}
size_t size;
char *body = body_compress(buff, &size);
lua_pushlstring(ctx, body, size);
free(body);
return 1;
}
int http_open_lib(lua_State *ctx) {
luaL_newlib(ctx, ((luaL_Reg[]) {
{ "get", lib_http_get },
{ NULL, NULL },
}));
return 1;
}