- next is 1.4.56
[lighttpd.git] / src / mod_setenv.c
blobb3832ec242219e9cc51c571cc9445a4336c97033
1 #include "first.h"
3 #include "base.h"
4 #include "log.h"
5 #include "buffer.h"
6 #include "http_header.h"
8 #include "plugin.h"
10 #include <stdlib.h>
11 #include <string.h>
13 /* plugin config for all request/connections */
15 typedef struct {
16 array *request_header;
17 array *set_request_header;
18 array *response_header;
19 array *set_response_header;
20 array *environment;
21 array *set_environment;
22 } plugin_config;
24 typedef struct {
25 PLUGIN_DATA;
27 plugin_config **config_storage;
29 plugin_config conf;
30 } plugin_data;
32 typedef struct {
33 int handled; /* make sure that we only apply the headers once */
34 plugin_config conf;
35 } handler_ctx;
37 static handler_ctx * handler_ctx_init(void) {
38 handler_ctx * hctx;
40 hctx = calloc(1, sizeof(*hctx));
42 hctx->handled = 0;
44 return hctx;
47 static void handler_ctx_free(handler_ctx *hctx) {
48 free(hctx);
52 /* init the plugin data */
53 INIT_FUNC(mod_setenv_init) {
54 plugin_data *p;
56 p = calloc(1, sizeof(*p));
58 return p;
61 /* detroy the plugin data */
62 FREE_FUNC(mod_setenv_free) {
63 plugin_data *p = p_d;
65 UNUSED(srv);
67 if (!p) return HANDLER_GO_ON;
69 if (p->config_storage) {
70 size_t i;
71 for (i = 0; i < srv->config_context->used; i++) {
72 plugin_config *s = p->config_storage[i];
74 if (NULL == s) continue;
76 array_free(s->request_header);
77 array_free(s->response_header);
78 array_free(s->environment);
79 array_free(s->set_request_header);
80 array_free(s->set_response_header);
81 array_free(s->set_environment);
83 free(s);
85 free(p->config_storage);
88 free(p);
90 return HANDLER_GO_ON;
93 /* handle plugin config and check values */
95 SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
96 plugin_data *p = p_d;
97 size_t i = 0;
99 config_values_t cv[] = {
100 { "setenv.add-request-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
101 { "setenv.add-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
102 { "setenv.add-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
103 { "setenv.set-request-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
104 { "setenv.set-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
105 { "setenv.set-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
106 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
109 if (!p) return HANDLER_ERROR;
111 p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
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;
117 s = calloc(1, sizeof(plugin_config));
118 s->request_header = array_init();
119 s->response_header = array_init();
120 s->environment = array_init();
121 s->set_request_header = array_init();
122 s->set_response_header = array_init();
123 s->set_environment = array_init();
125 cv[0].destination = s->request_header;
126 cv[1].destination = s->response_header;
127 cv[2].destination = s->environment;
128 cv[3].destination = s->set_request_header;
129 cv[4].destination = s->set_response_header;
130 cv[5].destination = s->set_environment;
132 p->config_storage[i] = s;
134 if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
135 return HANDLER_ERROR;
138 if ( !array_is_kvstring(s->request_header)
139 || !array_is_kvstring(s->response_header)
140 || !array_is_kvstring(s->environment)
141 || !array_is_kvstring(s->set_request_header)
142 || !array_is_kvstring(s->set_response_header)
143 || !array_is_kvstring(s->set_environment)) {
144 log_error_write(srv, __FILE__, __LINE__, "s",
145 "unexpected value for setenv.xxxxxx; expected list of \"envvar\" => \"value\"");
146 return HANDLER_ERROR;
151 return HANDLER_GO_ON;
154 #define PATCH(x) \
155 p->conf.x = s->x;
156 static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data *p) {
157 size_t i, j;
158 plugin_config *s = p->config_storage[0];
160 PATCH(request_header);
161 PATCH(set_request_header);
162 PATCH(response_header);
163 PATCH(set_response_header);
164 PATCH(environment);
165 PATCH(set_environment);
167 /* skip the first, the global context */
168 for (i = 1; i < srv->config_context->used; i++) {
169 data_config *dc = (data_config *)srv->config_context->data[i];
170 s = p->config_storage[i];
172 /* condition didn't match */
173 if (!config_check_cond(srv, con, dc)) continue;
175 /* merge config */
176 for (j = 0; j < dc->value->used; j++) {
177 data_unset *du = dc->value->data[j];
179 if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-request-header"))) {
180 PATCH(request_header);
181 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.set-request-header"))) {
182 PATCH(set_request_header);
183 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-response-header"))) {
184 PATCH(response_header);
185 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.set-response-header"))) {
186 PATCH(set_response_header);
187 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-environment"))) {
188 PATCH(environment);
189 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.set-environment"))) {
190 PATCH(set_environment);
195 return 0;
197 #undef PATCH
199 URIHANDLER_FUNC(mod_setenv_uri_handler) {
200 plugin_data *p = p_d;
201 size_t k;
202 handler_ctx *hctx;
204 if (con->plugin_ctx[p->id]) {
205 hctx = con->plugin_ctx[p->id];
206 } else {
207 hctx = handler_ctx_init();
209 con->plugin_ctx[p->id] = hctx;
212 if (hctx->handled) {
213 return HANDLER_GO_ON;
216 hctx->handled = 1;
218 mod_setenv_patch_connection(srv, con, p);
219 memcpy(&hctx->conf, &p->conf, sizeof(plugin_config));
221 for (k = 0; k < p->conf.request_header->used; k++) {
222 data_string *ds = (data_string *)p->conf.request_header->data[k];
223 enum http_header_e id = http_header_hkey_get(CONST_BUF_LEN(ds->key));
224 http_header_request_append(con, id, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
227 for (k = 0; k < hctx->conf.set_request_header->used; ++k) {
228 data_string *ds = (data_string *)hctx->conf.set_request_header->data[k];
229 enum http_header_e id = http_header_hkey_get(CONST_BUF_LEN(ds->key));
230 !buffer_string_is_empty(ds->value)
231 ? http_header_request_set(con, id, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value))
232 : http_header_request_unset(con, id, CONST_BUF_LEN(ds->key));
235 return HANDLER_GO_ON;
238 CONNECTION_FUNC(mod_setenv_handle_request_env) {
239 plugin_data *p = p_d;
240 handler_ctx *hctx = con->plugin_ctx[p->id];
241 if (NULL == hctx) return HANDLER_GO_ON;
242 if (hctx->handled > 1) return HANDLER_GO_ON;
243 hctx->handled = 2;
244 UNUSED(srv);
246 for (size_t k = 0; k < hctx->conf.environment->used; ++k) {
247 data_string *ds = (data_string *)hctx->conf.environment->data[k];
248 http_header_env_append(con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
251 for (size_t k = 0; k < hctx->conf.set_environment->used; ++k) {
252 data_string *ds = (data_string *)hctx->conf.set_environment->data[k];
253 http_header_env_set(con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
256 return HANDLER_GO_ON;
259 CONNECTION_FUNC(mod_setenv_handle_response_start) {
260 plugin_data *p = p_d;
261 handler_ctx *hctx = con->plugin_ctx[p->id];
262 if (NULL == hctx) return HANDLER_GO_ON;
263 UNUSED(srv);
265 for (size_t k = 0; k < hctx->conf.response_header->used; ++k) {
266 data_string *ds = (data_string *)hctx->conf.response_header->data[k];
267 enum http_header_e id = http_header_hkey_get(CONST_BUF_LEN(ds->key));
268 http_header_response_insert(con, id, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
271 for (size_t k = 0; k < hctx->conf.set_response_header->used; ++k) {
272 data_string *ds = (data_string *)hctx->conf.set_response_header->data[k];
273 enum http_header_e id = http_header_hkey_get(CONST_BUF_LEN(ds->key));
274 !buffer_string_is_empty(ds->value)
275 ? http_header_response_set(con, id, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value))
276 : http_header_response_unset(con, id, CONST_BUF_LEN(ds->key));
279 return HANDLER_GO_ON;
282 CONNECTION_FUNC(mod_setenv_reset) {
283 plugin_data *p = p_d;
285 UNUSED(srv);
287 if (con->plugin_ctx[p->id]) {
288 handler_ctx_free(con->plugin_ctx[p->id]);
289 con->plugin_ctx[p->id] = NULL;
292 return HANDLER_GO_ON;
295 /* this function is called at dlopen() time and inits the callbacks */
297 int mod_setenv_plugin_init(plugin *p);
298 int mod_setenv_plugin_init(plugin *p) {
299 p->version = LIGHTTPD_VERSION_ID;
300 p->name = buffer_init_string("setenv");
302 p->init = mod_setenv_init;
303 p->handle_uri_clean = mod_setenv_uri_handler;
304 p->handle_request_env = mod_setenv_handle_request_env;
305 p->handle_response_start = mod_setenv_handle_response_start;
306 p->set_defaults = mod_setenv_set_defaults;
307 p->cleanup = mod_setenv_free;
309 p->connection_reset = mod_setenv_reset;
311 p->data = NULL;
313 return 0;