xref: /lighttpd1.4/src/mod_skeleton.c (revision 49e9f0ac)
1 #include "first.h"
2 
3 #include <stdlib.h>
4 #include <string.h>
5 
6 #include "plugin.h"
7 
8 #include "base.h"
9 #include "log.h"
10 #include "buffer.h"
11 #include "array.h"
12 
13 /**
14  * this is a skeleton for a lighttpd plugin
15  *
16  * just replaces every occurrence of 'skeleton' by your plugin name
17  *
18  * e.g. in vim:
19  *
20  *   :%s/skeleton/myhandler/
21  *
22  */
23 
24 
25 /* plugin config for all request/connections */
26 
27 typedef struct {
28 	array *match;
29 } plugin_config;
30 
31 typedef struct {
32 	PLUGIN_DATA;
33 	plugin_config **config_storage;
34 	plugin_config conf;
35 } plugin_data;
36 
37 
38 #if 0 /* (needed if module keeps state for request) */
39 
40 typedef struct {
41 	size_t foo;
42 } handler_ctx;
43 
44 static handler_ctx * handler_ctx_init() {
45 	handler_ctx * hctx = calloc(1, sizeof(*hctx));
46 	force_assert(hctx);
47 	return hctx;
48 }
49 
50 static void handler_ctx_free(handler_ctx *hctx) {
51 	free(hctx);
52 }
53 
54 #endif
55 
56 
57 /* init the plugin data */
58 INIT_FUNC(mod_skeleton_init) {
59 	return calloc(1, sizeof(plugin_data));
60 }
61 
62 /* destroy the plugin data */
63 FREE_FUNC(mod_skeleton_free) {
64 	plugin_data *p = p_d;
65 	UNUSED(srv);
66 	if (!p) return HANDLER_GO_ON;
67 	if (p->config_storage) {
68 		for (size_t i = 0; i < srv->config_context->used; i++) {
69 			plugin_config *s = p->config_storage[i];
70 			if (NULL == s) continue;
71 			array_free(s->match);
72 			free(s);
73 		}
74 		free(p->config_storage);
75 	}
76 	free(p);
77 	return HANDLER_GO_ON;
78 }
79 
80 /* handle plugin config and check values */
81 SETDEFAULTS_FUNC(mod_skeleton_set_defaults) {
82 	plugin_data *p = p_d;
83 	size_t i = 0;
84 
85 	config_values_t cv[] = {
86 		{ "skeleton.array",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
87 		{ NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
88 	};
89 
90 	if (!p) return HANDLER_ERROR;
91 
92 	p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
93 	force_assert(p->config_storage);
94 
95 	for (i = 0; i < srv->config_context->used; i++) {
96 		data_config const* config = (data_config const*)srv->config_context->data[i];
97 		plugin_config *s = calloc(1, sizeof(plugin_config));
98 		force_assert(s);
99 		s->match    = array_init();
100 
101 		cv[0].destination = s->match;
102 
103 		p->config_storage[i] = s;
104 
105 		if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
106 			return HANDLER_ERROR;
107 		}
108 
109 		if (!array_is_vlist(s->match)) {
110 			log_error_write(srv, __FILE__, __LINE__, "s",
111 					"unexpected value for skeleton.array; expected list of \"urlpath\"");
112 			return HANDLER_ERROR;
113 		}
114 	}
115 
116 	return HANDLER_GO_ON;
117 }
118 
119 #define PATCH(x) \
120 	p->conf.x = s->x;
121 static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) {
122 	plugin_config *s = p->config_storage[0];
123 
124 	PATCH(match);
125 
126 	/* skip the first, the global context */
127 	for (size_t i = 1; i < srv->config_context->used; ++i) {
128 		data_config *dc = (data_config *)srv->config_context->data[i];
129 		s = p->config_storage[i];
130 
131 		/* condition didn't match */
132 		if (!config_check_cond(srv, con, dc)) continue;
133 
134 		/* merge config */
135 		for (size_t j = 0; j < dc->value->used; ++j) {
136 			data_unset *du = dc->value->data[j];
137 
138 			if (buffer_is_equal_string(du->key, CONST_STR_LEN("skeleton.array"))) {
139 				PATCH(match);
140 			}
141 		}
142 	}
143 
144 	return 0;
145 }
146 #undef PATCH
147 
148 URIHANDLER_FUNC(mod_skeleton_uri_handler) {
149 	plugin_data *p = p_d;
150 	UNUSED(srv);
151 
152 	/* determine whether or not module participates in request */
153 
154 	if (con->mode != DIRECT) return HANDLER_GO_ON;
155 	if (buffer_string_is_empty(con->uri.path)) return HANDLER_GO_ON;
156 
157 	/* get module config for request */
158 	mod_skeleton_patch_connection(srv, con, p);
159 
160 	if (NULL == array_match_value_suffix(p->conf.match, con->uri.path)) {
161 		return HANDLER_GO_ON;
162 	}
163 
164 	/* module participates in request; business logic here */
165 
166 	con->http_status = 403; /* example: reject request with 403 Forbidden */
167 	return HANDLER_FINISHED;
168 }
169 
170 /* this function is called at dlopen() time and inits the callbacks */
171 int mod_skeleton_plugin_init(plugin *p);
172 int mod_skeleton_plugin_init(plugin *p) {
173 	p->version     = LIGHTTPD_VERSION_ID;
174 	p->name        = buffer_init_string("skeleton");
175 	p->data        = NULL;
176 	p->init        = mod_skeleton_init;
177 	p->cleanup     = mod_skeleton_free;
178 	p->set_defaults= mod_skeleton_set_defaults;
179 
180 	p->handle_uri_clean = mod_skeleton_uri_handler;
181 
182 	return 0;
183 }
184