Skip to content

Instantly share code, notes, and snippets.

@svagionitis
Forked from aaronhurt/curltest.c
Last active September 27, 2020 11:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save svagionitis/6eea918d94bae34a7456 to your computer and use it in GitHub Desktop.
Save svagionitis/6eea918d94bae34a7456 to your computer and use it in GitHub Desktop.
example code using libcurl and json-c to post and parse a return from http://jsonplaceholder.typicode.com
/**
* example C code using libcurl and json-c
* to post and return a payload using
* http://jsonplaceholder.typicode.com
*
* Requirements:
*
* json-c - https://github.com/json-c/json-c
* libcurl - http://curl.haxx.se/libcurl/c
*
* Build:
*
* cc curltest.c -lcurl -ljson-c -o curltest
*
* Run:
*
* ./curltest
*
*/
/* standard includes */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
/* json-c (https://github.com/json-c/json-c) */
#include <json-c/json.h>
/* libcurl (http://curl.haxx.se/libcurl/c) */
#include <curl/curl.h>
struct curl_fetch_payload {
char *payload;
size_t size;
};
static size_t
curl_fetch_callback (void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct curl_fetch_payload *mem = (struct curl_fetch_payload *) userp;
char *tmp = NULL;
tmp = realloc (mem->payload, mem->size + realsize + 1);
if (tmp != NULL) {
mem->payload = tmp;
} else {
if (mem->payload) {
free (mem->payload);
mem->payload = NULL;
}
return 0;
}
/* Copy contents to buffer */
memcpy (&(mem->payload[mem->size]), contents, realsize);
/* Set ne buffer size */
mem->size += realsize;
/* Null termination */
mem->payload[mem->size] = 0;
return realsize;
}
/* fetch and return url body via curl */
static CURLcode
fetch_url_curl (CURL *curl_ctx, const char *url, struct curl_fetch_payload *fetch)
{
CURLcode rcode;
/* will be grown as needed by realloc from the callback */
fetch->payload = malloc (1);
if (fetch->payload == NULL) {
return CURLE_OUT_OF_MEMORY;
}
/* init size */
fetch->size = 0;
/* set url to fetch */
curl_easy_setopt (curl_ctx, CURLOPT_URL, url);
/* set calback function */
curl_easy_setopt (curl_ctx, CURLOPT_WRITEFUNCTION, curl_fetch_callback);
/* pass fetch struct pointer */
curl_easy_setopt (curl_ctx, CURLOPT_WRITEDATA, (void *) fetch);
/* some servers don't like requests that are made without a user-agent
field, so we provide one */
curl_easy_setopt (curl_ctx, CURLOPT_USERAGENT, "libcurl-agent/1.0");
/* set timeout to 90 seconds */
curl_easy_setopt (curl_ctx, CURLOPT_TIMEOUT, 90);
/* enable location redirects */
curl_easy_setopt (curl_ctx, CURLOPT_FOLLOWLOCATION, 1);
/* set maximum allowed redirects */
curl_easy_setopt (curl_ctx, CURLOPT_MAXREDIRS, 1);
/* make connection get closed at once after use */
curl_easy_setopt (curl_ctx, CURLOPT_FORBID_REUSE, 1);
/* fetch the url */
rcode = curl_easy_perform (curl_ctx);
return rcode;
}
int
post_json_curl (char **response, size_t *response_sz, const char *url, const char *json)
{
int ret = 0;
CURL *curl_ctx = NULL;
CURLcode rcode = 0, http_code = 0;
struct curl_slist *headers = NULL;
struct curl_fetch_payload fetch_response;
char *tmp;
if ( *response )
*response = NULL;
if (url == NULL || strlen (url) == 0) {
fprintf (stderr, "No URL specified.\n");
ret = -1;
goto out;
}
if (json == NULL || strlen (json) == 0) {
fprintf (stderr, "No json object specified.\n");
ret = -1;
goto out;
}
curl_ctx = curl_easy_init();
if (curl_ctx == NULL) {
fprintf (stderr, "Failed to create curl handle in fetch_session\n");
ret = -1;
goto out;
}
/* set content type */
headers = curl_slist_append (headers, "Accept: application/json");
headers = curl_slist_append (headers, "Content-Type: application/json");
/* set curl options */
curl_easy_setopt (curl_ctx, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt (curl_ctx, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt (curl_ctx, CURLOPT_POSTFIELDS, json);
/* fetch page and capture return code */
rcode = fetch_url_curl (curl_ctx, url, &fetch_response);
tmp = fetch_response.payload;
if (rcode != CURLE_OK || fetch_response.size < 1) {
fprintf (stderr, "Failed to post data to %s -- %s\n", url, curl_easy_strerror (rcode));
ret = rcode;
goto free_payload;
} else {
/* Get the HTTP code */
curl_easy_getinfo (curl_ctx, CURLINFO_RESPONSE_CODE, &http_code);
fetch_response.payload = tmp;
if (http_code != (CURLcode) 200)
ret += (int) http_code;
}
if (fetch_response.payload == NULL) {
fprintf (stderr, "Failed to populate payload.\n");
ret = -1;
goto free_payload;
}
*response = fetch_response.payload;
*response_sz = fetch_response.size;
goto out;
free_payload:
if (fetch_response.payload) {
free (fetch_response.payload);
fetch_response.payload = NULL;
}
out:
if (curl_ctx) {
curl_easy_cleanup (curl_ctx);
curl_ctx = NULL;
}
if (headers) {
curl_slist_free_all (headers);
headers = NULL;
}
return ret;
}
void
usage(char *argv0)
{
fprintf(stdout, "Usage: %s <URL> <JSON to POST>\n", argv0);
}
int main(int argc, char *argv[])
{
char *response = NULL;
size_t response_sz = 0;
if (argc != 3) {
usage(argv[0]);
return -1;
}
int ret = post_json_curl (&response, &response_sz, argv[1], argv[2]);
if (ret < 0) {
fprintf(stderr, "Error posting '%s' to '%s'\n", argv[2], argv[1]);
return -1;
}
fprintf (stdout, "Response: '%s' -- Size: %zu\n", response, response_sz);
/* exit */
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment