You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Reif Peter <ga...@adv.magwien.gv.at> on 2000/09/06 10:57:00 UTC
Bug? in mod_perl when POST request yields REDIRECT
I am using a self written mod_perl module that does proxy requests. It acts
as content handler and fetches the requestet documents via LWP::UserAgent.
The program works fine but when the request is a POST request and the
response is a redirection (301, 302, ...) with a Location: header, no data
is sent to the browser.
If I don't read the postet data, everything works. So my suspicion is the
following:
For any reason, if the module returns a redirecting result code (301, 302,
...), mod_perl tries to read again the posted data and waits forever.
My solution is simple: Just set the Content-lengt: header to undef:
$r->header_in('Content-length' => undef);
Is this a bug or a feature?
I include my module and the part of my server config.
Peter
Server config:
==============
<Directory proxy:>
SetHandler perl-script
PerlHandler Apache::Proxy_test
</Directory>
Proxy_test.pm:
==============
package Apache::Proxy_test;
use strict;
use Apache::Constants qw(:response :methods :http);
use Apache::File ();
use Apache::Log ();
use Apache::ModuleConfig ();
use Apache::Table;
use Apache::URI ();
use LWP::UserAgent ();
my $UA = LWP::UserAgent->new;
sub handler {
my $r = shift;
my $not_modified = $r->meets_conditions == HTTP_NOT_MODIFIED;
#
# create request
#
my $filename = $r->filename();
$filename =~ s/^proxy://;
my $parsed_uri = $r->parsed_uri;
my $query = $parsed_uri->query;
$filename .= "?$query" if $query;
$r->log->debug ("filename: $filename");
my $request = HTTP::Request->new($r->method, $filename);
$UA->agent ($r->header_in ('User-Agent'));
# copy POST data, if any
if($r->method eq 'POST') {
my $len = $r->header_in('Content-length');
my $buf;
my $ret = read(STDIN, $buf, $len);
$request->content($buf);
# next line prevents bug !!!
$r->header_in('Content-length' => undef);
}
$r->log->debug ("subrequest:\n\n", $request->as_string);
#
# evaluate response
#
my $response = $UA->simple_request($request);
if ($response->code != 200) {
$r->log->debug ("response not OK:\n\n",
$response->as_string);
$response->scan(sub {
my ($header, $value) = @_;
$r->log->debug ("Header-out: $header $value");
$r->header_out($header, $value);
});
} else {
$r->content_type($response->header('Content-type'));
$r->status($response->code);
$r->status_line(join " ", $response->code,
$response->message);
$r->send_http_header();
unless ($r->header_only) {
print $response->content;
}
}
$r->log->debug("send:\n\n", $r->as_string);
$r->log->debug("return ", $response->code);
return $response->code;
}
1;
__END__
Re: Bug? in mod_perl when POST request yields REDIRECT
Posted by Doug MacEachern <do...@covalent.net>.
take 2 on that patch, this one adds a check so ap_setup_client_block() is
only called once. with this part of the fix you can call $r->content
multiple times without hanging:
my $data = $r->content;
$data = $r->content;
however, any calls to $r->content after the first will return undef.
(unless you happen to subclass and override the content method to cache
the read data somewhere)
Index: src/modules/perl/Apache.xs
===================================================================
RCS file: /home/cvs/modperl/src/modules/perl/Apache.xs,v
retrieving revision 1.109
diff -u -r1.109 Apache.xs
--- src/modules/perl/Apache.xs 2000/09/27 16:25:56 1.109
+++ src/modules/perl/Apache.xs 2000/09/27 19:38:34
@@ -954,22 +954,27 @@
int bufsiz
PREINIT:
- long nrd = 0;
+ long nrd = 0, old_read_length;
int rc;
PPCODE:
- if ((rc = setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK) {
- aplog_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, r->server,
- "mod_perl: setup_client_block failed: %d", rc);
- XSRETURN_UNDEF;
+ if (!r->read_length) {
+ if ((rc = setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK) {
+ aplog_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, r->server,
+ "mod_perl: setup_client_block failed: %d", rc);
+ XSRETURN_UNDEF;
+ }
}
+ old_read_length = r->read_length;
+ r->read_length = 0;
+
if (should_client_block(r)) {
SvUPGRADE(buffer, SVt_PV);
SvGROW(buffer, bufsiz+1);
nrd = get_client_block(r, SvPVX(buffer), bufsiz);
- r->read_length = 0;
- }
+ }
+ r->read_length += old_read_length;
if (nrd > 0) {
XPUSHs(sv_2mortal(newSViv((long)nrd)));
Re: Bug? in mod_perl when POST request yields REDIRECT
Posted by Doug MacEachern <do...@covalent.net>.
On Wed, 6 Sep 2000, Reif Peter wrote:
> I am using a self written mod_perl module that does proxy requests. It acts
> as content handler and fetches the requestet documents via LWP::UserAgent.
> The program works fine but when the request is a POST request and the
> response is a redirection (301, 302, ...) with a Location: header, no data
> is sent to the browser.
>
> If I don't read the postet data, everything works. So my suspicion is the
> following:
> For any reason, if the module returns a redirecting result code (301, 302,
> ...), mod_perl tries to read again the posted data and waits forever.
>
> My solution is simple: Just set the Content-lengt: header to undef:
>
> $r->header_in('Content-length' => undef);
>
> Is this a bug or a feature?
it's a known issue, from the ToDo:
"- should $r->content unset $r->headers_in('content-length') ?
NOTE: im worried this could break apps who need to know content-length
after data has been read"
looking at mod_perl Changes:
=item 1.00b2 - 07/07/97
...
make compatible with 1.2.1 r->read_length change so we don't hang
on file uploads
the problem is that a drastic api change in Apache was made around that
time, which we had to fit into Perl's api. ap_setup_client_block() and
ap_should_client_block() are only supposed to be called once according to
the api spec. Apache.xs calls them everytime $r->read is called, and the
change above was setting r->read_length = 0; so ap_setup_client_block()
would return true the second time it is called. when a redirect or error
is thrown, ap_discard_request_body() also checks ap_should_client_block()
which returns true because we've set r->read_length = 0;
so, i think a reasonable fix for now is to localize the r->read_length
change with this patch:
Index: src/modules/perl/Apache.xs
===================================================================
RCS file: /home/cvs/modperl/src/modules/perl/Apache.xs,v
retrieving revision 1.109
diff -u -r1.109 Apache.xs
--- src/modules/perl/Apache.xs 2000/09/27 16:25:56 1.109
+++ src/modules/perl/Apache.xs 2000/09/27 19:19:20
@@ -954,7 +954,7 @@
int bufsiz
PREINIT:
- long nrd = 0;
+ long nrd = 0, old_read_length;
int rc;
PPCODE:
@@ -964,12 +964,15 @@
XSRETURN_UNDEF;
}
+ old_read_length = r->read_length;
+ r->read_length = 0;
+
if (should_client_block(r)) {
SvUPGRADE(buffer, SVt_PV);
SvGROW(buffer, bufsiz+1);
nrd = get_client_block(r, SvPVX(buffer), bufsiz);
- r->read_length = 0;
- }
+ }
+ r->read_length += old_read_length;
if (nrd > 0) {
XPUSHs(sv_2mortal(newSViv((long)nrd)));