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)));