Skip to content

Instantly share code, notes, and snippets.

@opsJson
Last active June 6, 2023 22:15
Show Gist options
  • Save opsJson/e50d3698f2a31dfb6510f79b074af77e to your computer and use it in GitHub Desktop.
Save opsJson/e50d3698f2a31dfb6510f79b074af77e to your computer and use it in GitHub Desktop.
C interface for libcurl.
#ifndef _GO_H_
#define _GO_H_
#include <curl/curl.h>
typedef struct {
char *headers;
char *body;
CURL *handle;
long int statuscode;
} GO_Response;
struct _GO_STRING {
char *ptr;
unsigned int size;
};
int _go_args_count(char *arg, ...) {
va_list args;
int i, size, count;
char flag;
va_start(args, arg);
if (va_arg(args, char *) == NULL) return 0;
va_end(args);
size = strlen(arg);
count = 1;
flag = 0;
if (size == 2) return 0;
for (i=0; i<size; i++) {
if ((i == 0 && arg[i] == '\"') || (i > 0 && arg[i] == '\"' && arg[i-1] != '\\')) {
flag = !flag;
}
if (flag) continue;
if (arg[i] == ',') count++;
}
return count;
}
static size_t _go_writefunction(void *data, size_t size, size_t nmemb, void *clientp) {
struct _GO_STRING *str = (struct _GO_STRING*)clientp;
char *aux;
if (str->size == 0) {
str->size = size * nmemb + 1;
str->ptr = malloc(str->size);
if (!str->ptr) return -1;
strncpy(str->ptr, data, str->size);
}
else {
str->size += size * nmemb;
aux = realloc(str->ptr, str->size);
if (!aux) {
free(str->ptr);
return -1;
}
str->ptr = aux;
strncat(str->ptr, data, size * nmemb);
}
return size * nmemb;
}
void GO_free(GO_Response *response) {
if (!response) return;
free(response->headers);
free(response->body);
free(response);
}
GO_Response *GO(char *method, char *url, char *body, curl_off_t size, int args_count, ...) {
int i;
CURL *curl;
CURLcode res;
va_list args;
GO_Response *response;
struct curl_slist *aux, *chunk = NULL;
struct _GO_STRING response_body = {0}, response_headers = {0};
if (!method || !url) return NULL;
va_start(args, args_count);
for (i=0; i<args_count; i++) {
aux = curl_slist_append(chunk, va_arg(args, char*));
if (!aux) {
if (chunk) curl_slist_free_all(chunk);
return NULL;
}
chunk = aux;
}
va_end(args);
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (!curl) {
curl_global_cleanup();
return NULL;
}
if (strcmp(method, "WS") == 0 || strcmp(method, "WSS") == 0) {
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
}
else curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method);
curl_easy_setopt(curl, CURLOPT_URL, url);
if (size == -1) {
size = strlen(body);
}
if (size != 0) {
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, size);
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, _go_writefunction);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &response_headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _go_writefunction);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body);
curl_easy_setopt(curl, CURLOPT_CAINFO , "cacert.pem");
res = curl_easy_perform(curl);
if (chunk) curl_slist_free_all(chunk);
if (res != CURLE_OK) {
curl_easy_cleanup(curl);
curl_global_cleanup();
return NULL;
}
if ((response = calloc(1, sizeof(GO_Response))) == NULL) return NULL;
response->handle = curl;
if (response_headers.size > 0) {
response->headers = response_headers.ptr;
response->headers[response_headers.size-1] = 0;
}
if (response_body.size > 0) {
response->body = response_body.ptr;
response->body[response_body.size-1] = 0;
}
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response->statuscode);
if (strcmp(method, "WS") == 0 || strcmp(method, "WSS") == 0) {
return response;
}
curl_easy_cleanup(curl);
curl_global_cleanup();
return response;
}
#define GO(method, url, body, size, ...) GO(method, url, body, size, _go_args_count(#__VA_ARGS__, __VA_ARGS__), __VA_ARGS__)
#endif /* _GO_H_ */
/*///////////////////////////////////
Testing:
///////////////////////////////////*/
int main(void) {
GO_Response *r = GO("GET", "https://github.com/", "", -1, NULL);
printf("Headers: %s\n\n", r->headers);
printf("Body: %s\n\n", r->body);
printf("Status Code: %i\n", (int)r->statuscode);
GO_free(r);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment