mp2] [mod_proxy] [filter] mod_proxy is not playing with my request filter.

mp2] [mod_proxy] [filter] mod_proxy is not playing with my request filter.

am 24.08.2010 15:20:21 von James Lee

--000325559cfa83ce8a048e91a0c5
Content-Type: text/plain; charset=ISO-8859-1

Hi mod_perl community, this is my first post so be gentle with me.

I'm trying to create something which translates a GET request into a POST
(creating the body dynamically) and then hand off the POST to another
server.

I have created a mod_perl connection filter to change the GET to a POST in
the request line. It also adds Content-Length and Content-Type headers and
this works fine.

I then have a request filter which creates the POST body. This works when
the request is handled by a PerlResponseHandler but I'm trying to offload
the request to mod_proxy as the responses can be quite large but I just
can't get it to play ball. I see the request filter being called but the
POST body never arrives at the target server. I suspect this is a timing
issue, ie: mod_proxy kicking in before my request filter but I'm not
certain.

Can anybody shed some light on this or correct my approach. I was going to
add the POST body in the connection filter but it seemed cleaner/easier to
do it in a request filter.

I've looked on the mailing list and found a few things that touch on this (
http://tech.groups.yahoo.com/group/modperl/message/54541) but nothing that's
close enough to help.

Config below ... I've not included perl code as this message is quite long
anyway. Please let me know if it would be helpful.
Thanks in advance, James.


***
httpd.conf extract:


PerlInputFilterHandler Sample::RequestTweaker::change_get_to_post


PerlInputFilterHandler Sample::RequestTweaker::inject_post_data
ProxyPass http://appserver/reports-engine


--000325559cfa83ce8a048e91a0c5
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

Hi mod_perl community, this is my first post so be gentle with me.

I=
'm trying to create something which translates a GET request into a POS=
T
(creating the body dynamically) and then hand off the POST to another<=
br>


server.

I have created a mod_perl connection filter to change the GE=
T to a POST in
the request line. It also adds Content-Length and Content=
-Type headers and
this works fine.

I then have a request filter w=
hich creates the POST body. This works when



the request is handled by a PerlResponseHandler but I'm trying to offlo=
ad
the request to mod_proxy as the responses can be quite large but I ju=
st
can't get it to play ball. I see the request filter being called =
but the



POST body never arrives at the target server. I suspect this is a timing >issue, ie: mod_proxy kicking in before my request filter but I'm not r>certain.

Can anybody shed some light on this or correct my approac=
h. I was going to



add the POST body in the connection filter but it seemed cleaner/easier to<=
br>do it in a request filter.

I've looked on the mailing list an=
d found a few things that touch on this (
yahoo.com/group/modperl/message/54541" target=3D"_blank">http://tech.groups=
..yahoo.com/group/modperl/message/54541
) but nothing that's



close enough to help.

Config below ... I've not included perl co=
de as this message is quite long
anyway. Please let me know if it would =
be helpful.
Thanks in advance, James.


***
httpd.conf extra=
ct:





PerlInputFilterHandler Sample::RequestTweaker::change_get_to_post r>
<Location /reports>
   PerlInputFilterHandler Sample::Re=
questTweaker::inject_post_data
   ProxyPass ver/reports-engine" target=3D"_blank">http://appserver/reports-engine r>


</Location>



--000325559cfa83ce8a048e91a0c5--

Re: mp2] [mod_proxy] [filter] mod_proxy is not playing with my requestfilter.

am 25.08.2010 08:12:27 von aw

James Lee wrote:
> Hi mod_perl community, this is my first post so be gentle with me.
>
> I'm trying to create something which translates a GET request into a POST
> (creating the body dynamically) and then hand off the POST to another
> server.
>
> I have created a mod_perl connection filter to change the GET to a POST in
> the request line. It also adds Content-Length and Content-Type headers and
> this works fine.
>
> I then have a request filter which creates the POST body. This works when
> the request is handled by a PerlResponseHandler but I'm trying to offload
> the request to mod_proxy as the responses can be quite large but I just
> can't get it to play ball. I see the request filter being called but the
> POST body never arrives at the target server. I suspect this is a timing
> issue, ie: mod_proxy kicking in before my request filter but I'm not
> certain.

Exactly. By the time your response handler is invoked, the time for mod_proxy is long past.

One approach would be : have your PerlResponseHandler send the request directly to the
back-end server, using LWP, read the response, and return this response as the response
for your response handler. In other words, do yourself what mod_proxy would do.

>
> Can anybody shed some light on this or correct my approach. I was going to
> add the POST body in the connection filter but it seemed cleaner/easier to
> do it in a request filter.

In the mod_perl documentation, there is somewhere a schema of the different Apache phases,
and when the different handlers get invoked. I beliebe mod_proxygets invoked somewhere
around the Fixup phase, so if you want to beat it, you have to be earlier than that.

>
> I've looked on the mailing list and found a few things that touch on this (
> http://tech.groups.yahoo.com/group/modperl/message/54541) but nothing that's
> close enough to help.
>
> Config below ... I've not included perl code as this message is quite long
> anyway. Please let me know if it would be helpful.
> Thanks in advance, James.
>
>
> ***
> httpd.conf extract:
>
>
> PerlInputFilterHandler Sample::RequestTweaker::change_get_to_post
>
>
> PerlInputFilterHandler Sample::RequestTweaker::inject_post_data
> ProxyPass http://appserver/reports-engine
>

>

Re: mp2] [mod_proxy] [filter] mod_proxy is not playing with myrequest filter.

am 25.08.2010 10:41:05 von James Lee

--001636c5b018a1c8d5048ea1d726
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

Hi Andre, thanks for the response.

I don't actually want to use a PerlResponseHandler, I was just using that t=
o
make sure my filter did what I wanted it to do.

I actually wanted the request filter to add the POST body expecting then
that mod_proxy would do the rest. I expected mod_proxy to kick in around
PerlTransHandler time but wasn't sure when my request filter got called.
Either way it wasn't working :)

I may see whether I can get the connection filter to add the content I was
just after a little clarification when filters were called in relation to
mod_proxy.

Thanks again.


On 25 August 2010 07:12, Andr=E9 Warnier wrote:

> James Lee wrote:
>
>> Hi mod_perl community, this is my first post so be gentle with me.
>>
>> I'm trying to create something which translates a GET request into a POS=
T
>> (creating the body dynamically) and then hand off the POST to another
>> server.
>>
>> I have created a mod_perl connection filter to change the GET to a POST =
in
>> the request line. It also adds Content-Length and Content-Type headers a=
nd
>> this works fine.
>>
>> I then have a request filter which creates the POST body. This works whe=
n
>> the request is handled by a PerlResponseHandler but I'm trying to offloa=
d
>> the request to mod_proxy as the responses can be quite large but I just
>> can't get it to play ball. I see the request filter being called but the
>> POST body never arrives at the target server. I suspect this is a timing
>> issue, ie: mod_proxy kicking in before my request filter but I'm not
>> certain.
>>
>
> Exactly. By the time your response handler is invoked, the time for
> mod_proxy is long past.
>
> One approach would be : have your PerlResponseHandler send the request
> directly to the back-end server, using LWP, read the response, and return
> this response as the response for your response handler. In other words,=
do
> yourself what mod_proxy would do.
>
>
>
>> Can anybody shed some light on this or correct my approach. I was going =
to
>> add the POST body in the connection filter but it seemed cleaner/easier =
to
>> do it in a request filter.
>>
>
> In the mod_perl documentation, there is somewhere a schema of the differe=
nt
> Apache phases, and when the different handlers get invoked. I beliebe
> mod_proxygets invoked somewhere around the Fixup phase, so if you want to
> beat it, you have to be earlier than that.
>
>
>
>> I've looked on the mailing list and found a few things that touch on thi=
s
>> (
>> http://tech.groups.yahoo.com/group/modperl/message/54541) but nothing
>> that's
>> close enough to help.
>>
>> Config below ... I've not included perl code as this message is quite lo=
ng
>> anyway. Please let me know if it would be helpful.
>> Thanks in advance, James.
>>
>>
>> ***
>> httpd.conf extract:
>>
>>
>> PerlInputFilterHandler Sample::RequestTweaker::change_get_to_post
>>
>>
>> PerlInputFilterHandler Sample::RequestTweaker::inject_post_data
>> ProxyPass http://appserver/reports-engine
>>

>>
>>
>

--001636c5b018a1c8d5048ea1d726
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

Hi Andre, thanks for the response.

I don't actually want to use =
a PerlResponseHandler, I was just using that to make sure my filter did wha=
t I wanted it to do.

I actually wanted the request filter to add the=
POST body expecting then that mod_proxy would do the rest. I expected mod_=
proxy to kick in around PerlTransHandler time but wasn't sure when my r=
equest filter got called. Either way it wasn't working :)


I may see whether I can get the connection filter to add the content I =
was just after a little clarification when filters were called in relation =
to mod_proxy.

Thanks again.



On 25 August 2010 07:12, Andr=E9 Warnier < ailto:aw@ice-sa.com">aw@ice-sa.com> wrote:
ss=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px sol=
id rgb(204, 204, 204); padding-left: 1ex;">
James Lee wrote:

r-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
Hi mod_perl community, this is my first post so be gentle with me.



I'm trying to create something which translates a GET request into a PO=
ST

(creating the body dynamically) and then hand off the POST to another

server.



I have created a mod_perl connection filter to change the GET to a POST in<=
br>
the request line. It also adds Content-Length and Content-Type headers and<=
br>
this works fine.



I then have a request filter which creates the POST body. This works when r>
the request is handled by a PerlResponseHandler but I'm trying to offlo=
ad

the request to mod_proxy as the responses can be quite large but I just

can't get it to play ball. I see the request filter being called but th=
e

POST body never arrives at the target server. I suspect this is a timing >
issue, ie: mod_proxy kicking in before my request filter but I'm not >
certain.




Exactly. By the time your response handler is invoked, the time for mod_pro=
xy is long past.



One approach would be : have your PerlResponseHandler send the request dire=
ctly to the back-end server, using LWP, read the response, and return this =
response as the response for your response handler. =A0In other words, do y=
ourself what mod_proxy would do.





r-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">


Can anybody shed some light on this or correct my approach. I was going to<=
br>
add the POST body in the connection filter but it seemed cleaner/easier to<=
br>
do it in a request filter.




In the mod_perl documentation, there is somewhere a schema of the different=
Apache phases, and when the different handlers get invoked. =A0I beliebe m=
od_proxygets invoked somewhere around the Fixup phase, so if you want to be=
at it, you have to be earlier than that.





r-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">


I've looked on the mailing list and found a few things that touch on th=
is (

=3D"_blank">http://tech.groups.yahoo.com/group/modperl/messa ge/54541) b=
ut nothing that's

close enough to help.



Config below ... I've not included perl code as this message is quite l=
ong

anyway. Please let me know if it would be helpful.

Thanks in advance, James.





***

httpd.conf extract:





PerlInputFilterHandler Sample::RequestTweaker::change_get_to_post



<Location /reports>

=A0 PerlInputFilterHandler Sample::RequestTweaker::inject_post_data

=A0 ProxyPass ">http://appserver/reports-engine

</Location>









--001636c5b018a1c8d5048ea1d726--

Re: mp2] [mod_proxy] [filter] mod_proxy is not playing with myrequest filter.

am 26.08.2010 18:28:47 von James Lee

--001636c5a2581c6ab1048ebc7eb5
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

I'm still having issues attempting to modify the body of an http request -
this time using a FilterConnectionHandler.

I've had to park this due to deadlines and write it using LWP in a
PerlResponseHandler. This is far from ideal as some of the responses are
upwards of 5MB, and what I'm trying to do does feel very doable in mod_perl=
..

What I really want is to be able to do is pass the request off to mod_proxy
(which I assume is better setup for streaming responses through Apache ... =
I
may be wrong) and then through mod_deflate to compress the results.

I've attached the code and configuration if anybody has a second and could
shed some light over what I'm doing wrong.

I'm basically trying to convert a GET request to 'http://hostname/echo' int=
o
a POST request and attach a payload, however as it hangs mod_proxy becomes
largely academic.

Again any help would be much appreciated.
Thanks, James.


PerlModule Example::Echo
PerlModule Example::ConnectionFilter

PerlInputFilterHandler Example::ConnectionFilter::forward_get_as_post


SetHandler modperl
PerlResponseHandler Example::Echo




package Example::Echo;

use strict;
use warnings;

use Apache2::Const -compile =3D> qw(OK);
use Apache2::RequestIO;
use Apache2::RequestRec;


sub handler
{
my $r =3D shift;

$r->content_type('text/plain');
$r->read(my $buffer, 1024);
$r->print("received post data: '".$buffer."'");

return Apache2::Const::OK;
}


1;



package Example::ConnectionFilter;

use strict;
use warnings;

use base qw/Apache2::Filter/;

use Apache2::Connection;
use Apache2::Const -compile =3D> qw(OK DECLINED);
use Apache2::FilterRec;
use Apache2::Log;
use Apache2::RequestRec;
use Apache2::RequestIO;

use APR::Const -compile =3D> ':common';
use APR::Brigade;
use APR::Bucket;
use APR::BucketType;
use APR::Error;


sub forward_get_as_post :FilterConnectionHandler
{
my ($f, $bb, $mode, $block, $readbytes) =3D @_;
my $ctx =3D $f->ctx || { 'state' =3D> 'waiting_for_request_line' };

warn "state =3D ".$ctx->{'state'}."\r\n";

# check whether we need to process this request.
return Apache2::Const::DECLINED if ($ctx->{'state'} eq 'ignore');

# read into a tmp brigade.
my $connection =3D $f->c;
my $tmp_bb =3D APR::Brigade->new($connection->pool,
$connection->bucket_alloc);
my $rv =3D $f->next->get_brigade($tmp_bb, $mode, $block, $readbytes);

return $rv unless $rv == APR::Const::SUCCESS;

while (!$tmp_bb->is_empty)
{
# pop buckets from this brigade.
my $bucket =3D $tmp_bb->first;
$bucket->remove();

if ($ctx->{'state'} eq 'waiting_for_request_line')
{
# assumes request line is first bucket.
$bucket->read(my $request_line);
my ($method, $uri, $version) =3D ($request_line =3D~ m|^(.*?) (=
..*?)
HTTP/(.*?)\r\n$|);

if (defined ($method) and $method eq "GET" and $uri =3D~
m|^/echo|)
{
my $new_uri =3D 'POST '.$uri.' HTTP/'.$version."\r\n";
my $new_uri_bucket =3D
APR::Bucket->new($connection->bucket_alloc, $new_uri);

$bb->insert_tail($new_uri_bucket);

my $bucket2 =3D APR::Bucket->new($connection->bucket_alloc,
"Content-Type: application/x-www-form-urlencoded\r\n");
$bb->insert_tail($bucket2);

my $bucket3 =3D APR::Bucket->new($connection->bucket_alloc,
"Content-Length: 9\r\n");
$bb->insert_tail($bucket3);

$ctx->{'state'} =3D 'waiting_for_end_of_headers';
}
else
{
$bb->insert_tail($bucket);
$ctx->{'state'} =3D 'ignore';
}
}
elsif ($ctx->{'state'} eq 'waiting_for_end_of_headers')
{
$bucket->read(my $header);
warn "received header ... ".$header."\r\n";

if ($header =3D~ m|^\r\n$|)
{
warn "detected end_of_headers\r\n";

my $post_data =3D &get_post_data();


### as soon as I add 'data=3Dtest' to this bucket the reque=
st
appears to hang.
############################################


my $end_of_headers_bucket =3D
APR::Bucket->new($connection->bucket_alloc, "\r\ndata=3Dtest");

$bb->insert_tail($end_of_headers_bucket);
$ctx->{'state'} =3D 'finished';
}
else
{
$bb->insert_tail($bucket);
}
}
}

# set context.
$f->ctx($ctx);

return Apache2::Const::OK;
}


1;







On 25 August 2010 09:41, James Lee wrote:

> Hi Andre, thanks for the response.
>
> I don't actually want to use a PerlResponseHandler, I was just using that
> to make sure my filter did what I wanted it to do.
>
> I actually wanted the request filter to add the POST body expecting then
> that mod_proxy would do the rest. I expected mod_proxy to kick in around
> PerlTransHandler time but wasn't sure when my request filter got called.
> Either way it wasn't working :)
>
> I may see whether I can get the connection filter to add the content I wa=
s
> just after a little clarification when filters were called in relation to
> mod_proxy.
>
> Thanks again.
>
>
>
> On 25 August 2010 07:12, Andr=E9 Warnier wrote:
>
>> James Lee wrote:
>>
>>> Hi mod_perl community, this is my first post so be gentle with me.
>>>
>>> I'm trying to create something which translates a GET request into a PO=
ST
>>> (creating the body dynamically) and then hand off the POST to another
>>> server.
>>>
>>> I have created a mod_perl connection filter to change the GET to a POST
>>> in
>>> the request line. It also adds Content-Length and Content-Type headers
>>> and
>>> this works fine.
>>>
>>> I then have a request filter which creates the POST body. This works wh=
en
>>> the request is handled by a PerlResponseHandler but I'm trying to offlo=
ad
>>> the request to mod_proxy as the responses can be quite large but I just
>>> can't get it to play ball. I see the request filter being called but th=
e
>>> POST body never arrives at the target server. I suspect this is a timin=
g
>>> issue, ie: mod_proxy kicking in before my request filter but I'm not
>>> certain.
>>>
>>
>> Exactly. By the time your response handler is invoked, the time for
>> mod_proxy is long past.
>>
>> One approach would be : have your PerlResponseHandler send the request
>> directly to the back-end server, using LWP, read the response, and retur=
n
>> this response as the response for your response handler. In other words=
, do
>> yourself what mod_proxy would do.
>>
>>
>>
>>> Can anybody shed some light on this or correct my approach. I was going
>>> to
>>> add the POST body in the connection filter but it seemed cleaner/easier
>>> to
>>> do it in a request filter.
>>>
>>
>> In the mod_perl documentation, there is somewhere a schema of the
>> different Apache phases, and when the different handlers get invoked. I
>> beliebe mod_proxygets invoked somewhere around the Fixup phase, so if yo=
u
>> want to beat it, you have to be earlier than that.
>>
>>
>>
>>> I've looked on the mailing list and found a few things that touch on th=
is
>>> (
>>> http://tech.groups.yahoo.com/group/modperl/message/54541) but nothing
>>> that's
>>> close enough to help.
>>>
>>> Config below ... I've not included perl code as this message is quite
>>> long
>>> anyway. Please let me know if it would be helpful.
>>> Thanks in advance, James.
>>>
>>>
>>> ***
>>> httpd.conf extract:
>>>
>>>
>>> PerlInputFilterHandler Sample::RequestTweaker::change_get_to_post
>>>
>>>
>>> PerlInputFilterHandler Sample::RequestTweaker::inject_post_data
>>> ProxyPass http://appserver/reports-engine
>>>

>>>
>>>
>>
>

--001636c5a2581c6ab1048ebc7eb5
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

I'm still having issues attempting to modify the body of an http reques=
t - this time using a FilterConnectionHandler.

I've had to park =
this due to deadlines and write it using LWP in a PerlResponseHandler. This=
is far from ideal as some of the responses are upwards of 5MB, and what I&=
#39;m trying to do does feel very doable in mod_perl.


What I really want is to be able to do is pass the request off to mod_p=
roxy (which I assume is better setup for streaming responses through Apache=
... I may be wrong) and then through mod_deflate to compress the results.<=
br>

I've attached the code and configuration if anybody has a second an=
d could shed some light over what I'm doing wrong.

I'm basic=
ally trying to convert a GET request to ' o">http://hostname/echo' into a POST request and attach a payload, =
however as it hangs mod_proxy becomes largely academic.


Again any help would be much appreciated.
Thanks, James.


=
PerlModule Example::Echo
PerlModule Example::ConnectionFilter

Per=
lInputFilterHandler Example::ConnectionFilter::forward_get_as_post


<Location /echo>
  =A0 SetHandler modperl
  =A0 PerlRes=
ponseHandler Example::Echo
</Location>



package Exam=
ple::Echo;

use strict;
use warnings;

use Apache2::Const -c=
ompile =3D> qw(OK);

use Apache2::RequestIO;
use Apache2::RequestRec;


sub handler<=
br>{
  =A0 my $r =3D shift;

  =A0 $r->content_type(=
9;text/plain');
  =A0 $r->read(my $buffer, 1024);
  =
=A0 $r->print("received post data: '".$buffer."'&=
quot;);

  =A0
  =A0 return Apache2::Const::OK;
}


1;
r>

package Example::ConnectionFilter;

use strict;
use warn=
ings;

use base qw/Apache2::Filter/;

use Apache2::Connection;<=
br>use Apache2::Const -compile =3D> qw(OK DECLINED);

use Apache2::FilterRec;
use Apache2::Log;
use Apache2::RequestRec; >use Apache2::RequestIO;

use APR::Const -compile =3D> ':commo=
n';
use APR::Brigade;
use APR::Bucket;
use APR::BucketType; >
use APR::Error;


sub forward_get_as_post :FilterConnectionHandler=

{
  =A0 my ($f, $bb, $mode, $block, $readbytes) =3D @_;
=A0=
   my $ctx =3D $f->ctx || { 'state' =3D> 'waiting_for=
_request_line' };

  =A0
  =A0 warn "state =3D ".$ctx->{'state=
9;}."\r\n";

  =A0 # check whether we need to process t=
his request.
  =A0 return Apache2::Const::DECLINED if ($ctx->{=
9;state'} eq 'ignore');

  =A0
  =A0 # read into a tmp brigade.
  =A0 my $connect=
ion =3D $f->c;
  =A0 my $tmp_bb =3D APR::Brigade->new($connect=
ion->pool, $connection->bucket_alloc);
  =A0 my $rv =3D $f->=
;next->get_brigade($tmp_bb, $mode, $block, $readbytes);

  =A0
  =A0 return $rv unless $rv == APR::Const::SUCCESS; r>  =A0
  =A0 while (!$tmp_bb->is_empty)
  =A0 {
=
  =A0   =A0 # pop buckets from this brigade.
  =A0   =A0=
my $bucket =3D $tmp_bb->first;
  =A0   =A0 $bucket->remov=
e();


  =A0   =A0 if ($ctx->{'state'} eq 'waiting_for_=
request_line')
  =A0   =A0 {
  =A0   =A0   =
=A0 # assumes request line is first bucket.
  =A0   =A0   =
=A0 $bucket->read(my $request_line);
  =A0   =A0   =A0 my=
($method, $uri, $version) =3D ($request_line =3D~ m|^(.*?) (.*?) HTTP/(.*?=
)\r\n$|);

  =A0   =A0   =A0
  =A0   =A0   =A0 if (defined=
($method) and $method eq "GET" and $uri =3D~ m|^/echo|)
=A0=
     =A0   =A0 {
  =A0   =A0   =A0   =A0 my =
$new_uri =3D 'POST '.$uri.' HTTP/'.$version."\r\n"=
;;

  =A0   =A0   =A0   =A0 my $new_uri_bucket =3D APR::Bucket-=
>new($connection->bucket_alloc, $new_uri);
  =A0   =A0 =A0=
     =A0
  =A0   =A0   =A0   =A0 $bb->insert=
_tail($new_uri_bucket);
  =A0   =A0   =A0   =A0
=A0=
     =A0   =A0   =A0 my $bucket2 =3D APR::Bucket->new($c=
onnection->bucket_alloc, "Content-Type: application/x-www-form-urle=
ncoded\r\n");

  =A0   =A0   =A0   =A0 $bb->insert_tail($bucket2);
=
  =A0   =A0   =A0   =A0
  =A0   =A0   =A0 =
  =A0 my $bucket3 =3D APR::Bucket->new($connection->bucket_alloc,=
"Content-Length: 9\r\n");
  =A0   =A0   =A0 =A0=
   $bb->insert_tail($bucket3);

  =A0   =A0   =A0   =A0
  =A0   =A0   =A0 =
  =A0 $ctx->{'state'} =3D 'waiting_for_end_of_headers=
9;;
  =A0   =A0   =A0 }
  =A0   =A0   =A0 els=
e
  =A0   =A0   =A0 {
  =A0   =A0   =A0 =A0=
   $bb->insert_tail($bucket);
  =A0   =A0   =A0 =A0=
   $ctx->{'state'} =3D 'ignore';

  =A0   =A0   =A0 }
  =A0   =A0 }
  =A0 =A0=
   elsif ($ctx->{'state'} eq 'waiting_for_end_of_headers=
')
  =A0   =A0 {
  =A0   =A0   =A0 $bucket-&g=
t;read(my $header);
  =A0   =A0   =A0 warn "received he=
ader ... ".$header."\r\n";


  =A0   =A0   =A0 if ($header =3D~ m|^\r\n$|)
  =A0 =
  =A0   =A0 {
  =A0   =A0   =A0   =A0 warn "=
;detected end_of_headers\r\n";
  =A0   =A0   =A0   =
=A0
  =A0   =A0   =A0   =A0 my $post_data =3D &get_=
post_data();
  =A0   =A0   =A0   =A0

  =A0   =A0   =A0   =A0
  =A0   =A0   =A0 =
  =A0 ### as soon as I add 'data=3Dtest' to this bucket the req=
uest appears to hang.
  =A0   =A0   =A0   =A0 ##########=
##################################
  =A0   =A0   =A0   =
=A0
  =A0   =A0   =A0   =A0

  =A0   =A0   =A0   =A0 my $end_of_headers_bucket =3D APR::=
Bucket->new($connection->bucket_alloc, "\r\ndata=3Dtest");<=
br>  =A0   =A0   =A0   =A0
  =A0   =A0   =
=A0   =A0 $bb->insert_tail($end_of_headers_bucket);
  =A0 =A0=
     =A0   =A0 $ctx->{'state'} =3D 'finished'=
;;

  =A0   =A0   =A0 }
  =A0   =A0   =A0 else
=
  =A0   =A0   =A0 {
  =A0   =A0   =A0   =A0 =
$bb->insert_tail($bucket);
  =A0   =A0   =A0 }
  =
=A0   =A0 }
  =A0 }

  =A0 # set context.  =A0 >  =A0 $f->ctx($ctx);

  =A0 return Apache2::Const::OK; >
}


1;







O=
n 25 August 2010 09:41, James Lee < odperl.nunk@gmail.com">modperl.nunk@gmail.com> wrote:
ckquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; border-le=
ft: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
Hi Andre, thanks for the response.

I don't actually want to use =
a PerlResponseHandler, I was just using that to make sure my filter did wha=
t I wanted it to do.

I actually wanted the request filter to add the=
POST body expecting then that mod_proxy would do the rest. I expected mod_=
proxy to kick in around PerlTransHandler time but wasn't sure when my r=
equest filter got called. Either way it wasn't working :)



I may see whether I can get the connection filter to add the content I =
was just after a little clarification when filters were called in relation =
to mod_proxy.

Thanks again.





On 25 August 2010 07:12, Andr=E9 Warnier < ailto:aw@ice-sa.com" target=3D"_blank">aw@ice-sa.com> wrote:<=
br>
rder-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">

James Lee wrote:

r-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
Hi mod_perl community, this is my first post so be gentle with me.



I'm trying to create something which translates a GET request into a PO=
ST

(creating the body dynamically) and then hand off the POST to another

server.



I have created a mod_perl connection filter to change the GET to a POST in<=
br>
the request line. It also adds Content-Length and Content-Type headers and<=
br>
this works fine.



I then have a request filter which creates the POST body. This works when r>
the request is handled by a PerlResponseHandler but I'm trying to offlo=
ad

the request to mod_proxy as the responses can be quite large but I just

can't get it to play ball. I see the request filter being called but th=
e

POST body never arrives at the target server. I suspect this is a timing >
issue, ie: mod_proxy kicking in before my request filter but I'm not >
certain.




Exactly. By the time your response handler is invoked, the time for mod_pro=
xy is long past.



One approach would be : have your PerlResponseHandler send the request dire=
ctly to the back-end server, using LWP, read the response, and return this =
response as the response for your response handler. =A0In other words, do y=
ourself what mod_proxy would do.






r-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">


Can anybody shed some light on this or correct my approach. I was going to<=
br>
add the POST body in the connection filter but it seemed cleaner/easier to<=
br>
do it in a request filter.




In the mod_perl documentation, there is somewhere a schema of the different=
Apache phases, and when the different handlers get invoked. =A0I beliebe m=
od_proxygets invoked somewhere around the Fixup phase, so if you want to be=
at it, you have to be earlier than that.






r-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">


I've looked on the mailing list and found a few things that touch on th=
is (

=3D"_blank">http://tech.groups.yahoo.com/group/modperl/messa ge/54541) b=
ut nothing that's

close enough to help.



Config below ... I've not included perl code as this message is quite l=
ong

anyway. Please let me know if it would be helpful.

Thanks in advance, James.





***

httpd.conf extract:





PerlInputFilterHandler Sample::RequestTweaker::change_get_to_post



<Location /reports>

=A0 PerlInputFilterHandler Sample::RequestTweaker::inject_post_data

=A0 ProxyPass ">http://appserver/reports-engine

</Location>











--001636c5a2581c6ab1048ebc7eb5--

Re: mp2] [mod_proxy] [filter] mod_proxy is not playing with my request filter.

am 26.08.2010 19:47:48 von torsten.foertsch

On Thursday, August 26, 2010 18:28:47 James Lee wrote:

A few comments below.

The goal of the code is to fill up $bb. Nothing is copied there unless you =
do.
The way you do it is to start with an empty brigade.

> sub forward_get_as_post :FilterConnectionHandler
> {
> my ($f, $bb, $mode, $block, $readbytes) =3D @_;
> my $ctx =3D $f->ctx || { 'state' =3D> 'waiting_for_request_line' };
>=20
> warn "state =3D ".$ctx->{'state'}."\r\n";
>=20
> # check whether we need to process this request.
> return Apache2::Const::DECLINED if ($ctx->{'state'} eq 'ignore');
>=20
> # read into a tmp brigade.
> my $connection =3D $f->c;
> my $tmp_bb =3D APR::Brigade->new($connection->pool,
> $connection->bucket_alloc);
> my $rv =3D $f->next->get_brigade($tmp_bb, $mode, $block, $readbytes);
>=20
> return $rv unless $rv == APR::Const::SUCCESS;
>=20
> while (!$tmp_bb->is_empty)
> {
> # pop buckets from this brigade.
> my $bucket =3D $tmp_bb->first;
> $bucket->remove();
>=20
> if ($ctx->{'state'} eq 'waiting_for_request_line')
> {
> # assumes request line is first bucket.
> $bucket->read(my $request_line);
> my ($method, $uri, $version) =3D ($request_line =3D~ m|^(.*?)=
(.*?)
> HTTP/(.*?)\r\n$|);
>=20
> if (defined ($method) and $method eq "GET" and $uri =3D~
> m|^/echo|)
> {
> my $new_uri =3D 'POST '.$uri.' HTTP/'.$version."\r\n";
> my $new_uri_bucket =3D
> APR::Bucket->new($connection->bucket_alloc, $new_uri);
>=20
> $bb->insert_tail($new_uri_bucket);
>=20
> my $bucket2 =3D APR::Bucket->new($connection->bucket_allo=
c,
> "Content-Type: application/x-www-form-urlencoded\r\n");
> $bb->insert_tail($bucket2);
>=20
> my $bucket3 =3D APR::Bucket->new($connection->bucket_allo=
c,
> "Content-Length: 9\r\n");
> $bb->insert_tail($bucket3);

by now you have inserted these lines:

POST /echo HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 9

You have read the 1st bucket of the input. That bucket may (or may not)=20
contain the whole request including the empty line that signals end-of-
headers. So, you have to check also the rest of the bucket.

>=20
> $ctx->{'state'} =3D 'waiting_for_end_of_headers';
> }
> else
> {
> $bb->insert_tail($bucket);
> $ctx->{'state'} =3D 'ignore';
> }
> }
> elsif ($ctx->{'state'} eq 'waiting_for_end_of_headers')
> {
> $bucket->read(my $header);
> warn "received header ... ".$header."\r\n";
>=20
> if ($header =3D~ m|^\r\n$|)
> {
> warn "detected end_of_headers\r\n";
>=20
> my $post_data =3D &get_post_data();
>=20
>=20
> ### as soon as I add 'data=3Dtest' to this bucket the req=
uest
> appears to hang.
> ############################################
>=20
>=20
> my $end_of_headers_bucket =3D
> APR::Bucket->new($connection->bucket_alloc, "\r\ndata=3Dtest");
>=20
> $bb->insert_tail($end_of_headers_bucket);

by now you have sent

POST /echo HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 9

data=3Dtest

Correct me if I am wrong but don't you have to insert an EOS marker? Haven'=
t=20
tried connection input filter yet. But normally a stream is closed with a

$bb->insert_tail(APR::Bucket::eos_create $connection->bucket_alloc);

> $ctx->{'state'} =3D 'finished';
> }
> else
> {
> $bb->insert_tail($bucket);
> }
> }
> }
>=20
> # set context.
> $f->ctx($ctx);
>=20
> return Apache2::Const::OK;
> }

If it works with the EOS bucket it will probably work for most of the=20
requests. But RFC2616 doesn't forbid GET requests to have a request body. T=
hat=20
means you should read the input until EOS. Don't know if your code does tha=
t=20
actually. Otherwise your client may still send the request while your handl=
er=20
is already done with the response.

Torsten Förtsch

=2D-=20
Need professional modperl support? Hire me! (http://foertsch.name)

Like fantasy? http://kabatinte.net

Re: mp2] [mod_proxy] [filter] mod_proxy is not playing with myrequest filter.

am 26.08.2010 21:12:18 von James Lee

--0016e6d7787ce9685d048ebec696
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

Hi, thanks for the response.

To my knowledge (which is about a weeks worth) you don't need or indeed see
an end_of_stream bucket in a connection filter till the connection is close=
d
and then only in the output filter.

Conveniently the request headers seem to be passed from the core filter one
brigade at a time which makes my code quite easy, no need for buffering
buckets between calls. As I said the code works fine until I append the
'data=3Dtest' to the end of the headers which should be my request body.

It's been driving me crazy all day and I can't understand why its doing wha=
t
it is doing! It's just frustrating because it sounds like something I shoul=
d
be able to do.


James.



2010/8/26 Torsten Förtsch

> On Thursday, August 26, 2010 18:28:47 James Lee wrote:
>
> A few comments below.
>
> The goal of the code is to fill up $bb. Nothing is copied there unless yo=
u
> do.
> The way you do it is to start with an empty brigade.
>
> > sub forward_get_as_post :FilterConnectionHandler
> > {
> > my ($f, $bb, $mode, $block, $readbytes) =3D @_;
> > my $ctx =3D $f->ctx || { 'state' =3D> 'waiting_for_request_line' };
> >
> > warn "state =3D ".$ctx->{'state'}."\r\n";
> >
> > # check whether we need to process this request.
> > return Apache2::Const::DECLINED if ($ctx->{'state'} eq 'ignore');
> >
> > # read into a tmp brigade.
> > my $connection =3D $f->c;
> > my $tmp_bb =3D APR::Brigade->new($connection->pool,
> > $connection->bucket_alloc);
> > my $rv =3D $f->next->get_brigade($tmp_bb, $mode, $block, $readbytes=
);
> >
> > return $rv unless $rv == APR::Const::SUCCESS;
> >
> > while (!$tmp_bb->is_empty)
> > {
> > # pop buckets from this brigade.
> > my $bucket =3D $tmp_bb->first;
> > $bucket->remove();
> >
> > if ($ctx->{'state'} eq 'waiting_for_request_line')
> > {
> > # assumes request line is first bucket.
> > $bucket->read(my $request_line);
> > my ($method, $uri, $version) =3D ($request_line =3D~ m|^(.*=
?)
> (.*?)
> > HTTP/(.*?)\r\n$|);
> >
> > if (defined ($method) and $method eq "GET" and $uri =3D~
> > m|^/echo|)
> > {
> > my $new_uri =3D 'POST '.$uri.' HTTP/'.$version."\r\n";
> > my $new_uri_bucket =3D
> > APR::Bucket->new($connection->bucket_alloc, $new_uri);
> >
> > $bb->insert_tail($new_uri_bucket);
> >
> > my $bucket2 =3D APR::Bucket->new($connection->bucket_al=
loc,
> > "Content-Type: application/x-www-form-urlencoded\r\n");
> > $bb->insert_tail($bucket2);
> >
> > my $bucket3 =3D APR::Bucket->new($connection->bucket_al=
loc,
> > "Content-Length: 9\r\n");
> > $bb->insert_tail($bucket3);
>
> by now you have inserted these lines:
>
> POST /echo HTTP/1.1
> Content-Type: application/x-www-form-urlencoded
> Content-Length: 9
>
> You have read the 1st bucket of the input. That bucket may (or may not)
> contain the whole request including the empty line that signals end-of-
> headers. So, you have to check also the rest of the bucket.
>
> >
> > $ctx->{'state'} =3D 'waiting_for_end_of_headers';
> > }
> > else
> > {
> > $bb->insert_tail($bucket);
> > $ctx->{'state'} =3D 'ignore';
> > }
> > }
> > elsif ($ctx->{'state'} eq 'waiting_for_end_of_headers')
> > {
> > $bucket->read(my $header);
> > warn "received header ... ".$header."\r\n";
> >
> > if ($header =3D~ m|^\r\n$|)
> > {
> > warn "detected end_of_headers\r\n";
> >
> > my $post_data =3D &get_post_data();
> >
> >
> > ### as soon as I add 'data=3Dtest' to this bucket the
> request
> > appears to hang.
> > ############################################
> >
> >
> > my $end_of_headers_bucket =3D
> > APR::Bucket->new($connection->bucket_alloc, "\r\ndata=3Dtest");
> >
> > $bb->insert_tail($end_of_headers_bucket);
>
> by now you have sent
>
> POST /echo HTTP/1.1
> Content-Type: application/x-www-form-urlencoded
> Content-Length: 9
>
> data=3Dtest
>
> Correct me if I am wrong but don't you have to insert an EOS marker?
> Haven't
> tried connection input filter yet. But normally a stream is closed with a
>
> $bb->insert_tail(APR::Bucket::eos_create $connection->bucket_alloc);
>
> > $ctx->{'state'} =3D 'finished';
> > }
> > else
> > {
> > $bb->insert_tail($bucket);
> > }
> > }
> > }
> >
> > # set context.
> > $f->ctx($ctx);
> >
> > return Apache2::Const::OK;
> > }
>
> If it works with the EOS bucket it will probably work for most of the
> requests. But RFC2616 doesn't forbid GET requests to have a request body.
> That
> means you should read the input until EOS. Don't know if your code does
> that
> actually. Otherwise your client may still send the request while your
> handler
> is already done with the response.
>
> Torsten Förtsch
>
> --
> Need professional modperl support? Hire me! (http://foertsch.name)
>
> Like fantasy? http://kabatinte.net
>

--0016e6d7787ce9685d048ebec696
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

Hi, thanks for the response.

To my knowledge (which is about a weeks=
worth) you don't need or indeed see an end_of_stream bucket in a conne=
ction filter till the connection is closed and then only in the output filt=
er.


Conveniently the request headers seem to be passed from the core filter=
one brigade at a time which makes my code quite easy, no need for bufferin=
g buckets between calls.=A0 As I said the code works fine until I append th=
e 'data=3Dtest' to the end of the headers which should be my reques=
t body.



It's been driving me crazy all day and I can't understand why its d=
oing what it is doing! It's just frustrating because it sounds like som=
ething I should be able to do.



James.



2010/8/26 Torsten =
Förtsch < >torsten.foertsch@gmx.net>
e" style=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204,=
204); padding-left: 1ex;">
On Thursday, August 26, 2010 18:28:47 James Lee wrote:



A few comments below.



The goal of the code is to fill up $bb. Nothing is copied there unless you =
do.

The way you do it is to start with an empty brigade.



> sub forward_get_as_post :FilterConnectionHandler

> {

> =A0 =A0 my ($f, $bb, $mode, $block, $readbytes) =3D @_;

> =A0 =A0 my $ctx =3D $f->ctx || { 'state' =3D> 'waiti=
ng_for_request_line' };

>

> =A0 =A0 warn "state =3D ".$ctx->{'state'}."\=
r\n";

>

> =A0 =A0 # check whether we need to process this request.

> =A0 =A0 return Apache2::Const::DECLINED if ($ctx->{'state'}=
eq 'ignore');

>

> =A0 =A0 # read into a tmp brigade.

> =A0 =A0 my $connection =3D $f->c;

> =A0 =A0 my $tmp_bb =3D APR::Brigade->new($connection->pool,

> $connection->bucket_alloc);

> =A0 =A0 my $rv =3D $f->next->get_brigade($tmp_bb, $mode, $block,=
$readbytes);

>

> =A0 =A0 return $rv unless $rv == APR::Const::SUCCESS;

>

> =A0 =A0 while (!$tmp_bb->is_empty)

> =A0 =A0 {

> =A0 =A0 =A0 =A0 # pop buckets from this brigade.

> =A0 =A0 =A0 =A0 my $bucket =3D $tmp_bb->first;

> =A0 =A0 =A0 =A0 $bucket->remove();

>

> =A0 =A0 =A0 =A0 if ($ctx->{'state'} eq 'waiting_for_req=
uest_line')

> =A0 =A0 =A0 =A0 {

> =A0 =A0 =A0 =A0 =A0 =A0 # assumes request line is first bucket.

> =A0 =A0 =A0 =A0 =A0 =A0 $bucket->read(my $request_line);

> =A0 =A0 =A0 =A0 =A0 =A0 my ($method, $uri, $version) =3D ($request_lin=
e =3D~ m|^(.*?) (.*?)

> HTTP/(.*?)\r\n$|);

>

> =A0 =A0 =A0 =A0 =A0 =A0 if (defined ($method) and $method eq "GET=
" and $uri =3D~

> m|^/echo|)

> =A0 =A0 =A0 =A0 =A0 =A0 {

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 my $new_uri =3D 'POST '.$uri.&=
#39; HTTP/'.$version."\r\n";

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 my $new_uri_bucket =3D

> APR::Bucket->new($connection->bucket_alloc, $new_uri);

>

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 $bb->insert_tail($new_uri_bucket);<=
br>
>

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 my $bucket2 =3D APR::Bucket->new($c=
onnection->bucket_alloc,

> "Content-Type: application/x-www-form-urlencoded\r\n");

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 $bb->insert_tail($bucket2);

>

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 my $bucket3 =3D APR::Bucket->new($c=
onnection->bucket_alloc,

> "Content-Length: 9\r\n");

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 $bb->insert_tail($bucket3);



by now you have inserted these lines:



POST /echo HTTP/1.1

Content-Type: application/x-www-form-urlencoded

Content-Length: 9



You have read the 1st bucket of the input. That bucket may (or may not)

contain the whole request including the empty line that signals end-of-

headers. So, you have to check also the rest of the bucket.



>

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 $ctx->{'state'} =3D 'wa=
iting_for_end_of_headers';

> =A0 =A0 =A0 =A0 =A0 =A0 }

> =A0 =A0 =A0 =A0 =A0 =A0 else

> =A0 =A0 =A0 =A0 =A0 =A0 {

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 $bb->insert_tail($bucket);

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 $ctx->{'state'} =3D 'ig=
nore';

> =A0 =A0 =A0 =A0 =A0 =A0 }

> =A0 =A0 =A0 =A0 }

> =A0 =A0 =A0 =A0 elsif ($ctx->{'state'} eq 'waiting_for_=
end_of_headers')

> =A0 =A0 =A0 =A0 {

> =A0 =A0 =A0 =A0 =A0 =A0 $bucket->read(my $header);

> =A0 =A0 =A0 =A0 =A0 =A0 warn "received header ... ".$header.=
"\r\n";

>

> =A0 =A0 =A0 =A0 =A0 =A0 if ($header =3D~ m|^\r\n$|)

> =A0 =A0 =A0 =A0 =A0 =A0 {

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 warn "detected end_of_headers\r\n=
";

>

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 my $post_data =3D &get_post_data()=
;

>

>

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ### as soon as I add 'data=3Dtest&=
#39; to this bucket the request

> appears to hang.

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ######################################=
######

>

>

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 my $end_of_headers_bucket =3D

> APR::Bucket->new($connection->bucket_alloc, "\r\ndata=3Dtes=
t");

>

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 $bb->insert_tail($end_of_headers_bu=
cket);



by now you have sent



POST /echo HTTP/1.1

Content-Type: application/x-www-form-urlencoded

Content-Length: 9



data=3Dtest



Correct me if I am wrong but don't you have to insert an EOS marker? Ha=
ven't

tried connection input filter yet. But normally a stream is closed with a r>


$bb->insert_tail(APR::Bucket::eos_create $connection->bucket_alloc);<=
br>


> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 $ctx->{'state'} =3D 'fi=
nished';

> =A0 =A0 =A0 =A0 =A0 =A0 }

> =A0 =A0 =A0 =A0 =A0 =A0 else

> =A0 =A0 =A0 =A0 =A0 =A0 {

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 $bb->insert_tail($bucket);

> =A0 =A0 =A0 =A0 =A0 =A0 }

> =A0 =A0 =A0 =A0 }

> =A0 =A0 }

>

> =A0 =A0 # set context.

> =A0 =A0 $f->ctx($ctx);

>

> =A0 =A0 return Apache2::Const::OK;

> }



If it works with the EOS bucket it will probably work for most of the=


requests. But RFC2616 doesn't forbid GET requests to have a request bod=
y. That

means you should read the input until EOS. Don't know if your code does=
that

actually. Otherwise your client may still send the request while your handl=
er

is already done with the response.



Torsten Förtsch



--

Need professional modperl support? Hire me! ( e" target=3D"_blank">http://foertsch.name)



Like fantasy? http://kab=
atinte.net





--0016e6d7787ce9685d048ebec696--