Skip to content

Instantly share code, notes, and snippets.

@vinikira
Last active January 14, 2022 19:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vinikira/8b2670224ab06627643f86cf9b2135df to your computer and use it in GitHub Desktop.
Save vinikira/8b2670224ab06627643f86cf9b2135df to your computer and use it in GitHub Desktop.
Curl request and JSON Parsing in C
#!/bin/sh
set -xe
cc -Wall -Werror -std=c11 -pedantic -lcurl -ljson-c -o main main.c
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include <json-c/json.h>
struct ResponseBuffer {
char *payload;
size_t size;
};
int curl_callback(void *data, size_t size, size_t nmemb, void *buffer_in) {
size_t real_size = size * nmemb;
struct ResponseBuffer *p = (struct ResponseBuffer *) buffer_in;
char *temp = realloc(p->payload, p->size + real_size + 1);
if (temp == NULL) {
fprintf(stderr, "ERROR: Failed to expand buffer in curl_callback.\n");
free(p->payload);
return 1;
}
p->payload = temp;
memcpy(&(p->payload[p->size]), data, real_size);
p->size += real_size;
p->payload[p->size] = 0;
return real_size;
}
CURLcode make_curl_request(char *url, struct ResponseBuffer *rb) {
CURL *curl;
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: application/json");
headers = curl_slist_append(headers, "charset: utf-8");
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl == NULL) {
fprintf(stderr, "ERROR: Could not initialize curl.\n");
return 1;
}
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) rb);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 1);
CURLcode response_code = curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_slist_free_all(headers);
curl_global_cleanup();
return response_code;
}
int main(void) {
char url[] = "https://api.myip.com";
struct ResponseBuffer response_buffer;
response_buffer.payload = (char *) calloc(1, sizeof(response_buffer.payload));
if (response_buffer.payload == NULL) {
fprintf(stderr, "ERROR: Failed to allocate response buffer.\n");
return CURLE_FAILED_INIT;
}
response_buffer.size = 0;
CURLcode response_code = make_curl_request(url, &response_buffer);
if (response_code != CURLE_OK) {
fprintf(stderr, "ERROR: Request failed: %s\n", curl_easy_strerror(response_code));
return 1;
} else {
printf("DEBUG: Raw response: %d\n", response_code);
}
if (response_buffer.payload == NULL) {
fprintf(stderr, "ERROR: Failed to populate response buffer.");
return 1;
}
enum json_tokener_error jerr = json_tokener_success;
json_object *json = json_tokener_parse_verbose(response_buffer.payload, &jerr);
printf("DEBUG: Size - %zu\n", response_buffer.size);
printf("DEBUG: Payload - %s\n", response_buffer.payload);
printf("DEBUG: JSON parsed - %s\n", json_object_to_json_string(json));
free(response_buffer.payload);
struct json_object *ip;
struct json_object *country;
struct json_object *cc;
json_object_object_get_ex(json, "ip", &ip);
json_object_object_get_ex(json, "country", &country);
json_object_object_get_ex(json, "cc", &cc);
printf("INFO: Result: \n");
printf(" My ip: %s\n", json_object_get_string(ip));
printf(" My country: %s\n", json_object_get_string(country));
printf(" My country code: %s\n", json_object_get_string(cc));
json_object_put(json);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment