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