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 34c2f31a93016062ca38c04d049eccc96ad6b39c
parent c80e1d3767569ce5a0702de5824b2cd9d2502ee8
Author: Joris Vink <joris@coders.se>
Date:   Sat,  9 Nov 2013 16:21:52 +0100

Add validators to kore, specified in the configuration using 'validator' keyword.

Example:
	validator	v_id	function	v_id_function
	validator	v_url	regex		^/url/path/[a-z]*$

You can then call these using kore_validator_run(char *, char *), example:

	if (!kore_validator_run("v_url", req->path))
		[req->path is bad];

Diffstat:
Makefile | 2+-
includes/kore.h | 19+++++++++++++++++++
modules/example/module.conf | 7+++++++
modules/example/src/example.c | 34++++++++++++++++++++++++++++++++++
src/config.c | 27+++++++++++++++++++++++++++
src/kore.c | 1+
src/module.c | 8++++++++
src/validator.c | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 207 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile @@ -5,7 +5,7 @@ BIN=kore S_SRC+= src/kore.c src/accesslog.c src/buf.c src/config.c src/connection.c \ src/domain.c src/http.c src/mem.c src/module.c src/net.c src/pool.c \ - src/spdy.c src/utils.c src/worker.c src/zlib_dict.c + src/spdy.c src/validator.c src/utils.c src/worker.c src/zlib_dict.c S_OBJS= $(S_SRC:.c=.o) CFLAGS+=-Wall -Wstrict-prototypes -Wmissing-prototypes diff --git a/includes/kore.h b/includes/kore.h @@ -194,6 +194,19 @@ struct kore_domain { TAILQ_HEAD(kore_domain_h, kore_domain); +#define KORE_VALIDATOR_TYPE_REGEX 1 +#define KORE_VALIDATOR_TYPE_FUNCTION 2 + +struct kore_validator { + u_int8_t type; + char *name; + char *arg; + regex_t rctx; + int (*func)(char *); + + TAILQ_ENTRY(kore_validator) list; +}; + #define KORE_BUF_INITIAL 128 #define KORE_BUF_INCREMENT KORE_BUF_INITIAL @@ -333,11 +346,17 @@ void kore_module_load(char *); void kore_module_reload(void); int kore_module_loaded(void); void kore_domain_closelogs(void); +void *kore_module_getsym(char *); void kore_domain_sslstart(struct kore_domain *); int kore_module_handler_new(char *, char *, char *, int); struct kore_domain *kore_domain_lookup(const char *); struct kore_module_handle *kore_module_handler_find(char *, char *); +void kore_validator_init(void); +void kore_validator_reload(void); +int kore_validator_add(char *, u_int8_t, char *); +int kore_validator_run(char *, char *); + void fatal(const char *, ...); void kore_debug_internal(char *, int, const char *, ...); diff --git a/modules/example/module.conf b/modules/example/module.conf @@ -53,6 +53,12 @@ workers 4 # Specifies what module to be loaded. load modules/example/example.module +# Validators +# validator name type regex|function +# +validator v_example function v_example_func +validator v_regex regex ^/test/[a-z]*$ + # 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 @@ -98,6 +104,7 @@ domain localhost { static /spdy-reset serve_spdyreset static /upload serve_file_upload static /lock-test serve_lock_test + static /validator serve_validator } #domain domain.com { diff --git a/modules/example/src/example.c b/modules/example/src/example.c @@ -26,8 +26,10 @@ 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 *); void my_callback(void); +int v_example_func(char *); void test_base64(u_int8_t *, u_int32_t, struct kore_buf *); char *b64tests[] = { @@ -204,6 +206,27 @@ test_base64(u_int8_t *src, u_int32_t slen, struct kore_buf *res) kore_buf_appendf(res, "\n"); } +int +serve_validator(struct http_request *req) +{ + if (kore_validator_run("v_example", "test")) + kore_log(LOG_NOTICE, "v_example ok (expected)"); + else + kore_log(LOG_NOTICE, "v_example failed"); + + if (kore_validator_run("v_regex", "/test/123")) + kore_log(LOG_NOTICE, "regex #1 ok"); + else + kore_log(LOG_NOTICE, "regex #1 failed (expected)"); + + if (kore_validator_run("v_regex", "/test/joris")) + kore_log(LOG_NOTICE, "regex #2 ok (expected)"); + else + kore_log(LOG_NOTICE, "regex #2 failed"); + + return (http_response(req, 200, (u_int8_t *)"OK", 2)); +} + void my_callback(void) { @@ -212,3 +235,14 @@ my_callback(void) else kore_log(LOG_NOTICE, "running from parent"); } + +int +v_example_func(char *data) +{ + kore_log(LOG_NOTICE, "v_example_func called"); + + if (!strcmp(data, "test")) + return (KORE_RESULT_OK); + + return (KORE_RESULT_ERROR); +} diff --git a/src/config.c b/src/config.c @@ -46,6 +46,7 @@ static int configure_http_header_max(char **); static int configure_http_postbody_max(char **); static int configure_http_hsts_enable(char **); static int configure_http_keepalive_time(char **); +static int configure_validator(char **); static void domain_sslstart(void); static struct { @@ -77,6 +78,7 @@ static struct { { "http_postbody_max", configure_http_postbody_max }, { "http_hsts_enable", configure_http_hsts_enable }, { "http_keepalive_time", configure_http_keepalive_time }, + { "validator", configure_validator }, { NULL, NULL }, }; @@ -599,6 +601,31 @@ configure_http_keepalive_time(char **argv) return (KORE_RESULT_OK); } +static int +configure_validator(char **argv) +{ + u_int8_t type; + + if (argv[3] == NULL) + return (KORE_RESULT_ERROR); + + if (!strcmp(argv[2], "regex")) { + type = KORE_VALIDATOR_TYPE_REGEX; + } else if (!strcmp(argv[2], "function")) { + type = KORE_VALIDATOR_TYPE_FUNCTION; + } else { + printf("bad type for validator %s\n", argv[1]); + return (KORE_RESULT_ERROR); + } + + if (!kore_validator_add(argv[1], type, argv[3])) { + printf("bad validator specified: %s\n", argv[1]); + return (KORE_RESULT_ERROR); + } + + return (KORE_RESULT_OK); +} + static void domain_sslstart(void) { diff --git a/src/kore.c b/src/kore.c @@ -87,6 +87,7 @@ main(int argc, char *argv[]) kore_log_init(); kore_mem_init(); kore_domain_init(); + kore_validator_init(); kore_server_sslstart(); kore_parse_config(); diff --git a/src/module.c b/src/module.c @@ -86,6 +86,8 @@ kore_module_reload(void) } } + kore_validator_reload(); + if (kore_module_onload != NULL) { onload = dlsym(mod_handle, kore_module_onload); if (onload == NULL) @@ -169,3 +171,9 @@ kore_module_handler_find(char *domain, char *path) return (NULL); } + +void * +kore_module_getsym(char *symbol) +{ + return (dlsym(mod_handle, symbol)); +} diff --git a/src/validator.c b/src/validator.c @@ -0,0 +1,110 @@ +/* + * 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" + +TAILQ_HEAD(, kore_validator) validators; + +void +kore_validator_init(void) +{ + TAILQ_INIT(&validators); +} + +int +kore_validator_add(char *name, u_int8_t type, char *arg) +{ + struct kore_validator *val; + + val = kore_malloc(sizeof(*val)); + val->type = type; + + switch (val->type) { + case KORE_VALIDATOR_TYPE_REGEX: + if (regcomp(&(val->rctx), arg, REG_NOSUB)) { + kore_mem_free(val); + kore_log(LOG_NOTICE, + "validator %s has bad regex %s", name, arg); + return (KORE_RESULT_ERROR); + } + break; + case KORE_VALIDATOR_TYPE_FUNCTION: + if ((val->func = kore_module_getsym(arg)) == NULL) { + kore_mem_free(val); + kore_log(LOG_NOTICE, + "validator %s has undefined callback %s", + name, arg); + return (KORE_RESULT_ERROR); + } + break; + default: + kore_mem_free(val); + return (KORE_RESULT_ERROR); + } + + val->arg = kore_strdup(arg); + val->name = kore_strdup(name); + TAILQ_INSERT_TAIL(&validators, val, list); + + return (KORE_RESULT_OK); +} + +int +kore_validator_run(char *name, char *data) +{ + int r; + struct kore_validator *val; + + TAILQ_FOREACH(val, &validators, list) { + if (strcmp(val->name, name)) + continue; + + switch (val->type) { + case KORE_VALIDATOR_TYPE_REGEX: + if (!regexec(&(val->rctx), data, 0, NULL, 0)) + r = KORE_RESULT_OK; + else + r = KORE_RESULT_ERROR; + break; + case KORE_VALIDATOR_TYPE_FUNCTION: + r = val->func(data); + break; + default: + r = KORE_RESULT_ERROR; + kore_log(LOG_NOTICE, "invalid type %d for validator %s", + val->type, val->name); + break; + } + + return (r); + } + + return (KORE_RESULT_ERROR); +} + +void +kore_validator_reload(void) +{ + struct kore_validator *val; + + TAILQ_FOREACH(val, &validators, list) { + if (val->type != KORE_VALIDATOR_TYPE_FUNCTION) + continue; + + if ((val->func = kore_module_getsym(val->arg)) == NULL) + fatal("no function for validator %s found", val->name); + } +}