170 lines
5.1 KiB
Perl
Executable file
170 lines
5.1 KiB
Perl
Executable file
# File: Repsonder.pm
|
|
# based heavily on Ken MacLeod's Frontier::Daemon
|
|
# Author: Joe Johnston 7/2000
|
|
# Revisions:
|
|
# 11/2000 - Cleaned/Add POD. Took out 'use CGI'.
|
|
#
|
|
# Meant to be called from a CGI process to answer client
|
|
# requests and emit the appropriate reponses. See POD for details.
|
|
#
|
|
# LICENSE: This code is released under the same licensing
|
|
# as Perl itself.
|
|
#
|
|
# Use the code where ever you want, but due credit is appreciated.
|
|
|
|
package Frontier::Responder;
|
|
|
|
use strict;
|
|
use vars qw/@ISA/;
|
|
|
|
use Frontier::RPC2;
|
|
|
|
my $snappy_answer = "Hey, I need to return true, don't I?";
|
|
|
|
# Class constructor.
|
|
# Input: (expects parameters to be passed in as a hash)
|
|
# methods => hashref, keys are API procedure names, values are
|
|
# subroutine references
|
|
#
|
|
# Output: blessed reference
|
|
sub new {
|
|
my $class = shift;
|
|
my %args = @_;
|
|
my $self = bless {}, (ref $class ? ref $class : $class);
|
|
|
|
# Store the dispatch table away for future use.
|
|
$self->{methods} = $args{methods};
|
|
$self->{_decode} = Frontier::RPC2->new();
|
|
|
|
return $self;
|
|
}
|
|
|
|
# Grabs input from CGI "stream", makes request
|
|
# if possible, packs up the response in purddy
|
|
# XML
|
|
# Input: None
|
|
# Output: A XML string suitable for printing from a CGI process
|
|
sub answer{
|
|
my $self = shift;
|
|
|
|
# fetch the xml message sent
|
|
my $request = get_cgi_request();
|
|
|
|
unless( defined $request ){
|
|
print
|
|
"Content-Type: text/txt\n\n";
|
|
exit;
|
|
}
|
|
|
|
# Let's figure out the method to execute
|
|
# along with its arguments
|
|
my $response = $self->{_decode}->serve( $request,
|
|
$self->{methods} );
|
|
# Ship it!
|
|
return
|
|
"Content-Type: text/xml \n\n" . $response;
|
|
|
|
}
|
|
|
|
# private function. No need to advertise this.
|
|
# Remember, this is just XML.
|
|
# CGI.pm doesn't grok this.
|
|
sub get_cgi_request{
|
|
my $in;
|
|
if( $ENV{REQUEST_METHOD} eq 'POST' ){
|
|
my $len = $ENV{CONTENT_LENGTH};
|
|
unless ( read( STDIN, $in, $len ) == $len ){
|
|
return;
|
|
}
|
|
}else{
|
|
$in = $ENV{QUERY_STRING};
|
|
}
|
|
|
|
return $in;
|
|
}
|
|
|
|
=pod
|
|
|
|
=head1 NAME
|
|
|
|
Frontier::Responder - Create XML-RPC listeners for normal CGI processes
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
use Frontier::Responder;
|
|
my $res = Frontier::Responder->new( methods => {
|
|
add => sub{ $_[0] + $_[1] },
|
|
cat => sub{ $_[0] . $_[1] },
|
|
},
|
|
);
|
|
print $res->answer;
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
Use I<Frontier::Responder> whenever you need to create an XML-RPC listener
|
|
using a standard CGI interface. To be effective, a script using this class
|
|
will often have to be put a directory from which a web server is authorized
|
|
to execute CGI programs. An XML-RPC listener using this library will be
|
|
implementing the API of a particular XML-RPC application. Each remote
|
|
procedure listed in the API of the user defined application will correspond
|
|
to a hash key that is defined in the C<new> method of a I<Frontier::Responder>
|
|
object. This is exactly the way I<Frontier::Daemon> works as well.
|
|
In order to process the request and get the response, the C<answer> method
|
|
is needed. Its return value is XML ready for printing.
|
|
|
|
For those new to XML-RPC, here is a brief description of this protocol.
|
|
XML-RPC is a way to execute functions on a different
|
|
machine. Both the client's request and listeners response are wrapped
|
|
up in XML and sent over HTTP. Because the XML-RPC conversation is in
|
|
XML, the implementation languages of the server (here called a I<listener>),
|
|
and the client can be different. This can be a powerful and simple way
|
|
to have very different platforms work together without acrimony. Implicit
|
|
in the use of XML-RPC is a contract or API that an XML-RPC listener
|
|
implements and an XML-RPC client calls. The API needs to list not only
|
|
the various procedures that can be called, but also the XML-RPC datatypes
|
|
expected for input and output. Remember that although Perl is permissive
|
|
about datatyping, other languages are not. Unforuntately, the XML-RPC spec
|
|
doesn't say how to document the API. It is recomended that the author
|
|
of a Perl XML-RPC listener should at least use POD to explain the API.
|
|
This allows for the programmatic generation of a clean web page.
|
|
|
|
=head1 METHODS
|
|
|
|
=over 4
|
|
|
|
=item new( I<OPTIONS> )
|
|
|
|
This is the class constructor. As is traditional, it returns
|
|
a blessed reference to a I<Frontier::Responder> object. It expects
|
|
arguments to be given like a hash (Perl's named parameter mechanism).
|
|
To be effective, populate the C<methods> parameter with a hashref
|
|
that has API procedure names as keys and subroutine references as
|
|
values. See the SYNOPSIS for a sample usage.
|
|
|
|
|
|
=item answer()
|
|
|
|
In order to parse the request and execute the procedure, this method
|
|
must be called. It returns a XML string that contains the procedure's
|
|
response. In a typical CGI program, this string will simply be printed
|
|
to STDOUT.
|
|
|
|
|
|
=back
|
|
|
|
=head1 SEE ALSO
|
|
|
|
perl(1), Frontier::RPC2(3)
|
|
|
|
<http://www.scripting.com/frontier5/xml/code/rpc.html>
|
|
|
|
=head1 AUTHOR
|
|
|
|
Ken MacLeod <ken@bitsko.slc.ut.us> wrote the underlying
|
|
RPC library.
|
|
|
|
Joe Johnston <jjohn@cs.umb.edu> wrote an adaptation
|
|
of the Frontier::Daemon class to create this CGI XML-RPC
|
|
listener class.
|
|
|
|
=cut
|