Responder.pm 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. # File: Repsonder.pm
  2. # based heavily on Ken MacLeod's Frontier::Daemon
  3. # Author: Joe Johnston 7/2000
  4. # Revisions:
  5. # 11/2000 - Cleaned/Add POD. Took out 'use CGI'.
  6. #
  7. # Meant to be called from a CGI process to answer client
  8. # requests and emit the appropriate reponses. See POD for details.
  9. #
  10. # LICENSE: This code is released under the same licensing
  11. # as Perl itself.
  12. #
  13. # Use the code where ever you want, but due credit is appreciated.
  14. package Frontier::Responder;
  15. use strict;
  16. use vars qw/@ISA/;
  17. use Frontier::RPC2;
  18. my $snappy_answer = "Hey, I need to return true, don't I?";
  19. # Class constructor.
  20. # Input: (expects parameters to be passed in as a hash)
  21. # methods => hashref, keys are API procedure names, values are
  22. # subroutine references
  23. #
  24. # Output: blessed reference
  25. sub new {
  26. my $class = shift;
  27. my %args = @_;
  28. my $self = bless {}, (ref $class ? ref $class : $class);
  29. # Store the dispatch table away for future use.
  30. $self->{methods} = $args{methods};
  31. $self->{_decode} = Frontier::RPC2->new();
  32. return $self;
  33. }
  34. # Grabs input from CGI "stream", makes request
  35. # if possible, packs up the response in purddy
  36. # XML
  37. # Input: None
  38. # Output: A XML string suitable for printing from a CGI process
  39. sub answer{
  40. my $self = shift;
  41. # fetch the xml message sent
  42. my $request = get_cgi_request();
  43. unless( defined $request ){
  44. print
  45. "Content-Type: text/txt\n\n";
  46. exit;
  47. }
  48. # Let's figure out the method to execute
  49. # along with its arguments
  50. my $response = $self->{_decode}->serve( $request,
  51. $self->{methods} );
  52. # Ship it!
  53. return
  54. "Content-Type: text/xml \n\n" . $response;
  55. }
  56. # private function. No need to advertise this.
  57. # Remember, this is just XML.
  58. # CGI.pm doesn't grok this.
  59. sub get_cgi_request{
  60. my $in;
  61. if( $ENV{REQUEST_METHOD} eq 'POST' ){
  62. my $len = $ENV{CONTENT_LENGTH};
  63. unless ( read( STDIN, $in, $len ) == $len ){
  64. return;
  65. }
  66. }else{
  67. $in = $ENV{QUERY_STRING};
  68. }
  69. return $in;
  70. }
  71. =pod
  72. =head1 NAME
  73. Frontier::Responder - Create XML-RPC listeners for normal CGI processes
  74. =head1 SYNOPSIS
  75. use Frontier::Responder;
  76. my $res = Frontier::Responder->new( methods => {
  77. add => sub{ $_[0] + $_[1] },
  78. cat => sub{ $_[0] . $_[1] },
  79. },
  80. );
  81. print $res->answer;
  82. =head1 DESCRIPTION
  83. Use I<Frontier::Responder> whenever you need to create an XML-RPC listener
  84. using a standard CGI interface. To be effective, a script using this class
  85. will often have to be put a directory from which a web server is authorized
  86. to execute CGI programs. An XML-RPC listener using this library will be
  87. implementing the API of a particular XML-RPC application. Each remote
  88. procedure listed in the API of the user defined application will correspond
  89. to a hash key that is defined in the C<new> method of a I<Frontier::Responder>
  90. object. This is exactly the way I<Frontier::Daemon> works as well.
  91. In order to process the request and get the response, the C<answer> method
  92. is needed. Its return value is XML ready for printing.
  93. For those new to XML-RPC, here is a brief description of this protocol.
  94. XML-RPC is a way to execute functions on a different
  95. machine. Both the client's request and listeners response are wrapped
  96. up in XML and sent over HTTP. Because the XML-RPC conversation is in
  97. XML, the implementation languages of the server (here called a I<listener>),
  98. and the client can be different. This can be a powerful and simple way
  99. to have very different platforms work together without acrimony. Implicit
  100. in the use of XML-RPC is a contract or API that an XML-RPC listener
  101. implements and an XML-RPC client calls. The API needs to list not only
  102. the various procedures that can be called, but also the XML-RPC datatypes
  103. expected for input and output. Remember that although Perl is permissive
  104. about datatyping, other languages are not. Unforuntately, the XML-RPC spec
  105. doesn't say how to document the API. It is recomended that the author
  106. of a Perl XML-RPC listener should at least use POD to explain the API.
  107. This allows for the programmatic generation of a clean web page.
  108. =head1 METHODS
  109. =over 4
  110. =item new( I<OPTIONS> )
  111. This is the class constructor. As is traditional, it returns
  112. a blessed reference to a I<Frontier::Responder> object. It expects
  113. arguments to be given like a hash (Perl's named parameter mechanism).
  114. To be effective, populate the C<methods> parameter with a hashref
  115. that has API procedure names as keys and subroutine references as
  116. values. See the SYNOPSIS for a sample usage.
  117. =item answer()
  118. In order to parse the request and execute the procedure, this method
  119. must be called. It returns a XML string that contains the procedure's
  120. response. In a typical CGI program, this string will simply be printed
  121. to STDOUT.
  122. =back
  123. =head1 SEE ALSO
  124. perl(1), Frontier::RPC2(3)
  125. <http://www.scripting.com/frontier5/xml/code/rpc.html>
  126. =head1 AUTHOR
  127. Ken MacLeod <[email protected]> wrote the underlying
  128. RPC library.
  129. Joe Johnston <[email protected]> wrote an adaptation
  130. of the Frontier::Daemon class to create this CGI XML-RPC
  131. listener class.
  132. =cut