-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* For now just some curl wrapper for all sorts of HTTP requests and a main() for testing. * Also added a little sinatra webapp as server side to test all the http requests that the curl wrapper supports.
- Loading branch information
Showing
4 changed files
with
299 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
WARNFLAGS= -Wsystem-headers -Wall -W -Wno-unused-parameter \ | ||
-Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith \ | ||
-Wold-style-definition -Wreturn-type -Wwrite-strings \ | ||
-Wswitch -Wshadow -Wcast-align -Wchar-subscripts \ | ||
-Winline -Wnested-externs | ||
|
||
CFLAGS= -g3 -O0 $(WARNFLAGS) | ||
CC?= gcc | ||
|
||
all: | ||
$(CC) $(CFLAGS) http_json.c -o http_json -ljansson -lcurl | ||
|
||
clean: | ||
rm -f confrd | ||
|
||
realclean: clean | ||
rm -f *~ *.bak |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
#include <sys/types.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
|
||
#include <jansson.h> | ||
#include <curl/curl.h> | ||
|
||
#define METHOD_GET 0x00 | ||
#define METHOD_POST 0x01 | ||
#define METHOD_PUT 0x02 | ||
#define METHOD_PATCH 0x03 | ||
#define METHOD_DELETE 0x04 | ||
|
||
|
||
struct write_data { | ||
char *data; | ||
size_t maxsz; | ||
int pos; | ||
}; | ||
|
||
struct read_data { | ||
const char *data; | ||
size_t total_sz; | ||
int pos; | ||
}; | ||
|
||
|
||
static | ||
size_t | ||
_writedata(char *ptr, size_t size, size_t nmemb, void *priv) | ||
{ | ||
struct write_data *wd = priv; | ||
size_t wrsize = size*nmemb; | ||
|
||
if (wd->pos + wrsize >= wd->maxsz - 1) { | ||
fprintf(stderr, "out of buffer space\n"); | ||
/* Returning a value != size*nmemb signals error */ | ||
return 0; | ||
} | ||
|
||
memcpy(wd->data + wd->pos, ptr, wrsize); | ||
wd->pos += wrsize; | ||
|
||
return wrsize; | ||
} | ||
|
||
|
||
static | ||
size_t | ||
_readdata(void *ptr, size_t size, size_t nmemb, void *priv) | ||
{ | ||
struct read_data *rd = priv; | ||
size_t rdsize = size*nmemb; | ||
|
||
if (rd->total_sz < rdsize) | ||
rdsize = rd->total_sz; | ||
|
||
memcpy(ptr, rd->data + rd->pos, rdsize); | ||
rd->pos += rdsize; | ||
rd->total_sz -= rdsize; | ||
|
||
return rdsize; | ||
} | ||
|
||
|
||
static | ||
int | ||
req(const char *url, int method, const char *ctype, | ||
const char *data, size_t data_len, | ||
char *dest, size_t bufsz, size_t *sz) | ||
{ | ||
CURL *curl; | ||
CURLcode status; | ||
long code; | ||
int ret = 0; | ||
struct write_data wd; | ||
struct read_data rd; | ||
struct curl_slist *slist = NULL; | ||
char buf[256]; | ||
|
||
|
||
if ((curl = curl_easy_init()) == NULL) { | ||
fprintf(stderr, "Curl error\n"); | ||
return -1; | ||
} | ||
|
||
wd.data = dest; | ||
wd.maxsz = bufsz; | ||
wd.pos = 0; | ||
|
||
curl_easy_setopt(curl, CURLOPT_URL, url); | ||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _writedata); | ||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &wd); | ||
|
||
if (method != METHOD_GET && data != NULL && data_len > 0) { | ||
rd.data = data; | ||
rd.total_sz = data_len; | ||
rd.pos = 0; | ||
|
||
snprintf(buf, 256, "Content-Length: %ju", data_len); | ||
slist = curl_slist_append(slist, buf); | ||
|
||
curl_easy_setopt(curl, CURLOPT_READFUNCTION, _readdata); | ||
curl_easy_setopt(curl, CURLOPT_READDATA, &rd); | ||
} | ||
|
||
if (method == METHOD_POST) { | ||
curl_easy_setopt(curl, CURLOPT_POST, (method == METHOD_POST)); | ||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); | ||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data_len); | ||
} else if (method == METHOD_PUT || method == METHOD_PATCH) { | ||
curl_easy_setopt(curl, CURLOPT_PUT, 1); | ||
} | ||
|
||
if (method != METHOD_GET && ctype != NULL) { | ||
snprintf(buf, 256, "Content-Type: %s", ctype); | ||
slist = curl_slist_append(slist, buf); | ||
} | ||
|
||
if (method == METHOD_DELETE) { | ||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); | ||
} else if (method == METHOD_PATCH) { | ||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH"); | ||
} | ||
|
||
if (slist != NULL) { | ||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist); | ||
} | ||
|
||
status = curl_easy_perform(curl); | ||
|
||
if (slist != NULL) | ||
curl_slist_free_all(slist); | ||
|
||
if (status != 0) { | ||
fprintf(stderr, "curl err: %s\n", curl_easy_strerror(status)); | ||
ret = 1; | ||
goto out; | ||
} | ||
|
||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); | ||
if (code != 200) { | ||
fprintf(stderr, "Server error: %ld\n", code); | ||
ret = (int)code; | ||
goto out; | ||
} | ||
|
||
*sz = (size_t)wd.pos; | ||
|
||
out: | ||
curl_easy_cleanup(curl); | ||
curl_global_cleanup(); | ||
|
||
return ret; | ||
} | ||
|
||
|
||
int | ||
main(void) | ||
{ | ||
char url[1024]; | ||
char recv_buf[1024 * 1024]; | ||
char send_buf[1024 * 1024]; | ||
int error; | ||
size_t bytes_recvd; | ||
|
||
|
||
printf("test main\n"); | ||
|
||
snprintf(url, 1024, "http://127.0.0.1:4567/test"); | ||
snprintf(send_buf, 1024*1024, "{'message':'hello'}"); | ||
|
||
|
||
/* HTTP GET */ | ||
error = req(url, METHOD_GET, NULL, NULL, 0, recv_buf, sizeof(recv_buf), &bytes_recvd); | ||
if (error != 0) { | ||
fprintf(stderr, "Bailing out after GET\n"); | ||
exit(1); | ||
} | ||
|
||
recv_buf[bytes_recvd] = '\0'; | ||
printf("GET -> Received: %s\n", recv_buf); | ||
|
||
|
||
/* HTTP DELETE */ | ||
error = req(url, METHOD_DELETE, NULL, NULL, 0, recv_buf, sizeof(recv_buf), &bytes_recvd); | ||
if (error != 0) { | ||
fprintf(stderr, "Bailing out after DELETE\n"); | ||
exit(1); | ||
} | ||
|
||
recv_buf[bytes_recvd] = '\0'; | ||
printf("DELETE -> Received: %s\n", recv_buf); | ||
|
||
|
||
/* HTTP POST */ | ||
error = req(url, METHOD_POST, "application/json", send_buf, strlen(send_buf), recv_buf, sizeof(recv_buf), &bytes_recvd); | ||
if (error != 0) { | ||
fprintf(stderr, "Bailing out after POST\n"); | ||
exit(1); | ||
} | ||
|
||
recv_buf[bytes_recvd] = '\0'; | ||
printf("POST -> Received: %s\n", recv_buf); | ||
|
||
|
||
/* HTTP PUT */ | ||
error = req(url, METHOD_PUT, "application/json", send_buf, strlen(send_buf), recv_buf, sizeof(recv_buf), &bytes_recvd); | ||
if (error != 0) { | ||
fprintf(stderr, "Bailing out after PUT\n"); | ||
exit(1); | ||
} | ||
|
||
recv_buf[bytes_recvd] = '\0'; | ||
printf("PUT -> Received: %s\n", recv_buf); | ||
|
||
|
||
/* HTTP PATCH */ | ||
error = req(url, METHOD_PATCH, "application/json", send_buf, strlen(send_buf), recv_buf, sizeof(recv_buf), &bytes_recvd); | ||
if (error != 0) { | ||
fprintf(stderr, "Bailing out after PATCH\n"); | ||
exit(1); | ||
} | ||
|
||
recv_buf[bytes_recvd] = '\0'; | ||
printf("PATCH -> Received: %s\n", recv_buf); | ||
|
||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# A sample Gemfile | ||
source "https://rubygems.org" | ||
|
||
gem "sinatra", "~> 1.3.2" | ||
gem "json", "~> 1.6.6" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
require 'sinatra' | ||
require 'json' | ||
|
||
get '/hi' do | ||
"Hello world!" | ||
end | ||
|
||
get '/test' do | ||
"Message for you!" | ||
end | ||
|
||
|
||
delete '/test' do | ||
end | ||
|
||
|
||
post '/test' do | ||
content_type :json | ||
|
||
puts 'Content Type: ' << request.content_type | ||
puts 'Content Length: ' << request.content_length | ||
puts 'Request body: ' << request.body.read | ||
|
||
{ :key1 => 'value1', :key2 => 'value2' }.to_json | ||
end | ||
|
||
|
||
put '/test' do | ||
content_type :json | ||
|
||
puts 'Content Type: ' << request.content_type | ||
puts 'Content Length: ' << request.content_length | ||
puts 'Request body: ' << request.body.read | ||
|
||
{ :key3 => 'value3', :key4 => [1,2,3,4] }.to_json | ||
end | ||
|
||
|
||
patch '/test' do | ||
content_type :json | ||
|
||
puts 'Content Type: ' << request.content_type | ||
puts 'Content Length: ' << request.content_length | ||
puts 'Request body: ' << request.body.read | ||
|
||
{ :key3 => 'value3', :key4 => { :subkey1 => [1,2], :subkey2 => 'hi', :subkey3 => nil} }.to_json | ||
end |