7676#include "http_request.h"
7777#include "http_log.h"
7878#include "util_filter.h"
79+ #include "http_protocol.h" /* ap_hook_insert_error_filter */
7980
8081/* format_tag_hash is initialized during pre-config */
8182static apr_hash_t * format_tag_hash ;
@@ -88,10 +89,12 @@ typedef enum {
8889 hdr_echo = 'e' /* echo headers from request to response */
8990} hdr_actions ;
9091
91- typedef enum {
92- hdr_in = 0 , /* RequestHeader */
93- hdr_out = 1 /* Header */
94- } hdr_inout ;
92+ /*
93+ * magic cmd->info values
94+ */
95+ static char hdr_in = '0' ; /* RequestHeader */
96+ static char hdr_out = '1' ; /* Header onsuccess */
97+ static char hdr_err = '2' ; /* Header always */
9598
9699/*
97100 * There is an array of struct format_tag per Header/RequestHeader
@@ -126,6 +129,7 @@ typedef struct {
126129typedef struct {
127130 apr_array_header_t * fixup_in ;
128131 apr_array_header_t * fixup_out ;
132+ apr_array_header_t * fixup_err ;
129133} headers_conf ;
130134
131135module AP_MODULE_DECLARE_DATA headers_module ;
@@ -158,29 +162,26 @@ static const char *header_request_env_var(request_rec *r, char *a)
158162/*
159163 * Config routines
160164 */
161- static void * create_headers_config (apr_pool_t * p , server_rec * s )
165+ static void * create_headers_config (apr_pool_t * p , char * dummy )
162166{
163- headers_conf * conf = apr_pcalloc (p , sizeof (* conf ));
167+ headers_conf * conf = apr_palloc (p , sizeof (* conf ));
164168
165169 conf -> fixup_in = apr_array_make (p , 2 , sizeof (header_entry ));
166170 conf -> fixup_out = apr_array_make (p , 2 , sizeof (header_entry ));
171+ conf -> fixup_err = apr_array_make (p , 2 , sizeof (header_entry ));
167172
168173 return conf ;
169174}
170175
171- static void * create_headers_dir_config (apr_pool_t * p , char * d )
172- {
173- return create_headers_config (p , NULL );
174- }
175-
176176static void * merge_headers_config (apr_pool_t * p , void * basev , void * overridesv )
177177{
178- headers_conf * newconf = apr_pcalloc (p , sizeof (* newconf ));
178+ headers_conf * newconf = apr_palloc (p , sizeof (* newconf ));
179179 headers_conf * base = basev ;
180180 headers_conf * overrides = overridesv ;
181181
182182 newconf -> fixup_in = apr_array_append (p , base -> fixup_in , overrides -> fixup_in );
183183 newconf -> fixup_out = apr_array_append (p , base -> fixup_out , overrides -> fixup_out );
184+ newconf -> fixup_err = apr_array_append (p , base -> fixup_err , overrides -> fixup_err );
184185
185186 return newconf ;
186187}
@@ -317,17 +318,12 @@ static const char *header_inout_cmd(cmd_parms *cmd, void *indirconf,
317318 char * colon ;
318319 char * hdr = apr_pstrdup (cmd -> pool , inhdr );
319320 header_entry * new ;
320- server_rec * s = cmd -> server ;
321- headers_conf * serverconf = ap_get_module_config ( s -> module_config ,
322- & headers_module );
323- hdr_inout inout = ( hdr_inout ) cmd -> info ;
321+ apr_array_header_t * fixup = ( cmd -> info == & hdr_in )
322+ ? dirconf -> fixup_in : ( cmd -> info == & hdr_err )
323+ ? dirconf -> fixup_err
324+ : dirconf -> fixup_out ;
324325
325- if (cmd -> path ) {
326- new = (header_entry * ) apr_array_push ((hdr_in == inout ) ? dirconf -> fixup_in : dirconf -> fixup_out );
327- }
328- else {
329- new = (header_entry * ) apr_array_push ((hdr_in == inout ) ? serverconf -> fixup_in : serverconf -> fixup_out );
330- }
326+ new = (header_entry * ) apr_array_push (fixup );
331327
332328 if (!strcasecmp (action , "set" ))
333329 new -> action = hdr_set ;
@@ -350,7 +346,7 @@ static const char *header_inout_cmd(cmd_parms *cmd, void *indirconf,
350346 regex_t * regex ;
351347 if (value )
352348 return "Header echo takes two arguments" ;
353- else if (inout != hdr_out )
349+ else if (cmd -> info == & hdr_in )
354350 return "Header echo only valid on Header directive" ;
355351 else {
356352 regex = ap_pregcomp (cmd -> pool , hdr , REG_EXTENDED | REG_NOSUB );
@@ -396,10 +392,24 @@ static const char *header_cmd(cmd_parms *cmd, void *indirconf,
396392
397393 s = apr_pstrdup (cmd -> pool , args );
398394 action = ap_getword_conf (cmd -> pool , & s );
395+ if (cmd -> info == & hdr_out ) {
396+ if (!strcasecmp (action , "always" )) {
397+ cmd -> info = & hdr_err ;
398+ action = ap_getword_conf (cmd -> pool , & s );
399+ }
400+ else if (!strcasecmp (action , "onsuccess" )) {
401+ action = ap_getword_conf (cmd -> pool , & s );
402+ }
403+ }
399404 hdr = ap_getword_conf (cmd -> pool , & s );
400405 val = * s ? ap_getword_conf (cmd -> pool , & s ) : NULL ;
401406 envclause = * s ? ap_getword_conf (cmd -> pool , & s ) : NULL ;
402407
408+ if (* s ) {
409+ return apr_pstrcat (cmd -> pool , cmd -> cmd -> name ,
410+ " has too many arguments" , NULL );
411+ }
412+
403413 return header_inout_cmd (cmd , indirconf , action , hdr , val , envclause );
404414}
405415
@@ -440,11 +450,10 @@ static int echo_header(echo_do *v, const char *key, const char *val)
440450 return 1 ;
441451}
442452
443- static void do_headers_fixup (request_rec * r , hdr_inout inout ,
453+ static void do_headers_fixup (request_rec * r , apr_table_t * headers ,
444454 apr_array_header_t * fixup )
445455{
446456 int i ;
447- apr_table_t * headers = (hdr_in == inout ) ? r -> headers_in : r -> headers_out ;
448457
449458 for (i = 0 ; i < fixup -> nelts ; ++ i ) {
450459 header_entry * hdr = & ((header_entry * ) (fixup -> elts ))[i ];
@@ -490,30 +499,55 @@ static void do_headers_fixup(request_rec *r, hdr_inout inout,
490499
491500static void ap_headers_insert_output_filter (request_rec * r )
492501{
493- headers_conf * serverconf = ap_get_module_config (r -> server -> module_config ,
494- & headers_module );
495502 headers_conf * dirconf = ap_get_module_config (r -> per_dir_config ,
496503 & headers_module );
497504
498- if (serverconf -> fixup_out -> nelts || dirconf -> fixup_out -> nelts ) {
505+ if (dirconf -> fixup_out -> nelts || dirconf -> fixup_err -> nelts ) {
499506 ap_add_output_filter ("FIXUP_HEADERS_OUT" , NULL , r , r -> connection );
500507 }
501508}
502509
510+ static void ap_headers_insert_error_filter (request_rec * r )
511+ {
512+ headers_conf * dirconf = ap_get_module_config (r -> per_dir_config ,
513+ & headers_module );
514+
515+ if (dirconf -> fixup_err -> nelts ) {
516+ ap_add_output_filter ("FIXUP_HEADERS_ERR" , NULL , r , r -> connection );
517+ }
518+ }
519+
503520static apr_status_t ap_headers_output_filter (ap_filter_t * f ,
504521 apr_bucket_brigade * in )
505522{
506- headers_conf * serverconf = ap_get_module_config (f -> r -> server -> module_config ,
507- & headers_module );
508523 headers_conf * dirconf = ap_get_module_config (f -> r -> per_dir_config ,
509524 & headers_module );
510525
511526 ap_log_error (APLOG_MARK , APLOG_DEBUG , 0 , f -> r -> server ,
512527 "headers: ap_headers_output_filter()" );
513528
514529 /* do the fixup */
515- do_headers_fixup (f -> r , hdr_out , serverconf -> fixup_out );
516- do_headers_fixup (f -> r , hdr_out , dirconf -> fixup_out );
530+ do_headers_fixup (f -> r , f -> r -> err_headers_out , dirconf -> fixup_err );
531+ do_headers_fixup (f -> r , f -> r -> headers_out , dirconf -> fixup_out );
532+
533+ /* remove ourselves from the filter chain */
534+ ap_remove_output_filter (f );
535+
536+ /* send the data up the stack */
537+ return ap_pass_brigade (f -> next ,in );
538+ }
539+
540+ static apr_status_t ap_headers_error_filter (ap_filter_t * f ,
541+ apr_bucket_brigade * in )
542+ {
543+ headers_conf * dirconf = ap_get_module_config (f -> r -> per_dir_config ,
544+ & headers_module );
545+
546+ ap_log_error (APLOG_MARK , APLOG_DEBUG , 0 , f -> r -> server ,
547+ "headers: ap_headers_error_filter()" );
548+
549+ /* do the fixup */
550+ do_headers_fixup (f -> r , f -> r -> err_headers_out , dirconf -> fixup_err );
517551
518552 /* remove ourselves from the filter chain */
519553 ap_remove_output_filter (f );
@@ -524,25 +558,23 @@ static apr_status_t ap_headers_output_filter(ap_filter_t *f,
524558
525559static apr_status_t ap_headers_fixup (request_rec * r )
526560{
527- headers_conf * serverconf = ap_get_module_config (r -> server -> module_config ,
528- & headers_module );
529561 headers_conf * dirconf = ap_get_module_config (r -> per_dir_config ,
530562 & headers_module );
531563
532564 /* do the fixup */
533- if (serverconf -> fixup_in -> nelts || dirconf -> fixup_in -> nelts ) {
534- do_headers_fixup (r , hdr_in , serverconf -> fixup_in );
535- do_headers_fixup (r , hdr_in , dirconf -> fixup_in );
565+ if (dirconf -> fixup_in -> nelts ) {
566+ do_headers_fixup (r , r -> headers_in , dirconf -> fixup_in );
536567 }
537568
538569 return DECLINED ;
539570}
540571
541572static const command_rec headers_cmds [] =
542573{
543- AP_INIT_RAW_ARGS ("Header" , header_cmd , (void * )hdr_out , OR_FILEINFO ,
544- "an action, header and value followed by optional env clause" ),
545- AP_INIT_RAW_ARGS ("RequestHeader" , header_cmd , (void * )hdr_in , OR_FILEINFO ,
574+ AP_INIT_RAW_ARGS ("Header" , header_cmd , & hdr_out , OR_FILEINFO ,
575+ "an optional condition, an action, header and value "
576+ "followed by optional env clause" ),
577+ AP_INIT_RAW_ARGS ("RequestHeader" , header_cmd , & hdr_in , OR_FILEINFO ,
546578 "an action, header and value" ),
547579 {NULL }
548580};
@@ -567,18 +599,21 @@ static void register_hooks(apr_pool_t *p)
567599{
568600 ap_hook_pre_config (header_pre_config ,NULL ,NULL ,APR_HOOK_MIDDLE );
569601 ap_hook_insert_filter (ap_headers_insert_output_filter , NULL , NULL , APR_HOOK_LAST );
602+ ap_hook_insert_error_filter (ap_headers_insert_error_filter , NULL , NULL , APR_HOOK_LAST );
570603 ap_hook_fixups (ap_headers_fixup , NULL , NULL , APR_HOOK_LAST );
571604 ap_register_output_filter ("FIXUP_HEADERS_OUT" , ap_headers_output_filter ,
572605 NULL , AP_FTYPE_CONTENT_SET );
606+ ap_register_output_filter ("FIXUP_HEADERS_ERR" , ap_headers_error_filter ,
607+ NULL , AP_FTYPE_CONTENT_SET );
573608}
574609
575610module AP_MODULE_DECLARE_DATA headers_module =
576611{
577612 STANDARD20_MODULE_STUFF ,
578- create_headers_dir_config , /* dir config creater */
613+ create_headers_config , /* dir config creater */
579614 merge_headers_config , /* dir merger --- default is to override */
580- create_headers_config , /* server config */
581- merge_headers_config , /* merge server configs */
615+ NULL , /* server config */
616+ NULL , /* merge server configs */
582617 headers_cmds , /* command apr_table_t */
583- register_hooks /* register hooks */
618+ register_hooks /* register hooks */
584619};
0 commit comments