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

James Lee <[email protected]>
Newsgroups gmane.comp.apache.mod-perl
Message-ID <[email protected]>
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 closed
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=test' 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 what
it is doing! It's just frustrating because it sounds like something I should
be able to do.


James.



2010/8/26 Torsten Förtsch <[email protected]>

> 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) = @_;
> >     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);
>
> 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'} = '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);
>
> by now you have sent
>
> POST /echo HTTP/1.1
> Content-Type: application/x-www-form-urlencoded
> Content-Length: 9
>
> data=test
>
> 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'} = '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
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.