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' 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 PerlInputFilterHandler Example::ConnectionFilter::forward_get_as_post <Location /echo> SetHandler modperl PerlResponseHandler Example::Echo </Location> package Example::Echo; use strict; use warnings; use Apache2::Const -compile => qw(OK); use Apache2::RequestIO; use Apache2::RequestRec; sub handler { my $r = 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 => qw(OK DECLINED); use Apache2::FilterRec; use Apache2::Log; use Apache2::RequestRec; use Apache2::RequestIO; use APR::Const -compile => ':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) = @_; my $ctx = $f->ctx || { 'state' => 'waiting_for_request_line' }; warn "state = ".$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 = $f->c; my $tmp_bb = APR::Brigade->new($connection->pool, $connection->bucket_alloc); my $rv = $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 = $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) = ($request_line =~ m|^(.*?) (.*?) HTTP/(.*?)\r\n$|); if (defined ($method) and $method eq "GET" and $uri =~ m|^/echo|) { my $new_uri = 'POST '.$uri.' HTTP/'.$version."\r\n"; my $new_uri_bucket = APR::Bucket->new($connection->bucket_alloc, $new_uri); $bb->insert_tail($new_uri_bucket); my $bucket2 = APR::Bucket->new($connection->bucket_alloc, "Content-Type: application/x-www-form-urlencoded\r\n"); $bb->insert_tail($bucket2); my $bucket3 = APR::Bucket->new($connection->bucket_alloc, "Content-Length: 9\r\n"); $bb->insert_tail($bucket3); $ctx->{'state'} = 'waiting_for_end_of_headers'; } else { $bb->insert_tail($bucket); $ctx->{'state'} = 'ignore'; } } elsif ($ctx->{'state'} eq 'waiting_for_end_of_headers') { $bucket->read(my $header); warn "received header ... ".$header."\r\n"; if ($header =~ m|^\r\n$|) { warn "detected end_of_headers\r\n"; my $post_data = &get_post_data(); ### as soon as I add 'data=test' to this bucket the request appears to hang. ############################################ my $end_of_headers_bucket = APR::Bucket->new($connection->bucket_alloc, "\r\ndata=test"); $bb->insert_tail($end_of_headers_bucket); $ctx->{'state'} = 'finished'; } else { $bb->insert_tail($bucket); } } } # set context. $f->ctx($ctx); return Apache2::Const::OK; } 1; On 25 August 2010 09:41, James Lee <modperl.n...@gmail.com> 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 was > just after a little clarification when filters were called in relation to > mod_proxy. > > Thanks again. > > > > On 25 August 2010 07:12, André Warnier <a...@ice-sa.com> 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 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 >>> >>> <Location /reports> >>> PerlInputFilterHandler Sample::RequestTweaker::inject_post_data >>> ProxyPass http://appserver/reports-engine >>> </Location> >>> >>> >> >