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