#include "cli.h"
#include <curl/curl.h>
typedef struct {
uint8_t *buf;
size_t len;
size_t cap;
} CurlBuf;
static size_t write_cb(void *data, size_t size, size_t nmemb, void *userp)
{
CurlBuf *b = userp;
size_t total = size * nmemb;
if (b->len + total >= b->cap) {
b->cap = (b->len + total) * 2 + 4096;
uint8_t *tmp = realloc(b->buf, b->cap);
if (!tmp) return 0;
b->buf = tmp;
}
memcpy(b->buf + b->len, data, total);
b->len += total;
return total;
}
uint8_t *fetch_url_bytes_ex(const char *url, size_t *out_len, char **effective_url_out)
{
CURL *curl = curl_easy_init();
if (!curl) return NULL;
CurlBuf b = { malloc(65536), 0, 65536 };
if (!b.buf) { curl_easy_cleanup(curl); return NULL; }
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_USERAGENT,
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &b);
CURLcode res = curl_easy_perform(curl);
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
if (effective_url_out) {
char *eff = NULL;
curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &eff);
*effective_url_out = eff ? strdup(eff) : NULL;
}
curl_easy_cleanup(curl);
if (res != CURLE_OK) {
fprintf(stderr, "curl: %s\n", curl_easy_strerror(res));
free(b.buf);
return NULL;
}
if (http_code >= 400) {
fprintf(stderr, "curl: HTTP %ld for %s\n", http_code, url);
free(b.buf);
return NULL;
}
*out_len = b.len;
return b.buf;
}
uint8_t *fetch_url_bytes(const char *url, size_t *out_len)
{
return fetch_url_bytes_ex(url, out_len, NULL);
}