📄 mod_setenvif.c
字号:
/* if the last entry has an identical headername and regex then * merge with it */ i = sconf->conditionals->nelts - 1; icase = cmd->info == ICASE_MAGIC; if (i < 0 || entries[i].name != fname || entries[i].icase != icase || strcmp(entries[i].regex, regex)) { /* no match, create a new entry */ new = apr_array_push(sconf->conditionals); new->name = fname; new->regex = regex; new->icase = icase; if ((simple_pattern = non_regex_pattern(cmd->pool, regex))) { new->pattern = apr_strmatch_precompile(cmd->pool, simple_pattern, !icase); if (new->pattern == NULL) { return apr_pstrcat(cmd->pool, cmd->cmd->name, " pattern could not be compiled.", NULL); } new->preg = NULL; } else { new->preg = ap_pregcomp(cmd->pool, regex, (REG_EXTENDED | (icase ? REG_ICASE : 0))); if (new->preg == NULL) { return apr_pstrcat(cmd->pool, cmd->cmd->name, " regex could not be compiled.", NULL); } new->pattern = NULL; } new->features = apr_table_make(cmd->pool, 2); if (!strcasecmp(fname, "remote_addr")) { new->special_type = SPECIAL_REMOTE_ADDR; } else if (!strcasecmp(fname, "remote_host")) { new->special_type = SPECIAL_REMOTE_HOST; } else if (!strcasecmp(fname, "request_uri")) { new->special_type = SPECIAL_REQUEST_URI; } else if (!strcasecmp(fname, "request_method")) { new->special_type = SPECIAL_REQUEST_METHOD; } else if (!strcasecmp(fname, "request_protocol")) { new->special_type = SPECIAL_REQUEST_PROTOCOL; } else if (!strcasecmp(fname, "server_addr")) { new->special_type = SPECIAL_SERVER_ADDR; } else { new->special_type = SPECIAL_NOT; /* Handle fname as a regular expression. * If fname a simple header string, identify as such * (new->pnamereg = NULL) to avoid the overhead of searching * through headers_in for a regex match. */ if (is_header_regex(cmd->pool, fname)) { new->pnamereg = ap_pregcomp(cmd->pool, fname, (REG_EXTENDED | REG_NOSUB | (icase ? REG_ICASE : 0))); if (new->pnamereg == NULL) return apr_pstrcat(cmd->pool, cmd->cmd->name, "Header name regex could not be " "compiled.", NULL); } else { new->pnamereg = NULL; } } } else { new = &entries[i]; } for ( ; ; ) { feature = ap_getword_conf(cmd->pool, &args); if (!*feature) { break; } beenhere++; var = ap_getword(cmd->pool, &feature, '='); if (*feature) { apr_table_setn(new->features, var, feature); } else if (*var == '!') { apr_table_setn(new->features, var + 1, "!"); } else { apr_table_setn(new->features, var, "1"); } } if (!beenhere) { return apr_pstrcat(cmd->pool, "Missing envariable expression for ", cmd->cmd->name, NULL); } return NULL;}static const char *add_setenvif(cmd_parms *cmd, void *mconfig, const char *args){ char *fname; /* get header name */ fname = ap_getword_conf(cmd->pool, &args); if (!*fname) { return apr_pstrcat(cmd->pool, "Missing header-field name for ", cmd->cmd->name, NULL); } return add_setenvif_core(cmd, mconfig, fname, args);}/* * This routine handles the BrowserMatch* directives. It simply turns around * and feeds them, with the appropriate embellishments, to the general-purpose * command handler. */static const char *add_browser(cmd_parms *cmd, void *mconfig, const char *args){ return add_setenvif_core(cmd, mconfig, "User-Agent", args);}static const command_rec setenvif_module_cmds[] ={ AP_INIT_RAW_ARGS("SetEnvIf", add_setenvif, NULL, OR_FILEINFO, "A header-name, regex and a list of variables."), AP_INIT_RAW_ARGS("SetEnvIfNoCase", add_setenvif, ICASE_MAGIC, OR_FILEINFO, "a header-name, regex and a list of variables."), AP_INIT_RAW_ARGS("BrowserMatch", add_browser, NULL, OR_FILEINFO, "A browser regex and a list of variables."), AP_INIT_RAW_ARGS("BrowserMatchNoCase", add_browser, ICASE_MAGIC, OR_FILEINFO, "A browser regex and a list of variables."), { NULL },};/* * This routine gets called at two different points in request processing: * once before the URI has been translated (during the post-read-request * phase) and once after (during the header-parse phase). We use different * config records for the two different calls to reduce overhead (by not * re-doing the server-wide settings during directory processing), and * signal which call it is by having the earlier one pass a flag to the * later one. */static int match_headers(request_rec *r){ sei_cfg_rec *sconf; sei_entry *entries; const apr_table_entry_t *elts; const char *val; apr_size_t val_len = 0; int i, j; char *last_name; regmatch_t regm[AP_MAX_REG_MATCH]; if (!ap_get_module_config(r->request_config, &setenvif_module)) { ap_set_module_config(r->request_config, &setenvif_module, SEI_MAGIC_HEIRLOOM); sconf = (sei_cfg_rec *) ap_get_module_config(r->server->module_config, &setenvif_module); } else { sconf = (sei_cfg_rec *) ap_get_module_config(r->per_dir_config, &setenvif_module); } entries = (sei_entry *) sconf->conditionals->elts; last_name = NULL; val = NULL; for (i = 0; i < sconf->conditionals->nelts; ++i) { sei_entry *b = &entries[i]; /* Optimize the case where a bunch of directives in a row use the * same header. Remember we don't need to strcmp the two header * names because we made sure the pointers were equal during * configuration. */ if (b->name != last_name) { last_name = b->name; switch (b->special_type) { case SPECIAL_REMOTE_ADDR: val = r->connection->remote_ip; break; case SPECIAL_SERVER_ADDR: val = r->connection->local_ip; break; case SPECIAL_REMOTE_HOST: val = ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME, NULL); break; case SPECIAL_REQUEST_URI: val = r->uri; break; case SPECIAL_REQUEST_METHOD: val = r->method; break; case SPECIAL_REQUEST_PROTOCOL: val = r->protocol; break; case SPECIAL_NOT: if (b->pnamereg) { /* Matching headers_in against a regex. Iterate through * the headers_in until we find a match or run out of * headers. */ const apr_array_header_t *arr = apr_table_elts(r->headers_in); elts = (const apr_table_entry_t *) arr->elts; val = NULL; for (j = 0; j < arr->nelts; ++j) { if (!ap_regexec(b->pnamereg, elts[j].key, 0, NULL, 0)) { val = elts[j].val; } } } else { /* Not matching against a regex */ val = apr_table_get(r->headers_in, b->name); if (val == NULL) { val = apr_table_get(r->subprocess_env, b->name); } } } val_len = val ? strlen(val) : 0; } /* * A NULL value indicates that the header field or special entity * wasn't present or is undefined. Represent that as an empty string * so that REs like "^$" will work and allow envariable setting * based on missing or empty field. */ if (val == NULL) { val = ""; val_len = 0; } if ((b->pattern && apr_strmatch(b->pattern, val, val_len)) || (!b->pattern && !ap_regexec(b->preg, val, AP_MAX_REG_MATCH, regm, 0))) { const apr_array_header_t *arr = apr_table_elts(b->features); elts = (const apr_table_entry_t *) arr->elts; for (j = 0; j < arr->nelts; ++j) { if (*(elts[j].val) == '!') { apr_table_unset(r->subprocess_env, elts[j].key); } else { if (!b->pattern) { char *replaced = ap_pregsub(r->pool, elts[j].val, val, AP_MAX_REG_MATCH, regm); if (replaced) { apr_table_setn(r->subprocess_env, elts[j].key, replaced); } } else { apr_table_setn(r->subprocess_env, elts[j].key, elts[j].val); } } } } } return DECLINED;}static void register_hooks(apr_pool_t *p){ ap_hook_header_parser(match_headers, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_post_read_request(match_headers, NULL, NULL, APR_HOOK_MIDDLE);}module AP_MODULE_DECLARE_DATA setenvif_module ={ STANDARD20_MODULE_STUFF, create_setenvif_config_dir, /* dir config creater */ merge_setenvif_config, /* dir merger --- default is to override */ create_setenvif_config_svr, /* server config */ merge_setenvif_config, /* merge server configs */ setenvif_module_cmds, /* command apr_table_t */ register_hooks /* register hooks */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -