A patch for module mod_setenvif
You may want to read the related blog entry to understand why this patch has been submit, and how it works.
Download mod_setenvif-2-2-x.patch
Read mod_setenvif-2-2-x.patch
- Index: modules/metadata/mod_setenvif.c
- ===================================================================
- --- modules/metadata/mod_setenvif.c (revision 410287)
- +++ modules/metadata/mod_setenvif.c (working copy)
- @@ -102,7 +102,8 @@
- SPECIAL_REQUEST_URI,
- SPECIAL_REQUEST_METHOD,
- SPECIAL_REQUEST_PROTOCOL,
- - SPECIAL_SERVER_ADDR
- + SPECIAL_SERVER_ADDR,
- + SPECIAL_OUTPUT_HEADER
- };
- typedef struct {
- char *name; /* header name */
- @@ -113,10 +114,12 @@
- apr_table_t *features; /* env vars to set (or unset) */
- enum special special_type; /* is it a "special" header ? */
- int icase; /* ignoring case? */
- + int iscontent_type; /* is content type ? */
- } sei_entry;
- typedef struct {
- apr_array_header_t *conditionals;
- + int output_filter_on; /* act as output_filter for headers_out ? */
- } sei_cfg_rec;
- module AP_MODULE_DECLARE_DATA setenvif_module;
- @@ -135,6 +138,7 @@
- sei_cfg_rec *new = (sei_cfg_rec *) apr_palloc(p, sizeof(sei_cfg_rec));
- new->conditionals = apr_array_make(p, 20, sizeof(sei_entry));
- + new->output_filter_on = 0;
- return (void *) new;
- }
- @@ -155,6 +159,8 @@
- a->conditionals = apr_array_append(p, base->conditionals,
- overrides->conditionals);
- + if(base->output_filter_on || overrides->output_filter_on)
- + a->output_filter_on = 1;
- return a;
- }
- @@ -164,6 +170,7 @@
- */
- #define ICASE_MAGIC ((void *)(&setenvif_module))
- #define SEI_MAGIC_HEIRLOOM "setenvif-phase-flag"
- +#define SEI_OUTPUT_FILTER_NAME "setenvif-output-filter"
- static int is_header_regex(apr_pool_t *p, const char* name)
- {
- @@ -307,6 +314,7 @@
- new->name = fname;
- new->regex = regex;
- new->icase = icase;
- + new->iscontent_type = 0;
- if ((simple_pattern = non_regex_pattern(cmd->pool, regex))) {
- new->pattern = apr_strmatch_precompile(cmd->pool,
- simple_pattern, !icase);
- @@ -345,7 +353,37 @@
- else if (!strcasecmp(fname, "server_addr")) {
- new->special_type = SPECIAL_SERVER_ADDR;
- }
- - else {
- + else if (!strcasecmp(fname, "output_header")) {
- + new->special_type = SPECIAL_OUTPUT_HEADER;
- + sconf->output_filter_on = 1;
- + /*
- + * The regex is the 3rd word here, because we keep the same syntax
- + * as for header string, but we added the output_header key word to
- + * keep backward compatibility. (to avoid the matching of both
- + * request and response header on a regex).
- + * In this case the 2nd param of the directive is the header
- + * regex/name.
- + */
- + new->name = regex;
- + if (is_header_regex(cmd->pool, new->name)) {
- + new->pnamereg = ap_pregcomp(cmd->pool, new->name, (AP_REG_EXTENDED |
- + AP_REG_NOSUB | (icase ? AP_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;
- + if(!strcasecmp(new->name, "content-type"))
- + new->iscontent_type = 1;
- + }
- + regex = ap_getword_conf(cmd->pool, &args);
- + if (!*regex) {
- + return apr_pstrcat(cmd->pool, "Missing regular expression for ",
- + cmd->cmd->name, NULL);
- + }
- + new->regex = regex;
- + }
- + else {
- new->special_type = SPECIAL_NOT;
- /* Handle fname as a regular expression.
- * If fname a simple header string, identify as such
- @@ -365,6 +403,30 @@
- new->pnamereg = NULL;
- }
- }
- + /*
- + * This block must be after the identification of the parameters, as
- + * the regex may be in an other position than the second one depends
- + * of the special type.
- + */
- + 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,
- + (AP_REG_EXTENDED | (icase ? AP_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);
- }
- else {
- new = &entries[i];
- @@ -436,6 +498,95 @@
- };
- /*
- + * This routine get from a header (or subprocess_env if no match in header),
- + * the value that correspond to a header name or a header matching regexp.
- + * (according to a sei_entry).
- + */
- +static void get_header_val(sei_entry *b, apr_table_t *headers, apr_table_t *subprocess_env, char const **val, request_rec *r) {
- + const apr_table_entry_t *elts;
- + /* Matching headers_in against a regex. Iterate through
- + * the headers until we find a match or run out of
- + * headers.
- + */
- + const apr_array_header_t *arr = apr_table_elts(headers);
- + int j;
- +
- +
- + if (b->pnamereg) {
- + 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 {
- + if(!b->iscontent_type) {
- + /* Not matching against a regex */
- + *val = apr_table_get(headers, b->name);
- + if (*val == NULL) {
- + *val = apr_table_get(subprocess_env, b->name);
- + }
- + }
- + else {
- + *val = r->content_type;
- + }
- + }
- +}
- +
- +
- +/*
- + * This routine set environment variable according to val.
- + * Question : why sei_entry's not const ? because ap_regexec is not defined as
- + * well... pcreposix does not define the use of the regex as not modifying it?
- + */
- +static void setenvif_val_match(request_rec *r, const char *val, apr_size_t
- + val_len, sei_entry *b) {
- + ap_regmatch_t regm[AP_MAX_REG_MATCH];
- + const apr_table_entry_t *elts;
- + int j;
- +
- + /*
- + * 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);
- + }
- + }
- + }
- + }
- +}
- +
- +/*
- * 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
- @@ -565,13 +716,64 @@
- }
- }
- + if (sconf->output_filter_on == 1)
- + ap_add_output_filter(SEI_OUTPUT_FILTER_NAME, sconf, r, r->connection);
- +
- return DECLINED;
- }
- +/*
- + * This (output) filter process headers_out to find condition to set env.
- + */
- +static apr_status_t setenvif_out_filter(ap_filter_t * f, apr_bucket_brigade * bb)
- +{
- + sei_cfg_rec *sconf;
- + sei_entry *entries;
- + const char *val;
- + apr_size_t val_len = 0;
- + int i;
- + char *last_name;
- +
- + sconf = (sei_cfg_rec *) f->ctx;
- + entries = (sei_entry *) sconf->conditionals->elts;
- + last_name = NULL;
- + for (i = 0; i < sconf->conditionals->nelts; ++i) {
- + sei_entry *b = &entries[i];
- +
- + val = NULL;
- + /*
- + * 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;
- + if (b->special_type == SPECIAL_OUTPUT_HEADER) {
- + /*
- + * As output filter, only headers_out are interresting for us
- + * so we just process this type of conditions.
- + */
- + get_header_val(b, f->r->headers_out, f->r->subprocess_env, &val, f->r);
- + val_len = val ? strlen(val) : 0;
- + setenvif_val_match(f->r, val, val_len, b);
- + }
- + }
- + }
- +
- + ap_remove_output_filter(f);
- + return ap_pass_brigade(f->next, bb);
- +}
- +
- 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);
- + /*
- + * ftype is set to AP_FTYPE_CONTENT_SET + 1 to make this filter hooked
- + * before deflate (it's specific for the moment).
- + */
- + ap_register_output_filter(SEI_OUTPUT_FILTER_NAME, setenvif_out_filter, NULL, AP_FTYPE_CONTENT_SET);
- }
- module AP_MODULE_DECLARE_DATA setenvif_module =
Download mod_setenvif-2-0-x.patch
Read mod_setenvif-2-0-x.patch
- Index: modules/metadata/mod_setenvif.c
- ===================================================================
- --- modules/metadata/mod_setenvif.c (revision 410296)
- +++ modules/metadata/mod_setenvif.c (working copy)
- @@ -102,7 +102,8 @@
- SPECIAL_REQUEST_URI,
- SPECIAL_REQUEST_METHOD,
- SPECIAL_REQUEST_PROTOCOL,
- - SPECIAL_SERVER_ADDR
- + SPECIAL_SERVER_ADDR,
- + SPECIAL_OUTPUT_HEADER
- };
- typedef struct {
- char *name; /* header name */
- @@ -113,10 +114,12 @@
- apr_table_t *features; /* env vars to set (or unset) */
- enum special special_type; /* is it a "special" header ? */
- int icase; /* ignoring case? */
- + int iscontent_type; /* is content type ? */
- } sei_entry;
- typedef struct {
- apr_array_header_t *conditionals;
- + int output_filter_on; /* act as output_filter for headers_out ? */
- } sei_cfg_rec;
- module AP_MODULE_DECLARE_DATA setenvif_module;
- @@ -135,6 +138,7 @@
- sei_cfg_rec *new = (sei_cfg_rec *) apr_palloc(p, sizeof(sei_cfg_rec));
- new->conditionals = apr_array_make(p, 20, sizeof(sei_entry));
- + new->output_filter_on = 0;
- return (void *) new;
- }
- @@ -155,6 +159,8 @@
- a->conditionals = apr_array_append(p, base->conditionals,
- overrides->conditionals);
- + if(base->output_filter_on || overrides->output_filter_on)
- + a->output_filter_on = 1;
- return a;
- }
- @@ -164,6 +170,7 @@
- */
- #define ICASE_MAGIC ((void *)(&setenvif_module))
- #define SEI_MAGIC_HEIRLOOM "setenvif-phase-flag"
- +#define SEI_OUTPUT_FILTER_NAME "setenvif-output-filter"
- static int is_header_regex(apr_pool_t *p, const char* name)
- {
- @@ -307,26 +314,7 @@
- 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);
- -
- + new->iscontent_type = 0;
- if (!strcasecmp(fname, "remote_addr")) {
- new->special_type = SPECIAL_REMOTE_ADDR;
- }
- @@ -345,7 +333,37 @@
- else if (!strcasecmp(fname, "server_addr")) {
- new->special_type = SPECIAL_SERVER_ADDR;
- }
- - else {
- + else if (!strcasecmp(fname, "output_header")) {
- + new->special_type = SPECIAL_OUTPUT_HEADER;
- + sconf->output_filter_on = 1;
- + /*
- + * The regex is the 3rd word here, because we keep the same syntax
- + * as for header string, but we added the output_header key word to
- + * keep backward compatibility. (to avoid the matching of both
- + * request and response header on a regex).
- + * In this case the 2nd param of the directive is the header
- + * regex/name.
- + */
- + new->name = regex;
- + if (is_header_regex(cmd->pool, new->name)) {
- + new->pnamereg = ap_pregcomp(cmd->pool, new->name, (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;
- + if(!strcasecmp(new->name, "content-type"))
- + new->iscontent_type = 1;
- + }
- + regex = ap_getword_conf(cmd->pool, &args);
- + if (!*regex) {
- + return apr_pstrcat(cmd->pool, "Missing regular expression for ",
- + cmd->cmd->name, NULL);
- + }
- + new->regex = regex;
- + }
- + else {
- new->special_type = SPECIAL_NOT;
- /* Handle fname as a regular expression.
- * If fname a simple header string, identify as such
- @@ -365,6 +383,30 @@
- new->pnamereg = NULL;
- }
- }
- + /*
- + * This block must be after the identification of the parameters, as
- + * the regex may be in an other position than the second one depends
- + * of the special type.
- + */
- + 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);
- }
- else {
- new = &entries[i];
- @@ -436,6 +478,95 @@
- };
- /*
- + * This routine get from a header (or subprocess_env if no match in header),
- + * the value that correspond to a header name or a header matching regexp.
- + * (according to a sei_entry).
- + */
- +static void get_header_val(sei_entry *b, apr_table_t *headers, apr_table_t *subprocess_env, char const **val, request_rec *r) {
- + const apr_table_entry_t *elts;
- + /* Matching headers_in against a regex. Iterate through
- + * the headers until we find a match or run out of
- + * headers.
- + */
- + const apr_array_header_t *arr = apr_table_elts(headers);
- + int j;
- +
- +
- + if (b->pnamereg) {
- + 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 {
- + if(!b->iscontent_type) {
- + /* Not matching against a regex */
- + *val = apr_table_get(headers, b->name);
- + if (*val == NULL) {
- + *val = apr_table_get(subprocess_env, b->name);
- + }
- + }
- + else {
- + *val = r->content_type;
- + }
- + }
- +}
- +
- +
- +/*
- + * This routine set environment variable according to val.
- + * Question : why sei_entry's not const ? because ap_regexec is not defined as
- + * well... pcreposix does not define the use of the regex as not modifying it?
- + */
- +static void setenvif_val_match(request_rec *r, const char *val, apr_size_t
- + val_len, sei_entry *b) {
- + regmatch_t regm[AP_MAX_REG_MATCH];
- + const apr_table_entry_t *elts;
- + int j;
- +
- + /*
- + * 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);
- + }
- + }
- + }
- + }
- +}
- +
- +/*
- * 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
- @@ -448,12 +579,10 @@
- {
- 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;
- + int i;
- 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,
- @@ -467,10 +596,11 @@
- }
- entries = (sei_entry *) sconf->conditionals->elts;
- last_name = NULL;
- - val = NULL;
- +
- for (i = 0; i < sconf->conditionals->nelts; ++i) {
- sei_entry *b = &entries[i];
- + val = NULL;
- /* 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
- @@ -499,79 +629,73 @@
- 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);
- - }
- - }
- + get_header_val(b, r->headers_in, r->subprocess_env, &val, r);
- }
- val_len = val ? strlen(val) : 0;
- }
- + setenvif_val_match(r, val, val_len, b);
- +
- + }
- +
- + if (sconf->output_filter_on == 1)
- + ap_add_output_filter(SEI_OUTPUT_FILTER_NAME, sconf, r, r->connection);
- +
- + return DECLINED;
- +}
- +
- +/*
- + * This (output) filter process headers_out to find condition to set env.
- + */
- +static apr_status_t setenvif_out_filter(ap_filter_t * f, apr_bucket_brigade * bb)
- +{
- + sei_cfg_rec *sconf;
- + sei_entry *entries;
- + const char *val;
- + apr_size_t val_len = 0;
- + int i;
- + char *last_name;
- +
- + sconf = (sei_cfg_rec *) f->ctx;
- + entries = (sei_entry *) sconf->conditionals->elts;
- + last_name = NULL;
- + for (i = 0; i < sconf->conditionals->nelts; ++i) {
- + sei_entry *b = &entries[i];
- +
- + val = NULL;
- /*
- - * 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.
- + * 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 (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);
- - }
- - }
- + if (b->name != last_name) {
- + last_name = b->name;
- + if (b->special_type == SPECIAL_OUTPUT_HEADER) {
- + /*
- + * As output filter, only headers_out are interresting for us
- + * so we just process this type of conditions.
- + */
- + get_header_val(b, f->r->headers_out, f->r->subprocess_env, &val, f->r);
- + val_len = val ? strlen(val) : 0;
- + setenvif_val_match(f->r, val, val_len, b);
- }
- }
- }
- - return DECLINED;
- + ap_remove_output_filter(f);
- + return ap_pass_brigade(f->next, bb);
- }
- 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);
- + /*
- + * ftype is set to AP_FTYPE_CONTENT_SET + 1 to make this filter hooked
- + * before deflate (it's specific for the moment).
- + */
- + ap_register_output_filter(SEI_OUTPUT_FILTER_NAME, setenvif_out_filter, NULL, AP_FTYPE_CONTENT_SET);
- }
- module AP_MODULE_DECLARE_DATA setenvif_module =