From 77a9d0050c16ffd6c4d3a2b17533954d560bb019 Mon Sep 17 00:00:00 2001 From: nirav Date: Fri, 8 Mar 2019 01:40:21 +0530 Subject: Add async http post support --- Makefile | 5 ++- src/auth.c | 74 ++++++++++++++++++++++++++++++++----- src/auth.h | 1 + src/http.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/http.h | 1 + src/main.c | 1 + src/window.c | 3 -- 7 files changed, 181 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index 663d8e6..f2f4921 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,9 @@ PKGCONFIG=$(shell which pkg-config) CFLAGS=-o2 -pipe CFLAGS+=-Wall -Wextra -Wno-unused-parameter -CFLAGS+=$(shell $(PKGCONFIG) --cflags gtk+-3.0 libcurl jansson) -LDFLAGS+=$(shell $(PKGCONFIG) --libs gtk+-3.0 libcurl jansson) +CFLAGS+=$(shell $(PKGCONFIG) --cflags gtk+-3.0 libcurl jansson) -lpthread +LDFLAGS+=$(shell $(PKGCONFIG) --libs gtk+-3.0 libcurl jansson) -lpthread +LDFLAGS+= DESTDIR= PREFIX=/usr/local BINDIR=$(PREFIX)/bin diff --git a/src/auth.c b/src/auth.c index b0ba98c..901a863 100644 --- a/src/auth.c +++ b/src/auth.c @@ -10,17 +10,62 @@ char *instance_domain; char *auth_token; +char *req_data; +char *client_id; +char *client_secret; static char *protocol = "https://"; static char *app_register_url = "/api/v1/apps"; +static void register_callback(char *data) +{ + if (req_data) + free(req_data); + if (!data) { + fprintf(stderr, "register_callback(): null data\n"); + return; + } + + json_t *root; + root = json_loads(data, 0, NULL); + free(data); + if (!root) { + fprintf(stderr, "register_callback(): failed to parse json\n"); + return; + } + + if (!json_is_object(root)) { + fprintf(stderr, "register_callback(): json root is not object\n"); + json_decref(root); + return; + } + + json_t *cid = json_object_get(root, "client_id"); + json_t *csec = json_object_get(root, "client_secret"); + if (!json_is_string(cid) || !json_is_string(csec)) { + fprintf(stderr, + "register_callback(): invalid client_id or client_secret\n"); + json_decref(root); + return; + } + + client_id = strdup(json_string_value(cid)); + client_secret = strdup(json_string_value(csec)); + json_decref(root); + if (strlen(client_id) < 1 || strlen(client_secret) < 1) { + fprintf(stderr, + "register_callback(): invalid client_id or client_secret\n"); + return; + } + + printf("cid: %s\ncsec: %s\n", client_id, client_secret); +} + int register_app(char *instance) { json_t *root; json_error_t error; char *url; - char *req_data; - char *res_data; root = json_pack_ex(&error, 1, "{s:s, s:s, s:s}", "client_name", CLIENT_NAME, "redirect_uris", "urn:ietf:wg:oauth:2.0:oob", "scopes", @@ -39,22 +84,33 @@ int register_app(char *instance) return -1; } - size_t s = strlen(protocol) + strlen(instance) + strlen(app_register_url) + 1; + size_t s = + strlen(protocol) + strlen(instance) + strlen(app_register_url) + 1; url = malloc(s); if (!url) { err(1, "register_app(): "); } sprintf(url, "%s%s%s", protocol, instance, app_register_url); - res_data = post_request(url, req_data); - if (!res_data) { + if (http_post_async(url, req_data, ®ister_callback)) { + fprintf(stderr, "register_app(): failed to send http request\n"); free(req_data); return -1; } - printf("res: \n%s\n", res_data); - - free(req_data); - free(res_data); return 0; } + +void auth_cleanup() +{ + if (instance_domain) + free(instance_domain); + if (auth_token) + free(auth_token); + if (req_data) + free(req_data); + if (client_id) + free(client_id); + if (client_secret) + free(client_secret); +} diff --git a/src/auth.h b/src/auth.h index d3e03ec..e5e597c 100644 --- a/src/auth.h +++ b/src/auth.h @@ -5,6 +5,7 @@ extern char *instance_domain; extern char *auth_token; int register_app(char *instance); +void auth_cleanup(); #endif diff --git a/src/http.c b/src/http.c index 35130af..a865f96 100644 --- a/src/http.c +++ b/src/http.c @@ -1,6 +1,8 @@ #define _POSIX_C_SOURCE 200809L #include #include +#include +#include #include #include "string-util.h" #include "auth.h" @@ -41,6 +43,7 @@ static size_t write_response(void *ptr, size_t size, size_t nmemb, void *stream) char *get_request(const char *url) { + CURL *curl = NULL; CURLcode status; struct curl_slist *headers = NULL; @@ -58,8 +61,10 @@ char *get_request(const char *url) struct write_result write_result = {.data = data, .pos = 0}; if (auth_token) { - char *auth_header_val = malloc(strlen(AUTH_HEADER_STR_PREFIX) + strlen(auth_token) + 1); - strlcpy(auth_header_val, AUTH_HEADER_STR_PREFIX, sizeof(auth_header_val)); + char *auth_header_val = + malloc(strlen(AUTH_HEADER_STR_PREFIX) + strlen(auth_token) + 1); + strlcpy(auth_header_val, AUTH_HEADER_STR_PREFIX, + sizeof(auth_header_val)); strlcat(auth_header_val, auth_token, sizeof(auth_header_val)); headers = curl_slist_append(headers, auth_header_val); } @@ -71,7 +76,8 @@ char *get_request(const char *url) status = curl_easy_perform(curl); if (status != 0) { - fprintf(stderr, "get_request(): unable to request data from %s: %s\n", url, curl_easy_strerror(status)); + fprintf(stderr, "get_request(): unable to request data from %s: %s\n", + url, curl_easy_strerror(status)); goto error; } @@ -105,7 +111,6 @@ char *post_request(const char *url, char *post_data) char *data = NULL; long code; - curl = curl_easy_init(); if (!curl) goto error; @@ -117,8 +122,10 @@ char *post_request(const char *url, char *post_data) struct write_result write_result = {.data = data, .pos = 0}; if (auth_token) { - char *auth_header_val = malloc(strlen(AUTH_HEADER_STR_PREFIX) + strlen(auth_token) + 1); - strlcpy(auth_header_val, AUTH_HEADER_STR_PREFIX, sizeof(auth_header_val)); + char *auth_header_val = + malloc(strlen(AUTH_HEADER_STR_PREFIX) + strlen(auth_token) + 1); + strlcpy(auth_header_val, AUTH_HEADER_STR_PREFIX, + sizeof(auth_header_val)); strlcat(auth_header_val, auth_token, sizeof(auth_header_val)); headers = curl_slist_append(headers, auth_header_val); } @@ -135,7 +142,8 @@ char *post_request(const char *url, char *post_data) status = curl_easy_perform(curl); if (status != 0) { - fprintf(stderr, "post_request(): unable to request data from %s: %s\n", url, curl_easy_strerror(status)); + fprintf(stderr, "post_request(): unable to request data from %s: %s\n", + url, curl_easy_strerror(status)); goto error; } @@ -160,3 +168,98 @@ error: curl_easy_cleanup(curl); return NULL; } + +struct post_request_arg { + char *url; + char *post_data; + void (*callback)(char *); +}; + +void *post_one_url(void *arg) +{ + + struct post_request_arg *req_args = (struct post_request_arg *)arg; + CURL *curl = NULL; + CURLcode status; + struct curl_slist *headers = NULL; + char *data = NULL; + long code; + + curl = curl_easy_init(); + if (!curl) + goto error; + + data = malloc(BUFFER_SIZE); + if (!data) + goto error; + + struct write_result write_result = {.data = data, .pos = 0}; + + if (auth_token) { + char *auth_header_val = + malloc(strlen(AUTH_HEADER_STR_PREFIX) + strlen(auth_token) + 1); + strlcpy(auth_header_val, AUTH_HEADER_STR_PREFIX, + sizeof(auth_header_val)); + strlcat(auth_header_val, auth_token, sizeof(auth_header_val)); + headers = curl_slist_append(headers, auth_header_val); + } + if (req_args->post_data) { + char *content_type_header_val = "Content-Type: application/json"; + headers = curl_slist_append(headers, content_type_header_val); + } + + curl_easy_setopt(curl, CURLOPT_URL, req_args->url); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_response); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_result); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req_args->post_data); + + status = curl_easy_perform(curl); + if (status != 0) { + fprintf(stderr, "post_request(): unable to request data from %s: %s\n", + req_args->url, curl_easy_strerror(status)); + goto error; + } + + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); + if (code != 200) { + fprintf(stderr, "post_request(): server responded with code %ld\n", code); + goto error; + } + + data[write_result.pos] = '\0'; + + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + + (*(req_args->callback))(data); + return NULL; + +error: + if (data) + free(data); + if (headers) + curl_slist_free_all(headers); + if (curl) + curl_easy_cleanup(curl); + + (*(req_args->callback))(NULL); + return NULL; +} + +int http_post_async(char *url, char *post_data, void (*callback)(char *)) +{ + struct post_request_arg *arg; + pthread_t t; + + arg = calloc(1, sizeof(struct post_request_arg)); + if (!arg) { + err(1, "http_post_async(): calloc failed"); + return -1; + } + arg->url = url; + arg->post_data = post_data; + arg->callback = callback; + + return pthread_create(&t, NULL, post_one_url, arg); +} diff --git a/src/http.h b/src/http.h index d7ba313..32828db 100644 --- a/src/http.h +++ b/src/http.h @@ -5,5 +5,6 @@ int http_init(); void http_cleanup(); char *get_request(const char *url); char *post_request(const char *url, char *data); +int http_post_async(char *url, char *post_data, void (*callback)(char *)); #endif diff --git a/src/main.c b/src/main.c index 69778bd..3db9eb6 100644 --- a/src/main.c +++ b/src/main.c @@ -86,6 +86,7 @@ int main(int argc, char **argv) g_object_unref(app); http_cleanup(); + auth_cleanup(); return status; diff --git a/src/window.c b/src/window.c index 02c6073..831be60 100644 --- a/src/window.c +++ b/src/window.c @@ -26,6 +26,3 @@ void create_main_window() gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(scrolled_window)); gtk_widget_show_all(GTK_WIDGET(window)); } - - - -- cgit v1.2.3