commit 55b344f1c3826a9303927cc0d3d7e5dde59c0c65
parent 93fa404470cd0ea12015471a6c035bdd61225d08
Author: Joris Vink <joris@coders.se>
Date: Sun, 3 Aug 2014 17:47:29 +0200
Redo last move, but properly this time
Diffstat:
28 files changed, 872 insertions(+), 872 deletions(-)
diff --git a/examples/examples/generic/assets/index.html b/examples/examples/generic/assets/index.html
@@ -1,15 +0,0 @@
-<!DOCTYPE>
-<html>
-<head>
- <link rel="stylesheet" href="/css/style.css" type="text/css">
- <title>Your KORE module worked!</title>
-</head>
-
-<body>
-
-<div class="content">
- <p>Your first Kore module worked.</p>
-</div>
-
-</body>
-</html>
diff --git a/examples/examples/generic/assets/intro.jpg b/examples/examples/generic/assets/intro.jpg
Binary files differ.
diff --git a/examples/examples/generic/assets/params.html b/examples/examples/generic/assets/params.html
@@ -1,33 +0,0 @@
-<!DOCTYPE>
-<html>
-<head>
- <link rel="stylesheet" href="/css/style.css" type="text/css">
- <title>Kore params test</title>
-</head>
-
-<body style="overflow: auto">
-
-<div class="content" style="font-size: 12px; font-weight: normal">
- <p>You can pass one GET parameter (arg1), any other GET parameter will
- be filtered out</p>
- <p>Only two out of the three input fields will be visible to Kore.</p>
- <p>The first field accepts the input "test"</p>
- <p>The second field accepts anything like /test/[a-z]*</p>
- <p>The third field will be removed by Kore, as it is not in the params
- block configured for this page.</p>
- <form method="POST">
- <input type="input" name="test1" value="$test1$">
- <input type="input" name="test2" value="$test2$">
- <input type="input" name="test3" value="$test3$">
- <input type="submit">
- </form>
-
- <p style="font-size: 12px; font-weight: normal">GET param arg1: $arg1$</p>
- <p style="font-size: 12px; font-weight: normal">GET param arg2: $arg2$</p>
- <p style="font-size: 12px; font-weight: normal">test1: $test1$</p>
- <p style="font-size: 12px; font-weight: normal">test2: $test2$</p>
- <p style="font-size: 12px; font-weight: normal">test3: $test3$</p>
-</div>
-
-</body>
-</html>
diff --git a/examples/examples/generic/assets/private.html b/examples/examples/generic/assets/private.html
@@ -1,16 +0,0 @@
-<!DOCTYPE>
-<html>
-<head>
- <link rel="stylesheet" href="/css/style.css" type="text/css">
- <title>Kore Authentication tests</title>
-</head>
-
-<body>
-
-<div class="content">
- <p style="font-size: small">The cookie session_id should now be set.</p>
- <p style="font-size: small">You can continue to <a href="/private/test">view page handler in auth block</a></p>
-</div>
-
-</body>
-</html>
diff --git a/examples/examples/generic/assets/private_test.html b/examples/examples/generic/assets/private_test.html
@@ -1,15 +0,0 @@
-<!DOCTYPE>
-<html>
-<head>
- <link rel="stylesheet" href="/css/style.css" type="text/css">
- <title>Kore Authentication tests</title>
-</head>
-
-<body>
-
-<div class="content">
- <p style="font-size: small">If you see this, the authentication worked. This page should redirect back to /private once you remove your session_id cookie.</p>
-</div>
-
-</body>
-</html>
diff --git a/examples/examples/generic/assets/style.css b/examples/examples/generic/assets/style.css
@@ -1,16 +0,0 @@
-body {
- width: 100%;
- margin: 0px;
- color: #000;
- overflow: hidden;
- background-color: #fff;
-}
-
-.content {
- width: 800px;
- margin-left: auto;
- margin-right: auto;
- margin-top: 100px;
- font-size: 60px;
- text-align: center;
-}
diff --git a/examples/examples/generic/assets/upload.html b/examples/examples/generic/assets/upload.html
@@ -1,22 +0,0 @@
-<!DOCTYPE>
-<html>
-<head>
- <link rel="stylesheet" href="/css/style.css" type="text/css">
- <title>Kore upload test</title>
-</head>
-
-<body style="overflow: auto">
-
-<div class="content">
- <form method="POST" enctype="multipart/form-data">
- <input type="input" name="firstname">
- <input type="file" name="file">
- <input type="submit" value="upload">
- </form>
-
- <p style="font-size: 12px; font-weight: normal">$upload$</p>
- <p style="font-size: 12px; font-weight: normal">$firstname$</p>
-</div>
-
-</body>
-</html>
diff --git a/examples/examples/generic/conf/generic.conf b/examples/examples/generic/conf/generic.conf
@@ -1,49 +0,0 @@
-# Placeholder configuration
-
-bind 127.0.0.1 8888
-pidfile kore.pid
-
-load ./generic.so example_load
-
-validator v_example function v_example_func
-validator v_regex regex ^/test/[a-z]*$
-validator v_number regex ^[0-9]*$
-validator v_session function v_session_validate
-
-ssl_no_compression
-
-authentication auth_example {
- authentication_type cookie
- authentication_value session_id
- authentication_validator v_session
- authentication_uri /private
-}
-
-domain 127.0.0.1 {
- certfile cert/server.crt
- certkey cert/server.key
- accesslog kore_access.log
-
- static /css/style.css serve_style_css
- static / serve_index
- static /intro.jpg serve_intro
- static /b64test serve_b64test
- static /spdy-reset serve_spdyreset
- static /upload serve_file_upload
- static /lock-test serve_lock_test
- static /validator serve_validator
- static /params-test serve_params_test
- static /private serve_private
-
- static /private/test serve_private_test auth_example
-
- params post /params-test {
- validate test1 v_example
- validate test2 v_regex
- }
-
- params get /params-test {
- validate arg1 v_example
- validate id v_number
- }
-}
diff --git a/examples/examples/generic/src/example.c b/examples/examples/generic/src/example.c
@@ -1,361 +0,0 @@
-/*
- * Copyright (c) 2013 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.
- */
-
-#include <kore/kore.h>
-#include <kore/http.h>
-
-#include "assets.h"
-
-void example_load(int);
-
-int serve_style_css(struct http_request *);
-int serve_index(struct http_request *);
-int serve_intro(struct http_request *);
-int serve_b64test(struct http_request *);
-int serve_spdyreset(struct http_request *);
-int serve_file_upload(struct http_request *);
-int serve_lock_test(struct http_request *);
-int serve_validator(struct http_request *);
-int serve_params_test(struct http_request *);
-int serve_private(struct http_request *);
-int serve_private_test(struct http_request *);
-
-void my_callback(void);
-int v_example_func(struct http_request *, char *);
-int v_session_validate(struct http_request *, char *);
-void test_base64(u_int8_t *, u_int32_t, struct kore_buf *);
-
-char *b64tests[] = {
- "1234567890",
- "One two three four five",
- "Man",
- "any carnal pleasure.",
- "any carnal pleasure",
- "any carnal pleas",
- "I am a nobody, nobody is perfect, therefor I am.",
- NULL
-};
-
-void
-example_load(int state)
-{
- switch (state) {
- case KORE_MODULE_LOAD:
- kore_log(LOG_NOTICE, "module loading");
- break;
- case KORE_MODULE_UNLOAD:
- kore_log(LOG_NOTICE, "module unloading");
- break;
- default:
- kore_log(LOG_NOTICE, "state %d unknown!", state);
- break;
- }
-}
-
-int
-serve_style_css(struct http_request *req)
-{
- char *date;
- time_t tstamp;
-
- tstamp = 0;
- if (http_request_header_get(req, "if-modified-since", &date)) {
- tstamp = kore_date_to_time(date);
- kore_mem_free(date);
-
- kore_debug("header was present with %ld", tstamp);
- }
-
- if (tstamp != 0 && tstamp <= asset_mtime_style_css) {
- http_response(req, 304, NULL, 0);
- } else {
- date = kore_time_to_date(asset_mtime_style_css);
- if (date != NULL)
- http_response_header_add(req, "last-modified", date);
-
- http_response_header_add(req, "content-type", "text/css");
- http_response(req, 200, asset_style_css, asset_len_style_css);
- }
-
- return (KORE_RESULT_OK);
-}
-
-int
-serve_index(struct http_request *req)
-{
- http_response_header_add(req, "content-type", "text/html");
- http_response(req, 200, asset_index_html, asset_len_index_html);
-
- return (KORE_RESULT_OK);
-}
-
-int
-serve_intro(struct http_request *req)
-{
- http_response_header_add(req, "content-type", "image/jpg");
- http_response(req, 200, asset_intro_jpg, asset_len_intro_jpg);
-
- return (KORE_RESULT_OK);
-}
-
-int
-serve_b64test(struct http_request *req)
-{
- int i;
- u_int32_t len;
- struct kore_buf *res;
- u_int8_t *data;
-
- res = kore_buf_create(1024);
- for (i = 0; b64tests[i] != NULL; i++)
- test_base64((u_int8_t *)b64tests[i], strlen(b64tests[i]), res);
-
- data = kore_buf_release(res, &len);
-
- http_response_header_add(req, "content-type", "text/plain");
- http_response(req, 200, data, len);
- kore_mem_free(data);
-
- return (KORE_RESULT_OK);
-}
-
-int
-serve_spdyreset(struct http_request *req)
-{
- spdy_session_teardown(req->owner, SPDY_SESSION_ERROR_OK);
- return (KORE_RESULT_OK);
-}
-
-int
-serve_file_upload(struct http_request *req)
-{
- int r;
- u_int8_t *d;
- struct kore_buf *b;
- u_int32_t len;
- char *name, buf[BUFSIZ];
-
- b = kore_buf_create(asset_len_upload_html);
- kore_buf_append(b, asset_upload_html, asset_len_upload_html);
-
- if (req->method == HTTP_METHOD_POST) {
- http_populate_multipart_form(req, &r);
- if (http_argument_get_string("firstname", &name, &len)) {
- kore_buf_replace_string(b, "$firstname$", name, len);
- } else {
- kore_buf_replace_string(b, "$firstname$", NULL, 0);
- }
-
- if (http_file_lookup(req, "file", &name, &d, &len)) {
- snprintf(buf, sizeof(buf), "%s is %d bytes", name, len);
- kore_buf_replace_string(b,
- "$upload$", buf, strlen(buf));
- } else {
- kore_buf_replace_string(b, "$upload$", NULL, 0);
- }
- } else {
- kore_buf_replace_string(b, "$upload$", NULL, 0);
- kore_buf_replace_string(b, "$firstname$", NULL, 0);
- }
-
- d = kore_buf_release(b, &len);
-
- http_response_header_add(req, "content-type", "text/html");
- http_response(req, 200, d, len);
- kore_mem_free(d);
-
- return (KORE_RESULT_OK);
-}
-
-int
-serve_lock_test(struct http_request *req)
-{
- kore_log(LOG_NOTICE, "lock-test called on worker %d", worker->id);
- kore_worker_acceptlock_release();
-
- http_response(req, 200, "OK", 2);
- return (KORE_RESULT_OK);
-}
-
-void
-test_base64(u_int8_t *src, u_int32_t slen, struct kore_buf *res)
-{
- char *in;
- u_int32_t len;
- u_int8_t *out;
-
- kore_buf_appendf(res, "test '%s'\n", src);
-
- if (!kore_base64_encode(src, slen, &in)) {
- kore_buf_appendf(res, "encoding '%s' failed\n", src);
- } else {
- kore_buf_appendf(res, "encoded: '%s'\n", in);
-
- if (!kore_base64_decode(in, &out, &len)) {
- kore_buf_appendf(res, "decoding failed\n");
- } else {
- kore_buf_appendf(res, "decoded: ");
- kore_buf_append(res, out, len);
- kore_buf_appendf(res, "\n");
- kore_mem_free(out);
- }
-
- kore_mem_free(in);
- }
-
- kore_buf_appendf(res, "\n");
-}
-
-int
-serve_validator(struct http_request *req)
-{
- if (kore_validator_run(NULL, "v_example", "test"))
- kore_log(LOG_NOTICE, "v_example ok (expected)");
- else
- kore_log(LOG_NOTICE, "v_example failed");
-
- if (kore_validator_run(NULL, "v_regex", "/test/123"))
- kore_log(LOG_NOTICE, "regex #1 ok");
- else
- kore_log(LOG_NOTICE, "regex #1 failed (expected)");
-
- if (kore_validator_run(NULL, "v_regex", "/test/joris"))
- kore_log(LOG_NOTICE, "regex #2 ok (expected)");
- else
- kore_log(LOG_NOTICE, "regex #2 failed");
-
- http_response(req, 200, "OK", 2);
-
- return (KORE_RESULT_OK);
-}
-
-int
-serve_params_test(struct http_request *req)
-{
- struct kore_buf *b;
- u_int8_t *d;
- u_int32_t len;
- int r, i;
- char *test, name[10];
-
- http_populate_arguments(req);
-
- b = kore_buf_create(asset_len_params_html);
- kore_buf_append(b, asset_params_html, asset_len_params_html);
-
- /*
- * The GET parameters will be filtered out on POST.
- */
- if (http_argument_get_string("arg1", &test, &len)) {
- kore_buf_replace_string(b, "$arg1$", test, len);
- } else {
- kore_buf_replace_string(b, "$arg1$", NULL, 0);
- }
-
- if (http_argument_get_string("arg2", &test, &len)) {
- kore_buf_replace_string(b, "$arg2$", test, len);
- } else {
- kore_buf_replace_string(b, "$arg2$", NULL, 0);
- }
-
- if (req->method == HTTP_METHOD_GET) {
- kore_buf_replace_string(b, "$test1$", NULL, 0);
- kore_buf_replace_string(b, "$test2$", NULL, 0);
- kore_buf_replace_string(b, "$test3$", NULL, 0);
-
- if (http_argument_get_uint16("id", &r))
- kore_log(LOG_NOTICE, "id: %d", r);
- else
- kore_log(LOG_NOTICE, "No id set");
-
- http_response_header_add(req, "content-type", "text/html");
- d = kore_buf_release(b, &len);
- http_response(req, 200, d, len);
- kore_mem_free(d);
-
- return (KORE_RESULT_OK);
- }
-
- for (i = 1; i < 4; i++) {
- snprintf(name, sizeof(name), "test%d", i);
- if (http_argument_get_string(name, &test, &len)) {
- snprintf(name, sizeof(name), "$test%d$", i);
- kore_buf_replace_string(b, name, test, len);
- } else {
- snprintf(name, sizeof(name), "$test%d$", i);
- kore_buf_replace_string(b, name, NULL, 0);
- }
- }
-
- http_response_header_add(req, "content-type", "text/html");
- d = kore_buf_release(b, &len);
- http_response(req, 200, d, len);
- kore_mem_free(d);
-
- return (KORE_RESULT_OK);
-}
-
-int
-serve_private(struct http_request *req)
-{
- http_response_header_add(req, "content-type", "text/html");
- http_response_header_add(req, "set-cookie", "session_id=test123");
- http_response(req, 200, asset_private_html, asset_len_private_html);
-
- return (KORE_RESULT_OK);
-}
-
-int
-serve_private_test(struct http_request *req)
-{
- http_response_header_add(req, "content-type", "text/html");
-
- http_response(req, 200, asset_private_test_html,
- asset_len_private_test_html);
-
- return (KORE_RESULT_OK);
-}
-
-void
-my_callback(void)
-{
- if (worker != NULL)
- kore_log(LOG_NOTICE, "running on worker %d", worker->id);
- else
- kore_log(LOG_NOTICE, "running from parent");
-}
-
-int
-v_example_func(struct http_request *req, char *data)
-{
- kore_log(LOG_NOTICE, "v_example_func called");
-
- if (!strcmp(data, "test"))
- return (KORE_RESULT_OK);
-
- return (KORE_RESULT_ERROR);
-}
-
-int
-v_session_validate(struct http_request *req, char *data)
-{
- kore_log(LOG_NOTICE, "v_session_validate: %s", data);
-
- if (!strcmp(data, "test123"))
- return (KORE_RESULT_OK);
-
- return (KORE_RESULT_ERROR);
-}
diff --git a/examples/examples/pgsql/conf/pgsql.conf b/examples/examples/pgsql/conf/pgsql.conf
@@ -1,17 +0,0 @@
-# Kore pgsql_test configuration
-
-bind 127.0.0.1 8888
-pidfile kore.pid
-
-ssl_no_compression
-load ./pgsql.so pgsql_load
-
-pgsql_conn_max 5
-
-domain localhost {
- certfile cert/server.crt
- certkey cert/server.key
-
- accesslog kore_access.log
- static / serve_pgsql_test
-}
diff --git a/examples/examples/pgsql/src/pgsql.c b/examples/examples/pgsql/src/pgsql.c
@@ -1,73 +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.
- */
-
-#include <kore/kore.h>
-#include <kore/http.h>
-#include <kore/pgsql.h>
-
-void pgsql_load(int);
-int serve_pgsql_test(struct http_request *);
-
-void
-pgsql_load(int state)
-{
- switch (state) {
- case KORE_MODULE_LOAD:
- pgsql_conn_string = "Your connection string";
- break;
- default:
- break;
- }
-}
-
-int
-serve_pgsql_test(struct http_request *req)
-{
- int r, i;
- char *col1, *col2;
-
- KORE_PGSQL(req, "SELECT * FROM test", 0, {
- if (req->pgsql[0]->state == KORE_PGSQL_STATE_ERROR) {
- kore_pgsql_logerror(req->pgsql[0]);
- http_response(req, 500, "fail\n", 5);
- return (KORE_RESULT_OK);
- }
-
- r = kore_pgsql_ntuples(req->pgsql[0]);
- for (i = 0; i < r; i++) {
- col1 = kore_pgsql_getvalue(req->pgsql[0], i, 0);
- col2 = kore_pgsql_getvalue(req->pgsql[0], i, 1);
-
- kore_log(LOG_NOTICE, "%s and %s", col1, col2);
- }
- });
-
- KORE_PGSQL(req, "SELECT * FROM foobar", 1, {
- if (req->pgsql[1]->state != KORE_PGSQL_STATE_ERROR) {
- kore_log(LOG_NOTICE, "expected error, got %d",
- req->pgsql[1]->state);
- http_response(req, 500, "fail2\n", 6);
- return (KORE_RESULT_OK);
- } else {
- kore_pgsql_logerror(req->pgsql[1]);
- }
- });
-
- /* Query successfully completed */
- http_response(req, 200, "ok\n", 3);
-
- return (KORE_RESULT_OK);
-}
diff --git a/examples/examples/tasks/README b/examples/examples/tasks/README
@@ -1,3 +0,0 @@
-Compile this example using:
-
-# env KORE_LDFLAGS="-I/path/to/libcurl -lcurl"
diff --git a/examples/examples/tasks/conf/tasks.conf b/examples/examples/tasks/conf/tasks.conf
@@ -1,27 +0,0 @@
-# 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/examples/examples/tasks/src/tasks.c b/examples/examples/tasks/src/tasks.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: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);
-}
diff --git a/examples/generic/assets/index.html b/examples/generic/assets/index.html
@@ -0,0 +1,15 @@
+<!DOCTYPE>
+<html>
+<head>
+ <link rel="stylesheet" href="/css/style.css" type="text/css">
+ <title>Your KORE module worked!</title>
+</head>
+
+<body>
+
+<div class="content">
+ <p>Your first Kore module worked.</p>
+</div>
+
+</body>
+</html>
diff --git a/examples/generic/assets/intro.jpg b/examples/generic/assets/intro.jpg
Binary files differ.
diff --git a/examples/generic/assets/params.html b/examples/generic/assets/params.html
@@ -0,0 +1,33 @@
+<!DOCTYPE>
+<html>
+<head>
+ <link rel="stylesheet" href="/css/style.css" type="text/css">
+ <title>Kore params test</title>
+</head>
+
+<body style="overflow: auto">
+
+<div class="content" style="font-size: 12px; font-weight: normal">
+ <p>You can pass one GET parameter (arg1), any other GET parameter will
+ be filtered out</p>
+ <p>Only two out of the three input fields will be visible to Kore.</p>
+ <p>The first field accepts the input "test"</p>
+ <p>The second field accepts anything like /test/[a-z]*</p>
+ <p>The third field will be removed by Kore, as it is not in the params
+ block configured for this page.</p>
+ <form method="POST">
+ <input type="input" name="test1" value="$test1$">
+ <input type="input" name="test2" value="$test2$">
+ <input type="input" name="test3" value="$test3$">
+ <input type="submit">
+ </form>
+
+ <p style="font-size: 12px; font-weight: normal">GET param arg1: $arg1$</p>
+ <p style="font-size: 12px; font-weight: normal">GET param arg2: $arg2$</p>
+ <p style="font-size: 12px; font-weight: normal">test1: $test1$</p>
+ <p style="font-size: 12px; font-weight: normal">test2: $test2$</p>
+ <p style="font-size: 12px; font-weight: normal">test3: $test3$</p>
+</div>
+
+</body>
+</html>
diff --git a/examples/generic/assets/private.html b/examples/generic/assets/private.html
@@ -0,0 +1,16 @@
+<!DOCTYPE>
+<html>
+<head>
+ <link rel="stylesheet" href="/css/style.css" type="text/css">
+ <title>Kore Authentication tests</title>
+</head>
+
+<body>
+
+<div class="content">
+ <p style="font-size: small">The cookie session_id should now be set.</p>
+ <p style="font-size: small">You can continue to <a href="/private/test">view page handler in auth block</a></p>
+</div>
+
+</body>
+</html>
diff --git a/examples/generic/assets/private_test.html b/examples/generic/assets/private_test.html
@@ -0,0 +1,15 @@
+<!DOCTYPE>
+<html>
+<head>
+ <link rel="stylesheet" href="/css/style.css" type="text/css">
+ <title>Kore Authentication tests</title>
+</head>
+
+<body>
+
+<div class="content">
+ <p style="font-size: small">If you see this, the authentication worked. This page should redirect back to /private once you remove your session_id cookie.</p>
+</div>
+
+</body>
+</html>
diff --git a/examples/generic/assets/style.css b/examples/generic/assets/style.css
@@ -0,0 +1,16 @@
+body {
+ width: 100%;
+ margin: 0px;
+ color: #000;
+ overflow: hidden;
+ background-color: #fff;
+}
+
+.content {
+ width: 800px;
+ margin-left: auto;
+ margin-right: auto;
+ margin-top: 100px;
+ font-size: 60px;
+ text-align: center;
+}
diff --git a/examples/generic/assets/upload.html b/examples/generic/assets/upload.html
@@ -0,0 +1,22 @@
+<!DOCTYPE>
+<html>
+<head>
+ <link rel="stylesheet" href="/css/style.css" type="text/css">
+ <title>Kore upload test</title>
+</head>
+
+<body style="overflow: auto">
+
+<div class="content">
+ <form method="POST" enctype="multipart/form-data">
+ <input type="input" name="firstname">
+ <input type="file" name="file">
+ <input type="submit" value="upload">
+ </form>
+
+ <p style="font-size: 12px; font-weight: normal">$upload$</p>
+ <p style="font-size: 12px; font-weight: normal">$firstname$</p>
+</div>
+
+</body>
+</html>
diff --git a/examples/generic/conf/generic.conf b/examples/generic/conf/generic.conf
@@ -0,0 +1,49 @@
+# Placeholder configuration
+
+bind 127.0.0.1 8888
+pidfile kore.pid
+
+load ./generic.so example_load
+
+validator v_example function v_example_func
+validator v_regex regex ^/test/[a-z]*$
+validator v_number regex ^[0-9]*$
+validator v_session function v_session_validate
+
+ssl_no_compression
+
+authentication auth_example {
+ authentication_type cookie
+ authentication_value session_id
+ authentication_validator v_session
+ authentication_uri /private
+}
+
+domain 127.0.0.1 {
+ certfile cert/server.crt
+ certkey cert/server.key
+ accesslog kore_access.log
+
+ static /css/style.css serve_style_css
+ static / serve_index
+ static /intro.jpg serve_intro
+ static /b64test serve_b64test
+ static /spdy-reset serve_spdyreset
+ static /upload serve_file_upload
+ static /lock-test serve_lock_test
+ static /validator serve_validator
+ static /params-test serve_params_test
+ static /private serve_private
+
+ static /private/test serve_private_test auth_example
+
+ params post /params-test {
+ validate test1 v_example
+ validate test2 v_regex
+ }
+
+ params get /params-test {
+ validate arg1 v_example
+ validate id v_number
+ }
+}
diff --git a/examples/generic/src/example.c b/examples/generic/src/example.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2013 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.
+ */
+
+#include <kore/kore.h>
+#include <kore/http.h>
+
+#include "assets.h"
+
+void example_load(int);
+
+int serve_style_css(struct http_request *);
+int serve_index(struct http_request *);
+int serve_intro(struct http_request *);
+int serve_b64test(struct http_request *);
+int serve_spdyreset(struct http_request *);
+int serve_file_upload(struct http_request *);
+int serve_lock_test(struct http_request *);
+int serve_validator(struct http_request *);
+int serve_params_test(struct http_request *);
+int serve_private(struct http_request *);
+int serve_private_test(struct http_request *);
+
+void my_callback(void);
+int v_example_func(struct http_request *, char *);
+int v_session_validate(struct http_request *, char *);
+void test_base64(u_int8_t *, u_int32_t, struct kore_buf *);
+
+char *b64tests[] = {
+ "1234567890",
+ "One two three four five",
+ "Man",
+ "any carnal pleasure.",
+ "any carnal pleasure",
+ "any carnal pleas",
+ "I am a nobody, nobody is perfect, therefor I am.",
+ NULL
+};
+
+void
+example_load(int state)
+{
+ switch (state) {
+ case KORE_MODULE_LOAD:
+ kore_log(LOG_NOTICE, "module loading");
+ break;
+ case KORE_MODULE_UNLOAD:
+ kore_log(LOG_NOTICE, "module unloading");
+ break;
+ default:
+ kore_log(LOG_NOTICE, "state %d unknown!", state);
+ break;
+ }
+}
+
+int
+serve_style_css(struct http_request *req)
+{
+ char *date;
+ time_t tstamp;
+
+ tstamp = 0;
+ if (http_request_header_get(req, "if-modified-since", &date)) {
+ tstamp = kore_date_to_time(date);
+ kore_mem_free(date);
+
+ kore_debug("header was present with %ld", tstamp);
+ }
+
+ if (tstamp != 0 && tstamp <= asset_mtime_style_css) {
+ http_response(req, 304, NULL, 0);
+ } else {
+ date = kore_time_to_date(asset_mtime_style_css);
+ if (date != NULL)
+ http_response_header_add(req, "last-modified", date);
+
+ http_response_header_add(req, "content-type", "text/css");
+ http_response(req, 200, asset_style_css, asset_len_style_css);
+ }
+
+ return (KORE_RESULT_OK);
+}
+
+int
+serve_index(struct http_request *req)
+{
+ http_response_header_add(req, "content-type", "text/html");
+ http_response(req, 200, asset_index_html, asset_len_index_html);
+
+ return (KORE_RESULT_OK);
+}
+
+int
+serve_intro(struct http_request *req)
+{
+ http_response_header_add(req, "content-type", "image/jpg");
+ http_response(req, 200, asset_intro_jpg, asset_len_intro_jpg);
+
+ return (KORE_RESULT_OK);
+}
+
+int
+serve_b64test(struct http_request *req)
+{
+ int i;
+ u_int32_t len;
+ struct kore_buf *res;
+ u_int8_t *data;
+
+ res = kore_buf_create(1024);
+ for (i = 0; b64tests[i] != NULL; i++)
+ test_base64((u_int8_t *)b64tests[i], strlen(b64tests[i]), res);
+
+ data = kore_buf_release(res, &len);
+
+ http_response_header_add(req, "content-type", "text/plain");
+ http_response(req, 200, data, len);
+ kore_mem_free(data);
+
+ return (KORE_RESULT_OK);
+}
+
+int
+serve_spdyreset(struct http_request *req)
+{
+ spdy_session_teardown(req->owner, SPDY_SESSION_ERROR_OK);
+ return (KORE_RESULT_OK);
+}
+
+int
+serve_file_upload(struct http_request *req)
+{
+ int r;
+ u_int8_t *d;
+ struct kore_buf *b;
+ u_int32_t len;
+ char *name, buf[BUFSIZ];
+
+ b = kore_buf_create(asset_len_upload_html);
+ kore_buf_append(b, asset_upload_html, asset_len_upload_html);
+
+ if (req->method == HTTP_METHOD_POST) {
+ http_populate_multipart_form(req, &r);
+ if (http_argument_get_string("firstname", &name, &len)) {
+ kore_buf_replace_string(b, "$firstname$", name, len);
+ } else {
+ kore_buf_replace_string(b, "$firstname$", NULL, 0);
+ }
+
+ if (http_file_lookup(req, "file", &name, &d, &len)) {
+ snprintf(buf, sizeof(buf), "%s is %d bytes", name, len);
+ kore_buf_replace_string(b,
+ "$upload$", buf, strlen(buf));
+ } else {
+ kore_buf_replace_string(b, "$upload$", NULL, 0);
+ }
+ } else {
+ kore_buf_replace_string(b, "$upload$", NULL, 0);
+ kore_buf_replace_string(b, "$firstname$", NULL, 0);
+ }
+
+ d = kore_buf_release(b, &len);
+
+ http_response_header_add(req, "content-type", "text/html");
+ http_response(req, 200, d, len);
+ kore_mem_free(d);
+
+ return (KORE_RESULT_OK);
+}
+
+int
+serve_lock_test(struct http_request *req)
+{
+ kore_log(LOG_NOTICE, "lock-test called on worker %d", worker->id);
+ kore_worker_acceptlock_release();
+
+ http_response(req, 200, "OK", 2);
+ return (KORE_RESULT_OK);
+}
+
+void
+test_base64(u_int8_t *src, u_int32_t slen, struct kore_buf *res)
+{
+ char *in;
+ u_int32_t len;
+ u_int8_t *out;
+
+ kore_buf_appendf(res, "test '%s'\n", src);
+
+ if (!kore_base64_encode(src, slen, &in)) {
+ kore_buf_appendf(res, "encoding '%s' failed\n", src);
+ } else {
+ kore_buf_appendf(res, "encoded: '%s'\n", in);
+
+ if (!kore_base64_decode(in, &out, &len)) {
+ kore_buf_appendf(res, "decoding failed\n");
+ } else {
+ kore_buf_appendf(res, "decoded: ");
+ kore_buf_append(res, out, len);
+ kore_buf_appendf(res, "\n");
+ kore_mem_free(out);
+ }
+
+ kore_mem_free(in);
+ }
+
+ kore_buf_appendf(res, "\n");
+}
+
+int
+serve_validator(struct http_request *req)
+{
+ if (kore_validator_run(NULL, "v_example", "test"))
+ kore_log(LOG_NOTICE, "v_example ok (expected)");
+ else
+ kore_log(LOG_NOTICE, "v_example failed");
+
+ if (kore_validator_run(NULL, "v_regex", "/test/123"))
+ kore_log(LOG_NOTICE, "regex #1 ok");
+ else
+ kore_log(LOG_NOTICE, "regex #1 failed (expected)");
+
+ if (kore_validator_run(NULL, "v_regex", "/test/joris"))
+ kore_log(LOG_NOTICE, "regex #2 ok (expected)");
+ else
+ kore_log(LOG_NOTICE, "regex #2 failed");
+
+ http_response(req, 200, "OK", 2);
+
+ return (KORE_RESULT_OK);
+}
+
+int
+serve_params_test(struct http_request *req)
+{
+ struct kore_buf *b;
+ u_int8_t *d;
+ u_int32_t len;
+ int r, i;
+ char *test, name[10];
+
+ http_populate_arguments(req);
+
+ b = kore_buf_create(asset_len_params_html);
+ kore_buf_append(b, asset_params_html, asset_len_params_html);
+
+ /*
+ * The GET parameters will be filtered out on POST.
+ */
+ if (http_argument_get_string("arg1", &test, &len)) {
+ kore_buf_replace_string(b, "$arg1$", test, len);
+ } else {
+ kore_buf_replace_string(b, "$arg1$", NULL, 0);
+ }
+
+ if (http_argument_get_string("arg2", &test, &len)) {
+ kore_buf_replace_string(b, "$arg2$", test, len);
+ } else {
+ kore_buf_replace_string(b, "$arg2$", NULL, 0);
+ }
+
+ if (req->method == HTTP_METHOD_GET) {
+ kore_buf_replace_string(b, "$test1$", NULL, 0);
+ kore_buf_replace_string(b, "$test2$", NULL, 0);
+ kore_buf_replace_string(b, "$test3$", NULL, 0);
+
+ if (http_argument_get_uint16("id", &r))
+ kore_log(LOG_NOTICE, "id: %d", r);
+ else
+ kore_log(LOG_NOTICE, "No id set");
+
+ http_response_header_add(req, "content-type", "text/html");
+ d = kore_buf_release(b, &len);
+ http_response(req, 200, d, len);
+ kore_mem_free(d);
+
+ return (KORE_RESULT_OK);
+ }
+
+ for (i = 1; i < 4; i++) {
+ snprintf(name, sizeof(name), "test%d", i);
+ if (http_argument_get_string(name, &test, &len)) {
+ snprintf(name, sizeof(name), "$test%d$", i);
+ kore_buf_replace_string(b, name, test, len);
+ } else {
+ snprintf(name, sizeof(name), "$test%d$", i);
+ kore_buf_replace_string(b, name, NULL, 0);
+ }
+ }
+
+ http_response_header_add(req, "content-type", "text/html");
+ d = kore_buf_release(b, &len);
+ http_response(req, 200, d, len);
+ kore_mem_free(d);
+
+ return (KORE_RESULT_OK);
+}
+
+int
+serve_private(struct http_request *req)
+{
+ http_response_header_add(req, "content-type", "text/html");
+ http_response_header_add(req, "set-cookie", "session_id=test123");
+ http_response(req, 200, asset_private_html, asset_len_private_html);
+
+ return (KORE_RESULT_OK);
+}
+
+int
+serve_private_test(struct http_request *req)
+{
+ http_response_header_add(req, "content-type", "text/html");
+
+ http_response(req, 200, asset_private_test_html,
+ asset_len_private_test_html);
+
+ return (KORE_RESULT_OK);
+}
+
+void
+my_callback(void)
+{
+ if (worker != NULL)
+ kore_log(LOG_NOTICE, "running on worker %d", worker->id);
+ else
+ kore_log(LOG_NOTICE, "running from parent");
+}
+
+int
+v_example_func(struct http_request *req, char *data)
+{
+ kore_log(LOG_NOTICE, "v_example_func called");
+
+ if (!strcmp(data, "test"))
+ return (KORE_RESULT_OK);
+
+ return (KORE_RESULT_ERROR);
+}
+
+int
+v_session_validate(struct http_request *req, char *data)
+{
+ kore_log(LOG_NOTICE, "v_session_validate: %s", data);
+
+ if (!strcmp(data, "test123"))
+ return (KORE_RESULT_OK);
+
+ return (KORE_RESULT_ERROR);
+}
diff --git a/examples/pgsql/conf/pgsql.conf b/examples/pgsql/conf/pgsql.conf
@@ -0,0 +1,17 @@
+# Kore pgsql_test configuration
+
+bind 127.0.0.1 8888
+pidfile kore.pid
+
+ssl_no_compression
+load ./pgsql.so pgsql_load
+
+pgsql_conn_max 5
+
+domain localhost {
+ certfile cert/server.crt
+ certkey cert/server.key
+
+ accesslog kore_access.log
+ static / serve_pgsql_test
+}
diff --git a/examples/pgsql/src/pgsql.c b/examples/pgsql/src/pgsql.c
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#include <kore/kore.h>
+#include <kore/http.h>
+#include <kore/pgsql.h>
+
+void pgsql_load(int);
+int serve_pgsql_test(struct http_request *);
+
+void
+pgsql_load(int state)
+{
+ switch (state) {
+ case KORE_MODULE_LOAD:
+ pgsql_conn_string = "Your connection string";
+ break;
+ default:
+ break;
+ }
+}
+
+int
+serve_pgsql_test(struct http_request *req)
+{
+ int r, i;
+ char *col1, *col2;
+
+ KORE_PGSQL(req, "SELECT * FROM test", 0, {
+ if (req->pgsql[0]->state == KORE_PGSQL_STATE_ERROR) {
+ kore_pgsql_logerror(req->pgsql[0]);
+ http_response(req, 500, "fail\n", 5);
+ return (KORE_RESULT_OK);
+ }
+
+ r = kore_pgsql_ntuples(req->pgsql[0]);
+ for (i = 0; i < r; i++) {
+ col1 = kore_pgsql_getvalue(req->pgsql[0], i, 0);
+ col2 = kore_pgsql_getvalue(req->pgsql[0], i, 1);
+
+ kore_log(LOG_NOTICE, "%s and %s", col1, col2);
+ }
+ });
+
+ KORE_PGSQL(req, "SELECT * FROM foobar", 1, {
+ if (req->pgsql[1]->state != KORE_PGSQL_STATE_ERROR) {
+ kore_log(LOG_NOTICE, "expected error, got %d",
+ req->pgsql[1]->state);
+ http_response(req, 500, "fail2\n", 6);
+ return (KORE_RESULT_OK);
+ } else {
+ kore_pgsql_logerror(req->pgsql[1]);
+ }
+ });
+
+ /* Query successfully completed */
+ http_response(req, 200, "ok\n", 3);
+
+ return (KORE_RESULT_OK);
+}
diff --git a/examples/tasks/README b/examples/tasks/README
@@ -0,0 +1,3 @@
+Compile this example using:
+
+# env KORE_LDFLAGS="-I/path/to/libcurl -lcurl"
diff --git a/examples/tasks/conf/tasks.conf b/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/examples/tasks/src/tasks.c b/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);
+}