omdb/fetch.c

157 lines
3.7 KiB
C
Raw Permalink Normal View History

2025-12-13 06:22:27 +00:00
#include <curl/curl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fetch.h"
static char curl_errbuf[CURL_ERROR_SIZE] = {'\0'};
CURLU *init_curl_url(const char *restrict ustr) {
/* Just validate and add options directly to the request now. */
CURLU *url = curl_url();
CURLUcode ures;
if (url == NULL) {
fputs("Out of memory.\n", stderr);
exit(EXIT_FAILURE);
}
if ((ures = curl_url_set(url, CURLUPART_URL, ustr, 0)) != CURLUE_OK) {
fprintf(stderr, "Couldn't set url: %s\n", curl_url_strerror(ures));
return NULL;
}
return url;
}
/* Set a URL query parameter. */
void set_param(CURLU *restrict url, const char *restrict key,
char *restrict value) {
CURLUcode err;
char param[256];
snprintf(param, sizeof param, "%s=%s", key, value);
if ((err = curl_url_set(url, CURLUPART_QUERY, param,
CURLU_APPENDQUERY | CURLU_URLENCODE)) != CURLUE_OK) {
fprintf(stderr, "Error setting url param '%s': %s\n", key,
curl_url_strerror(err));
exit(EXIT_FAILURE);
}
}
/* Just print the url if needed for debugging. */
void print_url(CURLU *restrict url) {
char *url_string = NULL;
curl_url_get(url, CURLUPART_URL, &url_string, 0);
printf("%s\n", url_string);
curl_free(url_string);
}
2025-12-13 06:22:27 +00:00
struct fetch *fetch_init(void) {
CURLcode res;
CURL *handle;
struct fetch *fh = NULL;
/*
* TODO: Not sure if calling this possibly more than once can cause
* an issue or not.
*/
if ((res = curl_global_init(CURL_GLOBAL_DEFAULT)) != CURLE_OK) {
fprintf(stderr, "Could not initialize curl: %s\n", curl_easy_strerror(res));
exit(EXIT_FAILURE);
}
handle = curl_easy_init();
if ((res = curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curl_errbuf)) !=
CURLE_OK) {
fprintf(stderr, "Error setting up error buffer: %s\n",
curl_easy_strerror(res));
curl_easy_cleanup(handle);
exit(EXIT_FAILURE);
}
if ((fh = malloc(sizeof *fh)) == NULL) {
fputs("Out of memory.\n", stderr);
exit(EXIT_FAILURE);
}
fh->handle = handle;
return fh;
}
void fetch_cleanup(struct fetch *restrict f) {
/* Don't even dignify this with a response */
if (f == NULL)
return;
curl_easy_cleanup(f->handle);
free(f);
}
size_t fetch_cb(void *ptr, size_t size, size_t nmemb, void *data) {
struct response *resp = (struct response *)data;
size_t real_size = size * nmemb;
if ((resp->data = realloc(resp->data, resp->size + real_size + 1)) == NULL) {
fputs("Out of memory.\n", stderr);
exit(EXIT_FAILURE);
}
// printf("Wrote %zd bytes\n", real_size);
2025-12-13 06:22:27 +00:00
memcpy(resp->data + resp->size, ptr, real_size);
resp->size += real_size;
resp->data[resp->size] = '\0';
return real_size;
}
struct response *fetch(struct fetch *restrict f, CURLU *restrict url) {
struct response *resp = NULL;
if (curl_easy_setopt(f->handle, CURLOPT_WRITEFUNCTION, fetch_cb) != CURLE_OK)
goto call_fetch_fail;
if (curl_easy_setopt(f->handle, CURLOPT_CURLU, url) != CURLE_OK)
goto call_fetch_fail;
if ((resp = malloc(sizeof *resp)) == NULL) {
fputs("Out of memory.", stderr);
exit(EXIT_FAILURE);
}
memset(resp, 0, sizeof *resp);
if (curl_easy_setopt(f->handle, CURLOPT_WRITEDATA, (void *)resp) != CURLE_OK)
goto call_fetch_fail;
if (curl_easy_perform(f->handle) != CURLE_OK)
goto call_fetch_fail;
if (curl_easy_getinfo(f->handle, CURLINFO_CONTENT_TYPE,
&resp->content_type) != CURLE_OK)
goto call_fetch_fail;
// printf("CONTENT TYPE: %s\n", resp->content_type);
2025-12-13 06:22:27 +00:00
return resp;
call_fetch_fail:
if (resp != NULL)
free(resp);
fputs(curl_errbuf, stderr);
return NULL;
}
void response_cleanup(struct response *resp) {
if (resp != NULL) {
free(resp->data);
free(resp);
}
}