File Coverage

blib/lib/POE/Component/Server/XMLRPC.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             # $Id: XMLRPC.pm,v 1.4 2003/03/20 23:26:02 mah Exp $
2             # License and documentation are after __END__.
3              
4             package POE::Component::Server::XMLRPC;
5              
6 1     1   13130 use warnings;
  1         3  
  1         47  
7 1     1   6 use strict;
  1         2  
  1         39  
8 1     1   5 use Carp qw(croak);
  1         6  
  1         61  
9              
10 1     1   6 use vars qw($VERSION);
  1         1  
  1         379  
11             $VERSION = '0.05';
12              
13 1     1   2726 use POE;
  0            
  0            
14             use POE::Component::Server::HTTP;
15             use XMLRPC::Lite;
16              
17             my %public_interfaces;
18              
19             sub new {
20             my $type = shift;
21              
22             croak "Must specify an even number of parameters to $type\->new()" if @_ % 2;
23             my %params = @_;
24              
25             my $alias = delete $params{alias};
26             croak "Must specify an alias in $type\->new()"
27             unless defined $alias and length $alias;
28              
29             my $interface = delete $params{interface};
30             croak "$type\->new() currently does not support the interface parameter"
31             if defined $interface;
32              
33             my $port = delete $params{port};
34             $port = 80 unless $port;
35              
36             POE::Session->create
37             ( inline_states =>
38             { _start => sub {
39             $_[KERNEL]->alias_set($alias);
40             },
41             publish => sub {
42             my ($alias, $event) = @_[ARG0, ARG1];
43             $public_interfaces{$alias}{$event} = 1;
44             },
45             rescind => sub {
46             my ($alias, $event) = @_[ARG0, ARG1];
47             delete $public_interfaces{$alias}{$event};
48             },
49             }
50             );
51              
52             POE::Component::Server::HTTP->new
53             ( Port => $port,
54             Headers =>
55             { Server => "POE::Component::Server::XMLRPC/$VERSION",
56             },
57             ContentHandler => { "/" => \&web_handler },
58             );
59              
60             undef;
61             }
62              
63             ### Handle web requests by farming them out to other sessions.
64              
65             sub web_handler {
66             my ($request, $response) = @_;
67              
68             # Parse useful things from the request.
69              
70             my $query_string = $request->uri->query();
71             unless (defined($query_string) and $query_string =~ /\bsession=(.+ $ )/x) {
72             $response->code(400);
73             return RC_OK;
74             }
75             my $session = $1;
76              
77             my $http_method = $request->method();
78             my $request_content_type = $request->header('Content-Type');
79             my $request_content_length = $request->header('Content-Length');
80             my $debug_request = $request->header('DebugRequest');
81             my $request_content = $request->content();
82             my $data = XMLRPC::Deserializer
83             ->deserialize($request_content);
84             my $method_name = $data->valueof("methodName");
85             my $args = $data->valueof("params");
86              
87             unless ($request_content_type =~ /^text\/xml(;.*)?$/) {
88             _request_failed( $response,
89             403,
90             "Bad Request",
91             "Content-Type must be text/xml.",
92             );
93             return RC_OK;
94             }
95              
96             unless (defined($method_name) and length($method_name)) {
97             _request_failed( $response,
98             403,
99             "Bad Request",
100             "methodName is required.",
101             );
102             return RC_OK;
103             }
104              
105             unless ($method_name =~ /^(\S+)$/) {
106             _request_failed( $response,
107             403,
108             "Bad Request",
109             "Unrecognized methodName: $method_name",
110             );
111             }
112              
113             unless (exists $public_interfaces{$session}) {
114             _request_failed( $response,
115             500,
116             "Bad Request",
117             "Unknown session: $session",
118             );
119             return RC_OK;
120             }
121              
122             unless (exists $public_interfaces{$session}{$method_name}) {
123             _request_failed( $response,
124             500,
125             "Bad Request",
126             "Unknown method: $method_name",
127             );
128             return RC_OK;
129             }
130              
131             eval {
132             XMLRPCTransaction->start($response, $session, $method_name, $args);
133             };
134              
135             if ($@) {
136             _request_failed( $response,
137             500,
138             "Application Faulted",
139             "An exception fired while processing the request: $@",
140             );
141             }
142              
143             return RC_WAIT;
144             }
145              
146             sub _request_failed {
147             my ($response, $fault_code, $fault_string, $result_description) = @_;
148              
149             my $response_content = qq{
150            
151            
152             faultCode$fault_code
153             faultString$fault_string
154            
155            
156             };
157              
158             $response->code(200);
159             $response->header("Content-Type", "text/xml");
160             $response->header("Content-Length", length($response_content));
161             $response->content($response_content);
162             }
163              
164             package XMLRPCTransaction;
165              
166             sub TR_RESPONSE () { 0 }
167             sub TR_SESSION () { 1 }
168             sub TR_EVENT () { 2 }
169             sub TR_ARGS () { 3 }
170              
171             sub start {
172             my ($type, $response, $session, $event, $args) = @_;
173              
174             my $self = bless
175             [ $response,
176             $session,
177             $event,
178             $args,
179             ], $type;
180              
181             $POE::Kernel::poe_kernel->post($session, $event, $self);
182             undef;
183             }
184              
185             sub params {
186             my $self = shift;
187             return $self->[TR_ARGS];
188             }
189              
190             sub return {
191             my ($self, $retval) = @_;
192              
193             my $content = XMLRPC::Serializer->envelope(response => 'toMethod', $retval);
194             my $response = $self->[TR_RESPONSE];
195              
196             $response->code(200);
197             $response->header("Content-Type", "text/xml");
198             $response->header("Content-Length", length($content));
199             $response->content($content);
200             $response->continue();
201             }
202              
203             1;
204              
205             __END__