| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- # 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 <[email protected]> wrote the underlying
- RPC library.
- Joe Johnston <[email protected]> wrote an adaptation
- of the Frontier::Daemon class to create this CGI XML-RPC
- listener class.
- =cut
|