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 }