diff --git a/Makefile b/Makefile index c036bc9..fd8cb8b 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,7 @@ ifneq ("$(NOHTTP)", "") FEATURES+=-DKORE_NO_HTTP else S_SRC+= src/auth.c src/accesslog.c src/http.c \ - src/validator.c src/websocket.c + src/route.c src/validator.c src/websocket.c endif ifneq ("$(PGSQL)", "") diff --git a/examples/async-curl/conf/async-curl.conf b/examples/async-curl/conf/async-curl.conf index 9f7c8fd..85c623a 100644 --- a/examples/async-curl/conf/async-curl.conf +++ b/examples/async-curl/conf/async-curl.conf @@ -5,8 +5,6 @@ server tls { } workers 1 -tls_dhparam dh2048.pem - pledge dns domain * { @@ -15,6 +13,11 @@ domain * { certfile cert/server.pem certkey cert/key.pem - route / http - route /ftp ftp + route / { + handler http + } + + route /ftp { + handler ftp + } } diff --git a/examples/cookies/conf/cookies.conf b/examples/cookies/conf/cookies.conf index 34f3dfd..1c0b219 100644 --- a/examples/cookies/conf/cookies.conf +++ b/examples/cookies/conf/cookies.conf @@ -6,15 +6,21 @@ server tls { load ./cookies.so -tls_dhparam dh2048.pem - domain * { attach tls certfile cert/server.pem certkey cert/key.pem - route / serve_cookies - route /secure serve_cookies - route /vault serve_cookies + route / { + handler serve_cookies + } + + route /secure { + handler serve_cookies + } + + route /vault { + handler serve_cookies + } } diff --git a/examples/cpp/conf/cpp.conf b/examples/cpp/conf/cpp.conf index 9cb58c7..6ed806f 100755 --- a/examples/cpp/conf/cpp.conf +++ b/examples/cpp/conf/cpp.conf @@ -5,12 +5,14 @@ server tls { } load ./cpp.so -tls_dhparam dh2048.pem domain * { attach tls certfile cert/server.pem certkey cert/key.pem - route / page + + route / { + handler page + } } diff --git a/examples/cpp/dh2048.pem b/examples/cpp/dh2048.pem deleted file mode 100755 index 511de69..0000000 --- a/examples/cpp/dh2048.pem +++ /dev/null @@ -1,8 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIIBCAKCAQEAn4f4Qn5SudFjEYPWTbUaOTLUH85YWmmPFW1+b5bRa9ygr+1wfamv -VKVT7jO8c4msSNikUf6eEfoH0H4VTCaj+Habwu+Sj+I416r3mliMD4SjNsUJrBrY -Y0QV3ZUgZz4A8ARk/WwQcRl8+ZXJz34IaLwAcpyNhoV46iHVxW0ty8ND0U4DIku/ -PNayKimu4BXWXk4RfwNVP59t8DQKqjshZ4fDnbotskmSZ+e+FHrd+Kvrq/WButvV -Bzy9fYgnUlJ82g/bziCI83R2xAdtH014fR63MpElkqdNeChb94pPbEdFlNUvYIBN -xx2vTUQMqRbB4UdG2zuzzr5j98HDdblQ+wIBAg== ------END DH PARAMETERS----- \ No newline at end of file diff --git a/examples/generic/conf/generic.conf b/examples/generic/conf/generic.conf index 18cdcca..5b43814 100644 --- a/examples/generic/conf/generic.conf +++ b/examples/generic/conf/generic.conf @@ -6,8 +6,6 @@ server tls { load ./generic.so example_load -tls_dhparam dh2048.pem - http_body_max 1024000000 http_body_disk_offload 1024000 diff --git a/examples/integers/README.md b/examples/integers/README.md index c2c1748..974a965 100644 --- a/examples/integers/README.md +++ b/examples/integers/README.md @@ -2,13 +2,13 @@ Test parameter to integer conversions. Run: ``` - # kodev run + $ kodev run ``` Test: ``` - # curl -i -k https://127.0.0.1:8888/?id=123123 - # curl -i -k https://127.0.0.1:8888/?id=-123123 + $ curl -i -k https://127.0.0.1:8888/?id=123123 + $ curl -i -k https://127.0.0.1:8888/?id=-123123 ``` The correct integer types should only be represented in the output. diff --git a/examples/integers/conf/integers.conf b/examples/integers/conf/integers.conf index 0493ff7..76d7941 100755 --- a/examples/integers/conf/integers.conf +++ b/examples/integers/conf/integers.conf @@ -9,8 +9,6 @@ load ./integers.so workers 2 worker_max_connections 5000 -tls_dhparam dh2048.pem - validator v_id regex ^-?[0-9]*.?[0-9]+$ domain * { @@ -18,10 +16,12 @@ domain * { certfile cert/server.pem certkey cert/key.pem - route / page - # allowed parameters in the query string for GETs - params qs:get / { - validate id v_id + route / { + handler page + methods get + + # allowed parameters in the query string for GETs + validate get id v_id } } diff --git a/examples/json/conf/json.conf b/examples/json/conf/json.conf index b896c13..3e26448 100755 --- a/examples/json/conf/json.conf +++ b/examples/json/conf/json.conf @@ -6,14 +6,14 @@ server tls { load ./json.so -tls_dhparam dh2048.pem - domain 127.0.0.1 { attach tls certfile cert/server.pem certkey cert/key.pem - route / page - restrict / post + route / { + handler page + methods post + } } diff --git a/examples/json_yajl/.gitignore b/examples/json_yajl/.gitignore deleted file mode 100755 index 28ab2ed..0000000 --- a/examples/json_yajl/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.o -.objs -json_yajl.so -assets.h -cert diff --git a/examples/json_yajl/README.md b/examples/json_yajl/README.md deleted file mode 100644 index 3c12590..0000000 --- a/examples/json_yajl/README.md +++ /dev/null @@ -1,21 +0,0 @@ -This example demonstrates how you can use external libs in your application. - -In this case we link against yajl (Yet Another JSON library) in order to -parse a JSON string that was POSTed to the server. - -Take a peek at conf/build.conf for different build flavors and how to -link to other libraries. - -Run: -``` - $ kodev run -``` - -Test: -``` - $ curl -i -k -d '{"foo":{"bar": "Hello world"}}' https://127.0.0.1:8888 -``` - -The result should echo back the foo.bar JSON path value: Hello world. - -The yajl repo is available @ https://github.com/lloyd/yajl diff --git a/examples/json_yajl/conf/build.conf b/examples/json_yajl/conf/build.conf deleted file mode 100644 index ec76646..0000000 --- a/examples/json_yajl/conf/build.conf +++ /dev/null @@ -1,19 +0,0 @@ -# json_yajl build config -# You can switch flavors using: kodev flavor [newflavor] - -# The cflags below are shared between flavors -cflags=-Wall -Wmissing-declarations -Wshadow -cflags=-Wstrict-prototypes -Wmissing-prototypes -cflags=-Wpointer-arith -Wcast-qual -Wsign-compare - -dev { - # These cflags are added to the shared ones when - # you build the "dev" flavor. - cflags=-g - ldflags=-lyajl -} - -#prod { -# You can specify additional CFLAGS here which are only -# included if you build with the "prod" flavor. -#} diff --git a/examples/json_yajl/conf/json_yajl.conf b/examples/json_yajl/conf/json_yajl.conf deleted file mode 100755 index 29d2c01..0000000 --- a/examples/json_yajl/conf/json_yajl.conf +++ /dev/null @@ -1,18 +0,0 @@ -# Placeholder configuration - -server tls { - bind 127.0.0.1 8888 -} - -load ./json_yajl.so - -tls_dhparam dh2048.pem - -domain 127.0.0.1 { - attach tls - - certfile cert/server.pem - certkey cert/key.pem - - route / page -} diff --git a/examples/json_yajl/src/json_yajl.c b/examples/json_yajl/src/json_yajl.c deleted file mode 100755 index 8490e7f..0000000 --- a/examples/json_yajl/src/json_yajl.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2013-2018 Joris Vink - * - * 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 -#include - -#include - -int page(struct http_request *); - -int -page(struct http_request *req) -{ - ssize_t ret; - struct kore_buf *buf; - char *body; - yajl_val node, v; - char eb[1024]; - u_int8_t data[BUFSIZ]; - const char *path[] = { "foo", "bar", NULL }; - - /* We only allow POST/PUT methods. */ - if (req->method != HTTP_METHOD_POST && - req->method != HTTP_METHOD_PUT) { - http_response_header(req, "allow", "POST, PUT"); - http_response(req, HTTP_STATUS_METHOD_NOT_ALLOWED, NULL, 0); - return (KORE_RESULT_OK); - } - - /* - * Read the entire received body into a memory buffer. - */ - buf = kore_buf_alloc(128); - for (;;) { - ret = http_body_read(req, data, sizeof(data)); - if (ret == -1) { - kore_buf_free(buf); - kore_log(LOG_NOTICE, "error reading body"); - http_response(req, 500, NULL, 0); - return (KORE_RESULT_OK); - } - - if (ret == 0) - break; - - kore_buf_append(buf, data, ret); - } - - /* Grab our body data as a NUL-terminated string. */ - body = kore_buf_stringify(buf, NULL); - - /* Parse the body via yajl now. */ - node = yajl_tree_parse(body, eb, sizeof(eb)); - if (node == NULL) { - if (strlen(eb)) { - kore_log(LOG_NOTICE, "parse error: %s", eb); - } else { - kore_log(LOG_NOTICE, "parse error: unknown"); - } - - kore_buf_free(buf); - http_response(req, 400, NULL, 0); - return (KORE_RESULT_OK); - } - - /* Reuse old buffer, don't need it anymore for body. */ - kore_buf_reset(buf); - - /* Attempt to grab foo.bar from the JSON tree. */ - v = yajl_tree_get(node, path, yajl_t_string); - if (v == NULL) { - kore_buf_appendf(buf, "no such path: foo.bar\n"); - } else { - kore_buf_appendf(buf, "foo.bar = '%s'\n", YAJL_GET_STRING(v)); - } - - /* Release the JSON tree now. */ - yajl_tree_free(node); - - /* Respond to the client. */ - http_response(req, 200, buf->data, buf->offset); - kore_buf_free(buf); - - return (KORE_RESULT_OK); -} diff --git a/examples/jsonrpc/conf/jsonrpc.conf b/examples/jsonrpc/conf/jsonrpc.conf index c8ff8d9..f727f12 100644 --- a/examples/jsonrpc/conf/jsonrpc.conf +++ b/examples/jsonrpc/conf/jsonrpc.conf @@ -6,14 +6,17 @@ server tls { load ./jsonrpc.so -tls_dhparam dh2048.pem - domain * { attach tls certfile cert/server.pem certkey cert/key.pem - route / homepage - route /v1 v1 + route / { + handler homepage + } + + route /v1 { + handler v1 + } } diff --git a/examples/memtag/conf/memtag.conf b/examples/memtag/conf/memtag.conf index f981b6c..5e9fc7b 100644 --- a/examples/memtag/conf/memtag.conf +++ b/examples/memtag/conf/memtag.conf @@ -6,13 +6,13 @@ server tls { load ./memtag.so init -tls_dhparam dh2048.pem - domain * { attach tls certfile cert/server.pem certkey cert/key.pem - route / page + route / { + handler page + } } diff --git a/examples/messaging/conf/messaging.conf b/examples/messaging/conf/messaging.conf index f8680ae..e195cb0 100644 --- a/examples/messaging/conf/messaging.conf +++ b/examples/messaging/conf/messaging.conf @@ -5,14 +5,18 @@ server tls { } load ./messaging.so init -tls_dhparam dh2048.pem -workers 4 domain * { attach tls certfile cert/server.pem certkey cert/key.pem - route / page - route /shutdown page_shutdown + + route / { + handler page + } + + route /shutdown { + handler page_shutdown + } } diff --git a/examples/nohttp/conf/nohttp.conf b/examples/nohttp/conf/nohttp.conf index d5912ad..409f37a 100644 --- a/examples/nohttp/conf/nohttp.conf +++ b/examples/nohttp/conf/nohttp.conf @@ -4,8 +4,6 @@ server tls { bind 127.0.0.1 8888 connection_setup } -tls_dhparam dh2048.pem - domain * { attach tls diff --git a/examples/parameters/conf/parameters.conf b/examples/parameters/conf/parameters.conf index c51798c..b6fe08c 100755 --- a/examples/parameters/conf/parameters.conf +++ b/examples/parameters/conf/parameters.conf @@ -6,8 +6,6 @@ server tls { load ./parameters.so -tls_dhparam dh2048.pem - # The validator used to validate the 'id' parameter # defined below. We'll use a simple regex to make sure # it only matches positive numbers. @@ -19,15 +17,10 @@ domain * { certfile cert/server.pem certkey cert/key.pem - route / page + route / { + handler page + methods get - # The parameters allowed for "/" (GET method). - # - # If you would want to declare parameters available - # to the page handler for POST, swap the 'get' setting - # to 'post' instead, Kore takes care of the rest. - params qs:get / { - # Validate the id parameter with the v_id validator. - validate id v_id + validate qs:get id v_id } } diff --git a/examples/pgsql-sync/conf/pgsql-sync.conf b/examples/pgsql-sync/conf/pgsql-sync.conf index 543c2b4..9ef54fa 100644 --- a/examples/pgsql-sync/conf/pgsql-sync.conf +++ b/examples/pgsql-sync/conf/pgsql-sync.conf @@ -4,13 +4,15 @@ server tls { bind 127.0.0.1 8888 } -load ./pgsql-sync.so init -tls_dhparam dh2048.pem +load ./pgsql-sync.so init domain * { attach tls certfile cert/server.pem certkey cert/key.pem - route / page + + route / { + handler page + } } diff --git a/examples/pgsql/conf/pgsql.conf b/examples/pgsql/conf/pgsql.conf index faeb3c9..49e0133 100755 --- a/examples/pgsql/conf/pgsql.conf +++ b/examples/pgsql/conf/pgsql.conf @@ -10,8 +10,6 @@ server other { bind 127.0.0.1 8889 connection_new } -tls_dhparam dh2048.pem - http_keepalive_time 0 domain * { @@ -20,6 +18,11 @@ domain * { certfile cert/server.pem certkey cert/key.pem - route / page - route /hello hello + route / { + handler page + } + + route /hello { + handler hello + } } diff --git a/examples/pipe_task/conf/pipe_task.conf b/examples/pipe_task/conf/pipe_task.conf index 4be394e..56b40ac 100755 --- a/examples/pipe_task/conf/pipe_task.conf +++ b/examples/pipe_task/conf/pipe_task.conf @@ -4,8 +4,6 @@ server tls { bind 127.0.0.1 8888 } -tls_dhparam dh2048.pem - websocket_maxframe 65536 websocket_timeout 10000 @@ -15,6 +13,12 @@ domain * { certfile cert/server.pem certkey cert/key.pem - route / page - route /connect page_ws_connect + route / { + handler page + } + + route /connect { + handler page_ws_connect + methods get + } } diff --git a/examples/pipe_task/src/pipe_task.c b/examples/pipe_task/src/pipe_task.c index 0b981b5..472e503 100755 --- a/examples/pipe_task/src/pipe_task.c +++ b/examples/pipe_task/src/pipe_task.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -49,17 +50,12 @@ void pipe_data_available(struct kore_task *); /* Our pipe reader. */ struct kore_task pipe_task; -/* Module init function (see config). */ -int -init(int state) +void +kore_worker_configure(void) { - /* Do not allow reload. */ - if (state == KORE_MODULE_UNLOAD) - return (KORE_RESULT_ERROR); - /* Only do this on a dedicated worker. */ if (worker->id != 1) - return (KORE_RESULT_OK); + return; /* Create our task. */ kore_task_create(&pipe_task, pipe_reader); @@ -69,8 +65,6 @@ init(int state) /* Start the task. */ kore_task_run(&pipe_task); - - return (KORE_RESULT_OK); } /* Called whenever we get a new websocket connection. */ diff --git a/examples/sse/conf/sse.conf b/examples/sse/conf/sse.conf index e373708..03cfb2c 100755 --- a/examples/sse/conf/sse.conf +++ b/examples/sse/conf/sse.conf @@ -4,10 +4,8 @@ server tls { bind 127.0.0.1 8888 } -load ./sse.so -tls_dhparam dh2048.pem - -http_keepalive_time 600 +load ./sse.so +http_keepalive_time 600 domain * { attach tls @@ -15,6 +13,11 @@ domain * { certfile cert/server.pem certkey cert/key.pem - route / page - route /subscribe subscribe + route / { + handler page + } + + route /subscribe { + handler subscribe + } } diff --git a/examples/tasks/conf/tasks.conf b/examples/tasks/conf/tasks.conf index b6f34df..3768391 100644 --- a/examples/tasks/conf/tasks.conf +++ b/examples/tasks/conf/tasks.conf @@ -4,8 +4,6 @@ server tls { bind 127.0.0.1 8888 } -tls_dhparam dh2048.pem - task_threads 4 worker_max_connections 1000 http_keepalive_time 0 @@ -19,14 +17,14 @@ domain * { certkey cert/key.pem accesslog kore_access.log - route / page_handler - route /post_back post_back - - params qs:get / { - validate user v_user + route / { + handler page_handler + validate qs:get user v_user } - params post /post_back { - validate user v_user + route /post_back { + handler post_back + methods post + validate post user v_user } } diff --git a/examples/tls-proxy/conf/tls-proxy.conf b/examples/tls-proxy/conf/tls-proxy.conf index 8b0742b..2a58dff 100755 --- a/examples/tls-proxy/conf/tls-proxy.conf +++ b/examples/tls-proxy/conf/tls-proxy.conf @@ -1,7 +1,6 @@ # Kore as a TLS proxy configuration. load ./tls-proxy.so -tls_dhparam dh2048.pem # # Bind the proxy to a given IP and port. For every diff --git a/examples/upload/conf/upload.conf b/examples/upload/conf/upload.conf index 1a73855..8958ff5 100644 --- a/examples/upload/conf/upload.conf +++ b/examples/upload/conf/upload.conf @@ -6,8 +6,6 @@ server tls { load ./upload.so -tls_dhparam dh2048.pem - http_body_max 1024000000 http_body_disk_offload 4096 @@ -17,5 +15,7 @@ domain * { certfile cert/server.pem certkey cert/key.pem - route / page + route / { + handler page + } } diff --git a/examples/video_stream/conf/video_stream.conf b/examples/video_stream/conf/video_stream.conf index c44f753..c918e6f 100755 --- a/examples/video_stream/conf/video_stream.conf +++ b/examples/video_stream/conf/video_stream.conf @@ -6,8 +6,6 @@ server tls { load ./video_stream.so init -tls_dhparam dh2048.pem - http_keepalive_time 600 domain * { @@ -17,6 +15,11 @@ domain * { certkey cert/key.pem accesslog access.log - route / asset_serve_video_html - route ^/[a-z]*.[a-z0-9]{3}$ video_stream + route / { + handler asset_serve_video_html + } + + route ^/[a-z]*.[a-z0-9]{3}$ { + handler video_stream + } } diff --git a/examples/websocket/conf/websocket.conf b/examples/websocket/conf/websocket.conf index 228f8d1..ac1ef9c 100755 --- a/examples/websocket/conf/websocket.conf +++ b/examples/websocket/conf/websocket.conf @@ -6,8 +6,6 @@ server tls { load ./websocket.so -tls_dhparam dh2048.pem - # Increase workers so connections are spread # across them to demonstrate WEBSOCKET_BROADCAST_GLOBAL. workers 4 @@ -21,6 +19,11 @@ domain * { certfile cert/server.pem certkey cert/key.pem - route / page - route /connect page_ws_connect + route / { + handler page + } + + route /connect { + handler page_ws_connect + } } diff --git a/include/kore/http.h b/include/kore/http.h index 7d823e5..9b3cf6c 100644 --- a/include/kore/http.h +++ b/include/kore/http.h @@ -268,7 +268,7 @@ struct http_request { void *hdlr_extra; size_t state_len; char *query_string; - struct kore_module_handle *hdlr; + struct kore_route *rt; struct http_runlock_queue *runlock; void (*onfree)(struct http_request *); diff --git a/include/kore/kore.h b/include/kore/kore.h index d7e59c5..ecb0749 100644 --- a/include/kore/kore.h +++ b/include/kore/kore.h @@ -304,6 +304,33 @@ struct kore_runtime_call { struct kore_runtime *runtime; }; +#if !defined(KORE_NO_HTTP) + +struct kore_route_params { + char *name; + int flags; + u_int8_t method; + struct kore_validator *validator; + + TAILQ_ENTRY(kore_route_params) list; +}; + +struct kore_route { + char *path; + char *func; + int type; + int errors; + regex_t rctx; + struct kore_domain *dom; + struct kore_runtime_call *rcall; + struct kore_auth *auth; + int methods; + TAILQ_HEAD(, kore_route_params) params; + TAILQ_ENTRY(kore_route) list; +}; + +#endif + struct kore_domain { u_int16_t id; int logerr; @@ -327,7 +354,7 @@ struct kore_domain { SSL_CTX *ssl_ctx; int x509_verify_depth; #if !defined(KORE_NO_HTTP) - TAILQ_HEAD(, kore_module_handle) handlers; + TAILQ_HEAD(, kore_route) routes; TAILQ_HEAD(, http_redirect) redirects; #endif TAILQ_ENTRY(kore_domain) list; @@ -363,15 +390,6 @@ LIST_HEAD(kore_server_list, kore_server); #define KORE_PARAMS_QUERY_STRING 0x0001 -struct kore_handler_params { - char *name; - int flags; - u_int8_t method; - struct kore_validator *validator; - - TAILQ_ENTRY(kore_handler_params) list; -}; - #define KORE_AUTH_TYPE_COOKIE 1 #define KORE_AUTH_TYPE_HEADER 2 #define KORE_AUTH_TYPE_REQUEST 3 @@ -420,23 +438,6 @@ struct kore_module { TAILQ_ENTRY(kore_module) list; }; -#if !defined(KORE_NO_HTTP) - -struct kore_module_handle { - char *path; - char *func; - int type; - int errors; - regex_t rctx; - struct kore_domain *dom; - struct kore_runtime_call *rcall; - struct kore_auth *auth; - int methods; - TAILQ_HEAD(, kore_handler_params) params; - TAILQ_ENTRY(kore_module_handle) list; -}; -#endif - /* * The workers get a 128KB log buffer per worker, and parent will fetch their * logs when it reached at least 75% of that or if its been > 1 second since @@ -471,7 +472,7 @@ struct kore_worker { u_int8_t has_lock; int restarted; u_int64_t time_locked; - struct kore_module_handle *active_hdlr; + struct kore_route *active_route; struct kore_privsep *ps; /* Used by the workers to store accesslogs. */ @@ -959,12 +960,16 @@ int kore_domain_attach(struct kore_domain *, struct kore_server *); void kore_domain_tlsinit(struct kore_domain *, int, const void *, size_t); void kore_domain_crl_add(struct kore_domain *, const void *, size_t); + #if !defined(KORE_NO_HTTP) -int kore_module_handler_new(struct kore_domain *, const char *, - const char *, const char *, int); -void kore_module_handler_free(struct kore_module_handle *); -int kore_module_handler_find(struct http_request *, - struct kore_domain *, int, struct kore_module_handle **); +void kore_route_reload(void); +void kore_route_free(struct kore_route *); +void kore_route_callback(struct kore_route *, const char *); + +struct kore_route *kore_route_create(struct kore_domain *, + const char *, int); +int kore_route_lookup(struct http_request *, + struct kore_domain *, int, struct kore_route **); #endif struct kore_runtime_call *kore_runtime_getcall(const char *); diff --git a/src/accesslog.c b/src/accesslog.c index 287fa5d..84af979 100644 --- a/src/accesslog.c +++ b/src/accesslog.c @@ -195,7 +195,7 @@ kore_accesslog(struct http_request *req) } hdr->loglen = len; - hdr->domain = req->hdlr->dom->id; + hdr->domain = req->rt->dom->id; worker->lb.offset += (size_t)len; break; diff --git a/src/cli.c b/src/cli.c index f102146..5ed97b1 100644 --- a/src/cli.c +++ b/src/cli.c @@ -293,7 +293,10 @@ static const char *config_data = "\tcertfile\tcert/server.pem\n" "\tcertkey\t\tcert/key.pem\n" "\n" - "\troute\t/\tpage\n" + "\troute / {\n" + "\t\thandler page\n" + "\t}\n" + "\n" "}\n"; static const char *build_data = diff --git a/src/config.c b/src/config.c index 3b66cf6..9d1d421 100644 --- a/src/config.c +++ b/src/config.c @@ -109,12 +109,13 @@ static int configure_client_verify_depth(char *); #if !defined(KORE_NO_HTTP) static int configure_route(char *); +static int configure_route_handler(char *); +static int configure_route_methods(char *); static int configure_filemap(char *); static int configure_return(char *); static int configure_redirect(char *); static int configure_static_handler(char *); static int configure_dynamic_handler(char *); -static int configure_restrict(char *); static int configure_accesslog(char *); static int configure_http_header_max(char *); static int configure_http_header_timeout(char *); @@ -132,7 +133,6 @@ static int configure_http_body_disk_path(char *); static int configure_http_server_version(char *); static int configure_http_pretty_error(char *); static int configure_validator(char *); -static int configure_params(char *); static int configure_validate(char *); static int configure_authentication(char *); static int configure_authentication_uri(char *); @@ -189,16 +189,16 @@ static struct { { "client_verify", configure_client_verify }, { "client_verify_depth", configure_client_verify_depth }, #if !defined(KORE_NO_HTTP) - { "route", configure_route}, + { "route", configure_route }, + { "handler", configure_route_handler }, + { "methods", configure_route_methods }, { "filemap", configure_filemap }, { "redirect", configure_redirect }, { "return", configure_return }, { "static", configure_static_handler }, { "dynamic", configure_dynamic_handler }, { "accesslog", configure_accesslog }, - { "restrict", configure_restrict }, { "validator", configure_validator }, - { "params", configure_params }, { "validate", configure_validate }, { "authentication", configure_authentication }, { "authentication_uri", configure_authentication_uri }, @@ -282,10 +282,8 @@ char *config_file = NULL; #endif #if !defined(KORE_NO_HTTP) -static u_int8_t current_method = 0; -static int current_flags = 0; static struct kore_auth *current_auth = NULL; -static struct kore_module_handle *current_handler = NULL; +static struct kore_route *current_route = NULL; #endif extern const char *__progname; @@ -341,10 +339,8 @@ kore_parse_config(void) fatal("getcwd: %s", errno_s); worker_privsep.root = kore_strdup(path); - if (!kore_quiet) { - kore_log(LOG_NOTICE, "privsep: no root path set, " - "using working directory"); - } + if (!kore_quiet) + kore_log(LOG_NOTICE, "privsep: no root path set"); } if (worker_privsep.runas == NULL) { @@ -352,26 +348,24 @@ kore_parse_config(void) fatal("getpwuid: %s", errno_s); worker_privsep.runas = kore_strdup(pwd->pw_name); - if (!kore_quiet) { - kore_log(LOG_NOTICE, "privsep: no runas user set, " - "using current user %s", worker_privsep.runas); - } + if (!kore_quiet) + kore_log(LOG_NOTICE, "privsep: no runas user set"); endpwent(); } configure_check_var(&keymgr_privsep.runas, worker_privsep.runas, - "privsep: no keymgr runas set, using 'privsep.worker.runas`"); + "privsep: no keymgr runas set"); #if defined(KORE_USE_ACME) configure_check_var(&acme_privsep.runas, worker_privsep.runas, - "privsep: no acme runas set, using 'privsep.worker.runas`"); + "privsep: no acme runas set"); #endif configure_check_var(&keymgr_privsep.root, worker_privsep.root, - "privsep: no keymgr root set, using 'privsep.worker.root`"); + "privsep: no keymgr root set"); #if defined(KORE_USE_ACME) configure_check_var(&acme_privsep.root, worker_privsep.root, - "privsep: no acme root set, using 'privsep.worker.root`"); + "privsep: no acme root set"); #endif if (skip_chroot) { @@ -426,11 +420,9 @@ kore_parse_config_file(FILE *fp) } #if !defined(KORE_NO_HTTP) - if (!strcmp(p, "}") && current_handler != NULL) { + if (!strcmp(p, "}") && current_route != NULL) { lineno++; - current_flags = 0; - current_method = 0; - current_handler = NULL; + current_route = NULL; continue; } @@ -476,7 +468,8 @@ kore_parse_config_file(FILE *fp) } if ((t = strchr(p, ' ')) == NULL) { - printf("ignoring \"%s\" on line %d\n", p, lineno++); + kore_log(LOG_NOTICE, + "ignoring \"%s\" on line %d", p, lineno++); continue; } @@ -486,7 +479,8 @@ kore_parse_config_file(FILE *fp) t = kore_text_trim(t, strlen(t)); if (strlen(p) == 0 || strlen(t) == 0) { - printf("ignoring \"%s\" on line %d\n", p, lineno++); + kore_log(LOG_NOTICE, + "ignoring \"%s\" on line %d", p, lineno++); continue; } @@ -517,8 +511,10 @@ kore_parse_config_file(FILE *fp) } } - if (config_settings[i].name == NULL) - printf("ignoring \"%s\" on line %d\n", p, lineno); + if (config_settings[i].name == NULL) { + kore_log(LOG_NOTICE, + "ignoring \"%s\" on line %d", p, lineno); + } lineno++; } @@ -592,24 +588,24 @@ configure_server(char *options) char *argv[3]; if (current_server != NULL) { - printf("nested server contexts are not allowed\n"); + kore_log(LOG_ERR, "nested server contexts are not allowed"); return (KORE_RESULT_ERROR); } kore_split_string(options, " ", argv, 3); if (argv[0] == NULL || argv[1] == NULL) { - printf("invalid server context\n"); + kore_log(LOG_ERR, "server context invalid"); return (KORE_RESULT_ERROR); } if (strcmp(argv[1], "{")) { - printf("server context not opened correctly\n"); + kore_log(LOG_ERR, "server context not opened correctly"); return (KORE_RESULT_ERROR); } if ((srv = kore_server_lookup(argv[0])) != NULL) { - printf("a server with name '%s' already exists\n", srv->name); + kore_log(LOG_ERR, "server with name '%s' exists", srv->name); return (KORE_RESULT_ERROR); } @@ -622,7 +618,7 @@ static int configure_tls(char *yesno) { if (current_server == NULL) { - printf("bind directive not inside a server context\n"); + kore_log(LOG_ERR, "bind keyword not inside a server context"); return (KORE_RESULT_ERROR); } @@ -631,7 +627,7 @@ configure_tls(char *yesno) } else if (!strcmp(yesno, "yes")) { current_server->tls = 1; } else { - printf("invalid '%s' for yes|no tls option\n", yesno); + kore_log(LOG_ERR, "invalid '%s' for yes|no tls option", yesno); return (KORE_RESULT_ERROR); } @@ -643,12 +639,13 @@ static int configure_acme(char *yesno) { if (current_domain == NULL) { - printf("acme directive not inside a domain context\n"); + kore_log(LOG_ERR, "acme keyword not inside a domain context"); return (KORE_RESULT_ERROR); } if (strchr(current_domain->domain, '*')) { - printf("wildcards not supported due to lack of dns-01\n"); + kore_log(LOG_ERR, + "wildcards not supported due to lack of dns-01"); return (KORE_RESULT_ERROR); } @@ -665,7 +662,7 @@ configure_acme(char *yesno) ¤t_domain->certkey, ¤t_domain->certfile); acme_domains++; } else { - printf("invalid '%s' for yes|no acme option\n", yesno); + kore_log(LOG_ERR, "invalid '%s' for yes|no acme option", yesno); return (KORE_RESULT_ERROR); } @@ -698,7 +695,7 @@ configure_bind(char *options) char *argv[4]; if (current_server == NULL) { - printf("bind directive not inside a server context\n"); + kore_log(LOG_ERR, "bind keyword not inside a server context"); return (KORE_RESULT_ERROR); } @@ -715,7 +712,8 @@ configure_bind_unix(char *options) char *argv[3]; if (current_server == NULL) { - printf("bind_unix directive not inside a server context\n"); + kore_log(LOG_ERR, + "bind_unix keyword not inside a server context"); return (KORE_RESULT_ERROR); } @@ -800,7 +798,9 @@ configure_tls_version(char *version) } else if (!strcmp(version, "both")) { tls_version = KORE_TLS_VERSION_BOTH; } else { - printf("unknown value for tls_version: %s\n", version); + kore_log(LOG_ERR, + "unknown value for tls_version: %s (use 1.3, 1.2, both)", + version); return (KORE_RESULT_ERROR); } @@ -811,7 +811,7 @@ static int configure_tls_cipher(char *cipherlist) { if (strcmp(kore_tls_cipher_list, KORE_DEFAULT_CIPHER_LIST)) { - printf("tls_cipher specified twice\n"); + kore_log(LOG_ERR, "tls_cipher specified twice"); return (KORE_RESULT_ERROR); } @@ -825,12 +825,12 @@ configure_tls_dhparam(char *path) BIO *bio; if (tls_dhparam != NULL) { - printf("tls_dhparam specified twice\n"); + kore_log(LOG_ERR, "tls_dhparam specified twice"); return (KORE_RESULT_ERROR); } if ((bio = BIO_new_file(path, "r")) == NULL) { - printf("%s did not exist\n", path); + kore_log(LOG_ERR, "tls_dhparam file '%s' not accessible", path); return (KORE_RESULT_ERROR); } @@ -838,7 +838,7 @@ configure_tls_dhparam(char *path) BIO_free(bio); if (tls_dhparam == NULL) { - printf("PEM_read_bio_DHparams(): %s\n", ssl_errno_s); + kore_log(LOG_ERR, "PEM_read_bio_DHparams(): %s", ssl_errno_s); return (KORE_RESULT_ERROR); } @@ -851,13 +851,14 @@ configure_client_verify_depth(char *value) int err, depth; if (current_domain == NULL) { - printf("client_verify_depth not specified in domain context\n"); + kore_log(LOG_ERR, + "client_verify_depth keyword not in domain context"); return (KORE_RESULT_ERROR); } depth = kore_strtonum(value, 10, 0, INT_MAX, &err); if (err != KORE_RESULT_OK) { - printf("bad client_verify_depth value: %s\n", value); + kore_log(LOG_ERR, "bad client_verify_depth value: %s", value); return (KORE_RESULT_ERROR); } @@ -872,18 +873,19 @@ configure_client_verify(char *options) char *argv[3]; if (current_domain == NULL) { - printf("client_verify not specified in domain context\n"); + kore_log(LOG_ERR, + "client_verify keyword not in domain context"); return (KORE_RESULT_ERROR); } kore_split_string(options, " ", argv, 3); if (argv[0] == NULL) { - printf("client_verify is missing a parameter\n"); + kore_log(LOG_ERR, "client_verify is missing a parameter"); return (KORE_RESULT_ERROR); } if (current_domain->cafile != NULL) { - printf("client_verify already set for %s\n", + kore_log(LOG_ERR, "client_verify already set for '%s'", current_domain->domain); return (KORE_RESULT_ERROR); } @@ -910,7 +912,8 @@ static int configure_certfile(char *path) { if (current_domain == NULL) { - printf("certfile not specified in domain context\n"); + kore_log(LOG_ERR, + "certfile keyword not specified in domain context"); return (KORE_RESULT_ERROR); } @@ -923,7 +926,8 @@ static int configure_certkey(char *path) { if (current_domain == NULL) { - printf("certkey not specified in domain text\n"); + kore_log(LOG_ERR, + "certkey keyword not specified in domain context"); return (KORE_RESULT_ERROR); } @@ -938,19 +942,19 @@ configure_privsep(char *options) char *argv[3]; if (current_privsep != NULL) { - printf("nested privsep contexts are not allowed\n"); + kore_log(LOG_ERR, "nested privsep contexts are not allowed"); return (KORE_RESULT_ERROR); } kore_split_string(options, " ", argv, 3); if (argv[0] == NULL || argv[1] == NULL) { - printf("invalid privsep context\n"); + kore_log(LOG_ERR, "invalid privsep context"); return (KORE_RESULT_ERROR); } if (strcmp(argv[1], "{")) { - printf("privsep context not opened correctly\n"); + kore_log(LOG_ERR, "privsep context not opened correctly"); return (KORE_RESULT_ERROR); } @@ -963,7 +967,7 @@ configure_privsep(char *options) current_privsep = &acme_privsep; #endif } else { - printf("unknown privsep context: %s\n", argv[0]); + kore_log(LOG_ERR, "unknown privsep context: %s", argv[0]); return (KORE_RESULT_ERROR); } @@ -974,7 +978,7 @@ static int configure_privsep_runas(char *user) { if (current_privsep == NULL) { - printf("runas not specified in privsep context\n"); + kore_log(LOG_ERR, "runas keyword not in privsep context"); return (KORE_RESULT_ERROR); } @@ -990,7 +994,7 @@ static int configure_privsep_root(char *root) { if (current_privsep == NULL) { - printf("root not specified in privsep context\n"); + kore_log(LOG_ERR, "root keyword not in privsep context"); return (KORE_RESULT_ERROR); } @@ -1006,14 +1010,14 @@ static int configure_privsep_skip(char *option) { if (current_privsep == NULL) { - printf("skip not specified in privsep context\n"); + kore_log(LOG_ERR, "skip keyword not in privsep context"); return (KORE_RESULT_ERROR); } if (!strcmp(option, "chroot")) { current_privsep->skip_chroot = 1; } else { - printf("unknown skip option '%s'\n", option); + kore_log(LOG_ERR, "unknown skip option '%s'", option); return (KORE_RESULT_ERROR); } @@ -1026,24 +1030,24 @@ configure_domain(char *options) char *argv[3]; if (current_domain != NULL) { - printf("nested domain contexts are not allowed\n"); + kore_log(LOG_ERR, "nested domain contexts are not allowed"); return (KORE_RESULT_ERROR); } kore_split_string(options, " ", argv, 3); if (argv[0] == NULL || argv[1] == NULL) { - printf("invalid domain context\n"); + kore_log(LOG_ERR, "invalid domain context"); return (KORE_RESULT_ERROR); } if (strcmp(argv[1], "{")) { - printf("domain context not opened correctly\n"); + kore_log(LOG_ERR, "domain context not opened correctly"); return (KORE_RESULT_ERROR); } if (strlen(argv[0]) >= KORE_DOMAINNAME_LEN - 1) { - printf("domain name '%s' too long\n", argv[0]); + kore_log(LOG_ERR, "domain name '%s' too long", argv[0]); return (KORE_RESULT_ERROR); } @@ -1058,23 +1062,23 @@ configure_attach(char *name) struct kore_server *srv; if (current_domain == NULL) { - printf("attach not specified in domain context\n"); + kore_log(LOG_ERR, "attach keyword not in domain context"); return (KORE_RESULT_ERROR); } if (current_domain->server != NULL) { - printf("domain '%s' already attached to server\n", + kore_log(LOG_ERR, "domain '%s' already attached to server", current_domain->domain); return (KORE_RESULT_ERROR); } if ((srv = kore_server_lookup(name)) == NULL) { - printf("server '%s' does not exist\n", name); + kore_log(LOG_ERR, "server '%s' does not exist", name); return (KORE_RESULT_ERROR); } if (!kore_domain_attach(current_domain, srv)) { - printf("failed to attach '%s' to '%s'\n", + kore_log(LOG_ERR, "failed to attach '%s' to '%s'", current_domain->domain, name); return (KORE_RESULT_ERROR); } @@ -1100,18 +1104,24 @@ configure_dynamic_handler(char *options) static int configure_route(char *options) { - int type; - char *argv[4]; + struct kore_route *rt; + int type; + char *argv[4]; if (current_domain == NULL) { - printf("route not specified in domain context\n"); + kore_log(LOG_ERR, "route keyword not in domain context"); + return (KORE_RESULT_ERROR); + } + + if (current_route != NULL) { + kore_log(LOG_ERR, "nested route contexts not allowed"); return (KORE_RESULT_ERROR); } kore_split_string(options, " ", argv, 4); - if (argv[0] == NULL || argv[1] == NULL) { - printf("missing parameters for route \n"); + if (argv[1] == NULL || strcmp(argv[1], "{")) { + kore_log(LOG_ERR, "invalid route context"); return (KORE_RESULT_ERROR); } @@ -1120,12 +1130,72 @@ configure_route(char *options) else type = HANDLER_TYPE_DYNAMIC; - if (!kore_module_handler_new(current_domain, - argv[0], argv[1], argv[2], type)) { - printf("cannot create route for %s\n", argv[0]); + if ((rt = kore_route_create(current_domain, argv[0], type)) == NULL) { + kore_log(LOG_ERR, + "failed to create route handler for '%s'", argv[0]); return (KORE_RESULT_ERROR); } + current_route = rt; + + return (KORE_RESULT_OK); +} + +static int +configure_route_handler(char *name) +{ + if (current_route == NULL) { + kore_log(LOG_ERR, + "handler keyword not inside of route context"); + return (KORE_RESULT_ERROR); + } + + kore_route_callback(current_route, name); + + return (KORE_RESULT_OK); +} + +static int +configure_route_methods(char *options) +{ + int i, cnt; + char *argv[10]; + + if (current_route == NULL) { + kore_log(LOG_ERR, + "methods keyword not inside of route context"); + return (KORE_RESULT_ERROR); + } + + cnt = kore_split_string(options, " ", argv, 10); + if (cnt < 1) { + kore_log(LOG_ERR, + "bad methods option '%s', missing methods", options); + return (KORE_RESULT_ERROR); + } + + current_route->methods = 0; + + for (i = 0; i < cnt; i++) { + if (!strcasecmp(argv[i], "post")) { + current_route->methods |= HTTP_METHOD_POST; + } else if (!strcasecmp(argv[i], "get")) { + current_route->methods |= HTTP_METHOD_GET; + } else if (!strcasecmp(argv[i], "put")) { + current_route->methods |= HTTP_METHOD_PUT; + } else if (!strcasecmp(argv[i], "delete")) { + current_route->methods |= HTTP_METHOD_DELETE; + } else if (!strcasecmp(argv[i], "head")) { + current_route->methods |= HTTP_METHOD_HEAD; + } else if (!strcasecmp(argv[i], "patch")) { + current_route->methods |= HTTP_METHOD_PATCH; + } else { + kore_log(LOG_ERR, "unknown method: %s in method for %s", + argv[i], current_route->path); + return (KORE_RESULT_ERROR); + } + } + return (KORE_RESULT_OK); } @@ -1136,24 +1206,25 @@ configure_return(char *options) int elm, status, err; if (current_domain == NULL) { - printf("return outside of domain context\n"); + kore_log(LOG_ERR, "return keyword not in domain context"); return (KORE_RESULT_ERROR); } elm = kore_split_string(options, " ", argv, 3); if (elm != 2) { - printf("missing parameters for return\n"); + kore_log(LOG_ERR, "missing parameters for return"); return (KORE_RESULT_ERROR); } status = kore_strtonum(argv[1], 10, 400, 600, &err); if (err != KORE_RESULT_OK) { - printf("invalid status code on return (%s)\n", argv[1]); + kore_log(LOG_ERR, + "invalid status code on return (%s)", argv[1]); return (KORE_RESULT_ERROR); } if (!http_redirect_add(current_domain, argv[0], status, NULL)) { - printf("invalid regex on return path\n"); + kore_log(LOG_ERR, "invalid regex on return path"); return (KORE_RESULT_ERROR); } @@ -1167,24 +1238,25 @@ configure_redirect(char *options) int elm, status, err; if (current_domain == NULL) { - printf("redirect outside of domain context\n"); + kore_log(LOG_ERR, "redirect keyword not in domain context"); return (KORE_RESULT_ERROR); } elm = kore_split_string(options, " ", argv, 4); if (elm != 3) { - printf("missing parameters for redirect\n"); + kore_log(LOG_ERR, "missing parameters for redirect"); return (KORE_RESULT_ERROR); } status = kore_strtonum(argv[1], 10, 300, 399, &err); if (err != KORE_RESULT_OK) { - printf("invalid status code on redirect (%s)\n", argv[1]); + kore_log(LOG_ERR, + "invalid status code on redirect (%s)", argv[1]); return (KORE_RESULT_ERROR); } if (!http_redirect_add(current_domain, argv[0], status, argv[2])) { - printf("invalid regex on redirect path\n"); + kore_log(LOG_ERR, "invalid regex on redirect path"); return (KORE_RESULT_ERROR); } @@ -1197,19 +1269,19 @@ configure_filemap(char *options) char *argv[3]; if (current_domain == NULL) { - printf("filemap outside of domain context\n"); + kore_log(LOG_ERR, "filemap keyword not in domain context"); return (KORE_RESULT_ERROR); } kore_split_string(options, " ", argv, 3); if (argv[0] == NULL || argv[1] == NULL) { - printf("missing parameters for filemap\n"); + kore_log(LOG_ERR, "missing parameters for filemap"); return (KORE_RESULT_ERROR); } if (!kore_filemap_create(current_domain, argv[1], argv[0])) { - printf("cannot create filemap for %s\n", argv[1]); + kore_log(LOG_ERR, "cannot create filemap for %s", argv[1]); return (KORE_RESULT_ERROR); } @@ -1225,7 +1297,7 @@ configure_accesslog(char *path) } if (current_domain->accesslog != -1) { - printf("domain %s already has an open accesslog\n", + kore_log(LOG_ERR, "domain '%s' already has an open accesslog", current_domain->domain); return (KORE_RESULT_ERROR); } @@ -1234,67 +1306,13 @@ configure_accesslog(char *path) O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (current_domain->accesslog == -1) { - printf("accesslog open(%s): %s\n", path, errno_s); + kore_log(LOG_ERR, "accesslog open(%s): %s", path, errno_s); return (KORE_RESULT_ERROR); } return (KORE_RESULT_OK); } -static int -configure_restrict(char *options) -{ - struct kore_module_handle *hdlr; - int i, cnt; - char *argv[10]; - - if (current_domain == NULL) { - printf("restrict not used in domain context\n"); - return (KORE_RESULT_ERROR); - } - - cnt = kore_split_string(options, " ", argv, 10); - if (cnt < 2) { - printf("bad restrict option '%s', missing methods\n", options); - return (KORE_RESULT_ERROR); - } - - hdlr = NULL; - TAILQ_FOREACH(hdlr, &(current_domain->handlers), list) { - if (!strcmp(hdlr->path, argv[0])) - break; - } - - if (hdlr == NULL) { - printf("bad restrict option handler '%s' not found\n", argv[0]); - return (KORE_RESULT_ERROR); - } - - hdlr->methods = 0; - - for (i = 1; i < cnt; i++) { - if (!strcasecmp(argv[i], "post")) { - hdlr->methods |= HTTP_METHOD_POST; - } else if (!strcasecmp(argv[i], "get")) { - hdlr->methods |= HTTP_METHOD_GET; - } else if (!strcasecmp(argv[i], "put")) { - hdlr->methods |= HTTP_METHOD_PUT; - } else if (!strcasecmp(argv[i], "delete")) { - hdlr->methods |= HTTP_METHOD_DELETE; - } else if (!strcasecmp(argv[i], "head")) { - hdlr->methods |= HTTP_METHOD_HEAD; - } else if (!strcasecmp(argv[i], "patch")) { - hdlr->methods |= HTTP_METHOD_PATCH; - } else { - printf("unknown method: %s in restrict for %s\n", - argv[i], argv[0]); - return (KORE_RESULT_ERROR); - } - } - - return (KORE_RESULT_OK); -} - static int configure_filemap_ext(char *ext) { @@ -1321,7 +1339,7 @@ configure_http_media_type(char *type) extensions = strchr(type, ' '); if (extensions == NULL) { - printf("bad http_media_type value: %s\n", type); + kore_log(LOG_ERR, "bad http_media_type value '%s'", type); return (KORE_RESULT_ERROR); } @@ -1330,13 +1348,14 @@ configure_http_media_type(char *type) kore_split_string(extensions, " \t", ext, 10); for (i = 0; ext[i] != NULL; i++) { if (!http_media_register(ext[i], type)) { - printf("duplicate extension found: %s\n", ext[i]); + kore_log(LOG_ERR, + "duplicate extension found '%s'", ext[i]); return (KORE_RESULT_ERROR); } } if (i == 0) { - printf("missing extensions in: %s\n", type); + kore_log(LOG_ERR, "missing extensions in '%s'", type); return (KORE_RESULT_ERROR); } @@ -1350,7 +1369,7 @@ configure_http_header_max(char *option) http_header_max = kore_strtonum(option, 10, 1, 65535, &err); if (err != KORE_RESULT_OK) { - printf("bad http_header_max value: %s\n", option); + kore_log(LOG_ERR, "bad http_header_max value '%s'", option); return (KORE_RESULT_ERROR); } @@ -1364,7 +1383,7 @@ configure_http_header_timeout(char *option) http_header_timeout = kore_strtonum(option, 10, 1, 65535, &err); if (err != KORE_RESULT_OK) { - printf("bad http_header_timeout value: %s\n", option); + kore_log(LOG_ERR, "bad http_header_timeout value '%s'", option); return (KORE_RESULT_ERROR); } @@ -1378,7 +1397,7 @@ configure_http_body_max(char *option) http_body_max = kore_strtonum(option, 10, 0, LONG_MAX, &err); if (err != KORE_RESULT_OK) { - printf("bad http_body_max value: %s\n", option); + kore_log(LOG_ERR, "bad http_body_max value '%s'", option); return (KORE_RESULT_ERROR); } @@ -1392,7 +1411,7 @@ configure_http_body_timeout(char *option) http_body_timeout = kore_strtonum(option, 10, 1, 65535, &err); if (err != KORE_RESULT_OK) { - printf("bad http_body_timeout value: %s\n", option); + kore_log(LOG_ERR, "bad http_body_timeout value '%s'", option); return (KORE_RESULT_ERROR); } @@ -1406,7 +1425,8 @@ configure_http_body_disk_offload(char *option) http_body_disk_offload = kore_strtonum(option, 10, 0, LONG_MAX, &err); if (err != KORE_RESULT_OK) { - printf("bad http_body_disk_offload value: %s\n", option); + kore_log(LOG_ERR, + "bad http_body_disk_offload value '%s'", option); return (KORE_RESULT_ERROR); } @@ -1439,8 +1459,8 @@ configure_http_pretty_error(char *yesno) } else if (!strcmp(yesno, "yes")) { http_pretty_error = 1; } else { - printf("invalid '%s' for yes|no http_pretty_error option\n", - yesno); + kore_log(LOG_ERR, + "invalid '%s' for yes|no http_pretty_error option", yesno); return (KORE_RESULT_ERROR); } @@ -1454,7 +1474,7 @@ configure_http_hsts_enable(char *option) http_hsts_enable = kore_strtonum(option, 10, 0, LONG_MAX, &err); if (err != KORE_RESULT_OK) { - printf("bad http_hsts_enable value: %s\n", option); + kore_log(LOG_ERR, "bad http_hsts_enable value '%s'", option); return (KORE_RESULT_ERROR); } @@ -1468,7 +1488,8 @@ configure_http_keepalive_time(char *option) http_keepalive_time = kore_strtonum(option, 10, 0, USHRT_MAX, &err); if (err != KORE_RESULT_OK) { - printf("bad http_keepalive_time value: %s\n", option); + kore_log(LOG_ERR, + "bad http_keepalive_time value '%s'", option); return (KORE_RESULT_ERROR); } @@ -1482,7 +1503,7 @@ configure_http_request_ms(char *option) http_request_ms = kore_strtonum(option, 10, 0, UINT_MAX, &err); if (err != KORE_RESULT_OK) { - printf("bad http_request_ms value: %s\n", option); + kore_log(LOG_ERR, "bad http_request_ms value '%s'", option); return (KORE_RESULT_ERROR); } @@ -1496,7 +1517,7 @@ configure_http_request_limit(char *option) http_request_limit = kore_strtonum(option, 10, 0, UINT_MAX, &err); if (err != KORE_RESULT_OK) { - printf("bad http_request_limit value: %s\n", option); + kore_log(LOG_ERR, "bad http_request_limit value '%s'", option); return (KORE_RESULT_ERROR); } @@ -1510,14 +1531,14 @@ configure_validator(char *name) char *tname, *value; if ((tname = strchr(name, ' ')) == NULL) { - printf("missing validator name\n"); + kore_log(LOG_ERR, "missing validator name"); return (KORE_RESULT_ERROR); } *(tname)++ = '\0'; tname = kore_text_trim(tname, strlen(tname)); if ((value = strchr(tname, ' ')) == NULL) { - printf("missing validator value\n"); + kore_log(LOG_ERR, "missing validator value"); return (KORE_RESULT_ERROR); } @@ -1529,12 +1550,13 @@ configure_validator(char *name) } else if (!strcmp(tname, "function")) { type = KORE_VALIDATOR_TYPE_FUNCTION; } else { - printf("bad type for validator %s\n", tname); + kore_log(LOG_ERR, + "bad type '%s' for validator '%s'", tname, name); return (KORE_RESULT_ERROR); } if (!kore_validator_add(name, type, value)) { - printf("bad validator specified: %s\n", tname); + kore_log(LOG_ERR, "bad validator specified for '%s'", name); return (KORE_RESULT_ERROR); } @@ -1542,101 +1564,75 @@ configure_validator(char *name) } static int -configure_params(char *options) +configure_validate(char *options) { - struct kore_module_handle *hdlr; - char *method, *argv[3]; + struct kore_validator *val; + struct kore_route_params *param; + char *method, *argv[4]; + int flags, http_method; - if (current_domain == NULL) { - printf("params not used in domain context\n"); + if (kore_split_string(options, " ", argv, 4) != 3) { + kore_log(LOG_ERR, + "validate keyword needs 3 args: method param validator"); return (KORE_RESULT_ERROR); } - if (current_handler != NULL) { - printf("previous params block not closed\n"); - return (KORE_RESULT_ERROR); - } - - kore_split_string(options, " ", argv, 3); - if (argv[1] == NULL) - return (KORE_RESULT_ERROR); + flags = 0; if ((method = strchr(argv[0], ':')) != NULL) { *(method)++ = '\0'; if (!strcasecmp(argv[0], "qs")) { - current_flags = KORE_PARAMS_QUERY_STRING; + flags = KORE_PARAMS_QUERY_STRING; } else { - printf("unknown prefix '%s' for '%s'\n", - argv[0], argv[1]); + kore_log(LOG_ERR, + "unknown validate method prefix '%s' for '%s'", + argv[0], current_route->path); return (KORE_RESULT_ERROR); } } else { method = argv[0]; } + if ((val = kore_validator_lookup(argv[2])) == NULL) { + kore_log(LOG_ERR, "unknown validator '%s'", argv[2]); + return (KORE_RESULT_ERROR); + } + if (!strcasecmp(method, "post")) { - current_method = HTTP_METHOD_POST; + http_method = HTTP_METHOD_POST; } else if (!strcasecmp(method, "get")) { - current_method = HTTP_METHOD_GET; + http_method = HTTP_METHOD_GET; /* Let params get /foo {} imply qs:get automatically. */ - current_flags |= KORE_PARAMS_QUERY_STRING; + flags |= KORE_PARAMS_QUERY_STRING; } else if (!strcasecmp(method, "put")) { - current_method = HTTP_METHOD_PUT; + http_method = HTTP_METHOD_PUT; } else if (!strcasecmp(method, "delete")) { - current_method = HTTP_METHOD_DELETE; + http_method = HTTP_METHOD_DELETE; } else if (!strcasecmp(method, "head")) { - current_method = HTTP_METHOD_HEAD; + http_method = HTTP_METHOD_HEAD; } else if (!strcasecmp(method, "patch")) { - current_method = HTTP_METHOD_PATCH; + http_method = HTTP_METHOD_PATCH; } else { - printf("unknown method: %s in params block for %s\n", - method, argv[1]); + kore_log(LOG_ERR, "unknown method: %s in validator for %s", + method, current_route->path); return (KORE_RESULT_ERROR); } - /* - * Find the handler ourselves, otherwise the regex is applied - * in case of a dynamic page. - */ - TAILQ_FOREACH(hdlr, &(current_domain->handlers), list) { - if (!strcmp(hdlr->path, argv[1])) { - current_handler = hdlr; - return (KORE_RESULT_OK); - } - } - - printf("params for unknown page handler: %s\n", argv[1]); - return (KORE_RESULT_ERROR); -} - -static int -configure_validate(char *options) -{ - struct kore_handler_params *p; - struct kore_validator *val; - char *argv[3]; - - if (current_handler == NULL) { - printf("validate not used in domain context\n"); + if (!(current_route->methods & http_method)) { + kore_log(LOG_ERR, "method '%s' not enabled for route '%s'", + method, current_route->path); return (KORE_RESULT_ERROR); } - kore_split_string(options, " ", argv, 3); - if (argv[1] == NULL) - return (KORE_RESULT_ERROR); + param = kore_calloc(1, sizeof(*param)); - if ((val = kore_validator_lookup(argv[1])) == NULL) { - printf("unknown validator %s for %s\n", argv[1], argv[0]); - return (KORE_RESULT_ERROR); - } + param->flags = flags; + param->validator = val; + param->method = http_method; + param->name = kore_strdup(argv[1]); - p = kore_malloc(sizeof(*p)); - p->validator = val; - p->flags = current_flags; - p->method = current_method; - p->name = kore_strdup(argv[0]); + TAILQ_INSERT_TAIL(¤t_route->params, param, list); - TAILQ_INSERT_TAIL(&(current_handler->params), p, list); return (KORE_RESULT_OK); } @@ -1646,18 +1642,18 @@ configure_authentication(char *options) char *argv[3]; if (current_auth != NULL) { - printf("previous authentication block not closed\n"); + kore_log(LOG_ERR, "previous authentication block not closed"); return (KORE_RESULT_ERROR); } kore_split_string(options, " ", argv, 3); if (argv[1] == NULL) { - printf("missing name for authentication block\n"); + kore_log(LOG_ERR, "missing name for authentication block"); return (KORE_RESULT_ERROR); } if (strcmp(argv[1], "{")) { - printf("missing { for authentication block\n"); + kore_log(LOG_ERR, "missing { for authentication block"); return (KORE_RESULT_ERROR); } @@ -1673,7 +1669,8 @@ static int configure_authentication_type(char *option) { if (current_auth == NULL) { - printf("authentication_type outside authentication context\n"); + kore_log(LOG_ERR, + "authentication_type keyword not in correct context"); return (KORE_RESULT_ERROR); } @@ -1684,7 +1681,7 @@ configure_authentication_type(char *option) } else if (!strcmp(option, "request")) { current_auth->type = KORE_AUTH_TYPE_REQUEST; } else { - printf("unknown authentication type '%s'\n", option); + kore_log(LOG_ERR, "unknown authentication type '%s'", option); return (KORE_RESULT_ERROR); } @@ -1695,7 +1692,8 @@ static int configure_authentication_value(char *option) { if (current_auth == NULL) { - printf("authentication_value outside authentication context\n"); + kore_log(LOG_ERR, + "authentication_value keyword not in correct context"); return (KORE_RESULT_ERROR); } @@ -1712,12 +1710,14 @@ configure_authentication_validator(char *validator) struct kore_validator *val; if (current_auth == NULL) { - printf("authentication_validator outside authentication\n"); + kore_log(LOG_ERR, + "authentication_validator not in correct context"); return (KORE_RESULT_ERROR); } if ((val = kore_validator_lookup(validator)) == NULL) { - printf("authentication validator '%s' not found\n", validator); + kore_log(LOG_ERR, + "authentication validator '%s' not found", validator); return (KORE_RESULT_ERROR); } @@ -1730,7 +1730,8 @@ static int configure_authentication_uri(char *uri) { if (current_auth == NULL) { - printf("authentication_uri outside authentication context\n"); + kore_log(LOG_ERR, + "authentication_uri keyword not in correct context"); return (KORE_RESULT_ERROR); } @@ -1748,7 +1749,8 @@ configure_websocket_maxframe(char *option) kore_websocket_maxframe = kore_strtonum64(option, 1, &err); if (err != KORE_RESULT_OK) { - printf("bad kore_websocket_maxframe value: %s\n", option); + kore_log(LOG_ERR, + "bad kore_websocket_maxframe value '%s'", option); return (KORE_RESULT_ERROR); } @@ -1762,7 +1764,8 @@ configure_websocket_timeout(char *option) kore_websocket_timeout = kore_strtonum64(option, 1, &err); if (err != KORE_RESULT_OK) { - printf("bad kore_websocket_timeout value: %s\n", option); + kore_log(LOG_ERR, + "bad kore_websocket_timeout value '%s'", option); return (KORE_RESULT_ERROR); } @@ -1787,7 +1790,7 @@ configure_workers(char *option) worker_count = kore_strtonum(option, 10, 1, KORE_WORKER_MAX, &err); if (err != KORE_RESULT_OK) { - printf("%s is not a valid worker number\n", option); + kore_log(LOG_ERR, "bad value for worker '%s'", option); return (KORE_RESULT_ERROR); } @@ -1811,7 +1814,8 @@ configure_max_connections(char *option) worker_max_connections = kore_strtonum(option, 10, 1, UINT_MAX, &err); if (err != KORE_RESULT_OK) { - printf("bad value for worker_max_connections: %s\n", option); + kore_log(LOG_ERR, + "bad value for worker_max_connections '%s'", option); return (KORE_RESULT_ERROR); } @@ -1825,7 +1829,8 @@ configure_rlimit_nofiles(char *option) worker_rlimit_nofiles = kore_strtonum(option, 10, 1, UINT_MAX, &err); if (err != KORE_RESULT_OK) { - printf("bad value for worker_rlimit_nofiles: %s\n", option); + kore_log(LOG_ERR, + "bad value for worker_rlimit_nofiles '%s'", option); return (KORE_RESULT_ERROR); } @@ -1839,7 +1844,8 @@ configure_accept_threshold(char *option) worker_accept_threshold = kore_strtonum(option, 0, 1, UINT_MAX, &err); if (err != KORE_RESULT_OK) { - printf("bad value for worker_accept_threshold: %s\n", option); + kore_log(LOG_ERR, + "bad value for worker_accept_threshold '%s'\n", option); return (KORE_RESULT_ERROR); } @@ -1854,7 +1860,8 @@ configure_death_policy(char *option) } else if (!strcmp(option, "terminate")) { worker_policy = KORE_WORKER_POLICY_TERMINATE; } else { - printf("bad value for worker_death_policy: %s\n", option); + kore_log(LOG_ERR, + "bad value for worker_death_policy '%s'\n", option); return (KORE_RESULT_ERROR); } @@ -1868,7 +1875,8 @@ configure_set_affinity(char *option) worker_set_affinity = kore_strtonum(option, 10, 0, 1, &err); if (err != KORE_RESULT_OK) { - printf("bad value for worker_set_affinity: %s\n", option); + kore_log(LOG_ERR, + "bad value for worker_set_affinity '%s'", option); return (KORE_RESULT_ERROR); } @@ -1882,7 +1890,7 @@ configure_socket_backlog(char *option) kore_socket_backlog = kore_strtonum(option, 10, 0, UINT_MAX, &err); if (err != KORE_RESULT_OK) { - printf("bad socket_backlog value: %s\n", option); + kore_log(LOG_ERR, "bad socket_backlog value: '%s'", option); return (KORE_RESULT_ERROR); } @@ -1897,7 +1905,7 @@ configure_pgsql_conn_max(char *option) pgsql_conn_max = kore_strtonum(option, 10, 0, USHRT_MAX, &err); if (err != KORE_RESULT_OK) { - printf("bad value for pgsql_conn_max: %s\n", option); + kore_log(LOG_ERR, "bad value for pgsql_conn_max '%s'", option); return (KORE_RESULT_ERROR); } @@ -1911,7 +1919,8 @@ configure_pgsql_queue_limit(char *option) pgsql_queue_limit = kore_strtonum(option, 10, 0, UINT_MAX, &err); if (err != KORE_RESULT_OK) { - printf("bad value for pgsql_queue_limit: %s\n", option); + kore_log(LOG_ERR, + "bad value for pgsql_queue_limit '%s'", option); return (KORE_RESULT_ERROR); } @@ -1927,7 +1936,7 @@ configure_task_threads(char *option) kore_task_threads = kore_strtonum(option, 10, 0, UCHAR_MAX, &err); if (err != KORE_RESULT_OK) { - printf("bad value for task_threads: %s\n", option); + kore_log(LOG_ERR, "bad value for task_threads: '%s'", option); return (KORE_RESULT_ERROR); } @@ -1980,7 +1989,7 @@ configure_curl_recv_max(char *option) kore_curl_recv_max = kore_strtonum64(option, 1, &err); if (err != KORE_RESULT_OK) { - printf("bad curl_recv_max value: %s\n", option); + kore_log(LOG_ERR, "bad curl_recv_max value '%s'\n", option); return (KORE_RESULT_ERROR); } @@ -1994,7 +2003,7 @@ configure_curl_timeout(char *option) kore_curl_timeout = kore_strtonum(option, 10, 0, USHRT_MAX, &err); if (err != KORE_RESULT_OK) { - printf("bad kore_curl_timeout value: %s\n", option); + kore_log(LOG_ERR, "bad kore_curl_timeout value: '%s'", option); return (KORE_RESULT_ERROR); } @@ -2011,8 +2020,8 @@ configure_seccomp_tracing(char *opt) } else if (!strcmp(opt, "no")) { kore_seccomp_tracing = 0; } else { - printf("bad seccomp_tracing value: %s (expected yes|no)\n", - opt); + kore_log(LOG_ERR, + "bad seccomp_tracing value '%s' (expected yes|no)\n", opt); return (KORE_RESULT_ERROR); } diff --git a/src/domain.c b/src/domain.c index 96caf63..78fbb4b 100644 --- a/src/domain.c +++ b/src/domain.c @@ -131,8 +131,8 @@ kore_domain_new(const char *domain) dom->domain = kore_strdup(domain); #if !defined(KORE_NO_HTTP) - TAILQ_INIT(&(dom->handlers)); - TAILQ_INIT(&(dom->redirects)); + TAILQ_INIT(&dom->routes); + TAILQ_INIT(&dom->redirects); #endif if (dom->id < KORE_DOMAIN_CACHE) { @@ -174,8 +174,8 @@ void kore_domain_free(struct kore_domain *dom) { #if !defined(KORE_NO_HTTP) + struct kore_route *rt; struct http_redirect *rdr; - struct kore_module_handle *hdlr; #endif if (dom == NULL) return; @@ -190,20 +190,17 @@ kore_domain_free(struct kore_domain *dom) if (dom->ssl_ctx != NULL) SSL_CTX_free(dom->ssl_ctx); - if (dom->cafile != NULL) - kore_free(dom->cafile); - if (dom->certkey != NULL) - kore_free(dom->certkey); - if (dom->certfile != NULL) - kore_free(dom->certfile); - if (dom->crlfile != NULL) - kore_free(dom->crlfile); + + kore_free(dom->cafile); + kore_free(dom->certkey); + kore_free(dom->certfile); + kore_free(dom->crlfile); #if !defined(KORE_NO_HTTP) /* Drop all handlers associated with this domain */ - while ((hdlr = TAILQ_FIRST(&(dom->handlers))) != NULL) { - TAILQ_REMOVE(&(dom->handlers), hdlr, list); - kore_module_handler_free(hdlr); + while ((rt = TAILQ_FIRST(&dom->routes)) != NULL) { + TAILQ_REMOVE(&dom->routes, rt, list); + kore_route_free(rt); } while ((rdr = TAILQ_FIRST(&(dom->redirects))) != NULL) { diff --git a/src/filemap.c b/src/filemap.c index 89918d8..293a83d 100644 --- a/src/filemap.c +++ b/src/filemap.c @@ -58,7 +58,7 @@ kore_filemap_create(struct kore_domain *dom, const char *path, const char *root) size_t sz; struct stat st; int len; - struct kore_module_handle *hdlr; + struct kore_route *rt; struct filemap_entry *entry; char regex[1024], fpath[PATH_MAX]; @@ -86,20 +86,11 @@ kore_filemap_create(struct kore_domain *dom, const char *path, const char *root) if (len == -1 || (size_t)len >= sizeof(regex)) fatal("kore_filemap_create: buffer too small"); - if (!kore_module_handler_new(dom, regex, "filemap_resolve", - NULL, HANDLER_TYPE_DYNAMIC)) + if ((rt = kore_route_create(dom, regex, HANDLER_TYPE_DYNAMIC)) == NULL) return (KORE_RESULT_ERROR); - hdlr = NULL; - TAILQ_FOREACH(hdlr, &dom->handlers, list) { - if (!strcmp(hdlr->path, regex)) - break; - } - - if (hdlr == NULL) - fatal("couldn't find newly created handler for filemap"); - - hdlr->methods = HTTP_METHOD_GET | HTTP_METHOD_HEAD; + kore_route_callback(rt, "filemap_resolve"); + rt->methods = HTTP_METHOD_GET | HTTP_METHOD_HEAD; entry = kore_calloc(1, sizeof(*entry)); entry->domain = dom; @@ -151,7 +142,7 @@ filemap_resolve(struct http_request *req) best_len = 0; TAILQ_FOREACH(entry, &maps, list) { - if (entry->domain != req->hdlr->dom) + if (entry->domain != req->rt->dom) continue; if (!strncmp(entry->root, req->path, entry->root_len)) { diff --git a/src/http.c b/src/http.c index adb7a43..88e8181 100644 --- a/src/http.c +++ b/src/http.c @@ -345,18 +345,18 @@ http_process_request(struct http_request *req) kore_debug("http_process_request: %p->%p (%s)", req->owner, req, req->path); - if (req->flags & HTTP_REQUEST_DELETE || req->hdlr == NULL) + if (req->flags & HTTP_REQUEST_DELETE || req->rt == NULL) return; req->start = kore_time_ms(); - if (req->hdlr->auth != NULL && !(req->flags & HTTP_REQUEST_AUTHED)) - r = kore_auth_run(req, req->hdlr->auth); + if (req->rt->auth != NULL && !(req->flags & HTTP_REQUEST_AUTHED)) + r = kore_auth_run(req, req->rt->auth); else r = KORE_RESULT_OK; switch (r) { case KORE_RESULT_OK: - r = kore_runtime_http_request(req->hdlr->rcall, req); + r = kore_runtime_http_request(req->rt->rcall, req); break; case KORE_RESULT_RETRY: break; @@ -389,7 +389,7 @@ http_process_request(struct http_request *req) fatal("A page handler returned an unknown result: %d", r); } - if (req->hdlr->dom->accesslog) + if (req->rt->dom->accesslog) kore_accesslog(req); req->flags |= HTTP_REQUEST_DELETE; @@ -2103,7 +2103,7 @@ http_request_new(struct connection *c, const char *host, } /* Checked further down below if we need to 404. */ - exists = kore_module_handler_find(req, dom, m, &req->hdlr); + exists = kore_route_lookup(req, dom, m, &req->rt); TAILQ_INIT(&(req->resp_headers)); TAILQ_INIT(&(req->req_headers)); @@ -2135,7 +2135,7 @@ http_request_new(struct connection *c, const char *host, return (NULL); } - if (req->hdlr == NULL) { + if (req->rt == NULL) { http_request_free(req); http_error_response(c, HTTP_STATUS_METHOD_NOT_ALLOWED); return (NULL); @@ -2339,14 +2339,14 @@ http_argument_add(struct http_request *req, char *name, char *value, int qs, int decode) { struct http_arg *q; - struct kore_handler_params *p; + struct kore_route_params *p; if (decode) { if (!http_argument_urldecode(name)) return; } - TAILQ_FOREACH(p, &(req->hdlr->params), list) { + TAILQ_FOREACH(p, &req->rt->params, list) { if (qs == 1 && !(p->flags & KORE_PARAMS_QUERY_STRING)) continue; if (qs == 0 && (p->flags & KORE_PARAMS_QUERY_STRING)) diff --git a/src/module.c b/src/module.c index ff57a35..47b5ab5 100644 --- a/src/module.c +++ b/src/module.c @@ -135,11 +135,6 @@ kore_module_reload(int cbs) { struct stat st; int ret; -#if !defined(KORE_NO_HTTP) - struct kore_server *srv; - struct kore_domain *dom; - struct kore_module_handle *hdlr; -#endif struct kore_module *module; TAILQ_FOREACH(module, &modules, list) { @@ -183,22 +178,7 @@ kore_module_reload(int cbs) } #if !defined(KORE_NO_HTTP) - LIST_FOREACH(srv, &kore_servers, list) { - TAILQ_FOREACH(dom, &srv->domains, list) { - TAILQ_FOREACH(hdlr, &(dom->handlers), list) { - kore_free(hdlr->rcall); - hdlr->rcall = kore_runtime_getcall(hdlr->func); - if (hdlr->rcall == NULL) { - fatal("no function '%s' found", - hdlr->func); - } - hdlr->errors = 0; - } - } - } -#endif - -#if !defined(KORE_NO_HTTP) + kore_route_reload(); kore_validator_reload(); #endif } @@ -212,112 +192,6 @@ kore_module_loaded(void) return (1); } -#if !defined(KORE_NO_HTTP) -int -kore_module_handler_new(struct kore_domain *dom, const char *path, - const char *func, const char *auth, int type) -{ - struct kore_auth *ap; - struct kore_module_handle *hdlr; - - if (auth != NULL) { - if ((ap = kore_auth_lookup(auth)) == NULL) - fatal("no authentication block '%s' found", auth); - } else { - ap = NULL; - } - - hdlr = kore_malloc(sizeof(*hdlr)); - hdlr->auth = ap; - hdlr->dom = dom; - hdlr->errors = 0; - hdlr->type = type; - hdlr->path = kore_strdup(path); - hdlr->func = kore_strdup(func); - hdlr->methods = HTTP_METHOD_ALL; - - TAILQ_INIT(&(hdlr->params)); - - if ((hdlr->rcall = kore_runtime_getcall(func)) == NULL) { - kore_module_handler_free(hdlr); - kore_log(LOG_ERR, "function '%s' not found", func); - return (KORE_RESULT_ERROR); - } - - if (hdlr->type == HANDLER_TYPE_DYNAMIC) { - if (regcomp(&(hdlr->rctx), hdlr->path, - REG_EXTENDED | REG_NOSUB)) { - kore_module_handler_free(hdlr); - kore_debug("regcomp() on %s failed", path); - return (KORE_RESULT_ERROR); - } - } - - TAILQ_INSERT_TAIL(&(dom->handlers), hdlr, list); - return (KORE_RESULT_OK); -} - -void -kore_module_handler_free(struct kore_module_handle *hdlr) -{ - struct kore_handler_params *param; - - if (hdlr == NULL) - return; - - if (hdlr->func != NULL) - kore_free(hdlr->func); - if (hdlr->path != NULL) - kore_free(hdlr->path); - if (hdlr->type == HANDLER_TYPE_DYNAMIC) - regfree(&(hdlr->rctx)); - - /* Drop all validators associated with this handler */ - while ((param = TAILQ_FIRST(&(hdlr->params))) != NULL) { - TAILQ_REMOVE(&(hdlr->params), param, list); - if (param->name != NULL) - kore_free(param->name); - kore_free(param); - } - - kore_free(hdlr); -} - -int -kore_module_handler_find(struct http_request *req, struct kore_domain *dom, - int method, struct kore_module_handle **out) -{ - struct kore_module_handle *hdlr; - int exists; - - exists = 0; - *out = NULL; - - TAILQ_FOREACH(hdlr, &(dom->handlers), list) { - if (hdlr->type == HANDLER_TYPE_STATIC) { - if (!strcmp(hdlr->path, req->path)) { - if (hdlr->methods & method) { - *out = hdlr; - return (1); - } - exists++; - } - } else { - if (!regexec(&(hdlr->rctx), req->path, - HTTP_CAPTURE_GROUPS, req->cgroups, 0)) { - if (hdlr->methods & method) { - *out = hdlr; - return (1); - } - exists++; - } - } - } - - return (exists); -} -#endif /* !KORE_NO_HTTP */ - void * kore_module_getsym(const char *symbol, struct kore_runtime **runtime) { diff --git a/src/python.c b/src/python.c index 1d9439e..4006842 100644 --- a/src/python.c +++ b/src/python.c @@ -82,13 +82,11 @@ static struct python_coro *python_coro_create(PyObject *, static struct kore_domain *python_route_domain_resolve(struct pyroute *); static int python_route_install(struct pyroute *); -static int python_route_params(PyObject *, - struct kore_module_handle *, const char *, - int, int); +static int python_route_params(PyObject *, struct kore_route *, + const char *, int, int); static int python_route_methods(PyObject *, PyObject *, - struct kore_module_handle *); -static int python_route_auth(PyObject *, - struct kore_module_handle *); + struct kore_route *); +static int python_route_auth(PyObject *, struct kore_route *); static int python_coro_run(struct python_coro *); static void python_coro_wakeup(struct python_coro *); @@ -1250,7 +1248,7 @@ python_runtime_http_request(void *addr, struct http_request *req) callable = (PyObject *)addr; /* starts at 1 to skip the full path. */ - if (req->hdlr->type == HANDLER_TYPE_DYNAMIC) { + if (req->rt->type == HANDLER_TYPE_DYNAMIC) { for (idx = 1; idx < HTTP_CAPTURE_GROUPS - 1; idx++) { if (req->cgroups[idx].rm_so == -1 || req->cgroups[idx].rm_eo == -1) @@ -5211,7 +5209,7 @@ python_route_install(struct pyroute *route) { const char *val; struct kore_domain *domain; - struct kore_module_handle *hdlr, *entry; + struct kore_route *rt, *entry; PyObject *kwargs, *repr, *obj; if ((repr = PyObject_Repr(route->func)) == NULL) { @@ -5221,56 +5219,56 @@ python_route_install(struct pyroute *route) domain = python_route_domain_resolve(route); - hdlr = kore_calloc(1, sizeof(*hdlr)); - hdlr->dom = domain; - hdlr->methods = HTTP_METHOD_ALL; - hdlr->path = kore_strdup(route->path); + rt = kore_calloc(1, sizeof(*rt)); + rt->dom = domain; + rt->methods = HTTP_METHOD_ALL; + rt->path = kore_strdup(route->path); - TAILQ_INIT(&hdlr->params); + TAILQ_INIT(&rt->params); val = PyUnicode_AsUTF8(repr); - hdlr->func = kore_strdup(val); + rt->func = kore_strdup(val); kwargs = route->kwargs; - hdlr->rcall = kore_calloc(1, sizeof(struct kore_runtime_call)); - hdlr->rcall->addr = route->func; - hdlr->rcall->runtime = &kore_python_runtime; - Py_INCREF(hdlr->rcall->addr); + rt->rcall = kore_calloc(1, sizeof(struct kore_runtime_call)); + rt->rcall->addr = route->func; + rt->rcall->runtime = &kore_python_runtime; + Py_INCREF(rt->rcall->addr); if (kwargs != NULL) { if ((obj = PyDict_GetItemString(kwargs, "methods")) != NULL) { - if (!python_route_methods(obj, kwargs, hdlr)) { + if (!python_route_methods(obj, kwargs, rt)) { kore_python_log_error("python_route_install"); - kore_module_handler_free(hdlr); + kore_route_free(rt); return (KORE_RESULT_ERROR); } } if ((obj = PyDict_GetItemString(kwargs, "auth")) != NULL) { - if (!python_route_auth(obj, hdlr)) { + if (!python_route_auth(obj, rt)) { kore_python_log_error("python_route_install"); - kore_module_handler_free(hdlr); + kore_route_free(rt); return (KORE_RESULT_ERROR); } } } - if (hdlr->path[0] == '/') { - hdlr->type = HANDLER_TYPE_STATIC; + if (rt->path[0] == '/') { + rt->type = HANDLER_TYPE_STATIC; } else { - hdlr->type = HANDLER_TYPE_DYNAMIC; - if (regcomp(&hdlr->rctx, hdlr->path, REG_EXTENDED)) - fatal("failed to compile regex for '%s'", hdlr->path); + rt->type = HANDLER_TYPE_DYNAMIC; + if (regcomp(&rt->rctx, rt->path, REG_EXTENDED)) + fatal("failed to compile regex for '%s'", rt->path); } - TAILQ_FOREACH(entry, &domain->handlers, list) { - if (!strcmp(entry->path, hdlr->path) && - (entry->methods & hdlr->methods)) + TAILQ_FOREACH(entry, &domain->routes, list) { + if (!strcmp(entry->path, rt->path) && + (entry->methods & rt->methods)) fatal("duplicate route for '%s'", route->path); } - TAILQ_INSERT_TAIL(&domain->handlers, hdlr, list); + TAILQ_INSERT_TAIL(&domain->routes, rt, list); return (KORE_RESULT_OK); } @@ -5312,8 +5310,7 @@ python_route_domain_resolve(struct pyroute *route) } static int -python_route_methods(PyObject *obj, PyObject *kwargs, - struct kore_module_handle *hdlr) +python_route_methods(PyObject *obj, PyObject *kwargs, struct kore_route *rt) { const char *val; PyObject *item; @@ -5323,7 +5320,7 @@ python_route_methods(PyObject *obj, PyObject *kwargs, if (!PyList_CheckExact(obj)) return (KORE_RESULT_ERROR); - hdlr->methods = 0; + rt->methods = 0; list_len = PyList_Size(obj); for (idx = 0; idx < list_len; idx++) { @@ -5339,14 +5336,14 @@ python_route_methods(PyObject *obj, PyObject *kwargs, return (KORE_RESULT_ERROR); } - hdlr->methods |= method; + rt->methods |= method; if (method == HTTP_METHOD_GET) - hdlr->methods |= HTTP_METHOD_HEAD; + rt->methods |= HTTP_METHOD_HEAD; - if (!python_route_params(kwargs, hdlr, val, method, 0)) + if (!python_route_params(kwargs, rt, val, method, 0)) return (KORE_RESULT_ERROR); - if (!python_route_params(kwargs, hdlr, "qs", method, 1)) + if (!python_route_params(kwargs, rt, "qs", method, 1)) return (KORE_RESULT_ERROR); } @@ -5354,14 +5351,14 @@ python_route_methods(PyObject *obj, PyObject *kwargs, } static int -python_route_params(PyObject *kwargs, struct kore_module_handle *hdlr, +python_route_params(PyObject *kwargs, struct kore_route *rt, const char *method, int type, int qs) { Py_ssize_t idx; const char *val; int vtype; struct kore_validator *vldr; - struct kore_handler_params *param; + struct kore_route_params *param; PyObject *obj, *key, *item; if ((obj = PyDict_GetItemString(kwargs, method)) == NULL) @@ -5418,14 +5415,14 @@ python_route_params(PyObject *kwargs, struct kore_module_handle *hdlr, if (type == HTTP_METHOD_GET || qs == 1) param->flags = KORE_PARAMS_QUERY_STRING; - TAILQ_INSERT_TAIL(&hdlr->params, param, list); + TAILQ_INSERT_TAIL(&rt->params, param, list); } return (KORE_RESULT_OK); } static int -python_route_auth(PyObject *dict, struct kore_module_handle *hdlr) +python_route_auth(PyObject *dict, struct kore_route *rt) { int type; struct kore_auth *auth; @@ -5449,7 +5446,7 @@ python_route_auth(PyObject *dict, struct kore_module_handle *hdlr) } else { PyErr_Format(PyExc_RuntimeError, "invalid 'type' (%s) in auth dictionary for '%s'", - value, hdlr->path); + value, rt->path); return (KORE_RESULT_ERROR); } @@ -5464,7 +5461,7 @@ python_route_auth(PyObject *dict, struct kore_module_handle *hdlr) if ((obj = PyDict_GetItemString(dict, "verify")) == NULL || !PyCallable_Check(obj)) { PyErr_Format(PyExc_RuntimeError, - "missing 'verify' in auth dictionary for '%s'", hdlr->path); + "missing 'verify' in auth dictionary for '%s'", rt->path); return (KORE_RESULT_ERROR); } @@ -5495,7 +5492,7 @@ python_route_auth(PyObject *dict, struct kore_module_handle *hdlr) Py_DECREF(repr); auth->validator = vldr; - hdlr->auth = auth; + rt->auth = auth; return (KORE_RESULT_OK); } diff --git a/src/route.c b/src/route.c new file mode 100644 index 0000000..fe79934 --- /dev/null +++ b/src/route.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2021 Joris Vink + * + * 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 +#include + +#include + +#include "kore.h" +#include "http.h" + +struct kore_route * +kore_route_create(struct kore_domain *dom, const char *path, int type) +{ + struct kore_route *rt; + + rt = kore_calloc(1, sizeof(*rt)); + rt->dom = dom; + rt->type = type; + rt->path = kore_strdup(path); + rt->methods = HTTP_METHOD_ALL; + + TAILQ_INIT(&rt->params); + + if (rt->type == HANDLER_TYPE_DYNAMIC) { + if (regcomp(&rt->rctx, rt->path, REG_EXTENDED | REG_NOSUB)) { + kore_route_free(rt); + return (NULL); + } + } + + TAILQ_INSERT_TAIL(&dom->routes, rt, list); + + return (rt); +} + +void +kore_route_free(struct kore_route *rt) +{ + struct kore_route_params *param; + + if (rt == NULL) + return; + + kore_free(rt->func); + kore_free(rt->path); + + if (rt->type == HANDLER_TYPE_DYNAMIC) + regfree(&rt->rctx); + + /* Drop all validators associated with this handler */ + while ((param = TAILQ_FIRST(&rt->params)) != NULL) { + TAILQ_REMOVE(&rt->params, param, list); + kore_free(param->name); + kore_free(param); + } + + kore_free(rt); +} + +void +kore_route_callback(struct kore_route *rt, const char *func) +{ + if ((rt->rcall = kore_runtime_getcall(func)) == NULL) + fatal("callback '%s' for '%s' not found", func, rt->path); + + kore_free(rt->func); + rt->func = kore_strdup(func); +} + +int +kore_route_lookup(struct http_request *req, struct kore_domain *dom, + int method, struct kore_route **out) +{ + struct kore_route *rt; + int exists; + + exists = 0; + *out = NULL; + + TAILQ_FOREACH(rt, &dom->routes, list) { + if (rt->type == HANDLER_TYPE_STATIC) { + if (!strcmp(rt->path, req->path)) { + if (rt->methods & method) { + *out = rt; + return (1); + } + exists++; + } + } else { + if (!regexec(&rt->rctx, req->path, + HTTP_CAPTURE_GROUPS, req->cgroups, 0)) { + if (rt->methods & method) { + *out = rt; + return (1); + } + exists++; + } + } + } + + return (exists); +} + +void +kore_route_reload(void) +{ + struct kore_route *rt; + struct kore_server *srv; + struct kore_domain *dom; + + LIST_FOREACH(srv, &kore_servers, list) { + TAILQ_FOREACH(dom, &srv->domains, list) { + TAILQ_FOREACH(rt, &dom->routes, list) { + kore_free(rt->rcall); + rt->rcall = kore_runtime_getcall(rt->func); + if (rt->rcall == NULL) { + fatal("no function '%s' for route '%s'", + rt->func, rt->path); + } + rt->errors = 0; + } + } + } +} diff --git a/src/worker.c b/src/worker.c index 6c70073..3c13a8a 100644 --- a/src/worker.c +++ b/src/worker.c @@ -191,10 +191,11 @@ kore_worker_spawn(u_int16_t idx, u_int16_t id, u_int16_t cpu) kw = WORKER(idx); kw->id = id; kw->cpu = cpu; - kw->has_lock = 0; - kw->active_hdlr = NULL; kw->running = 1; + kw->ready = 0; + kw->has_lock = 0; + kw->active_route = NULL; if (socketpair(AF_UNIX, SOCK_STREAM, 0, kw->pipe) == -1) fatal("socketpair(): %s", errno_s); @@ -743,7 +744,7 @@ kore_worker_started(void) if (!kore_quiet) { kore_log(LOG_NOTICE, - "process started (#%d %s=%s%s%s)", + "started (#%d %s=%s%s%s)", getpid(), chroot, worker->ps->root, worker->ps->skip_runas ? "" : " user=", worker->ps->skip_runas ? "" : worker->ps->runas); @@ -797,8 +798,8 @@ worker_reaper(pid_t pid, int status) func = "none"; #if !defined(KORE_NO_HTTP) - if (kw->active_hdlr != NULL) - func = kw->active_hdlr->func; + if (kw->active_route != NULL) + func = kw->active_route->func; #endif kore_log(LOG_NOTICE, "worker %d (pid: %d) (hdlr: %s) gone", @@ -828,12 +829,12 @@ worker_reaper(pid_t pid, int status) worker_unlock(); #if !defined(KORE_NO_HTTP) - if (kw->active_hdlr != NULL) { - kw->active_hdlr->errors++; + if (kw->active_route != NULL) { + kw->active_route->errors++; kore_log(LOG_NOTICE, "hdlr %s has caused %d error(s)", - kw->active_hdlr->func, - kw->active_hdlr->errors); + kw->active_route->func, + kw->active_route->errors); } #endif