IO::Scalar insanity

B

bill

I run into the need to do this *all* the time, but I have not come
up with a solution. This need arises almost invariably during the
debugging of a CGI script. At the beginning of the run I want to
inspect all the input that the CGI script will read from STDIN,
but I want to then "restore" this input back to the STDIN stream
so that execution/debugging session can proceed normally.

I *think* the best solution would be to slurp all the text into a
lexical

my $input = do { local $/; <STDIN> };
# {
# open my $out, ">debugging_data" or die "$!\n";
# print $out $input;
# close $out or die "$!\n";
# }

associate this lexical with an IO::Scalar handle

my $SH = IO::Scalar->new(\$input);

and then redefine STDIN so that it points to this IO::Scalar.
*This* is the part that I just can't figure out. Following what
I see in tutorials and books, I have tried

open(STDIN, "<&$SH") or die "$!\n";

but the open fails with an "invalid argument" error message. I've
also tried

open(STDIN, "<&=$SH") or die "$!\n";

(which fails with the same error), and

*STDIN = *SH;

and many variants thereof, all of which fail silently.

It is obvious that I have *no clue* and am just wildly trying out
random stuff.

I've read every bit of documentation I can think of, but I have
not hit on the answer to this question. I know this is all very
basic, but if someone could spell it out for me I'd greatly appreciate
it.

bill
 
M

Mark Clements

bill said:
I run into the need to do this *all* the time, but I have not come
up with a solution. This need arises almost invariably during the
debugging of a CGI script. At the beginning of the run I want to
inspect all the input that the CGI script will read from STDIN,
but I want to then "restore" this input back to the STDIN stream
so that execution/debugging session can proceed normally.

I *think* the best solution would be to slurp all the text into a
lexical

my $input = do { local $/; <STDIN> };
# {
# open my $out, ">debugging_data" or die "$!\n";
# print $out $input;
# close $out or die "$!\n";
# }

associate this lexical with an IO::Scalar handle

my $SH = IO::Scalar->new(\$input);

and then redefine STDIN so that it points to this IO::Scalar.
*This* is the part that I just can't figure out. Following what
I see in tutorials and books, I have tried

open(STDIN, "<&$SH") or die "$!\n";

you probably want to open it on the file descriptor (take a look at fileno):

redwood 24357 $ perl -le 'open IN,"</etc/passwd";open STDIN,"<&".fileno(IN);
$a=<STDIN>;
print "$a\n"'
root:x:0:1:Super-User:/:/sbin/sh


*but* what you probably want to be doing is using the CGI module to
parse your cgi parameters. You can initialize this from a FileHandle or
IO::File object as necessary, so you could slurp STDIN into a lexical
variable, create an IO::String object from this, dump out the results
and then initialize the CGI object from this. Also check out
restore_parameters in the CGI module.

It is highly likely that I am missing something obvious here.

Mark
 
A

A. Sinan Unur

@reader2.panix.com:

I run into the need to do this *all* the time, but I have not come
up with a solution. This need arises almost invariably during the
debugging of a CGI script. At the beginning of the run I want to
inspect all the input that the CGI script will read from STDIN,
but I want to then "restore" this input back to the STDIN stream
so that execution/debugging session can proceed normally.

http://search.cpan.org/~lds/CGI.pm-
3.05/CGI.pm#CREATING_A_NEW_QUERY_OBJECT_FROM_AN_INPUT_FILE

I am curious why that is not a satisfactory method.

Sinan.
 
K

kj

In said:
I run into the need to do this *all* the time, but I have not come
up with a solution. This need arises almost invariably during the
debugging of a CGI script. At the beginning of the run I want to
inspect all the input that the CGI script will read from STDIN,
but I want to then "restore" this input back to the STDIN stream
so that execution/debugging session can proceed normally.
I *think* the best solution would be to slurp all the text into a
lexical
my $input = do { local $/; <STDIN> };
# {
# open my $out, ">debugging_data" or die "$!\n";
# print $out $input;
# close $out or die "$!\n";
# }
associate this lexical with an IO::Scalar handle
my $SH = IO::Scalar->new(\$input);
and then redefine STDIN so that it points to this IO::Scalar.
*This* is the part that I just can't figure out. Following what
I see in tutorials and books, I have tried
open(STDIN, "<&$SH") or die "$!\n";
but the open fails with an "invalid argument" error message. I've
also tried
open(STDIN, "<&=$SH") or die "$!\n";
(which fails with the same error), and
*STDIN = *SH;
and many variants thereof, all of which fail silently.
It is obvious that I have *no clue* and am just wildly trying out
random stuff.
I've read every bit of documentation I can think of, but I have
not hit on the answer to this question. I know this is all very
basic, but if someone could spell it out for me I'd greatly appreciate
it.

Not so basic, I think. IIRC Perl can't do what you want it to do;
something having to do with needing a real file descriptor associated
with the handle before it can dupe it; IO::Scalar and the like
don't provide the FILENO method, AFAIK.

But how about putting this at some suitable location in your source:

my $peek = do { local $/; <STDIN> };

unless (my $pid = open(STDIN, "-|")) {
die "Fork failed: $!" unless defined $pid;
print $peek;
exit 0;
}

The subsequent parent code will read from STDIN as before, but now
it's coming from the child process.

kj
 
K

kj

In said:
@reader2.panix.com:


I am curious why that is not a satisfactory method.

For starters, it assumes that the CGI script is implemented through
CGI.pm, which may not be the case. Even when the script is
implemented using CGI.pm, if it was written by someone else in a
less than perspicuous style, I prefer to minimize the amount of
such code that I must understand.

kj
 
A

A. Sinan Unur

In <[email protected]> "A. Sinan Unur"


For starters, it assumes that the CGI script is implemented through
CGI.pm, which may not be the case.

I am not going to get into that argument.
Even when the script is implemented using CGI.pm, if it was written
by someone else in a less than perspicuous style, I prefer to minimize
the amount of such code that I must understand.

This makes no sense. How can coding style be an issue when we are talking
about passing parameters using an input file? No matter how bad the
original coding style, the way you would initialize a new CGI object from
a parameter file is the same.

Sinan.
 
A

Alan J. Flavell

For starters, it assumes that the CGI script is implemented through
CGI.pm, which may not be the case.

Anyone who's expert enough to produce a safe and reliable
implementation that doesn't use CGI.pm will have no difficulty in
solving that problem without any help from us.
Even when the script is implemented using CGI.pm, if it was written
by someone else in a less than perspicuous style, I prefer to
minimize the amount of such code that I must understand.

It sounds as if you're trying to solve a problem that has rather
little technical content, but is more an exercise in sociology.
 
K

kj

In said:
For starters, it assumes that the CGI script is implemented through
CGI.pm, which may not be the case.
[/QUOTE]
Anyone who's expert enough to produce a safe and reliable
implementation that doesn't use CGI.pm will have no difficulty in
solving that problem without any help from us.

The OP didn't specify whether he was debugging his own code, or
that what he was debugging was a "safe and reliable" anything.

kj
 
A

Alan J. Flavell

The OP didn't specify whether he was debugging his own code, or
that what he was debugging was a "safe and reliable" anything.

And what conclusion would you draw from that? (I've already drawn
mine, by the way.)
 
B

bill

Thanks for all the help.

BTW, the code I'm debugging is indeed something I wrote, but it
uses SOAP::Lite, whose documentation I find pretty unhelpful and
whose code I find absolutely impenetrable. I have no idea whether
SOAP::Lite uses CGI.pm for its "CGI-based" servers.

I am surprised to learn that one can't make a string/buffer look
like STDIN in a Perl script. I could *swear* I saw this done
somewhere.

bill
 
A

Alan J. Flavell

See my previous posts on this thread.

Thank you for offering me the opportunity to review your contributions
this thread. I've done so, and I don't see anything which relates to
the issue of safe and reliable CGI scripts.

If you're of the opinion that it doesn't matter whether CGI scripts
are safe or reliable, then there's this guy called Matt who you might
like to meet.

OTOH if you'd care to read Lincoln Stein's web security FAQ, I think
you might find there's quite a lot of pratfalls lying in wait for
those who don't take the issues seriously.

ttfn
 
B

Brian McCauley

bill said:
I run into the need to do this *all* the time, but I have not come
up with a solution. This need arises almost invariably during the
debugging of a CGI script. At the beginning of the run I want to
inspect all the input that the CGI script will read from STDIN,
but I want to then "restore" this input back to the STDIN stream
so that execution/debugging session can proceed normally.

I *think* the best solution would be to slurp all the text into a
lexical

If it's not too big.
my $input = do { local $/; <STDIN> };
# {
# open my $out, ">debugging_data" or die "$!\n";
# print $out $input;
# close $out or die "$!\n";
# }

associate this lexical with an IO::Scalar handle

my $SH = IO::Scalar->new(\$input);

and then redefine STDIN so that it points to this IO::Scalar.
*This* is the part that I just can't figure out. Following what
I see in tutorials and books, I have tried

open(STDIN, "<&$SH") or die "$!\n";

You cannot use the two argument form of open() to do a filedescriptor
duplication on a (blessed) GLOBref. You need to use the three arg form.

Not that this is relevant since you cannot duplicate the underlying OS
filedescriptor of a Perl file handle when the Perl file handle has no
underlying OS filedescriptor (as in IO::Scalar).
but the open fails with an "invalid argument" error message. I've
also tried

open(STDIN, "<&=$SH") or die "$!\n";

(which fails with the same error), and

That is because you cannot reuse the underlying OS filedescriptor of a
Perl file handle when the Perl file handle has no underlying OS
filedescriptor..

*STDIN = *SH;

and many variants thereof, all of which fail silently.

Should be:

*STDIN = $SH;

I tried testing it here but I've not got IO::Scalar installed (it's
rendered obsolete by Perl5.8). I replaced

my $SH = IO::Scalar->new(\$input);

with

open( my $SH, '<', \$input);

Seemed to work OK.
 
B

bill

In said:
bill wrote:
Should be:
*STDIN = $SH;
I tried testing it here but I've not got IO::Scalar installed (it's
rendered obsolete by Perl5.8). I replaced
my $SH = IO::Scalar->new(\$input);

open( my $SH, '<', \$input);
Seemed to work OK.

This appears to be the way to go (assuming v5.8 is available). I
first tried (wishfully)

open(STDIN, '<', \$input)

which failed (for reasons I don't understand, but I imagine have
to do with the old fileno issue you mentioned), but this worked

open(my $SH, '<', \$input); # or die, etc.
*STDIN = $SH;

Thanks!

bill
 
E

Eric Bohlman

This appears to be the way to go (assuming v5.8 is available). I
first tried (wishfully)

open(STDIN, '<', \$input)

which failed (for reasons I don't understand, but I imagine have
to do with the old fileno issue you mentioned), but this worked

open(my $SH, '<', \$input); # or die, etc.
*STDIN = $SH;

Your first attempt will work if you close STDIN first.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top