File Coverage

blib/lib/POE/Filter/XML/RPC.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package POE::Filter::XML::RPC;
2              
3 2     2   58140 use POE::Filter::XML::RPC::Request;
  0            
  0            
4             use POE::Filter::XML::RPC::Response;
5             use POE::Filter::XML::RPC::Fault;
6              
7             use POE::Filter::XML::Node;
8              
9             use base('POE::Filter');
10              
11             use constant
12             {
13             BUFFER => 0,
14             };
15              
16             our $VERSION = '0.04';
17              
18              
19             sub new()
20             {
21             my $class = shift;
22             my $self = [];
23            
24             $self->[+BUFFER] = [];
25              
26             return bless($self, $class);
27             }
28              
29             sub get_one_start()
30             {
31             my ($self, $raw) = @_;
32             if(@{$self->[+BUFFER]})
33             {
34             push(@{$self->[+BUFFER]}, @$raw);
35            
36             } elsif(ref($raw) eq 'ARRAY') {
37              
38             $self->[+BUFFER] = $raw;
39             }
40             else
41             {
42             $self->[+BUFFER] = [$raw];
43             }
44             }
45              
46             sub get_one()
47             {
48             my $self = shift(@_);
49             my $node = shift(@{$self->[+BUFFER]});
50            
51              
52             if(defined($node))
53             {
54             if($node->nodeName() eq 'methodCall')
55             {
56             if($node->exists('child::methodName'))
57             {
58             if(!$node->exists('child::methodName/child::text()'))
59             {
60             return
61             [
62             POE::Filter::XML::RPC::Response->new
63             (
64             POE::Filter::XML::RPC::Fault->new
65             (
66             102,
67             'Malformed XML-RPC: No methodName data defined'
68             )
69             )
70             ];
71             }
72            
73             } else {
74              
75             return
76             [
77             POE::Filter::XML::RPC::Response->new
78             (
79             POE::Filter::XML::RPC::Fault->new
80             (
81             103,
82             'Malformed XML-RPC: No methodName child tag present'
83             )
84             )
85             ];
86             }
87            
88             # params are optional, but let's be consistent for the
89             # Request code's sake.
90              
91             if(!$node->exists('child::params'))
92             {
93             $node->appendChild('params');
94            
95             } else {
96            
97             my $params =()= $node->findnodes('child::params/child::param');
98             my $vals =()= $node->findnodes('child::params/child::param/child::value');
99              
100             if($vals < $params)
101             {
102             return
103             [
104             POE::Filter::XML::RPC::Response->new
105             (
106             POE::Filter::XML::RPC::Fault->new
107             (
108             110,
109             'Malformed XML-RPC: No value tag within param'
110             )
111             )
112             ];
113             }
114             }
115            
116             return [bless($node, 'POE::Filter::XML::RPC::Request')];
117            
118             } elsif ($node->nodeName() eq 'methodResponse') {
119            
120             if(!$node->exists('child::params') and !$node->exists('child::fault'))
121             {
122             return
123             [
124             POE::Filter::XML::RPC::Response->new
125             (
126             POE::Filter::XML::RPC::Fault->new
127             (
128             104,
129             'Malformed XML-RPC: Response does not contain ' .
130             'parameters or a fault object'
131             )
132             )
133             ]
134            
135             } elsif($node->exists('child::params')) {
136            
137             my $params =()= $node->findnodes('child::params/child::param');
138              
139             if(!$params)
140             {
141             return
142             [
143             POE::Filter::XML::RPC::Response->new
144             (
145             POE::Filter::XML::RPC::Fault->new
146             (
147             105,
148             'Malformed XML-RPC: Return parameters does ' .
149             'not contain any param children'
150             )
151             )
152             ];
153            
154             }
155            
156             my $node_count =()= $node->findnodes('child::params/child::*');
157            
158             if($node_count > $params)
159             {
160             return
161             [
162             POE::Filter::XML::RPC::Response->new
163             (
164             POE::Filter::XML::RPC::Fault->new
165             (
166             108,
167             'Malformed XML-RPC: Params object ' .
168             'contains children other than param'
169             )
170             )
171             ];
172             }
173              
174             my $value_count =()= $node->findnodes('child::params/child::param/child::value');
175            
176             if($value_count < $params)
177             {
178             return
179             [
180             POE::Filter::XML::RPC::Response->new
181             (
182             POE::Filter::XML::RPC::Fault->new
183             (
184             109,
185             'Malformed XML-RPC: Param child does '.
186             'not contain a value object'
187             )
188             )
189             ];
190             }
191            
192             } elsif($node->exists('child::fault')) {
193              
194             if(!$node->exists('child::fault/child::value'))
195             {
196             return
197             [
198             POE::Filter::XML::RPC::Response->new
199             (
200             POE::Filter::XML::RPC::Fault->new
201             (
202             106,
203             'Malformed XML-RPC: Fault value is not a ' .
204             'valid struct object'
205             )
206             )
207             ];
208             }
209            
210             if(!$node->exists('child::fault/child::value/child::struct'))
211             {
212             return
213             [
214             POE::Filter::XML::RPC::Response->new
215             (
216             POE::Filter::XML::RPC::Fault->new
217             (
218             106,
219             'Malformed XML-RPC: Fault value is not a ' .
220             'valid struct object'
221             )
222             )
223             ];
224            
225             }
226            
227             my $code = $node->findvalue('child::fault/child::value/child::struct/child::member[child::name/child::text() = "faultCode"]/child::value/child::*/child::text()');
228             my $string = $node->findvalue('child::fault/child::value/child::struct/child::member[child::name/child::text() = "faultString"]/child::value/child::*/child::text()');
229              
230             if(!defined($code) or !defined($string) or !length($code) or !length($string))
231             {
232             return
233             [
234             POE::Filter::XML::RPC::Response->new
235             (
236             POE::Filter::XML::RPC::Fault->new
237             (
238             107,
239             'Malformed XML-RPC: Fault value does not ' .
240             'contain either a fault code or fault string'
241             )
242             )
243             ];
244             }
245             }
246            
247             return [bless($node, 'POE::Filter::XML::RPC::Response')];
248            
249             } else {
250            
251             return
252             [
253             POE::Filter::XML::RPC::Response->new
254             (
255             POE::Filter::XML::RPC::Fault->new
256             (
257             101,
258             'Malformed XML-RPC: Top level node is not valid'
259             )
260             )
261             ];
262             }
263            
264             } else {
265              
266             return [];
267             }
268             }
269              
270             sub put()
271             {
272             my ($self, $nodes) = @_;
273            
274             my $ret = [];
275              
276             foreach my $node (@$nodes)
277             {
278             push(@$ret, bless($node, 'POE::Filter::XML::Node'));
279             }
280            
281             return $ret;
282             }
283              
284             =pod
285              
286             =head1 NAME
287              
288             POE::Filter::XML::RPC - A POE Filter for marshalling XML-RPC
289              
290             =head1 SYNOPSIS
291              
292             use POE::Filter::XML::RPC;
293             use POE::Filter::XML::RPC::Request;
294             use POE::Filter::XML::RPC::Response;
295             use POE::Filter::XML::RPC::Fault;
296             use POE::Filter::XML::RPC::Value;
297              
298             my $filter = POE::Filter::XML::RPC->new();
299              
300             # Build/send a request
301             my $request = POE::Filter::XML::RPC::Request->new
302             (
303             'server_method',
304             POE::Filter::XML::RPC::Value->new({'NamedArgument' => 42})
305             );
306              
307             $filter->put($request);
308              
309             # Build/send a response
310              
311             my $reponse = POE::Filter::XML::RPC::Response->new
312             (
313             POE::Filter::XML::RPC::Value->new([qw/somevalue1 somevalue2/])
314             );
315              
316             $filter->put($reponse);
317              
318             =head1 DESCRIPTION
319              
320             POE::Filter::XML::RPC builds upon the work of POE::Filter::XML to parse XML-RPC
321             datagrams and deliver useful objects for the end developer.
322              
323             This filter is expected to be used in a chain of filters where it will receive
324             POE::Filter::XML::Nodes on input and output.
325              
326             =head1 PUBLIC METHODS
327              
328             There are no public methods outside of the implemented POE::Filter API
329              
330             =head1 NOTES
331              
332             Response, Request, Fault, and Value are based on POE::Filter::XML::Node. See
333             their individual PODs for more information.
334              
335             This filter only implements part of the XMLRPC spec[1], the HTTP portion is not
336             accounted for within this filter and in fact, only concerns itself with
337             POE::Filter::XML::Nodes received or sent.
338              
339             [1]: http://www.xmlrpc.com/spec
340              
341             =head1 AUTHOR
342              
343             Copyright 2009 Nicholas Perez.
344             Licensed and distributed under the GPL.
345              
346             =cut
347              
348             1;