stas 2004/08/15 00:54:01 Modified: src/docs/2.0/user/handlers filters.pod http.pod protocols.pod Log: - make sure that $b->remove is not called before $r->read. since if it does, and there is a filebucket, it'll get split into more than bucket and all but the first bucket will be lost. after read() it's safe to unlink the old bucket - other improvements Revision Changes Path 1.46 +27 -41 modperl-docs/src/docs/2.0/user/handlers/filters.pod Index: filters.pod =================================================================== RCS file: /home/cvs/modperl-docs/src/docs/2.0/user/handlers/filters.pod,v retrieving revision 1.45 retrieving revision 1.46 diff -u -u -r1.45 -r1.46 --- filters.pod 10 Jun 2004 15:02:21 -0000 1.45 +++ filters.pod 15 Aug 2004 07:54:00 -0000 1.46 @@ -1150,22 +1150,21 @@ my $data = ''; my $seen_eos = 0; do { - $r->input_filters->get_brigade($bb, - Apache::MODE_READBYTES, APR::BLOCK_READ, IOBUFSIZE); - - while (!$bb->is_empty) { - my $b = $bb->first; - $b->remove; + $r->input_filters->get_brigade($bb, Apache::MODE_READBYTES, + APR::BLOCK_READ, IOBUFSIZE); + for (my $b = $bb->first; $b; $b = $bb->next($b)) { if ($b->is_eos) { $seen_eos++; last; } - $b->read(my $data); - $data .= $buf; - } + if ($b->read(my $buf)) { + $data .= $buf; + } + $b->remove; # optimization to reuse memory + } } while (!$seen_eos); $bb->destroy; @@ -1536,8 +1535,8 @@ warn("data: $data\n"); if ($data and $data =~ s|^GET|HEAD|) { - my $bn = APR::Bucket->new($data); - $b->insert_after($bn); + my $nb = APR::Bucket->new($data); + $b->insert_after($nb); $b->remove; # no longer needed $f->ctx(1); # flag that that we have done the job last; @@ -1632,7 +1631,7 @@ we have just modified and immediately remove that bucket that we don't need anymore: - $b->insert_after($bn); + $b->insert_after($nb); $b->remove; # no longer needed Finally we set the context to 1, so we know not to apply the @@ -1764,8 +1763,6 @@ while (!$bb_ctx->is_empty) { my $b = $bb_ctx->first; - $b->remove; - if ($b->is_eos) { $bb->insert_tail($b); last; @@ -1774,6 +1771,7 @@ my $len = $b->read(my $data); $b = APR::Bucket->new(lc $data) if $len; + $b->remove; $bb->insert_tail($b); } @@ -2114,8 +2112,6 @@ while (!$bb->is_empty) { my $b = $bb->first; - $b->remove; - if ($b->is_eos) { $bb_ctx->insert_tail($b); last; @@ -2127,6 +2123,7 @@ $b = APR::Bucket->new($data); } + $b->remove; $bb_ctx->insert_tail($b); } @@ -2291,43 +2288,32 @@ sub read_post { my $r = shift; - my $debug = shift || 0; - my @data = (); - my $seen_eos = 0; - my $filters = $r->input_filters(); - my $ba = $r->connection->bucket_alloc; - my $bb = APR::Brigade->new($r->pool, $ba); + my $bb = APR::Brigade->new($r->pool, $r->connection->bucket_alloc); + my $data = ''; + my $seen_eos = 0; do { - my $rv = $filters->get_brigade($bb, - Apache::MODE_READBYTES, APR::BLOCK_READ, IOBUFSIZE); - if ($rv != APR::SUCCESS) { - return $rv; - } - - while (!$bb->is_empty) { - my $buf; - my $b = $bb->first; - - $b->remove; + $r->input_filters->get_brigade($bb, Apache::MODE_READBYTES, + APR::BLOCK_READ, IOBUFSIZE); + for (my $b = $bb->first; $b; $b = $bb->next($b)) { if ($b->is_eos) { - warn "EOS bucket:\n" if $debug; $seen_eos++; last; } - $b->read(my $buf); - warn "DATA bucket: [$buf]\n" if $debug; - push @data, $buf; - } - - $bb->destroy; + if ($b->read(my $buf)) { + $data .= $buf; + } + $b->remove; # optimization to reuse memory + } } while (!$seen_eos); - return join '', @data; + $bb->destroy; + + return $data; } The C<response()> handler is trivial -- it reads the POSTed data and 1.44 +8 -9 modperl-docs/src/docs/2.0/user/handlers/http.pod Index: http.pod =================================================================== RCS file: /home/cvs/modperl-docs/src/docs/2.0/user/handlers/http.pod,v retrieving revision 1.43 retrieving revision 1.44 diff -u -u -r1.43 -r1.44 --- http.pod 9 Aug 2004 03:04:23 -0000 1.43 +++ http.pod 15 Aug 2004 07:54:00 -0000 1.44 @@ -495,22 +495,21 @@ my $data = ''; my $seen_eos = 0; do { - $r->input_filters->get_brigade($bb, - Apache::MODE_READBYTES, APR::BLOCK_READ, IOBUFSIZE); - - while (!$bb->is_empty) { - my $b = $bb->first; - $b->remove; + $r->input_filters->get_brigade($bb, Apache::MODE_READBYTES, + APR::BLOCK_READ, IOBUFSIZE); + for (my $b = $bb->first; $b; $b = $bb->next($b)) { if ($b->is_eos) { $seen_eos++; last; } - $b->read(my $buf); - $data .= $buf; - } + if ($b->read(my $buf)) { + $data .= $buf; + } + $b->remove; # optimization to reuse memory + } } while (!$seen_eos); $bb->destroy; 1.28 +51 -2 modperl-docs/src/docs/2.0/user/handlers/protocols.pod Index: protocols.pod =================================================================== RCS file: /home/cvs/modperl-docs/src/docs/2.0/user/handlers/protocols.pod,v retrieving revision 1.27 retrieving revision 1.28 diff -u -u -r1.27 -r1.28 --- protocols.pod 5 Jul 2004 01:39:59 -0000 1.27 +++ protocols.pod 15 Aug 2004 07:54:00 -0000 1.28 @@ -358,8 +358,6 @@ while (!$bb_in->is_empty) { my $b = $bb_in->first; - $b->remove; - if ($b->is_eos) { $bb_out->insert_tail($b); last; @@ -371,6 +369,7 @@ $b = APR::Bucket->new($data); } + $b->remove; $bb_out->insert_tail($b); } @@ -446,6 +445,56 @@ the connection) or when the received data contains nothing but new line characters which we used to to tell the server to terminate the connection. + +Now that you've learned how to move buckets from one brigade to +another, let's see how the presented handler can be reimplemented +using a single bucket brigade. Here is the modified code: + + sub handler { + my $c = shift; + + $c->client_socket->opt_set(APR::SO_NONBLOCK, 0); + + my $bb = APR::Brigade->new($c->pool, $c->bucket_alloc); + + while (1) { + my $rc = $c->input_filters->get_brigade($bb, + Apache::MODE_GETLINE); + last if $rc == APR::EOF; + die APR::Error::strerror($rc) unless $rc == APR::SUCCESS; + + for (my $b = $bb->first; $b; $b = $bb->next($b)) { + + last if $b->is_eos; + + if ($b->read(my $data)) { + last if $data =~ /^[\r\n]+$/; + my $nb = APR::Bucket->new(uc $data); + # head->...->$nb->$b ->...->tail + $b->insert_before($nb); + $b->remove; + } + } + + $c->output_filters->fflush($bb); + } + + $bb->destroy; + + Apache::OK; + } + +This code is shorter and simpler. Since it sends out the same bucket +brigade it got from the incoming filters, it only needs to replace +buckets that get modified, which is probably the only tricky part +here. The code: + + # head->...->$nb->$b ->...->tail + $b->insert_before($nb); + $b->remove; + +inserts a new bucket in front of the currently processed bucket, so +that when the latter removed the former takes place of the latter. Notice that this handler could be much simpler, since we don't modify the data. We could simply pass the whole brigade unmodified without
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]