I believe parsing custom headers in the filter should not be a problem with the 'do' and 'get' methods. But how to add them in a CGI environment? As a quick, dirty and inefficient work-around I consider writing the dynamic paramenters into a file to be picked up by the filter.
On Sun, Feb 8, 2009 at 7:32 PM, André Warnier <a...@ice-sa.com> wrote: > Solutio at Gmail wrote: > >> Thanks, your version works like a charm...but doesn't quite meets our >> needs. I apologize for being too vague regarding passing parameters on to >> the filter. Basically, we would like to somehow link the location and name >> of the response dump with the request data, like the date/time of the >> request, session ID, username, URL. We log that information in the audit >> data repository. In other words, the file handle for the captured data needs >> to point to a dynamically created file name. >> >> > Well, I did understand that that was what you were really aiming at, I just > couldn't think of a way. These filters get invoked with a fixed set of > parameters, directly by Apache, so you can't do much there. > If your application (the response generator) was also made with mod_perl, > it would be different, because there is a structure in memory that is > available to the content handler, and can be retrieved by a filter. > But I can think of one way : if at the level where you generate a response, > you can generate an additional HTTP response header containing the necessary > information, then you could read this header in the filter, and use it to > construct your trace file name. > In the code below, the $r->headers_out is a structure out of which you can > retrieve a specific HTTP response header by name (and its corresponding > value). > The filter could even remove it after usage. > > So think of a way of generating such a response header, and when you do get > back to me. mod_headers may be helpful. > Will be tomorrow though, it's 2 AM here. > > > > > -------------------------------------------------- >> From: "André Warnier" <a...@ice-sa.com> >> Sent: Sunday, February 08, 2009 5:26 PM >> To: "Solutio at Gmail" <solu...@gmail.com> >> Subject: Re: Capturing Apache response >> >> Hi. >>> Sorry to top-post, but I think in this case it will be clearer. >>> Not being the ultimate guru, but being probably the only guy available at >>> this day and time, I'll try my hand, at the risk of getting contradicted by >>> the real gurus later. >>> So start with a backup of your current filter. >>> >>> I don't have a certain answer about how to pass a parameter. >>> I try to show a way below, I'm not sure it works. >>> It is based on having an Apache directive like this : >>> PerlSetvar filter_output_dir "/tmp" >>> >>> >>> >>> I would then modify the filter as follows : >>> >>> package httpd::FilterCaptureResponse; >>> >>> use strict; >>> use warnings FATAL => 'all'; >>> >>> use base qw(Apache2::Filter); >>> >>> use Apache2::RequestRec (); >>> >>> use APR::Table (); >>> use APR::Bucket (); >>> use APR::Brigade (); >>> >>> use Apache2::Const -compile => qw(OK DECLINED); >>> use APR::Const -compile => ':common'; >>> >>> # 1) not really essential, but considering it's a compile-time thing : >>> use Data::Dumper; # DEBUG >>> >>> sub handler { >>> my ($filter, $bb) = @_; >>> my $ctx = $filter->ctx; >>> my $fh; >>> >>> unless ($ctx->{invoked}) { >>> # you probably want to do this the first time you're called, >>> # not after the data has all gone through >>> my $r = $filter->r; >>> my $outdir = $r->dir_config('filter_output_dir'); >>> unless (open($fh,'>',$outdir/ApacheResponse.txt")) { >>> warn "filter: could not open trace file : $!"; return DECLINED; # don't >>> filter, let output through >>> } >>> $ctx->{fh} = $fh; # save the filehandle >>> my $r_headers = $r->headers_out; >>> # the following goes to the Apache error log >>> warn "Dumping Apache response headers"; # DEBUG >>> # but this goes to the trace file >>> print $fh Dumper($r_headers),"\n"; # DEBUG >>> $ctx->{invoked} = 0; # initialise >>> } >>> $ctx->{invoked}++; >>> $fh = $ctx->{fh}; # retrieve stored filehandle >>> my ($bdata, $seen_eos) = flatten_bb($bb); >>> if ($seen_eos) { >>> print $fh $bdata if length($bdata != 0); >>> close $fh; >>> return Apache2::Const::OK; >>> } >>> print $fh $bdata if length($bdata != 0); >>> # store context for all but the last invocation >>> $filter->ctx($ctx); >>> return Apache2::Const::OK; >>> } >>> >>> sub flatten_bb { >>> my ($bb) = shift; >>> my $seen_eos = 0; >>> my @data; >>> for (my $b = $bb->first; $b; $b = $bb->next($b)) { >>> $seen_eos++, last if $b->is_eos; >>> $b->read(my $bdata); >>> push @data, $bdata; >>> } >>> return (join('', @data), $seen_eos); >>> } >>> >>> 1; >>> >>> >>> Solutio at Gmail wrote: >>> >>>> We are trying to implement a solution that would allow us to capture >>>> Apache (v. 2.0.63) responses sent to clients, each in a separate file on >>>> the >>>> server. I added a bucket brigade based output filter that mimics an example >>>> found in >>>> http://perl.apache.org/docs/2.0/user/handlers/filters.html#Bucket_Brigade_based_Output_Filters, >>>> as follows: >>>> >>>> ____ >>>> >>>> package httpd::FilterCaptureResponse; >>>> >>>> use strict; >>>> use warnings FATAL => 'all'; >>>> >>>> use base qw(Apache2::Filter); >>>> >>>> use Apache2::RequestRec (); >>>> >>>> use APR::Table (); >>>> use APR::Bucket (); >>>> use APR::Brigade (); >>>> >>>> use Apache2::Const -compile => qw(OK); >>>> use APR::Const -compile => ':common'; >>>> >>>> sub handler { >>>> my ($filter, $bb) = @_; >>>> my $ctx = $filter->ctx; >>>> >>>> my $data = exists $ctx->{data} ? $ctx->{data} : ''; >>>> $ctx->{invoked}++; >>>> my ($bdata, $seen_eos) = flatten_bb($bb); >>>> # $bdata =~ s/-//g; >>>> $data .= $bdata if $bdata; >>>> >>>> if ($seen_eos) { >>>> my $r_headers = $filter->r->headers_out; >>>> use Data::Dumper; # DEBUG >>>> warn "Dumping Apache response headers:\n"; # DEBUG >>>> warn Dumper($r_headers); # DEBUG >>>> if ($data) { >>>> if (open(CAPTION, ">/tmp/ApacheResponse.txt")) { >>>> print CAPTION $data; >>>> close CAPTION; >>>> } >>>> else { warn "Unable to open caption file: $!\n" } >>>> $filter->print($data); >>>> } >>>> } >>>> else { >>>> # store context for all but the last invocation >>>> $ctx->{data} = $data; >>>> $filter->ctx($ctx); >>>> } >>>> >>>> return Apache2::Const::OK; >>>> } >>>> >>>> sub flatten_bb { >>>> my ($bb) = shift; >>>> my $seen_eos = 0; >>>> my @data; >>>> for (my $b = $bb->first; $b; $b = $bb->next($b)) { >>>> $seen_eos++, last if $b->is_eos; >>>> $b->read(my $bdata); >>>> push @data, $bdata; >>>> } >>>> return (join('', @data), $seen_eos); >>>> } >>>> >>>> 1; >>>> >>>> ----- >>>> >>>> It works fine for the response body, but doesn't get the headers. The >>>> document I mentioned says that headers can only be seen by connection >>>> filters, so apparently the log contains the empty hash >>>> >>>> $VAR1 = bless( {}, 'APR::Table' ); >>>> >>>> I wonder if there is a workaround for this without adding a connection >>>> filter? >>>> >>>> Another question is what the best way would be to pass on arguments to >>>> the filter so that we could tell it where to store the response? >>>> >>>> Thank you in advance. >>>> >>>> >>>> >>> >>> >