http://www.perlmonks.org?node_id=575898


in reply to Simple TCP server recomendations

The learning curve for POE isn't really that big if you start with a simple problem like this. Here is a simple little POE-based script that can give you an easily expandable REST-style http interface for doing the kinds of things you want to do...

#!/usr/bin/perl use warnings; use strict; use POE qw( Component::Server::HTTP ); use HTTP::Status; my $VERSION = '0.01'; POE::Component::Server::HTTP->new( Port => 42421, ContentHandler => { "/" => \&uri_handler, }, Headers => { Version => $VERSION }, ); POE::Kernel->run(); sub uri_handler { my ( $request, $response ) = @_; my $path = $request->uri->path; $path =~ s/\W+/_/g; $path = "remote_request".$path; # see update $response->content_type( 'text/plain' ); if ( ! defined &$path ) { $response->code( RC_NOT_FOUND ); return RC_OK; } my $content = eval { no strict 'refs'; &$path }; if ( $@ ) { $response->code( RC_INTERNAL_SERVER_ERROR ); warn $@; $response->content( "ERROR: $@" ); return RC_OK; } $response->code( RC_OK ); $response->content($content); return RC_OK; } sub remote_request_version { return "$VERSION\n" }

In this little server, the uri path that is requested just gets turned into a sub name (so a request for /version becomes _version), and if that sub exists, then it's output is returned as the HTTP response. This way you can add new features just by adding new subroutines.

Update: merlyn is right, I oversimplified a little while posting this, and a little more care should be taken with the functions you expose to this type of application. I added "remote_request" to the beginning of any functions that are accessible from the web interface to mitigate this.


We're not surrounded, we're in a target-rich environment!

Replies are listed 'Best First'.
Re^2: Simple TCP server recomendations
by merlyn (Sage) on Oct 02, 2006 at 17:07 UTC
    While your goal of making it easily extensible is admirable, this line troubles me:
    if ( ! defined &$path ) {
    Since you don't force any particular content on $path (except that it be strictly alphanumeric), you're also exposing any miscellaneous subroutines that happen to be defined. Are you sure that everything that POE exports is safe to be invoked, for example?

    A better strategy would be to narrow the namespace a bit:

    $path = "remote_request_$path"; ...
    which ensures that someone has to go to the trouble to name a subroutine a particular shape before it can be invoked.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

      That's a very good point, I had distilled this down from an application very similar to what the OP was looking for that I was actually using in production, and may have oversimplified it a bit.

      In the original, I was using attributes to flag subs that should be accessible through this interface, and didn't want to confuse the posting by leaving in all the attribute-related code. I had been thinking that it was unlikely that POE was exporting any functions that started with an underscore, but on further reflection it would certainly be possible to invoke random methods that didn't start with an underscore by hand-crafting your requests, although the amount of damage you could do would be limited by not being able to pass arguments to any of those methods, it is still something to keep in mind.


      We're not surrounded, we're in a target-rich environment!