perl-modperl mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Alexander Saip <solu...@gmail.com>
Subject Re: Capturing Apache response
Date Tue, 10 Feb 2009 05:52:58 GMT
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 <aw@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" <aw@ice-sa.com>
>> Sent: Sunday, February 08, 2009 5:26 PM
>> To: "Solutio at Gmail" <solutio@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.
>>>>
>>>>
>>>>
>>>
>>>
>

Mime
View raw message