#include #include #include #include #include #include #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; }