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