1 #include "first.h" 2 3 #include "base.h" 4 #include "array.h" 5 #include "buffer.h" 6 #include "log.h" 7 #include "http_header.h" 8 9 #include "plugin.h" 10 11 #include <stdlib.h> 12 #include <string.h> 13 14 typedef struct { 15 const array *request_header; 16 const array *set_request_header; 17 const array *response_header; 18 const array *set_response_header; 19 const array *environment; 20 const array *set_environment; 21 } plugin_config; 22 23 typedef struct { 24 PLUGIN_DATA; 25 plugin_config defaults; 26 plugin_config conf; 27 } plugin_data; 28 29 typedef struct { 30 int handled; /* make sure that we only apply the headers once */ 31 plugin_config conf; 32 } handler_ctx; 33 34 static handler_ctx * handler_ctx_init(void) { 35 handler_ctx * const hctx = calloc(1, sizeof(handler_ctx)); 36 force_assert(hctx); 37 return hctx; 38 } 39 40 static void handler_ctx_free(handler_ctx *hctx) { 41 free(hctx); 42 } 43 44 INIT_FUNC(mod_setenv_init) { 45 return calloc(1, sizeof(plugin_data)); 46 } 47 48 static void mod_setenv_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) { 49 switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */ 50 case 0: /* setenv.add-request-header */ 51 pconf->request_header = cpv->v.a; 52 break; 53 case 1: /* setenv.add-response-header */ 54 pconf->response_header = cpv->v.a; 55 break; 56 case 2: /* setenv.add-environment */ 57 pconf->environment = cpv->v.a; 58 break; 59 case 3: /* setenv.set-request-header */ 60 pconf->set_request_header = cpv->v.a; 61 break; 62 case 4: /* setenv.set-response-header */ 63 pconf->set_response_header = cpv->v.a; 64 break; 65 case 5: /* setenv.set-environment */ 66 pconf->set_environment = cpv->v.a; 67 break; 68 default:/* should not happen */ 69 return; 70 } 71 } 72 73 static void mod_setenv_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) { 74 do { 75 mod_setenv_merge_config_cpv(pconf, cpv); 76 } while ((++cpv)->k_id != -1); 77 } 78 79 static void mod_setenv_patch_config(request_st * const r, plugin_data * const p, plugin_config * const pconf) { 80 memcpy(pconf, &p->defaults, sizeof(plugin_config)); 81 for (int i = 1, used = p->nconfig; i < used; ++i) { 82 if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id)) 83 mod_setenv_merge_config(pconf, p->cvlist + p->cvlist[i].v.u2[0]); 84 } 85 } 86 87 static void mod_setenv_prep_ext (const array * const ac) { 88 array *a; 89 *(const array **)&a = ac; 90 for (uint32_t i = 0; i < a->used; ++i) { 91 data_string * const ds = (data_string *)a->data[i]; 92 ds->ext = http_header_hkey_get(CONST_BUF_LEN(&ds->key)); 93 } 94 } 95 96 SETDEFAULTS_FUNC(mod_setenv_set_defaults) { 97 static const config_plugin_keys_t cpk[] = { 98 { CONST_STR_LEN("setenv.add-request-header"), 99 T_CONFIG_ARRAY_KVSTRING, 100 T_CONFIG_SCOPE_CONNECTION } 101 ,{ CONST_STR_LEN("setenv.add-response-header"), 102 T_CONFIG_ARRAY_KVSTRING, 103 T_CONFIG_SCOPE_CONNECTION } 104 ,{ CONST_STR_LEN("setenv.add-environment"), 105 T_CONFIG_ARRAY_KVSTRING, 106 T_CONFIG_SCOPE_CONNECTION } 107 ,{ CONST_STR_LEN("setenv.set-request-header"), 108 T_CONFIG_ARRAY_KVSTRING, 109 T_CONFIG_SCOPE_CONNECTION } 110 ,{ CONST_STR_LEN("setenv.set-response-header"), 111 T_CONFIG_ARRAY_KVSTRING, 112 T_CONFIG_SCOPE_CONNECTION } 113 ,{ CONST_STR_LEN("setenv.set-environment"), 114 T_CONFIG_ARRAY_KVSTRING, 115 T_CONFIG_SCOPE_CONNECTION } 116 ,{ NULL, 0, 117 T_CONFIG_UNSET, 118 T_CONFIG_SCOPE_UNSET } 119 }; 120 121 plugin_data * const p = p_d; 122 if (!config_plugin_values_init(srv, p, cpk, "mod_setenv")) 123 return HANDLER_ERROR; 124 125 /* process and validate config directives 126 * (init i to 0 if global context; to 1 to skip empty global context) */ 127 for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) { 128 const config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0]; 129 for (; -1 != cpv->k_id; ++cpv) { 130 switch (cpv->k_id) { 131 case 0: /* setenv.add-request-header */ 132 case 1: /* setenv.add-response-header */ 133 mod_setenv_prep_ext(cpv->v.a); 134 break; 135 case 2: /* setenv.add-environment */ 136 break; 137 case 3: /* setenv.set-request-header */ 138 case 4: /* setenv.set-response-header */ 139 mod_setenv_prep_ext(cpv->v.a); 140 break; 141 case 5: /* setenv.set-environment */ 142 break; 143 default:/* should not happen */ 144 break; 145 } 146 } 147 } 148 149 /* initialize p->defaults from global config context */ 150 if (p->nconfig > 0 && p->cvlist->v.u2[1]) { 151 const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0]; 152 if (-1 != cpv->k_id) 153 mod_setenv_merge_config(&p->defaults, cpv); 154 } 155 156 return HANDLER_GO_ON; 157 } 158 159 URIHANDLER_FUNC(mod_setenv_uri_handler) { 160 plugin_data *p = p_d; 161 handler_ctx *hctx = r->plugin_ctx[p->id]; 162 if (!hctx) 163 r->plugin_ctx[p->id] = hctx = handler_ctx_init(); 164 else if (hctx->handled) 165 return HANDLER_GO_ON; 166 hctx->handled = 1; 167 168 mod_setenv_patch_config(r, p, &hctx->conf); 169 170 const array * const aa = hctx->conf.request_header; 171 const array * const as = hctx->conf.set_request_header; 172 173 if (aa) { 174 for (uint32_t k = 0; k < aa->used; ++k) { 175 const data_string * const ds = (const data_string *)aa->data[k]; 176 http_header_request_append(r, ds->ext, CONST_BUF_LEN(&ds->key), 177 CONST_BUF_LEN(&ds->value)); 178 } 179 } 180 181 if (as) { 182 for (uint32_t k = 0; k < as->used; ++k) { 183 const data_string * const ds = (const data_string *)as->data[k]; 184 !buffer_string_is_empty(&ds->value) 185 ? http_header_request_set(r, ds->ext, CONST_BUF_LEN(&ds->key), 186 CONST_BUF_LEN(&ds->value)) 187 : http_header_request_unset(r, ds->ext, CONST_BUF_LEN(&ds->key)); 188 } 189 } 190 191 return HANDLER_GO_ON; 192 } 193 194 REQUEST_FUNC(mod_setenv_handle_request_env) { 195 plugin_data *p = p_d; 196 handler_ctx *hctx = r->plugin_ctx[p->id]; 197 if (NULL == hctx) return HANDLER_GO_ON; 198 if (hctx->handled > 1) return HANDLER_GO_ON; 199 hctx->handled = 2; 200 201 const array * const aa = hctx->conf.environment; 202 const array * const as = hctx->conf.set_environment; 203 204 if (aa) { 205 for (uint32_t k = 0; k < hctx->conf.environment->used; ++k) { 206 const data_string * const ds = (const data_string *)aa->data[k]; 207 http_header_env_append(r, CONST_BUF_LEN(&ds->key), 208 CONST_BUF_LEN(&ds->value)); 209 } 210 } 211 212 if (as) { 213 for (uint32_t k = 0; k < as->used; ++k) { 214 const data_string * const ds = (const data_string *)as->data[k]; 215 http_header_env_set(r, CONST_BUF_LEN(&ds->key), 216 CONST_BUF_LEN(&ds->value)); 217 } 218 } 219 220 return HANDLER_GO_ON; 221 } 222 223 REQUEST_FUNC(mod_setenv_handle_response_start) { 224 plugin_data *p = p_d; 225 handler_ctx *hctx = r->plugin_ctx[p->id]; 226 if (NULL == hctx) return HANDLER_GO_ON; 227 228 const array * const aa = hctx->conf.response_header; 229 const array * const as = hctx->conf.set_response_header; 230 231 if (aa) { 232 for (uint32_t k = 0; k < aa->used; ++k) { 233 const data_string * const ds = (const data_string *)aa->data[k]; 234 http_header_response_insert(r, ds->ext, CONST_BUF_LEN(&ds->key), 235 CONST_BUF_LEN(&ds->value)); 236 } 237 } 238 239 if (as) { 240 for (uint32_t k = 0; k < as->used; ++k) { 241 const data_string * const ds = (const data_string *)as->data[k]; 242 !buffer_string_is_empty(&ds->value) 243 ? http_header_response_set(r, ds->ext, CONST_BUF_LEN(&ds->key), 244 CONST_BUF_LEN(&ds->value)) 245 : http_header_response_unset(r, ds->ext, CONST_BUF_LEN(&ds->key)); 246 } 247 } 248 249 return HANDLER_GO_ON; 250 } 251 252 REQUEST_FUNC(mod_setenv_handle_request_reset) { 253 void ** const hctx = r->plugin_ctx+((plugin_data_base *)p_d)->id; 254 if (*hctx) { handler_ctx_free(*hctx); *hctx = NULL; } 255 return HANDLER_GO_ON; 256 } 257 258 int mod_setenv_plugin_init(plugin *p); 259 int mod_setenv_plugin_init(plugin *p) { 260 p->version = LIGHTTPD_VERSION_ID; 261 p->name = "setenv"; 262 263 p->init = mod_setenv_init; 264 p->set_defaults= mod_setenv_set_defaults; 265 p->handle_uri_clean = mod_setenv_uri_handler; 266 p->handle_request_env = mod_setenv_handle_request_env; 267 p->handle_response_start = mod_setenv_handle_response_start; 268 p->handle_request_reset = mod_setenv_handle_request_reset; 269 270 271 return 0; 272 } 273