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

route.c (3131B)



      1 /*
      2  * Copyright (c) 2022 Joris Vink <joris@coders.se>
      3  *
      4  * Permission to use, copy, modify, and distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #include <sys/types.h>
     18 #include <sys/stat.h>
     19 
     20 #include <dlfcn.h>
     21 
     22 #include "kore.h"
     23 #include "http.h"
     24 
     25 struct kore_route *
     26 kore_route_create(struct kore_domain *dom, const char *path, int type)
     27 {
     28 	struct kore_route	*rt;
     29 
     30 	rt = kore_calloc(1, sizeof(*rt));
     31 	rt->dom = dom;
     32 	rt->type = type;
     33 	rt->path = kore_strdup(path);
     34 	rt->methods = HTTP_METHOD_ALL;
     35 
     36 	TAILQ_INIT(&rt->params);
     37 
     38 	if (rt->type == HANDLER_TYPE_DYNAMIC) {
     39 		if (regcomp(&rt->rctx, rt->path, REG_EXTENDED | REG_NOSUB)) {
     40 			kore_route_free(rt);
     41 			return (NULL);
     42 		}
     43 	}
     44 
     45 	TAILQ_INSERT_TAIL(&dom->routes, rt, list);
     46 
     47 	return (rt);
     48 }
     49 
     50 void
     51 kore_route_free(struct kore_route *rt)
     52 {
     53 	struct kore_route_params	*param;
     54 
     55 	if (rt == NULL)
     56 		return;
     57 
     58 	kore_free(rt->func);
     59 	kore_free(rt->path);
     60 
     61 	if (rt->type == HANDLER_TYPE_DYNAMIC)
     62 		regfree(&rt->rctx);
     63 
     64 	/* Drop all validators associated with this handler */
     65 	while ((param = TAILQ_FIRST(&rt->params)) != NULL) {
     66 		TAILQ_REMOVE(&rt->params, param, list);
     67 		kore_free(param->name);
     68 		kore_free(param);
     69 	}
     70 
     71 	kore_free(rt);
     72 }
     73 
     74 void
     75 kore_route_callback(struct kore_route *rt, const char *func)
     76 {
     77 	if ((rt->rcall = kore_runtime_getcall(func)) == NULL)
     78 		fatal("callback '%s' for '%s' not found", func, rt->path);
     79 
     80 	kore_free(rt->func);
     81 	rt->func = kore_strdup(func);
     82 }
     83 
     84 int
     85 kore_route_lookup(struct http_request *req, struct kore_domain *dom,
     86     int method, struct kore_route **out)
     87 {
     88 	struct kore_route	*rt;
     89 	int			exists;
     90 
     91 	exists = 0;
     92 	*out = NULL;
     93 
     94 	TAILQ_FOREACH(rt, &dom->routes, list) {
     95 		if (rt->type == HANDLER_TYPE_STATIC) {
     96 			if (!strcmp(rt->path, req->path)) {
     97 				if (rt->methods & method) {
     98 					*out = rt;
     99 					return (1);
    100 				}
    101 				exists++;
    102 			}
    103 		} else {
    104 			if (!regexec(&rt->rctx, req->path,
    105 			    HTTP_CAPTURE_GROUPS, req->cgroups, 0)) {
    106 				if (rt->methods & method) {
    107 					*out = rt;
    108 					return (1);
    109 				}
    110 				exists++;
    111 			}
    112 		}
    113 	}
    114 
    115 	return (exists);
    116 }
    117 
    118 void
    119 kore_route_reload(void)
    120 {
    121 	struct kore_route	*rt;
    122 	struct kore_server	*srv;
    123 	struct kore_domain	*dom;
    124 
    125 	LIST_FOREACH(srv, &kore_servers, list) {
    126 		TAILQ_FOREACH(dom, &srv->domains, list) {
    127 			TAILQ_FOREACH(rt, &dom->routes, list) {
    128 				kore_free(rt->rcall);
    129 				rt->rcall = kore_runtime_getcall(rt->func);
    130 				if (rt->rcall == NULL) {
    131 					fatal("no function '%s' for route '%s'",
    132 					    rt->func, rt->path);
    133 				}
    134 				rt->errors = 0;
    135 			}
    136 		}
    137 	}
    138 }