kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

commit ab592d2a594c0b0b65ada770bc83931b069167b4
parent f4f8b1e8b02d434a81940ce40e3d79a1fba49691
Author: Joris Vink <joris@coders.se>
Date:   Sun,  3 Aug 2014 17:44:36 +0200

Move task_curl example to tasks and into the new build framework

Diffstat:
contrib/examples/task_curl/build.sh | 50--------------------------------------------------
contrib/examples/task_curl/example.c | 225-------------------------------------------------------------------------------
contrib/examples/task_curl/module.conf | 31-------------------------------
contrib/examples/tasks/README | 3+++
contrib/examples/tasks/conf/tasks.conf | 27+++++++++++++++++++++++++++
contrib/examples/tasks/src/tasks.c | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 255 insertions(+), 306 deletions(-)

diff --git a/contrib/examples/task_curl/build.sh b/contrib/examples/task_curl/build.sh @@ -1,50 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2013 Joris Vink <joris@coders.se> -# -# Kore module build script, use this as a base for building -# your own modules for kore. - -# The name of the module you will be building -MODULE=task_curl.so - -# The directory containing your module source. -SOURCE_DIR=. - -# Compiler settings. -CC=gcc -CFLAGS="-I. -I/usr/local/include -Wall -Wstrict-prototypes \ - -Wmissing-prototypes -Wmissing-declarations -Wshadow \ - -Wpointer-arith -Wcast-qual -Wsign-compare -g" - -OSNAME=$(uname -s | sed -e 's/[-_].*//g' | tr A-Z a-z) -if [ "${OSNAME}" = "darwin" ]; then - LDFLAGS="-dynamiclib -undefined suppress -flat_namespace -lcurl" -else - LDFLAGS="-L/usr/local/lib -shared -lcurl" -fi - -MODULE_BUILD_DATE=$(date +"%Y-%m-%d %H:%M:%S") - -### Begin building #### -echo "Building module ${MODULE}..." -rm -f ${MODULE} - -if [ ! -d .objs ]; then - mkdir .objs; -fi -rm -f .objs/* - -for src in `find ${SOURCE_DIR} -type f -name \*.c`; do - base=`basename $src`; - ${CC} ${CFLAGS} -fPIC -c $src -o .objs/${base}.o - if [ $? -ne 0 ]; then - echo "Build error, check above messages for clues."; - exit 1; - fi -done - -${CC} ${LDFLAGS} `find .objs -name \*.o -type f` -o ${MODULE} -echo "Building completed!" - -rm -rf .objs diff --git a/contrib/examples/task_curl/example.c b/contrib/examples/task_curl/example.c @@ -1,225 +0,0 @@ -/* - * Copyright (c) 2014 Joris Vink <joris@coders.se> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * In this example, we use the background tasks available in Kore - * to fire off a POST to our /post_back page handler containing - * the user argument that was passed to us in our GET request to /. - * - * This illustrates how Kore its background tasks in effect work and - * how to operate on the channel in order to pass data back and forth. - * - * You need libcurl installed for this to build (including headers) - * - * Compile using build.sh, afterwards start using: - * # kore -nc module.conf (depending on where kore is installed) - * - * Test using: - * # curl -k https://127.0.0.1:4443/?user=foobar - * - * If the result echo'd back matches what you specified, its all green. - */ - -#include <curl/curl.h> - -#include <kore/kore.h> -#include <kore/http.h> -#include <kore/tasks.h> - -int run_curl(struct kore_task *); -int post_back(struct http_request *); -int page_handler(struct http_request *); -size_t curl_write_cb(char *, size_t, size_t, void *); - -int -page_handler(struct http_request *req) -{ - u_int32_t len; - char *user, result[64]; - - /* - * Lets check if a task has been created yet, this is important - * as we only want to fire this off once and we will be called - * again once it has been created. - */ - if (req->task == NULL) { - /* Grab the user argument */ - http_populate_arguments(req); - if (!http_argument_get_string("user", &user, &len)) { - http_response(req, 500, "ERROR\n", 6); - return (KORE_RESULT_OK); - } - - /* - * Create a new task that will execute the run_curl() - * function and bind it to our request. - * - * Binding a task to a request means Kore will reschedule - * the page handler for that request to refire after the - * task has completed or when it writes on the task channel. - */ - kore_task_create(&req->task, run_curl); - kore_task_bind_request(req->task, req); - - /* - * Start the task and write the user we received in our - * GET request to its channel. - */ - kore_task_run(req->task); - kore_task_channel_write(req->task, user, len); - - /* - * Tell Kore to retry us later. - */ - return (KORE_RESULT_RETRY); - } - - /* - * Our page handler is scheduled to be called when either the - * task finishes or has written data onto the channel. - * - * In order to distuingish between the two we can inspect the - * state of the task. - */ - if (kore_task_state(req->task) != KORE_TASK_STATE_FINISHED) { - http_request_sleep(req); - return (KORE_RESULT_RETRY); - } - - /* - * Task is finished, check the result. - */ - if (kore_task_result(req->task) != KORE_RESULT_OK) { - kore_task_destroy(req->task); - http_response(req, 500, NULL, 0); - return (KORE_RESULT_OK); - } - - /* - * Lets read what our task has written to the channel. - * - * kore_task_channel_read() will return the amount of bytes - * that it received for that read. If the returned bytes is - * larger then the buffer you passed this is a sign of truncation - * and should be treated carefully. - */ - len = kore_task_channel_read(req->task, result, sizeof(result)); - if (len > sizeof(result)) { - http_response(req, 500, NULL, 0); - } else { - http_response(req, 200, result, len); - } - - /* We good, destroy the task. */ - kore_task_destroy(req->task); - - return (KORE_RESULT_OK); -} - -int -post_back(struct http_request *req) -{ - u_int32_t len; - char *user; - - if (req->method != HTTP_METHOD_POST) { - http_response(req, 500, NULL, 0); - return (KORE_RESULT_OK); - } - - http_populate_arguments(req); - if (!http_argument_get_string("user", &user, &len)) { - http_response(req, 500, NULL, 0); - return (KORE_RESULT_OK); - } - - /* Simply echo the supplied user argument back. */ - http_response(req, 200, user, len); - - return (KORE_RESULT_OK); -} - -/* - * This is the function that is executed by our task which is created - * in the page_handler() callback. - * - * It sets up a CURL POST request to /post_back passing along the - * user argument which it receives from its channel from page_handler(). - */ -int -run_curl(struct kore_task *t) -{ - int l; - struct kore_buf *b; - u_int32_t len; - CURLcode res; - u_int8_t *data; - CURL *curl; - char user[64], fields[128]; - - /* - * Read the channel in order to obtain the user argument - * that was written to it by page_handler(). - */ - len = kore_task_channel_read(t, user, sizeof(user)); - if (len > sizeof(user)) - return (KORE_RESULT_ERROR); - - l = snprintf(fields, sizeof(fields), "user=%.*s", len, user); - if (l == -1 || (size_t)l >= sizeof(fields)) - return (KORE_RESULT_ERROR); - - if ((curl = curl_easy_init()) == NULL) - return (KORE_RESULT_ERROR); - - b = kore_buf_create(128); - - /* Do CURL magic. */ - curl_easy_setopt(curl, CURLOPT_POST, 1); - curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, b); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, fields); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_cb); - curl_easy_setopt(curl, CURLOPT_URL, "https://127.0.0.1:4443/post_back"); - - res = curl_easy_perform(curl); - if (res != CURLE_OK) { - kore_buf_free(b); - curl_easy_cleanup(curl); - return (KORE_RESULT_ERROR); - } - - /* - * Grab the response from the CURL request and write the - * result back to the task channel. - */ - data = kore_buf_release(b, &len); - kore_task_channel_write(t, data, len); - kore_mem_free(data); - - return (KORE_RESULT_OK); -} - -size_t -curl_write_cb(char *ptr, size_t size, size_t nmemb, void *udata) -{ - struct kore_buf *b = udata; - - kore_buf_append(b, ptr, size * nmemb); - return (size * nmemb); -} diff --git a/contrib/examples/task_curl/module.conf b/contrib/examples/task_curl/module.conf @@ -1,31 +0,0 @@ -# Configuration for the contrib/examples/task_curl example. - -bind 127.0.0.1 4443 -chroot # configure this (ex: /home/joris/src/kore) -runas # configure this (ex: joris) - -workers 1 -pidfile kore.pid - -load ./task_curl.so - -ssl_no_compression - -validator v_user regex ^[a-z]*$ - -domain 127.0.0.1 { - certfile # configure this (ex: cert/server.crt) - certkey # configure this (ex: cert/server.key) - accesslog kore_access.log - - static / page_handler - static /post_back post_back - - params get / { - validate user v_user - } - - params post /post_back { - validate user v_user - } -} diff --git a/contrib/examples/tasks/README b/contrib/examples/tasks/README @@ -0,0 +1,3 @@ +Compile this example using: + +# env KORE_LDFLAGS="-I/path/to/libcurl -lcurl" diff --git a/contrib/examples/tasks/conf/tasks.conf b/contrib/examples/tasks/conf/tasks.conf @@ -0,0 +1,27 @@ +# Kore config for tasks example + +bind 127.0.0.1 8888 +pidfile kore.pid + +load ./tasks.so + +ssl_no_compression + +validator v_user regex ^[a-z]*$ + +domain 127.0.0.1 { + certfile cert/server.crt + certkey cert/server.key + accesslog kore_access.log + + static / page_handler + static /post_back post_back + + params get / { + validate user v_user + } + + params post /post_back { + validate user v_user + } +} diff --git a/contrib/examples/tasks/src/tasks.c b/contrib/examples/tasks/src/tasks.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2014 Joris Vink <joris@coders.se> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * In this example, we use the background tasks available in Kore + * to fire off a POST to our /post_back page handler containing + * the user argument that was passed to us in our GET request to /. + * + * This illustrates how Kore its background tasks in effect work and + * how to operate on the channel in order to pass data back and forth. + * + * You need libcurl installed for this to build (including headers) + * + * Compile using build.sh, afterwards start using: + * # kore -nc module.conf (depending on where kore is installed) + * + * Test using: + * # curl -k https://127.0.0.1:4443/?user=foobar + * + * If the result echo'd back matches what you specified, its all green. + */ + +#include <curl/curl.h> + +#include <kore/kore.h> +#include <kore/http.h> +#include <kore/tasks.h> + +int run_curl(struct kore_task *); +int post_back(struct http_request *); +int page_handler(struct http_request *); +size_t curl_write_cb(char *, size_t, size_t, void *); + +int +page_handler(struct http_request *req) +{ + u_int32_t len; + char *user, result[64]; + + /* + * Lets check if a task has been created yet, this is important + * as we only want to fire this off once and we will be called + * again once it has been created. + */ + if (req->task == NULL) { + /* Grab the user argument */ + http_populate_arguments(req); + if (!http_argument_get_string("user", &user, &len)) { + http_response(req, 500, "ERROR\n", 6); + return (KORE_RESULT_OK); + } + + /* + * Create a new task that will execute the run_curl() + * function and bind it to our request. + * + * Binding a task to a request means Kore will reschedule + * the page handler for that request to refire after the + * task has completed or when it writes on the task channel. + */ + kore_task_create(&req->task, run_curl); + kore_task_bind_request(req->task, req); + + /* + * Start the task and write the user we received in our + * GET request to its channel. + */ + kore_task_run(req->task); + kore_task_channel_write(req->task, user, len); + + /* + * Tell Kore to retry us later. + */ + return (KORE_RESULT_RETRY); + } + + /* + * Our page handler is scheduled to be called when either the + * task finishes or has written data onto the channel. + * + * In order to distuingish between the two we can inspect the + * state of the task. + */ + if (kore_task_state(req->task) != KORE_TASK_STATE_FINISHED) { + http_request_sleep(req); + return (KORE_RESULT_RETRY); + } + + /* + * Task is finished, check the result. + */ + if (kore_task_result(req->task) != KORE_RESULT_OK) { + kore_task_destroy(req->task); + http_response(req, 500, NULL, 0); + return (KORE_RESULT_OK); + } + + /* + * Lets read what our task has written to the channel. + * + * kore_task_channel_read() will return the amount of bytes + * that it received for that read. If the returned bytes is + * larger then the buffer you passed this is a sign of truncation + * and should be treated carefully. + */ + len = kore_task_channel_read(req->task, result, sizeof(result)); + if (len > sizeof(result)) { + http_response(req, 500, NULL, 0); + } else { + http_response(req, 200, result, len); + } + + /* We good, destroy the task. */ + kore_task_destroy(req->task); + + return (KORE_RESULT_OK); +} + +int +post_back(struct http_request *req) +{ + u_int32_t len; + char *user; + + if (req->method != HTTP_METHOD_POST) { + http_response(req, 500, NULL, 0); + return (KORE_RESULT_OK); + } + + http_populate_arguments(req); + if (!http_argument_get_string("user", &user, &len)) { + http_response(req, 500, NULL, 0); + return (KORE_RESULT_OK); + } + + /* Simply echo the supplied user argument back. */ + http_response(req, 200, user, len); + + return (KORE_RESULT_OK); +} + +/* + * This is the function that is executed by our task which is created + * in the page_handler() callback. + * + * It sets up a CURL POST request to /post_back passing along the + * user argument which it receives from its channel from page_handler(). + */ +int +run_curl(struct kore_task *t) +{ + int l; + struct kore_buf *b; + u_int32_t len; + CURLcode res; + u_int8_t *data; + CURL *curl; + char user[64], fields[128]; + + /* + * Read the channel in order to obtain the user argument + * that was written to it by page_handler(). + */ + len = kore_task_channel_read(t, user, sizeof(user)); + if (len > sizeof(user)) + return (KORE_RESULT_ERROR); + + l = snprintf(fields, sizeof(fields), "user=%.*s", len, user); + if (l == -1 || (size_t)l >= sizeof(fields)) + return (KORE_RESULT_ERROR); + + if ((curl = curl_easy_init()) == NULL) + return (KORE_RESULT_ERROR); + + b = kore_buf_create(128); + + /* Do CURL magic. */ + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, b); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, fields); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_cb); + curl_easy_setopt(curl, CURLOPT_URL, "https://127.0.0.1:8888/post_back"); + + res = curl_easy_perform(curl); + if (res != CURLE_OK) { + kore_buf_free(b); + curl_easy_cleanup(curl); + return (KORE_RESULT_ERROR); + } + + /* + * Grab the response from the CURL request and write the + * result back to the task channel. + */ + data = kore_buf_release(b, &len); + kore_task_channel_write(t, data, len); + kore_mem_free(data); + + return (KORE_RESULT_OK); +} + +size_t +curl_write_cb(char *ptr, size_t size, size_t nmemb, void *udata) +{ + struct kore_buf *b = udata; + + kore_buf_append(b, ptr, size * nmemb); + return (size * nmemb); +}