Perl CGI using HTML::Template - html

I would like to make use of the
HTML::Template
module but somehow I can't set it up to work properly. Here is a very simple representative code I'm testing on:
use strict;
use warnings;
use CGI;
use HTML::Template;
my $test = new CGI;
my $tmpl = HTML::Template->new(filename => 'TemplateSimple.html');
$tmpl->param(
title => 'Test',
body => '<p>This is a test</p>',
);
my $out = $test->header(
-type => 'text/html',
-charset => 'utf-8'
);
print $out;
print $tmpl->output;
When calling the page I always end up with the browser displaying the server error message:
502 - Web server received an invalid response while acting as a
gateway or proxy server.
TemplateSimple.html
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title><TMPL_VAR NAME=title></title>
<link rel="SHORTCUT" ICON href="favicon.ico" />
</head>
<body>
<TMPL_VAR NAME=body>
</body>
</html>
I have to use CGI, because I want to process user input on the web page, but I would like to define the basic HTML structure in a template where I can insert code segments as necessary.
Edit
I think that it could have something to do with different configs between the local Perl (run from eclipse, which does run fine) and the Perl CGI config. Does anybody know of such a case?
Edit
After setting up a Perl CGI configuration in Eclipse, the script runs as expected from the local host. However, the problem when calling the page from an external source persists. So like DaveCross suggested, the bug lies in the web server configuration rather than the Perl script.

When initializing the HTML::Template object in the Perl script
my $tmpl = HTML::Template->new(filename => 'TemplateSimple.html');
I had to specify the full path instead of just the filename, so
my $tmpl = HTML::Template->new(filename => 'C:/inetpub/wwwroot/Project/TemplateSimple.html');
This solved my problem.
To whom it may interest, the webservice was set up with IIS 7, in the very basic and standard way.

Related

JSON::XS under mod_perl fails with POST requests

I am using the default install of Apache and mod_perl on Ubuntu 16.04.1 LTS, I also have reproduced this with the default JSON::XS and I updated to the latest from CPAN JSON-XS-3.02.
The code below works in all cases if I am not using mod_perl.
The script and html below work when using perl via mod_cgi with both POST and GET requests.
If however I am using mod_perl and I use a POST (as in the html provided) it fails, "Hello" does not print, and I get the following error in my apache log file.
Usage: JSON::XS::new(klass).
If I pass the same parameter(s) via a GET method, the script works fine.
test2.pl
#!/usr/bin/perl
use strict;
use warnings;
use CGI;
use JSON::XS;
my $q = new CGI();
print $q->header(-type => 'text/plain');
my $action = $q->param('a');
my $json_str = '{"foo":"bar"}';
my $pscalar = JSON::XS->new->utf8->decode($json_str);
print "Hello";
exit 1;
HTML to call the above (named test2.pl on the server)
<html>
<body>
<form action="test2.pl" method="POST">
<input type="text" name="a"/>
<button type="submit">
</form>
</body>
</html>
OK So this was a rather wild goose chase, analyzing apache core dumps and stack traces, fixing bugs that weren't really there... Long story short.
I was trying to add an include directory to my perl by using
PerlSwitches -I/usr/local/lib/site_perl/my_new_directory
As part of that I added
PerlOptions +Parent so that I would get a new interpreter for each virtual host so my -I was effective for only one virtual host at a time.
I had added those flags before I enabled mod_perl, so when I enabled mod_perl, it just never worked.
By removing the PerlOptions +Parent things started working as expected.
As a side note, it appears +Parent makes things wonky in genral.

Understanding JSON-RPC in Perl

I am trying to understand the concept of JSON RPC and it's Perl implementation. Though I can fin d a lot of examples for Python/Java, I find surprisingly little or no examples for it in Perl.
I am following this example but am not sure it is complete. The example I had in mind was to add 2 integers. Now I have a very basic HTML page set up, like so:
<html>
<body>
<input type="text" name="num1"><br>
<input type="text" name="num2"><br>
<button>Add</button>
</body>
</html>
Next, based on the example above, I have 3 files:
test1.pl
# Daemon version
use JSON::RPC::Server::Daemon;
# see documentation at:
# https://metacpan.org/pod/distribution/JSON-RPC/lib/JSON/RPC/Legacy.pm
my $server = JSON::RPC::Server::Daemon->new(LocalPort => 8080);
$server -> dispatch({'/test' => 'myApp'});
$server -> handle();
test2.pl
#!/usr/bin/perl
use JSON::RPC::Client;
my $client = new JSON::RPC::Client;
my $uri = 'http://localhost:8080/test';
my $obj = {
method => 'sum', # or 'MyApp.sum'
params => [10, 20],
};
my $res = $client->call( $uri, $obj );
if($res){
if ($res->is_error) {
print "Error : ", $res->error_message;
} else {
print $res->result;
}
} else {
print $client->status_line;
}
myApp.pl
package myApp;
#optionally, you can also
use base qw(JSON::RPC::Procedure); # for :Public and :Private attributes
sub sum : Public(a:num, b:num) {
my ($s, $obj) = #_;
return $obj->{a} + $obj->{b};
}
1;
While I understand what these files individually do, I am at a complete loss when it comes to combining them and making them work together.
My questions are as follows:
Does the button in the HTML page come inside a tag (like we would normally do in a CGI-based program)? If yes, what file does that call? If no, then how do I pass the values to be added?
What is the order of execution of the 3 Perl files? Which one calls which one? How is the flow of execution?
When I tried to run the perl files from the CLI, i.e using $./test2.pl, I got the following error: Error 301 Moved Permanently. What moved permanently? which file was it trying to access? I tried running the files from withing /var/www/html and /var/www/html/test.
Some help in understanding the nuances of this would really be appreciated. Thanks in advance
Does the button in the HTML page come inside a tag (like we would
*normally do in a CGI-based program)? If yes, what file does that call?*
If no, then how do I pass the values to be added?
HTML has nothing at all to do with JSON-RPC. While the RPC call is done via an HTTP POST request, if you're doing that from the browser, you'll need to use XMLHttpRequest (i.e: AJAX). Unlink an HTML form post the Content-encoding: header will need to be something specific to JSON-RPC (e.g: application/json or similar), and you'll need to encode your form data via JSON.stringify and correctly construct the JSON-RPC "envelope", including the id, jsonrpc, method and params properties.
Rather than doing this by hand you might use a purpose-build JSON-RPC JavaScript client like the jQuery-JSONRP plugin (there are many others) -- although the protocol is so simple that implementations usually are less than 20 lines of code.
From the jQuery-RPC documentation, you'd set up the connection like this:
$.jsonRPC.setup({
endPoint: '/ENDPOINT-ROUTE-GOES-HERE'
});
and you'd call the server-side method like this:
$.jsonRPC.request('sum', {
params: [YOURNUMBERINPUTELEMENT1.value, YOURNUMBERINPUT2.value],
success: function(result) {
/* Do something with the result here */
},
error: function(result) {
/* Result is an RPC 2.0 compatible response object */
}
});
What is the order of execution of the 3 Perl files? Which one calls
*which one? How is the flow of execution?*
You'll likely only need test2.pl for testing. It's an example implementation of a JSON-RPC client. You likely want your client to run in your web-browser (as described above). The client JavaScript will make an HTTP POST request to wherever test1.pl is serving content. (e.g: http://localhost:8080).
Or, if you want to keep your code as HTML<-->CGI, then you'll need to make JSON-RPC client calls from within your Perl CGI server-side code (which seems silly if it's on the same machine).
When test1.pl calls dispatch, the MyApp module will be loaded.
Then, when test1.pl calls handle, the sum function in the MyApp package will be called.
The JSON::RPC::Server module takes care of marshalling from JSON-RPC to perl datastructures and back again around the call to handle. die()ing in sum should result in a JSON-RPC exception being transmitted to the calling client, rather than death of the test1.pl script.
When I tried to run the perl files from the CLI, i.e using
*$./test2.pl, I got the following error: Error 301 Moved Permanently.*
What moved permanently? which file was it trying to access? I tried
*running the files from withing /var/www/html and /var/www/html/test.*
This largely depends the configuration of your machine. There's nothing obvious (in your code) to suggest that a 301 Moved Permanently would be issued in response to a valid JSON-RPC request.

Retrieving HTTP URLs using Perl scripting

I'm trying to save the whole web page on my system as a .html file and then parse that file, to find some tags and use them.
I'm able to save/parse http://<url>, but not able to save/parse https://<url>. I'm using Perl.
I'm using the following code to save HTTP and it works fine but doesn't work for HTTPS:
use strict;
use warnings;
use LWP::Simple qw($ua get);
use LWP::UserAgent;
use LWP::Protocol::https;
use HTTP::Cookies;
sub main
{
my $ua = LWP::UserAgent->new();
my $cookies = HTTP::Cookies->new(
file => "cookies.txt",
autosave => 1,
);
$ua->cookie_jar($cookies);
$ua->agent("Google Chrome/30");
#$ua->ssl_opts( SSL_ca_file => 'cert.pfx' );
$ua->proxy('http','http://proxy.com');
my $response = $ua->get('http://google.com');
#$ua->credentials($response, "", "usrname", "password");
unless($response->is_success) {
print "Error: " . $response->status_line;
}
# Let's save the output.
my $save = "save.html";
unless(open SAVE, '>' . $save) {
die "nCannot create save file '$save'n";
}
# Without this line, we may get a
# 'wide characters in print' warning.
binmode(SAVE, ":utf8");
print SAVE $response->decoded_content;
close SAVE;
print "Saved ",
length($response->decoded_content),
" bytes of data to '$save'.";
}
main();
Is it possible to parse an HTTPS page?
Always worth checking the documentation for the modules that you're using...
You're using modules from libwww-perl. That includes a cookbook. And in that cookbook, there is a section about HTTPS, which says:
URLs with https scheme are accessed in exactly the same way as with
http scheme, provided that an SSL interface module for LWP has been
properly installed (see the README.SSL file found in the libwww-perl
distribution for more details). If no SSL interface is installed for
LWP to use, then you will get "501 Protocol scheme 'https' is not
supported" errors when accessing such URLs.
The README.SSL file says this:
As of libwww-perl v6.02 you need to install the LWP::Protocol::https
module from its own separate distribution to enable support for
https://... URLs for LWP::UserAgent.
So you just need to install LWP::Protocol::https.
You need to have https://metacpan.org/module/Crypt::SSLeay for https links
It provides SSL support for LWP.
Bit me in the ass with a project of my own.

Download files with Perl

I have updated my code to look like this. When I run it though it says it cannot find the specified link. Also what is a good way to test that it is indeed connecting to the page?
#!/usr/bin/perl -w
use strict;
use LWP;
use WWW::Mechanize;
my $mech = WWW::Mechanize->new();
my $browser = LWP::UserAgent->new;
$browser->credentials(
'Apache/2.2.3 (CentOS):80',
'datawww2.wxc.com',
'************' => '*************'
);
my $response = $browser->get(
'http://datawww2.wxc.com/kml/echo/MESH_Max_180min/'
);
$mech->follow_link( n => 8);
(Original Post)
What is the best way to download small files with Perl?
I looked on CPAN and found lwp-download, but it seems to only download from the link. I have a page with links that change every thirty minutes with the date and time in the name so they are never the same. Is there a built-in function I can use? Everyone on Google keeps saying to use Wget, but I was kind of wanting to stick with Perl if possible just to help me learn it better while I program with it.
Also there is a user name and password to log into the site. I know how to access the site using Perl still, but I thought that might change what I can use to download with.
As stated in a comment in your other question: here
You can use the same method to retrieve .csv files as .html, or any other text-based file for the matter.
#!/usr/bin/perl -w
use strict;
use LWP::Simple;
my $csv = get("http://www.spc.noaa.gov/climo/reports/last3hours_hail.csv")
or die "Could not fetch NWS CSV page.";
To login, you may need to use WWW::Mechanize to fill out the webform (look at $mech->get(), $mech->submit_form(), and $mech->follow_link())
Basically, you need to fetch the page, parse it to get the URL, and then download the file.
Personally, I'd use HTML::TreeBuilder::XPath, write a quick XPath expression to go straight to the correct href attribute node, and then plug that into LWP.
use HTML::TreeBuilder::XPath;
my $tree = HTML::TreeBuilder::XPath->new;
$tree->parse({put page content here});
foreach($tree->findnodes({put xpath expression here}){
{download the file}
}

Getting the directory of an uploaded file with perl

I have a Perl script which will allow for a file to be uploaded to my server. I'm not completely done with it yet, but I would like to know, if there is any way for me to get the full path of a file i uploaded. Shouldn't this be possible by checking the PATH_INFO environment variable, but when i try to check the path info, nothing is there
#!/usr/bin/perl
use strict;
use CGI;
use File::Basename;
#Virtual Directory
eval
{
my ($uploadfile, $cgi);
$cgi = new CGI;
$uploadfile = $cgi->upload('uploadfile');
print $uploadfile;
use constant PASSWORD => 'p3rlD3v3l0p3r';
use constant UPLOAD_DIR => '/home/user/files';
print <<"HTML";
Status: 200 OK
Content-Type: text/html
<html>
<head>
<title>Virtual Directory</title>
</head>
<body>
$uploadfile
<h2>Upload a new file</h2>
<form method = "POST" enctype = "multipart/form-data" action =""/>
File:<input type = "file" name="uploadfile"/>
<p>Password:
<input type = "password" name ="passwd"/></p>
<p><input type = "submit" value= "Submit File" /></p>
</form>
</body>
</html>
HTML
print $ENV{"PATH_INFO"};
};
It is hard to make sense of your question. However, do read Processing a File Upload Field in CGI docs. I think you might be looking for:
Accessing the temp files directly
When processing an uploaded file, CGI.pm creates a temporary file on your hard disk and passes you a file handle to that file. After you are finished with the file handle, CGI.pm unlinks (deletes) the temporary file. If you need to you can access the temporary file directly. You can access the temp file for a file upload by passing the file name to the tmpFileName() method:
On the other hand, if you are trying to find out the full path of the file on the web site visitor's computer, I hope it should be obvious that there is no way for your script to retrieve this information if it is not submitted by the user's browser as the name of the file:
If you want the entered file name for the file, you can just call param():
$filename = $q->param('field_name');
Different browsers will return slightly different things for the name. Some browsers return the filename only. Others return the full path to the file, using the path conventions of the user's machine. Regardless, the name returned is always the name of the file on the user's machine, and is unrelated to the name of the temporary file that CGI.pm creates during upload spooling
PATH_INFO is for other purposes. You need "tmpFileName":
my $cgi = CGI->new;
my $filename = $cgi->param('uploadfile');
my $tmpfilename = $cgi->tmpFileName($filename);
You can extract path with "fileparse" from File::Basename.