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 22882261f7ca98640332b928ac256430a9652d11
parent f7190c8b12741c04b8fe6c6e402da6b1b004e706
Author: Joris Vink <joris@coders.se>
Date:   Mon, 31 Mar 2014 11:29:51 +0200

Properly use pg_config --includedirs + move modules to contrib

Diffstat:
Makefile | 2+-
contrib/modules/example/build.sh | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
contrib/modules/example/media/index.html | 15+++++++++++++++
contrib/modules/example/media/intro.jpg | 0
contrib/modules/example/media/params.html | 33+++++++++++++++++++++++++++++++++
contrib/modules/example/media/private.html | 16++++++++++++++++
contrib/modules/example/media/private_test.html | 15+++++++++++++++
contrib/modules/example/media/style.css | 16++++++++++++++++
contrib/modules/example/media/upload.html | 22++++++++++++++++++++++
contrib/modules/example/module.conf | 193+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
contrib/modules/example/src/example.c | 361+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
contrib/modules/example/tools/inject.c | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
contrib/modules/skeleton/build.sh | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
contrib/modules/skeleton/media/.gitignore | 0
contrib/modules/skeleton/src/.gitignore | 0
contrib/modules/skeleton/tools/inject.c | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
contrib/postgres/kore_pgsql.c | 2+-
modules/example/build.sh | 82-------------------------------------------------------------------------------
modules/example/media/index.html | 15---------------
modules/example/media/intro.jpg | 0
modules/example/media/params.html | 33---------------------------------
modules/example/media/private.html | 16----------------
modules/example/media/private_test.html | 15---------------
modules/example/media/style.css | 16----------------
modules/example/media/upload.html | 22----------------------
modules/example/module.conf | 193-------------------------------------------------------------------------------
modules/example/src/example.c | 361-------------------------------------------------------------------------------
modules/example/tools/inject.c | 119-------------------------------------------------------------------------------
modules/skeleton/build.sh | 86-------------------------------------------------------------------------------
modules/skeleton/media/.gitignore | 0
modules/skeleton/src/.gitignore | 0
modules/skeleton/tools/inject.c | 119-------------------------------------------------------------------------------
32 files changed, 1079 insertions(+), 1079 deletions(-)

diff --git a/Makefile b/Makefile @@ -21,7 +21,7 @@ endif ifneq ("$(PGSQL)", "") S_SRC+=contrib/postgres/kore_pgsql.c LDFLAGS+=-lpq - CFLAGS+=-DKORE_USE_PGSQL + CFLAGS+=-I$(shell pg_config --includedir) -DKORE_USE_PGSQL endif OSNAME=$(shell uname -s | sed -e 's/[-_].*//g' | tr A-Z a-z) diff --git a/contrib/modules/example/build.sh b/contrib/modules/example/build.sh @@ -0,0 +1,82 @@ +#!/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=example.module + +# The directory containing all your media files (HTML, CSS, ...). +# These files will be compiled into the module and symbols will +# be exported for you to use in your code. +MEDIA_DIR=media + +# The directory containing your module source. +SOURCE_DIR=src + +# The directory containing the Kore source code. +KORE_DIR=../../../ + +# Compiler settings. +CC=gcc +CFLAGS="-I. -I${KORE_DIR}/includes -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" +else + LDFLAGS="-shared" +fi + +MODULE_BUILD_DATE=$(date +"%Y-%m-%d %H:%M:%S") + +### Begin building #### +echo "Building module ${MODULE}..." +rm -f ${MODULE} + +${CC} ${CFLAGS} tools/inject.c -o tools/inject + +if [ ! -d ${SOURCE_DIR}/${MEDIA_DIR} ]; then + mkdir ${SOURCE_DIR}/${MEDIA_DIR}; +fi +rm -f ${SOURCE_DIR}/${MEDIA_DIR}/* + +if [ ! -d .objs ]; then + mkdir .objs; +fi +rm -f .objs/* + +rm -f static.h + +for file in `find ${MEDIA_DIR} -type f \( ! -name \*.swp \)`; do + echo "Injecting $file"; + base=`basename $file`; + ./tools/inject $file $base > ${SOURCE_DIR}/${MEDIA_DIR}/${base}.c; + if [ $? -ne 0 ]; then + echo "Injection error, check above messages for clues."; + exit 1; + fi +done + +echo "#define MODULE_BUILD_DATE \"${MODULE_BUILD_DATE}\"" >> static.h + +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 ${SOURCE_DIR}/${MEDIA_DIR} +rm -rf .objs +rm -f tools/inject +rm -f static.h diff --git a/contrib/modules/example/media/index.html b/contrib/modules/example/media/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/contrib/modules/example/media/intro.jpg b/contrib/modules/example/media/intro.jpg Binary files differ. diff --git a/contrib/modules/example/media/params.html b/contrib/modules/example/media/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/contrib/modules/example/media/private.html b/contrib/modules/example/media/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/contrib/modules/example/media/private_test.html b/contrib/modules/example/media/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/contrib/modules/example/media/style.css b/contrib/modules/example/media/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/contrib/modules/example/media/upload.html b/contrib/modules/example/media/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/contrib/modules/example/module.conf b/contrib/modules/example/module.conf @@ -0,0 +1,193 @@ +# Example Kore configuration + +# Server configuration. +bind 127.0.0.1 443 + +# The path worker processes will chroot into after starting. +chroot /home/joris/src/kore + +# Worker processes will run as the specified user. +runas joris + +# Set workers to the amount of CPU's available in your system, +# kore will automatically distribute all workers on them. +workers 4 + +# The number of active connections each worker can handle. +# You might have to tweak this number based on your hardware. +#worker_max_connections 250 + +# Store the main process its pid in this file. +#pidfile /var/run/kore.pid + +# You can define a callback Kore calls from its parent process or +# workers everytime the kore_cb_interval timer (in milliseconds) is reached. +# +# NOTE: Remember that the parent process runs as root and is not chroot(). +# NOTE: If you want the cb to run on a worker, be sure to set kore_cb_worker. +#kore_cb my_callback +#kore_cb_interval 1000 +#kore_cb_worker 3 + +# HTTP specific settings. +# http_header_max Maximum size of HTTP headers (in bytes). +# +# http_postbody_max Maximum size of an HTTP POST body (in bytes). +# +# http_keepalive_time Maximum seconds an HTTP connection can be +# kept alive by the browser. +# (Set to 0 to disable keepalive completely). +# +# http_hsts_enable Send Strict Transport Security header in +# all responses. Parameter is the age. +# (Set to 0 to disable sending this header). +#http_header_max 4096 +#http_postbody_max 10240000 +#http_keepalive_time 0 +#http_hsts_enable 31536000 + +# Load modules (you can load multiple at the same time). +# An additional parameter can be specified as the "onload" function +# which Kore will call when the module is loaded/reloaded. +load modules/example/example.module example_load + +# Validators +# validator name type regex|function +# +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 + +# Specify the SSL ciphers that will be used. +#ssl_cipher ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK + +# If you wish to use EDH / ECDH specify a file containing +# a generated DH key (See OpenSSL dhparam). +#ssl_dhparam dh2048.pem + +# Set this if you want to disable SSL zlib compression. +ssl_no_compression + +# Specify the amount of seconds a SPDY connection is kept open. +# You can keep it open indefinately by setting this to 0. +#spdy_idle_time 120 + +# Authentication configuration +# +# Using authentication blocks you can define a standard way for +# Kore to validate your users. In the example below we create +# a authentication block called auth_example, which requires +# a cookie (session_id) to be set. +# +# If no cookie is present or the cookie is not valid according +# to the set validator, Kore will redirect the browser to the +# URI set in authentication_uri. +# +# Page handlers can be bound to authentication by specifying +# authentication block at the end of the page directive (see below). +authentication auth_example { + # The authentication type denotes the way the user should + # be authenticated. + # + # Allow values: + # - cookie (checks for the cookie presence + pass to validator) + # - header (checks for header presence + pass to validator) + # - requuest (passes the http_request to the validator) + # + # Use cases for request could for example be IP based ACLs or + # any other criteria that can be extracted from a http_request. + # + # The request type does not need an authentication_validator. + # + authentication_type cookie + + # The name of whatever we are looking for. + authentication_value session_id + + # The validator that will be called to verify the cookie. + # Note this is YOUR validator, Kore does not have built-in + # session support. You must add this manually using your + # preferred method (Storing it in postgres, redis, ...) + authentication_validator v_session + + # The URI Kore will redirect to if a authentication fails. + # If this is not set, Kore will return a simple 403. + authentication_uri /private +} + +# Domain configuration +# +# Each domain configuration starts with listing what domain +# the directives that follow are to be applied upon. +# +# Additionally you can specify the following in a domain configuration: +# +# accesslog +# - File where all requests are logged. +# require_client_cert +# - Asks the client to present a certificate +# matching the CA given to require_client_cert +# +# Handlers +# +# Handlers are either static (for fixed paths) or dynamic. +# Dynamic handlers take a POSIX regular expression as its path. +# +# Syntax: +# handler path module_callback [auth block] +# +# Note that the auth block is optional and if set will force Kore to +# authenticate the user according to the authentication block its settings +# before allowing access to the page. + +# Example domain that responds to localhost. +domain localhost { + certfile cert/server.crt + certkey cert/server.key + accesslog /var/log/kore_access.log + + # Page handlers with no authentication required. + 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 + + # Page handlers with authentication. + static /private/test serve_private_test auth_example + + # Configure /params-test POST to only accept the following parameters. + # They are automatically tested against the validator listed. + # If the validator would fail Kore will automatically remove the + # failing parameter, indicating something was wrong with it. + # Any parameters not present in the params block are also filtered out. + params post /params-test { + validate test1 v_example + validate test2 v_regex + } + + # Configure a GET parameter that /params-test can received. As before + # this is validated against the validator and removed if validation + # fails. All extra parameters in the GET query are filtered out. + params get /params-test { + validate arg1 v_example + validate id v_number + } +} + +#domain domain.com { +# certfile cert/other/server.crt +# certkey cert/other/server.key +# accesslog /var/log/other_kore_access.log +# require_client_cert cert/other/ca.crt + +# static /css/style.css serve_style_css +# static / serve_index +# dynamic ^/[a-z0-9_]*$ serve_profile +#} diff --git a/contrib/modules/example/src/example.c b/contrib/modules/example/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.h" +#include "http.h" + +#include "static.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 <= static_mtime_css_style) { + http_response(req, 304, NULL, 0); + } else { + date = kore_time_to_date(static_mtime_css_style); + if (date != NULL) + http_response_header_add(req, "last-modified", date); + + http_response_header_add(req, "content-type", "text/css"); + http_response(req, 200, static_css_style, static_len_css_style); + } + + return (KORE_RESULT_OK); +} + +int +serve_index(struct http_request *req) +{ + http_response_header_add(req, "content-type", "text/html"); + http_response(req, 200, static_html_index, static_len_html_index); + + return (KORE_RESULT_OK); +} + +int +serve_intro(struct http_request *req) +{ + http_response_header_add(req, "content-type", "image/jpg"); + http_response(req, 200, static_jpg_intro, static_len_jpg_intro); + + 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(static_len_html_upload); + kore_buf_append(b, static_html_upload, static_len_html_upload); + + 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(static_len_html_params); + kore_buf_append(b, static_html_params, static_len_html_params); + + /* + * 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, static_html_private, static_len_html_private); + + 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, static_html_private_test, + static_len_html_private_test); + + 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/contrib/modules/example/tools/inject.c b/contrib/modules/example/tools/inject.c @@ -0,0 +1,119 @@ +/* + * 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 <sys/param.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <inttypes.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#if defined(OpenBSD) +#define PRI_TIME_T "d" +#endif + +#if defined(linux) +#if defined(__x86_64__) +#define PRI_TIME_T PRIu64 +#else +#define PRI_TIME_T "ld" +#endif +#endif + +#if defined(__MACH__) +#define PRI_TIME_T "ld" +#endif + +int +main(int argc, char *argv[]) +{ + struct stat st; + ssize_t len; + FILE *hdr; + char *ext; + unsigned char c[1]; + int fd, newline, count; + + if (argc != 3) + exit(1); + + if ((fd = open(argv[1], O_RDONLY)) == -1) + err(1, "open() %d", errno); + if ((hdr = fopen("static.h", "a+")) == NULL) + err(1, "fopen() %d", errno); + if ((ext = strchr(argv[2], '.')) != NULL) + *(ext)++ = '\0'; + else + ext = ""; + + if (stat(argv[1], &st) == -1) { + printf("stat(%s) failed: %d\n", argv[1], errno); + exit(1); + } + + printf("/**** AUTO GENERATED BY MAKEFILE - DO NOT TOUCH ****/\n"); + printf("#include <sys/param.h>\n\n"); + printf("u_int8_t static_%s_%s[] = {", ext, argv[2]); + + len = 0; + count = 0; + newline = 1; + for (;;) { + if (newline) { + printf("\n\t"); + count = 0; + newline = 0; + } + + len = read(fd, c, 1); + if (len == 0) + break; + + if (len == -1) { + printf("read(): %d\n", errno); + exit(1); + } + + if (len != 1) + exit(1); + + printf("0x%02x, ", c[0]); + if (count++ == 10) + newline = 1; + } + + close(fd); + + printf("};\n\n"); + printf("u_int32_t static_len_%s_%s = %" PRIu32 ";\n", + ext, argv[2], (u_int32_t)st.st_size); + + printf("time_t static_mtime_%s_%s = %" PRI_TIME_T ";\n", + ext, argv[2], st.st_mtime); + + fprintf(hdr, "extern u_int8_t static_%s_%s[];\n", ext, argv[2]); + fprintf(hdr, "extern u_int32_t static_len_%s_%s;\n", ext, argv[2]); + fprintf(hdr, "extern time_t static_mtime_%s_%s;\n", ext, argv[2]); + fclose(hdr); + + return (0); +} diff --git a/contrib/modules/skeleton/build.sh b/contrib/modules/skeleton/build.sh @@ -0,0 +1,86 @@ +#!/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=site.module + +# The directory containing all your media files (HTML, CSS, ...). +# These files will be compiled into the module and symbols will +# be exported for you to use in your code. +MEDIA_DIR=media + +# The directory containing your module source. +SOURCE_DIR=src + +# The directory containing the Kore source code. +KORE_DIR="notset" +if [ ${KORE_DIR} = "notset" ]; then + echo "Please edit build.sh and set KORE_DIR properly"; + exit; +fi + +# Compiler settings. +CC=gcc +CFLAGS="-I. -I${KORE_DIR}/includes -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" +else + LDFLAGS="-shared" +fi + +MODULE_BUILD_DATE=$(date +"%Y-%m-%d %H:%M:%S") + +### Begin building #### +echo "Building module ${MODULE}..." +rm -f ${MODULE} + +${CC} ${CFLAGS} tools/inject.c -o tools/inject + +if [ ! -d ${SOURCE_DIR}/${MEDIA_DIR} ]; then + mkdir ${SOURCE_DIR}/${MEDIA_DIR}; +fi +rm -f ${SOURCE_DIR}/${MEDIA_DIR}/* + +if [ ! -d .objs ]; then + mkdir .objs; +fi +rm -f .objs/* + +rm -f static.h + +for file in `find ${MEDIA_DIR} -type f \( ! -name \*.swp \)`; do + echo "Injecting $file"; + base=`basename $file`; + ./tools/inject $file $base > ${SOURCE_DIR}/${MEDIA_DIR}/${base}.c; + if [ $? -ne 0 ]; then + echo "Injection error, check above messages for clues."; + exit 1; + fi +done + +echo "#define MODULE_BUILD_DATE \"${MODULE_BUILD_DATE}\"" >> static.h + +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 ${SOURCE_DIR}/${MEDIA_DIR} +rm -rf .objs +rm -f tools/inject +rm -f static.h diff --git a/contrib/modules/skeleton/media/.gitignore b/contrib/modules/skeleton/media/.gitignore diff --git a/contrib/modules/skeleton/src/.gitignore b/contrib/modules/skeleton/src/.gitignore diff --git a/contrib/modules/skeleton/tools/inject.c b/contrib/modules/skeleton/tools/inject.c @@ -0,0 +1,119 @@ +/* + * 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 <sys/param.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <inttypes.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#if defined(OpenBSD) +#define PRI_TIME_T "d" +#endif + +#if defined(linux) +#if defined(__x86_64__) +#define PRI_TIME_T PRIu64 +#else +#define PRI_TIME_T "ld" +#endif +#endif + +#if defined(__MACH__) +#define PRI_TIME_T "ld" +#endif + +int +main(int argc, char *argv[]) +{ + struct stat st; + ssize_t len; + FILE *hdr; + char *ext; + unsigned char c[1]; + int fd, newline, count; + + if (argc != 3) + exit(1); + + if ((fd = open(argv[1], O_RDONLY)) == -1) + err(1, "open() %d", errno); + if ((hdr = fopen("static.h", "a+")) == NULL) + err(1, "fopen() %d", errno); + if ((ext = strchr(argv[2], '.')) != NULL) + *(ext)++ = '\0'; + else + ext = ""; + + if (stat(argv[1], &st) == -1) { + printf("stat(%s) failed: %d\n", argv[1], errno); + exit(1); + } + + printf("/**** AUTO GENERATED BY MAKEFILE - DO NOT TOUCH ****/\n"); + printf("#include <sys/param.h>\n\n"); + printf("u_int8_t static_%s_%s[] = {", ext, argv[2]); + + len = 0; + count = 0; + newline = 1; + for (;;) { + if (newline) { + printf("\n\t"); + count = 0; + newline = 0; + } + + len = read(fd, c, 1); + if (len == 0) + break; + + if (len == -1) { + printf("read(): %d\n", errno); + exit(1); + } + + if (len != 1) + exit(1); + + printf("0x%02x, ", c[0]); + if (count++ == 10) + newline = 1; + } + + close(fd); + + printf("};\n\n"); + printf("u_int32_t static_len_%s_%s = %" PRIu32 ";\n", + ext, argv[2], (u_int32_t)st.st_size); + + printf("time_t static_mtime_%s_%s = %" PRI_TIME_T ";\n", + ext, argv[2], st.st_mtime); + + fprintf(hdr, "extern u_int8_t static_%s_%s[];\n", ext, argv[2]); + fprintf(hdr, "extern u_int32_t static_len_%s_%s;\n", ext, argv[2]); + fprintf(hdr, "extern time_t static_mtime_%s_%s;\n", ext, argv[2]); + fclose(hdr); + + return (0); +} diff --git a/contrib/postgres/kore_pgsql.c b/contrib/postgres/kore_pgsql.c @@ -233,7 +233,7 @@ pgsql_conn_create(struct http_request *req, int idx) kore_debug("pgsql_conn_create(): %p", conn); memset(conn, 0, sizeof(*conn)); - conn->db = PQconnectdb("host=/tmp/ user=joris"); + conn->db = PQconnectdb("host=/var/run/postgresql/ user=joris"); if (conn->db == NULL || (PQstatus(conn->db) != CONNECTION_OK)) { req->pgsql[idx]->state = KORE_PGSQL_STATE_ERROR; req->pgsql[idx]->error = kore_strdup(PQerrorMessage(conn->db)); diff --git a/modules/example/build.sh b/modules/example/build.sh @@ -1,82 +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=example.module - -# The directory containing all your media files (HTML, CSS, ...). -# These files will be compiled into the module and symbols will -# be exported for you to use in your code. -MEDIA_DIR=media - -# The directory containing your module source. -SOURCE_DIR=src - -# The directory containing the Kore source code. -KORE_DIR=../../ - -# Compiler settings. -CC=gcc -CFLAGS="-I. -I${KORE_DIR}/includes -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" -else - LDFLAGS="-shared" -fi - -MODULE_BUILD_DATE=$(date +"%Y-%m-%d %H:%M:%S") - -### Begin building #### -echo "Building module ${MODULE}..." -rm -f ${MODULE} - -${CC} ${CFLAGS} tools/inject.c -o tools/inject - -if [ ! -d ${SOURCE_DIR}/${MEDIA_DIR} ]; then - mkdir ${SOURCE_DIR}/${MEDIA_DIR}; -fi -rm -f ${SOURCE_DIR}/${MEDIA_DIR}/* - -if [ ! -d .objs ]; then - mkdir .objs; -fi -rm -f .objs/* - -rm -f static.h - -for file in `find ${MEDIA_DIR} -type f \( ! -name \*.swp \)`; do - echo "Injecting $file"; - base=`basename $file`; - ./tools/inject $file $base > ${SOURCE_DIR}/${MEDIA_DIR}/${base}.c; - if [ $? -ne 0 ]; then - echo "Injection error, check above messages for clues."; - exit 1; - fi -done - -echo "#define MODULE_BUILD_DATE \"${MODULE_BUILD_DATE}\"" >> static.h - -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 ${SOURCE_DIR}/${MEDIA_DIR} -rm -rf .objs -rm -f tools/inject -rm -f static.h diff --git a/modules/example/media/index.html b/modules/example/media/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/modules/example/media/intro.jpg b/modules/example/media/intro.jpg Binary files differ. diff --git a/modules/example/media/params.html b/modules/example/media/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/modules/example/media/private.html b/modules/example/media/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/modules/example/media/private_test.html b/modules/example/media/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/modules/example/media/style.css b/modules/example/media/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/modules/example/media/upload.html b/modules/example/media/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/modules/example/module.conf b/modules/example/module.conf @@ -1,193 +0,0 @@ -# Example Kore configuration - -# Server configuration. -bind 127.0.0.1 443 - -# The path worker processes will chroot into after starting. -chroot /home/joris/src/kore - -# Worker processes will run as the specified user. -runas joris - -# Set workers to the amount of CPU's available in your system, -# kore will automatically distribute all workers on them. -workers 4 - -# The number of active connections each worker can handle. -# You might have to tweak this number based on your hardware. -#worker_max_connections 250 - -# Store the main process its pid in this file. -#pidfile /var/run/kore.pid - -# You can define a callback Kore calls from its parent process or -# workers everytime the kore_cb_interval timer (in milliseconds) is reached. -# -# NOTE: Remember that the parent process runs as root and is not chroot(). -# NOTE: If you want the cb to run on a worker, be sure to set kore_cb_worker. -#kore_cb my_callback -#kore_cb_interval 1000 -#kore_cb_worker 3 - -# HTTP specific settings. -# http_header_max Maximum size of HTTP headers (in bytes). -# -# http_postbody_max Maximum size of an HTTP POST body (in bytes). -# -# http_keepalive_time Maximum seconds an HTTP connection can be -# kept alive by the browser. -# (Set to 0 to disable keepalive completely). -# -# http_hsts_enable Send Strict Transport Security header in -# all responses. Parameter is the age. -# (Set to 0 to disable sending this header). -#http_header_max 4096 -#http_postbody_max 10240000 -#http_keepalive_time 0 -#http_hsts_enable 31536000 - -# Load modules (you can load multiple at the same time). -# An additional parameter can be specified as the "onload" function -# which Kore will call when the module is loaded/reloaded. -load modules/example/example.module example_load - -# Validators -# validator name type regex|function -# -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 - -# Specify the SSL ciphers that will be used. -#ssl_cipher ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK - -# If you wish to use EDH / ECDH specify a file containing -# a generated DH key (See OpenSSL dhparam). -#ssl_dhparam dh2048.pem - -# Set this if you want to disable SSL zlib compression. -ssl_no_compression - -# Specify the amount of seconds a SPDY connection is kept open. -# You can keep it open indefinately by setting this to 0. -#spdy_idle_time 120 - -# Authentication configuration -# -# Using authentication blocks you can define a standard way for -# Kore to validate your users. In the example below we create -# a authentication block called auth_example, which requires -# a cookie (session_id) to be set. -# -# If no cookie is present or the cookie is not valid according -# to the set validator, Kore will redirect the browser to the -# URI set in authentication_uri. -# -# Page handlers can be bound to authentication by specifying -# authentication block at the end of the page directive (see below). -authentication auth_example { - # The authentication type denotes the way the user should - # be authenticated. - # - # Allow values: - # - cookie (checks for the cookie presence + pass to validator) - # - header (checks for header presence + pass to validator) - # - requuest (passes the http_request to the validator) - # - # Use cases for request could for example be IP based ACLs or - # any other criteria that can be extracted from a http_request. - # - # The request type does not need an authentication_validator. - # - authentication_type cookie - - # The name of whatever we are looking for. - authentication_value session_id - - # The validator that will be called to verify the cookie. - # Note this is YOUR validator, Kore does not have built-in - # session support. You must add this manually using your - # preferred method (Storing it in postgres, redis, ...) - authentication_validator v_session - - # The URI Kore will redirect to if a authentication fails. - # If this is not set, Kore will return a simple 403. - authentication_uri /private -} - -# Domain configuration -# -# Each domain configuration starts with listing what domain -# the directives that follow are to be applied upon. -# -# Additionally you can specify the following in a domain configuration: -# -# accesslog -# - File where all requests are logged. -# require_client_cert -# - Asks the client to present a certificate -# matching the CA given to require_client_cert -# -# Handlers -# -# Handlers are either static (for fixed paths) or dynamic. -# Dynamic handlers take a POSIX regular expression as its path. -# -# Syntax: -# handler path module_callback [auth block] -# -# Note that the auth block is optional and if set will force Kore to -# authenticate the user according to the authentication block its settings -# before allowing access to the page. - -# Example domain that responds to localhost. -domain localhost { - certfile cert/server.crt - certkey cert/server.key - accesslog /var/log/kore_access.log - - # Page handlers with no authentication required. - 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 - - # Page handlers with authentication. - static /private/test serve_private_test auth_example - - # Configure /params-test POST to only accept the following parameters. - # They are automatically tested against the validator listed. - # If the validator would fail Kore will automatically remove the - # failing parameter, indicating something was wrong with it. - # Any parameters not present in the params block are also filtered out. - params post /params-test { - validate test1 v_example - validate test2 v_regex - } - - # Configure a GET parameter that /params-test can received. As before - # this is validated against the validator and removed if validation - # fails. All extra parameters in the GET query are filtered out. - params get /params-test { - validate arg1 v_example - validate id v_number - } -} - -#domain domain.com { -# certfile cert/other/server.crt -# certkey cert/other/server.key -# accesslog /var/log/other_kore_access.log -# require_client_cert cert/other/ca.crt - -# static /css/style.css serve_style_css -# static / serve_index -# dynamic ^/[a-z0-9_]*$ serve_profile -#} diff --git a/modules/example/src/example.c b/modules/example/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.h" -#include "http.h" - -#include "static.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 <= static_mtime_css_style) { - http_response(req, 304, NULL, 0); - } else { - date = kore_time_to_date(static_mtime_css_style); - if (date != NULL) - http_response_header_add(req, "last-modified", date); - - http_response_header_add(req, "content-type", "text/css"); - http_response(req, 200, static_css_style, static_len_css_style); - } - - return (KORE_RESULT_OK); -} - -int -serve_index(struct http_request *req) -{ - http_response_header_add(req, "content-type", "text/html"); - http_response(req, 200, static_html_index, static_len_html_index); - - return (KORE_RESULT_OK); -} - -int -serve_intro(struct http_request *req) -{ - http_response_header_add(req, "content-type", "image/jpg"); - http_response(req, 200, static_jpg_intro, static_len_jpg_intro); - - 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(static_len_html_upload); - kore_buf_append(b, static_html_upload, static_len_html_upload); - - 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(static_len_html_params); - kore_buf_append(b, static_html_params, static_len_html_params); - - /* - * 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, static_html_private, static_len_html_private); - - 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, static_html_private_test, - static_len_html_private_test); - - 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/modules/example/tools/inject.c b/modules/example/tools/inject.c @@ -1,119 +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 <sys/param.h> -#include <sys/stat.h> - -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <inttypes.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#if defined(OpenBSD) -#define PRI_TIME_T "d" -#endif - -#if defined(linux) -#if defined(__x86_64__) -#define PRI_TIME_T PRIu64 -#else -#define PRI_TIME_T "ld" -#endif -#endif - -#if defined(__MACH__) -#define PRI_TIME_T "ld" -#endif - -int -main(int argc, char *argv[]) -{ - struct stat st; - ssize_t len; - FILE *hdr; - char *ext; - unsigned char c[1]; - int fd, newline, count; - - if (argc != 3) - exit(1); - - if ((fd = open(argv[1], O_RDONLY)) == -1) - err(1, "open() %d", errno); - if ((hdr = fopen("static.h", "a+")) == NULL) - err(1, "fopen() %d", errno); - if ((ext = strchr(argv[2], '.')) != NULL) - *(ext)++ = '\0'; - else - ext = ""; - - if (stat(argv[1], &st) == -1) { - printf("stat(%s) failed: %d\n", argv[1], errno); - exit(1); - } - - printf("/**** AUTO GENERATED BY MAKEFILE - DO NOT TOUCH ****/\n"); - printf("#include <sys/param.h>\n\n"); - printf("u_int8_t static_%s_%s[] = {", ext, argv[2]); - - len = 0; - count = 0; - newline = 1; - for (;;) { - if (newline) { - printf("\n\t"); - count = 0; - newline = 0; - } - - len = read(fd, c, 1); - if (len == 0) - break; - - if (len == -1) { - printf("read(): %d\n", errno); - exit(1); - } - - if (len != 1) - exit(1); - - printf("0x%02x, ", c[0]); - if (count++ == 10) - newline = 1; - } - - close(fd); - - printf("};\n\n"); - printf("u_int32_t static_len_%s_%s = %" PRIu32 ";\n", - ext, argv[2], (u_int32_t)st.st_size); - - printf("time_t static_mtime_%s_%s = %" PRI_TIME_T ";\n", - ext, argv[2], st.st_mtime); - - fprintf(hdr, "extern u_int8_t static_%s_%s[];\n", ext, argv[2]); - fprintf(hdr, "extern u_int32_t static_len_%s_%s;\n", ext, argv[2]); - fprintf(hdr, "extern time_t static_mtime_%s_%s;\n", ext, argv[2]); - fclose(hdr); - - return (0); -} diff --git a/modules/skeleton/build.sh b/modules/skeleton/build.sh @@ -1,86 +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=site.module - -# The directory containing all your media files (HTML, CSS, ...). -# These files will be compiled into the module and symbols will -# be exported for you to use in your code. -MEDIA_DIR=media - -# The directory containing your module source. -SOURCE_DIR=src - -# The directory containing the Kore source code. -KORE_DIR="notset" -if [ ${KORE_DIR} = "notset" ]; then - echo "Please edit build.sh and set KORE_DIR properly"; - exit; -fi - -# Compiler settings. -CC=gcc -CFLAGS="-I. -I${KORE_DIR}/includes -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" -else - LDFLAGS="-shared" -fi - -MODULE_BUILD_DATE=$(date +"%Y-%m-%d %H:%M:%S") - -### Begin building #### -echo "Building module ${MODULE}..." -rm -f ${MODULE} - -${CC} ${CFLAGS} tools/inject.c -o tools/inject - -if [ ! -d ${SOURCE_DIR}/${MEDIA_DIR} ]; then - mkdir ${SOURCE_DIR}/${MEDIA_DIR}; -fi -rm -f ${SOURCE_DIR}/${MEDIA_DIR}/* - -if [ ! -d .objs ]; then - mkdir .objs; -fi -rm -f .objs/* - -rm -f static.h - -for file in `find ${MEDIA_DIR} -type f \( ! -name \*.swp \)`; do - echo "Injecting $file"; - base=`basename $file`; - ./tools/inject $file $base > ${SOURCE_DIR}/${MEDIA_DIR}/${base}.c; - if [ $? -ne 0 ]; then - echo "Injection error, check above messages for clues."; - exit 1; - fi -done - -echo "#define MODULE_BUILD_DATE \"${MODULE_BUILD_DATE}\"" >> static.h - -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 ${SOURCE_DIR}/${MEDIA_DIR} -rm -rf .objs -rm -f tools/inject -rm -f static.h diff --git a/modules/skeleton/media/.gitignore b/modules/skeleton/media/.gitignore diff --git a/modules/skeleton/src/.gitignore b/modules/skeleton/src/.gitignore diff --git a/modules/skeleton/tools/inject.c b/modules/skeleton/tools/inject.c @@ -1,119 +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 <sys/param.h> -#include <sys/stat.h> - -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <inttypes.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#if defined(OpenBSD) -#define PRI_TIME_T "d" -#endif - -#if defined(linux) -#if defined(__x86_64__) -#define PRI_TIME_T PRIu64 -#else -#define PRI_TIME_T "ld" -#endif -#endif - -#if defined(__MACH__) -#define PRI_TIME_T "ld" -#endif - -int -main(int argc, char *argv[]) -{ - struct stat st; - ssize_t len; - FILE *hdr; - char *ext; - unsigned char c[1]; - int fd, newline, count; - - if (argc != 3) - exit(1); - - if ((fd = open(argv[1], O_RDONLY)) == -1) - err(1, "open() %d", errno); - if ((hdr = fopen("static.h", "a+")) == NULL) - err(1, "fopen() %d", errno); - if ((ext = strchr(argv[2], '.')) != NULL) - *(ext)++ = '\0'; - else - ext = ""; - - if (stat(argv[1], &st) == -1) { - printf("stat(%s) failed: %d\n", argv[1], errno); - exit(1); - } - - printf("/**** AUTO GENERATED BY MAKEFILE - DO NOT TOUCH ****/\n"); - printf("#include <sys/param.h>\n\n"); - printf("u_int8_t static_%s_%s[] = {", ext, argv[2]); - - len = 0; - count = 0; - newline = 1; - for (;;) { - if (newline) { - printf("\n\t"); - count = 0; - newline = 0; - } - - len = read(fd, c, 1); - if (len == 0) - break; - - if (len == -1) { - printf("read(): %d\n", errno); - exit(1); - } - - if (len != 1) - exit(1); - - printf("0x%02x, ", c[0]); - if (count++ == 10) - newline = 1; - } - - close(fd); - - printf("};\n\n"); - printf("u_int32_t static_len_%s_%s = %" PRIu32 ";\n", - ext, argv[2], (u_int32_t)st.st_size); - - printf("time_t static_mtime_%s_%s = %" PRI_TIME_T ";\n", - ext, argv[2], st.st_mtime); - - fprintf(hdr, "extern u_int8_t static_%s_%s[];\n", ext, argv[2]); - fprintf(hdr, "extern u_int32_t static_len_%s_%s;\n", ext, argv[2]); - fprintf(hdr, "extern time_t static_mtime_%s_%s;\n", ext, argv[2]); - fclose(hdr); - - return (0); -}