How can I send POST and GET data to a Perl CGI script via the command line? - perl

I am trying to send a get or a post through a command-line argument. That is test the script in the command line before I test through a browser (the server has issues). I tried searching online, and I suppose I was probably using incorrect terminology because I got nothing. I know this is possible because I saw someone do it. I just don't remember how it was done.
Thanks! :)

To test a CGI program from the command line, you fake the environment that the server creates for the program. CGI.pm has a special offline mode, but often I find it easier not to use because of the extra setup I need to do for everything else my programs typically expect.
Depending on the implementation of your script, this involves setting many environment variables, which you can do from a wrapper script that pretends to be the server:
#!/bin/bash
export HTTP_COOKIE=...
export HTTP_HOST=test.example.com
export HTTP_REFERER=...
export HTTP_USER_AGENT=...
export PATH_INFO=
export QUERY_STRING=$(cat query_string);
export REQUEST_METHOD=GET
perl program.cgi
If you're doing this for a POST request, the environment is slightly different and you need to supply the POST data on standard input:
#!/bin/bash
export CONTENT_LENGTH=$(perl -e "print -s q/post_data/");
export HTTP_COOKIE=...
export HTTP_HOST=test.example.com
export HTTP_REFERER=...
export HTTP_USER_AGENT=...
export PATH_INFO=...
export QUERY_STRING=$(cat query_string);
export REQUEST_METHOD=POST
perl program.cgi < post_data
You can make this as fancy as you need and each time you want to test the program, you change up the data in the query_string or post_data files. If you don't want to do this in a shell script, it's just as easy to make a wrapper Perl script.

Are you using the standard CGI module?
For example, with the following program (notice -debug in the arguments to use CGI)
#! /usr/bin/perl
use warnings;
use strict;
use CGI qw/ :standard -debug /;
print "Content-type: text/plain\n\n",
map { $_ . " => " . param($_) . "\n" }
param;
you feed it parameters on the command line:
$ ./prog.cgi foo=bar baz=quux
Content-type: text/plain
foo => bar
baz => quux
You can also do so via the standard input:
$ ./prog.cgi
(offline mode: enter name=value pairs on standard input; press ^D or ^Z when done)
foo=bar
baz=quux
^D
Content-type: text/plain
foo => bar
baz => quux

Old discussion, but I was looking for the same answers - so for those who follow - this is what I found out
RTFM! from the CGI man page ( and there is more )
DEBUGGING
If you are running the script from the command line or in the perl
debugger, you can pass the script a list of keywords or parameter=value
pairs on the command line or from standard input (you don't have to
worry about tricking your script into reading from environment
variables). You can pass keywords like this:
your_script.pl keyword1 keyword2 keyword3
or this:
your_script.pl keyword1+keyword2+keyword3
or this:
your_script.pl name1=value1 name2=value2
or this:
your_script.pl name1=value1&name2=value2
To turn off this feature, use the -no_debug pragma.

If you don't want to alter the perl script, you can call it with at least two environment variables set, as others mentioned already. To simulate a GET request:
shell$ QUERY_STRING=limit=20 REQUEST_METHOD=GET ./events_html.pl
That's the console shortcut for www.myserver.org/events_html.pl?limit=20

Yes, it's possible to do this from the command line, bypassing your server. This page explains all: Perl CGI debugging (sitewizard.com) (Especially item 6 on that page). Here I quote the most important part:
To test the script offline using the
GET method, simply set the
QUERY_STRING environment variable
accordingly. If you are using Windows,
you might use the following command
line in a DOS window prior to running
the script in the same window:
set QUERY_STRING=recipient=John#Doe.com&Fullname=M+Name
To test the script offline using the
POST method, put the line below into a
text file named, say, testinput.txt.
recipient=John#Doe.com&Fullname=M+Name
Then redirect that file as an input to
the script. On Unix systems as well as
under Windows' MSDOS prompt, you can
do it this way:
perl -w scriptname.pl < testinput.txt
Your script will then receive that
input as though it was sent it by a
form on the website. Check the error
messages that perl spouts, if any, to
help you track the problem in the
script.

To give a cgi script post data:
$ echo -n 'a=b;c=d' | REQUEST_METHOD=POST CONTENT_LENGTH=999 perl index.cgi
To give a cgi script get data:
$ perl index.cgi 'a=b;c=d'

LWP comes with ready made scripts that can be used from the command-line. Check for GET and POST scripts in your system.

In Windows, you can use VBScript to write a command line util that calls into the MS XML library:
Dim XMLHttp : Set XMLHttp = CreateObject("Microsoft.XMLHTTP")
On Error Resume Next
strIPAddress = WScript.Arguments(0)
strMACAddress = WScript.Arguments(1)
strSubnetMask = WScript.Arguments(2)
On Error Goto 0
WScript.Echo "Attempting to wake host " & strIPAddress & " on NIC " & strMACAddress &
"using netmask " & strSubnetMask
strGetUrl = http://wolService/WolService/WolService.asmx/WakeBroadcast?hostIP=" &
strIPAddress & "&macAddress=" & strMACAddress & "&subnetMask=" & strSubnetMask
XMLHttp.Open "GET", strGetUrl, False
XMLHttp.Send ""
WScript.Echo XMLHttp.ResponseText
Edit: This script sends HTTP requests and can be used from the command line. I got confused by the question 'How can I send POST and GET data to a Perl CGI script via the command line' and thought this was about sending POST and GET data to a Perl CGI script via the command line from an unspecified client OS.

Related

How to pass password via Perl script

I have a situation where in I am calling the below Perl script
if (param("lremail") && param("lot")) {
my $address=param("lremailaddress");
my $lot=param("lot");
print a({-href=>"$dir/new.pl"},"Back to Top"),br;
print "Request submitted for $address.",br;
print "Lot $lot",br;
print "You will receive an e-mail with a link to the data when the request is complete.";
print end_html;
system ("ssh SERVERNAME /test/abc.csh $lot $$ $address &");
exit(1);
The above script does not run because when I execute the system is prompted for a password. Then I looked it up and found the below command..
expect -c 'spawn ssh SERVERNAME /test/abc.csh J213520 06 abc#gmail.com "ls -lh file"; expect "Password:"; send "PASSWORD\r"; interact'
The above command is executed successfully without any issue but from the command line only. When I incorporate the same(by replacing the system call) within the Perl script, it fails. How can I incorporate within the first script?
Reiterating and adding to comments:
Consider using a key-based authentication either with passphrase-less keys or with ssh-agent (e.g., using ssh-keygen generated/managed identities);
Consider using sshpass or another expect-like external;
Consider using the Perl Expect or an equivalent CPAN module; and/or,
Consider using the Perl Net::SSH or an equivalent CPAN module.
Also, system can easily introduce remote code execution vulnerabilities, especially when using its system LIST syntax.

wrapper script and GetOpts::Long perl

I have been trying to make GetOpts :: Long work for my code but it just doesn't respond. I have a wrapper script with about 8 scripts and 2 commands. I have been trying to GetOpts :: Long submit arguments into the separate codes, but it doesnt work!
For example, I've script 1 though 8, and on the command line I'm trying to a few options that I would like to submit to the separate scripts. When I use the GetOpts module in the seprate scripts and run them separately, they run fine. But when I try to run the wrapper script, say wrapper.pl which initiates script 1 with the module being called in it; the arguments submitted are not being taken by the separate scripts.
Please help!!!!
I hope this sort of explains the problem. wrapper script looks like this(wrapper.pl),using backticks:
perl script1.pl;
perl script2.pl; (etc)
script1.pl uses the GetOpts::Long option for the input file. script1.pl calls for the input file using the "-i" option, but the file is not being read when initiated on the command line.
command line option: perl wrapper.pl -i seqs.fa -o op.fa
Do you actually pass in the arguments from your wrapper.pl into the
scripts ? - how would they magically know what options they need to
handle?
vanHoesel asked the right questions; you have to do something like that in wrapper.pl:
use Getopt::Long;
GetOptions('i=s' => \$input_file,
'o=s' => \$output_file) || die "Usage: $0 -i INPUT -o OUTPUT\n";
`perl script1.pl -i $input_file`;
`perl script2.pl -o $output_file`;

how to collect ARGV using Perl CGI?

I want to run a script from my website using CGI.pm - The script I am running is usally ran from the command line and requires several command line ARGV inputs. How do I deal with this using CGI.pm? - can I insert a system($command) into Perl CGI script? The script can be seen here - http://www.ncbi.nlm.nih.gov/IEB/ToolBox/C_DOC/lxr/source/doc/blast/web_blast.pl
how to collect ARGV using Perl CGI?
#ARGV didn't go anywhere, but CGI doesn't use command line arguments, so there are no command line arguments to collect.
can I insert a system($command) into Perl CGI script?
Yes.
You can dual-purpose the script by checking if you are connected to a terminal:
if (-t STDOUT) {
# Command LIne mode, use #ARGV;
}
else {
# CGI mode, get ARGV equivalent from CGI->param
}
You will have to adjust the output to work in CGI mode, by adding content headers before you output anything.
If you use system($foo) in a web page, make sure the logic controlling what's in $foo is secure, otherwise you might end up hacked.

Is there a way to load a profile inside Perl?

Is there a way to load a profile inside Perl?
Like in shell files:
. ~user/.profile
What specifically do you mean by "profile"?
If you mean "retrieve the values of the shell environmental variables that your shell set via .profile", then yes - you do it through a special %ENV hash.
If you mean "read the actual variables set in .profile" like the shell itself does, it's possible but doing it "right" requires either parsing an arbitrary shell script and scrubbing anything that's not an environmental variable assignment, OR executing ". ~/.profile; env`"` and parsing the output.
If you mean "supply a generic configuration to any Perl program that runs via a separate configuration file", you need to add code to those Perl programs to read this configuration file (there are a number of CPAN modules for reading various config files).
If you mean "supply a generic configuration to any Perl program that runs without any special code in those Perl programs to read a separate configuration file, sort of like any shell script gets the stuff from .profile thanks to shell", then the asnwer is "may be". You can leverage PERLOPT environmental variable to supply options which would load up a special module (via -I) containing the configuration that gets set via its "import()". While somewhat doable, it seems like an awful hack that I would strongly recommend against using.
Env::Sourced should do what you need.
use Env::Sourced qw(~/user/profile);
print $ENV{VARAIBLE};
If you have bash configuration values in (or other configuration set up by) a shell script and want that to take effect only for the duration of one execution of a program, you can use a subshell:
( source ~/my_bash_file.sh; perl my_perl_script.pl )
You can access shell environment variables in Perl using the %ENV hash (see the index of Perl's special variables, perldoc perlvar):
my $user = $ENV{USER};
my $home_dir = $ENV{HOME};
Example:
my_bash_file.sh:
#!/bin/bash
export HOME="/home/nowhere"
my_perl_script.pl:
#!/usr/bin/perl
print "the value of HOME is $ENV{HOME}\n";
When executed as perl my_perl_script.pl, my_perl_script.pl prints:
the value of HOME is /home/ether
When executed as ( source ~/my_bash_file.sh; perl my_perl_script.pl ), the output is:
the value of HOME is /home/nowhere
$u=`echo -n ~user`;
open F, "<$u/.profile" || die;
while(<F>)
{print}

Missing output when running system command in perl/cgi file

I need to write a CGI program and it will display the output of a system command:
script.sh
echo "++++++"
VAR=$(expect -c " spawn ssh -o StrictHostKeyChecking=no $USER#$HOST $CMD match_max
100000 expect \"*?assword:*\" send -- \"$PASS\r\" send -- \"\r\" expect eof ")
echo $VAR
echo "++++++"
In CGI file:
my $command= "ksh ../cgi-bin/script.sh";
my #output= `$command`;
print #output;
Finally, when I run the CGI file in unix, the $VAR is a very long string including \n and some delimiters. However, when I run on web server, the output is
++++++
++++++
So $VAR is missing when passing in the web interface/browser.
I know maybe the problem is $VAR is very long string.
But anyway, is there anyway to solve this problem except writing the output to a file then retrieve it from browser?
Thanks if you are interested in my question.
script.sh uses several environment variables: $USER, $HOST, $CMD and $PASS. The CGI environment will have different environment variables set than a login shell. You may need to set these variables from your CGI script before calling script.sh.
Try finding where commands like expect and ssh that you are calling are on your system and adding their directory paths to the PATH used by your script.
I.e.
which expect
returns /usr/bin/expect then add the line:
PATH=$PATH:/usr/bin && export PATH
near the beginning of the ksh script. During debug you may also want to redirect stderr to a file by appending 2>/tmp/errors.txt to the end of your command since stderr is not shown in the browser.
my $command= "ksh ../cgi-bin/script.sh 2>/tmp/errors.txt";