On Mon, Apr 02, 2007 at 03:52:50PM -0700, Stas Bekman wrote:
> Stephane, you are correct in your observations that original STDIN and
> STDOUT filehandles are not preserved when perlio CGI mode is used.
> 
> This is because how Perl works. Consider the following perl program, run from 
> the command line (not mod_perl!):
> 

Hi Stas, that's not what I think happens though.

I suspected as well that the responsible code was in
src/modules/perl/modperl_io.c

And it does IIUC:

open STDIN_SAVED, "<&STDIN" or die "Can't dup STDIN: $!";
close STDIN;
open STDIN, "<:apache"

and same for STDOUT.

And it should work, except that the second open, which should
resolve to a dup2 or dup system call doesn't seem to do anything
file-descriptor-wise. It rather looks like is assignes the STDIN
perl handle to the Socket, so that STDIN no longer has the fd 0
(as demonstrated by my test of executing a lsof command within a
CGI script), but something more like 16, which was returned by
the accept() of the incoming HTTP connection.

[...]
> +    fprintf(stderr, "STDIN orig: %d\n",
> +            (int)PerlIO_fileno(IoIFP(GvIOn(handle))));
> +
>      MP_TRACE_o(MP_FUNC, "start");
> 
>      /* if STDIN is open, dup it, to be restored at the end of response */
>      if (handle && SvTYPE(handle) == SVt_PVGV &&
>          IoTYPE(GvIO(handle)) != IoTYPE_CLOSED) {
> +
>          handle_save = gv_fetchpv(Perl_form(aTHX_
>                                             "Apache2::RequestIO::_GEN_%ld",
>                                             (long)PL_gensym++),
> @@ -132,6 +138,21 @@
>           * have file descriptors, so STDIN must be closed before it can
>           * be reopened */
>          do_close(handle, TRUE);
> +
> +        /* now grab the just released fd, normally 0 */
> +        handle_save_fd = gv_fetchpv("GENX2", TRUE, SVt_PVIO);
> +
> +        /* open my $oldout, "<&=0" or die "Can't save STDIN's fd: $!"; */
> +        status = do_open(handle_save_fd, "</dev/null", 10, FALSE,
> +                         O_RDONLY, 0, Nullfp);
[...]

You don't want that IMO, you want the fd 0 and 1 to point to the
socket so that the CGI has both its stdin and stdout pointing to
the socket, because that's how unmodified CGI scripts do.

system("echo foo");

Should output "foo\n" to the page returned by the CGI. and echo
foo does a write(1, "foo\n", 4);

I must confess I tried to follow in the perl code what that
do_open9 call that was supposed to dup the socket into
stdin/stdout was doing but didn't get very far. I tried to
replace those perl functions to real close() and dup()s but it
didn't help either.

-- 
Stephane

Reply via email to