Skip to content

Instantly share code, notes, and snippets.

@noonat
Last active August 29, 2015 14:02
Show Gist options
  • Save noonat/cbc4192debe7894b1514 to your computer and use it in GitHub Desktop.
Save noonat/cbc4192debe7894b1514 to your computer and use it in GitHub Desktop.
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include "http.h"
int http_response_init(http_response_t * const response)
{
assert(response);
response->buffer_size = 1024;
response->buffer = malloc(response->buffer_size);
assert(response->buffer);
response->buffer_ptr = response->buffer;
return 0;
}
int http_response_free(http_response_t * const response)
{
assert(response != NULL);
if (response->buffer) {
free(response->buffer);
response->buffer = NULL;
}
response->buffer_ptr = NULL;
response->buffer_size = 0;
return 0;
}
static size_t _write_callback(char * data,
size_t item_size,
size_t num_items,
void * user_data)
{
http_response_t * const response = (http_response_t *)user_data;
size_t data_size = item_size * num_items;
size_t buffer_used_size = response->buffer_ptr - response->buffer;
if ((response->buffer_size - buffer_used_size) < data_size + 1) {
// buffer doesn't have enough space for the data, realloc
size_t realloc_size = response->buffer_size;
while ((realloc_size - buffer_used_size) < data_size + 1) {
realloc_size *= 2;
}
response->buffer = realloc(response->buffer, realloc_size);
assert(response->buffer);
response->buffer_size = realloc_size;
response->buffer_ptr = response->buffer + buffer_used_size;
}
memcpy(response->buffer_ptr, data, data_size);
response->buffer_ptr += data_size;
*response->buffer_ptr = 0;
return data_size;
}
// Perform an HTTP request to the url and store the response body in response.
// Returns zero on success, or a negative value for an error.
int http_get(const char * const url,
http_response_t * const response)
{
assert(response);
assert(response->buffer);
CURL * const curl = curl_easy_init();
if (!curl) {
fprintf(stderr, "curl_easy_init() error\n");
return -1;
}
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, response);
CURLcode result = curl_easy_perform(curl);
if (result != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() error: %s\n",
curl_easy_strerror(result));
curl_easy_cleanup(curl);
return -1;
}
curl_easy_cleanup(curl);
return 0;
}
// Perform an HTTP request to the url and parse the response as JSON.
// Returns the Jansson JSON object, or NULL for an error.
json_t * http_get_json(const char * const url)
{
http_response_t response;
if (http_response_init(&response) < 0) {
return NULL;
}
if (http_get(url, &response) < 0) {
http_response_free(&response);
return NULL;
}
json_error_t error;
json_t * const json = json_loads(response.buffer, 0, &error);
http_response_free(&response);
if (!json) {
fprintf(stderr, "http_get_json: JSON error on line %d: %s\n",
error.line, error.text);
return NULL;
}
return json;
}
#pragma once
#include <jansson.h>
typedef struct {
char * buffer;
char * buffer_ptr;
size_t buffer_size;
} http_response_t;
int http_response_init(http_response_t * const response);
int http_response_free(http_response_t * const response);
int http_get(const char * const url,
http_response_t * const response);
json_t * http_get_json(const char * const url);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment