1*76404edcSAsim Jamshed #include "base.h"
2*76404edcSAsim Jamshed #include "log.h"
3*76404edcSAsim Jamshed #include "buffer.h"
4*76404edcSAsim Jamshed 
5*76404edcSAsim Jamshed #include "plugin.h"
6*76404edcSAsim Jamshed 
7*76404edcSAsim Jamshed #include "response.h"
8*76404edcSAsim Jamshed 
9*76404edcSAsim Jamshed #include <stdlib.h>
10*76404edcSAsim Jamshed #include <string.h>
11*76404edcSAsim Jamshed 
12*76404edcSAsim Jamshed /* plugin config for all request/connections */
13*76404edcSAsim Jamshed 
14*76404edcSAsim Jamshed typedef struct {
15*76404edcSAsim Jamshed 	int handled; /* make sure that we only apply the headers once */
16*76404edcSAsim Jamshed } handler_ctx;
17*76404edcSAsim Jamshed 
18*76404edcSAsim Jamshed typedef struct {
19*76404edcSAsim Jamshed 	array *request_header;
20*76404edcSAsim Jamshed 	array *response_header;
21*76404edcSAsim Jamshed 
22*76404edcSAsim Jamshed 	array *environment;
23*76404edcSAsim Jamshed } plugin_config;
24*76404edcSAsim Jamshed 
25*76404edcSAsim Jamshed typedef struct {
26*76404edcSAsim Jamshed 	PLUGIN_DATA;
27*76404edcSAsim Jamshed 
28*76404edcSAsim Jamshed 	plugin_config **config_storage;
29*76404edcSAsim Jamshed 
30*76404edcSAsim Jamshed 	plugin_config conf;
31*76404edcSAsim Jamshed } plugin_data;
32*76404edcSAsim Jamshed 
handler_ctx_init(void)33*76404edcSAsim Jamshed static handler_ctx * handler_ctx_init(void) {
34*76404edcSAsim Jamshed 	handler_ctx * hctx;
35*76404edcSAsim Jamshed 
36*76404edcSAsim Jamshed 	hctx = calloc(1, sizeof(*hctx));
37*76404edcSAsim Jamshed 
38*76404edcSAsim Jamshed 	hctx->handled = 0;
39*76404edcSAsim Jamshed 
40*76404edcSAsim Jamshed 	return hctx;
41*76404edcSAsim Jamshed }
42*76404edcSAsim Jamshed 
handler_ctx_free(handler_ctx * hctx)43*76404edcSAsim Jamshed static void handler_ctx_free(handler_ctx *hctx) {
44*76404edcSAsim Jamshed 	free(hctx);
45*76404edcSAsim Jamshed }
46*76404edcSAsim Jamshed 
47*76404edcSAsim Jamshed 
48*76404edcSAsim Jamshed /* init the plugin data */
INIT_FUNC(mod_setenv_init)49*76404edcSAsim Jamshed INIT_FUNC(mod_setenv_init) {
50*76404edcSAsim Jamshed 	plugin_data *p;
51*76404edcSAsim Jamshed 
52*76404edcSAsim Jamshed 	p = calloc(1, sizeof(*p));
53*76404edcSAsim Jamshed 
54*76404edcSAsim Jamshed 	return p;
55*76404edcSAsim Jamshed }
56*76404edcSAsim Jamshed 
57*76404edcSAsim Jamshed /* detroy the plugin data */
FREE_FUNC(mod_setenv_free)58*76404edcSAsim Jamshed FREE_FUNC(mod_setenv_free) {
59*76404edcSAsim Jamshed 	plugin_data *p = p_d;
60*76404edcSAsim Jamshed 
61*76404edcSAsim Jamshed 	UNUSED(srv);
62*76404edcSAsim Jamshed 
63*76404edcSAsim Jamshed 	if (!p) return HANDLER_GO_ON;
64*76404edcSAsim Jamshed 
65*76404edcSAsim Jamshed 	if (p->config_storage) {
66*76404edcSAsim Jamshed 		size_t i;
67*76404edcSAsim Jamshed 		for (i = 0; i < srv->config_context->used; i++) {
68*76404edcSAsim Jamshed 			plugin_config *s = p->config_storage[i];
69*76404edcSAsim Jamshed 
70*76404edcSAsim Jamshed 			array_free(s->request_header);
71*76404edcSAsim Jamshed 			array_free(s->response_header);
72*76404edcSAsim Jamshed 			array_free(s->environment);
73*76404edcSAsim Jamshed 
74*76404edcSAsim Jamshed 			free(s);
75*76404edcSAsim Jamshed 		}
76*76404edcSAsim Jamshed 		free(p->config_storage);
77*76404edcSAsim Jamshed 	}
78*76404edcSAsim Jamshed 
79*76404edcSAsim Jamshed 	free(p);
80*76404edcSAsim Jamshed 
81*76404edcSAsim Jamshed 	return HANDLER_GO_ON;
82*76404edcSAsim Jamshed }
83*76404edcSAsim Jamshed 
84*76404edcSAsim Jamshed /* handle plugin config and check values */
85*76404edcSAsim Jamshed 
SETDEFAULTS_FUNC(mod_setenv_set_defaults)86*76404edcSAsim Jamshed SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
87*76404edcSAsim Jamshed 	plugin_data *p = p_d;
88*76404edcSAsim Jamshed 	size_t i = 0;
89*76404edcSAsim Jamshed 
90*76404edcSAsim Jamshed 	config_values_t cv[] = {
91*76404edcSAsim Jamshed 		{ "setenv.add-request-header",  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
92*76404edcSAsim Jamshed 		{ "setenv.add-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
93*76404edcSAsim Jamshed 		{ "setenv.add-environment",     NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
94*76404edcSAsim Jamshed 		{ NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
95*76404edcSAsim Jamshed 	};
96*76404edcSAsim Jamshed 
97*76404edcSAsim Jamshed 	if (!p) return HANDLER_ERROR;
98*76404edcSAsim Jamshed 
99*76404edcSAsim Jamshed 	p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
100*76404edcSAsim Jamshed 
101*76404edcSAsim Jamshed 	for (i = 0; i < srv->config_context->used; i++) {
102*76404edcSAsim Jamshed 		plugin_config *s;
103*76404edcSAsim Jamshed 
104*76404edcSAsim Jamshed 		s = calloc(1, sizeof(plugin_config));
105*76404edcSAsim Jamshed 		s->request_header   = array_init();
106*76404edcSAsim Jamshed 		s->response_header  = array_init();
107*76404edcSAsim Jamshed 		s->environment      = array_init();
108*76404edcSAsim Jamshed 
109*76404edcSAsim Jamshed 		cv[0].destination = s->request_header;
110*76404edcSAsim Jamshed 		cv[1].destination = s->response_header;
111*76404edcSAsim Jamshed 		cv[2].destination = s->environment;
112*76404edcSAsim Jamshed 
113*76404edcSAsim Jamshed 		p->config_storage[i] = s;
114*76404edcSAsim Jamshed 
115*76404edcSAsim Jamshed 		if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
116*76404edcSAsim Jamshed 			return HANDLER_ERROR;
117*76404edcSAsim Jamshed 		}
118*76404edcSAsim Jamshed 	}
119*76404edcSAsim Jamshed 
120*76404edcSAsim Jamshed 	return HANDLER_GO_ON;
121*76404edcSAsim Jamshed }
122*76404edcSAsim Jamshed 
123*76404edcSAsim Jamshed #define PATCH(x) \
124*76404edcSAsim Jamshed 	p->conf.x = s->x;
mod_setenv_patch_connection(server * srv,connection * con,plugin_data * p)125*76404edcSAsim Jamshed static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data *p) {
126*76404edcSAsim Jamshed 	size_t i, j;
127*76404edcSAsim Jamshed 	plugin_config *s = p->config_storage[0];
128*76404edcSAsim Jamshed 
129*76404edcSAsim Jamshed 	PATCH(request_header);
130*76404edcSAsim Jamshed 	PATCH(response_header);
131*76404edcSAsim Jamshed 	PATCH(environment);
132*76404edcSAsim Jamshed 
133*76404edcSAsim Jamshed 	/* skip the first, the global context */
134*76404edcSAsim Jamshed 	for (i = 1; i < srv->config_context->used; i++) {
135*76404edcSAsim Jamshed 		data_config *dc = (data_config *)srv->config_context->data[i];
136*76404edcSAsim Jamshed 		s = p->config_storage[i];
137*76404edcSAsim Jamshed 
138*76404edcSAsim Jamshed 		/* condition didn't match */
139*76404edcSAsim Jamshed 		if (!config_check_cond(srv, con, dc)) continue;
140*76404edcSAsim Jamshed 
141*76404edcSAsim Jamshed 		/* merge config */
142*76404edcSAsim Jamshed 		for (j = 0; j < dc->value->used; j++) {
143*76404edcSAsim Jamshed 			data_unset *du = dc->value->data[j];
144*76404edcSAsim Jamshed 
145*76404edcSAsim Jamshed 			if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-request-header"))) {
146*76404edcSAsim Jamshed 				PATCH(request_header);
147*76404edcSAsim Jamshed 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-response-header"))) {
148*76404edcSAsim Jamshed 				PATCH(response_header);
149*76404edcSAsim Jamshed 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-environment"))) {
150*76404edcSAsim Jamshed 				PATCH(environment);
151*76404edcSAsim Jamshed 			}
152*76404edcSAsim Jamshed 		}
153*76404edcSAsim Jamshed 	}
154*76404edcSAsim Jamshed 
155*76404edcSAsim Jamshed 	return 0;
156*76404edcSAsim Jamshed }
157*76404edcSAsim Jamshed #undef PATCH
158*76404edcSAsim Jamshed 
URIHANDLER_FUNC(mod_setenv_uri_handler)159*76404edcSAsim Jamshed URIHANDLER_FUNC(mod_setenv_uri_handler) {
160*76404edcSAsim Jamshed 	plugin_data *p = p_d;
161*76404edcSAsim Jamshed 	size_t k;
162*76404edcSAsim Jamshed 	handler_ctx *hctx;
163*76404edcSAsim Jamshed 
164*76404edcSAsim Jamshed 	if (con->plugin_ctx[p->id]) {
165*76404edcSAsim Jamshed 		hctx = con->plugin_ctx[p->id];
166*76404edcSAsim Jamshed 	} else {
167*76404edcSAsim Jamshed 		hctx = handler_ctx_init();
168*76404edcSAsim Jamshed 
169*76404edcSAsim Jamshed 		con->plugin_ctx[p->id] = hctx;
170*76404edcSAsim Jamshed 	}
171*76404edcSAsim Jamshed 
172*76404edcSAsim Jamshed 	if (hctx->handled) {
173*76404edcSAsim Jamshed 		return HANDLER_GO_ON;
174*76404edcSAsim Jamshed 	}
175*76404edcSAsim Jamshed 
176*76404edcSAsim Jamshed 	hctx->handled = 1;
177*76404edcSAsim Jamshed 
178*76404edcSAsim Jamshed 	mod_setenv_patch_connection(srv, con, p);
179*76404edcSAsim Jamshed 
180*76404edcSAsim Jamshed 	for (k = 0; k < p->conf.request_header->used; k++) {
181*76404edcSAsim Jamshed 		data_string *ds = (data_string *)p->conf.request_header->data[k];
182*76404edcSAsim Jamshed 		data_string *ds_dst;
183*76404edcSAsim Jamshed 
184*76404edcSAsim Jamshed 		if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
185*76404edcSAsim Jamshed 			ds_dst = data_string_init();
186*76404edcSAsim Jamshed 		}
187*76404edcSAsim Jamshed 
188*76404edcSAsim Jamshed 		buffer_copy_string_buffer(ds_dst->key, ds->key);
189*76404edcSAsim Jamshed 		buffer_copy_string_buffer(ds_dst->value, ds->value);
190*76404edcSAsim Jamshed 
191*76404edcSAsim Jamshed 		array_insert_unique(con->request.headers, (data_unset *)ds_dst);
192*76404edcSAsim Jamshed 	}
193*76404edcSAsim Jamshed 
194*76404edcSAsim Jamshed 	for (k = 0; k < p->conf.environment->used; k++) {
195*76404edcSAsim Jamshed 		data_string *ds = (data_string *)p->conf.environment->data[k];
196*76404edcSAsim Jamshed 		data_string *ds_dst;
197*76404edcSAsim Jamshed 
198*76404edcSAsim Jamshed 		if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
199*76404edcSAsim Jamshed 			ds_dst = data_string_init();
200*76404edcSAsim Jamshed 		}
201*76404edcSAsim Jamshed 
202*76404edcSAsim Jamshed 		buffer_copy_string_buffer(ds_dst->key, ds->key);
203*76404edcSAsim Jamshed 		buffer_copy_string_buffer(ds_dst->value, ds->value);
204*76404edcSAsim Jamshed 
205*76404edcSAsim Jamshed 		array_insert_unique(con->environment, (data_unset *)ds_dst);
206*76404edcSAsim Jamshed 	}
207*76404edcSAsim Jamshed 
208*76404edcSAsim Jamshed 	for (k = 0; k < p->conf.response_header->used; k++) {
209*76404edcSAsim Jamshed 		data_string *ds = (data_string *)p->conf.response_header->data[k];
210*76404edcSAsim Jamshed 
211*76404edcSAsim Jamshed 		response_header_insert(srv, con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
212*76404edcSAsim Jamshed 	}
213*76404edcSAsim Jamshed 
214*76404edcSAsim Jamshed 	/* not found */
215*76404edcSAsim Jamshed 	return HANDLER_GO_ON;
216*76404edcSAsim Jamshed }
217*76404edcSAsim Jamshed 
CONNECTION_FUNC(mod_setenv_reset)218*76404edcSAsim Jamshed CONNECTION_FUNC(mod_setenv_reset) {
219*76404edcSAsim Jamshed 	plugin_data *p = p_d;
220*76404edcSAsim Jamshed 
221*76404edcSAsim Jamshed 	UNUSED(srv);
222*76404edcSAsim Jamshed 
223*76404edcSAsim Jamshed 	if (con->plugin_ctx[p->id]) {
224*76404edcSAsim Jamshed 		handler_ctx_free(con->plugin_ctx[p->id]);
225*76404edcSAsim Jamshed 		con->plugin_ctx[p->id] = NULL;
226*76404edcSAsim Jamshed 	}
227*76404edcSAsim Jamshed 
228*76404edcSAsim Jamshed 	return HANDLER_GO_ON;
229*76404edcSAsim Jamshed }
230*76404edcSAsim Jamshed 
231*76404edcSAsim Jamshed /* this function is called at dlopen() time and inits the callbacks */
232*76404edcSAsim Jamshed 
233*76404edcSAsim Jamshed int mod_setenv_plugin_init(plugin *p);
mod_setenv_plugin_init(plugin * p)234*76404edcSAsim Jamshed int mod_setenv_plugin_init(plugin *p) {
235*76404edcSAsim Jamshed 	p->version     = LIGHTTPD_VERSION_ID;
236*76404edcSAsim Jamshed 	p->name        = buffer_init_string("setenv");
237*76404edcSAsim Jamshed 
238*76404edcSAsim Jamshed 	p->init        = mod_setenv_init;
239*76404edcSAsim Jamshed 	p->handle_uri_clean  = mod_setenv_uri_handler;
240*76404edcSAsim Jamshed 	p->set_defaults  = mod_setenv_set_defaults;
241*76404edcSAsim Jamshed 	p->cleanup     = mod_setenv_free;
242*76404edcSAsim Jamshed 
243*76404edcSAsim Jamshed 	p->connection_reset  = mod_setenv_reset;
244*76404edcSAsim Jamshed 
245*76404edcSAsim Jamshed 	p->data        = NULL;
246*76404edcSAsim Jamshed 
247*76404edcSAsim Jamshed 	return 0;
248*76404edcSAsim Jamshed }
249