Last week I needed to create a persistent Perl service to listening for incoming files and then process them. For the protocol I went with HTTP, because it is more than adequate to meet my humble needs. So all I needed was (A) an implementation of an HTTP server in Perl, and (B) a clue how to use it.
Solving the first half was pretty easy, and I quickly fell upon the HTTP::Server::Simple. From there I realized that it would be easiest to write my service using its CGI specific subclass HTTP::Server::Simple::CGI.
Installation was typically painless:
sudo perl -MCPAN -e shell
install HTTP::Server::Simple::CGI
And then I was ever so slightly stuck. There is documentation on how to create a simple CGI server, but it wasn't quite enough to get me to the service I needed.
The skeleton of creating a server looks like this:
#!/usr/local/bin/perl -w
package MyServer;
use strict;
use HTTP::Server::Simple::CGI;
use base qw(HTTP::Server::Simple::CGI);
my $port = 4569;
sub handle_request {
my ($self, $cgi) = @_;
return "Hi.";
}
my $pid = MyServer->new(4116)->background();
This is quite simple and concise, but then again our server isn't actually doing anything useful yet. That's where things get a bit less obviously documented, especially if you're unfamiliar with the CGI module, which is they key that unlocks all mysteries.
Here are a few recipes for writing the handle_request
subprocess.
Vary Response On HTTP Method
sub handle_request {
my ($self, $cgi) = @_;
my $method = $ENV{REQUEST_METHOD};
my $timestamp = time();
if (lc($method) eq 'post') {
print "Received POST request at $timestamp";
}
else {
print "Received request of type $method at $timestamp";
}
}
Receive POSTed File
sub handle_request {
my ($self, $cgi) = @_;
my $method = $ENV{REQUEST_METHOD};
if (lc($method) == 'post') {
my $file = $cgi->param('POSTDATA');
open OUT '>file.xml' or warn $!;
print OUT $file;
close OUT;
print 'Received data.';
}
else {
print 'Please POST a file.';
}
}
I've used the above code to handle rather large files (over 100 megs), but I strongly suspect that it wouldn't scale to multiple requests, but for a simple backend service the above code actually--somewhat to my surprise--behaves nicely.
Forking a Process for Requests
sub handle_request {
my ($self, $cgi) = @_;
my $pid = fork();
if ($pid == 0) {
exec('perl some_other_script.pl');
}
print 'Forked additional process.';
}
I think this approach is helpful, because it makes it easier to use a simple Perl server to manage your other processes. For example, you might write an XML parser in Java or C for speed, and then save a posted file (like the above example) and then fork a new process to run the parsing script.
Fin
All in all, HTTP::Server::Simple has been another very positive CPAN experience for me, and it is definitely the CPAN experience that is keeping me learning and playing with Perl. I do find the quality of documentation to be rather uneven (XML::Twig has an insurmountably large amount of documentation), and there are many fewer people randomly writing blog entries about Perl module X than you'd find in the Python or Ruby spheres. Hopefully this entry will turn up in some lost soul's search results.
Can you provide an example of how you post the upload file in your example? Thanks!
Reply to this entry