File Coverage

blib/lib/Lim/RPC/Protocol/REST.pm
Criterion Covered Total %
statement 31 111 27.9
branch 0 46 0.0
condition 0 12 0.0
subroutine 11 17 64.7
pod 5 5 100.0
total 47 191 24.6


line stmt bran cond sub pod time code
1             package Lim::RPC::Protocol::REST;
2              
3 3     3   5999 use common::sense;
  3         6  
  3         29  
4              
5 3     3   175 use Scalar::Util qw(blessed weaken);
  3         7  
  3         231  
6              
7 3     3   18 use HTTP::Status qw(:constants);
  3         8  
  3         1928  
8 3     3   20 use HTTP::Request ();
  3         7  
  3         60  
9 3     3   16 use HTTP::Response ();
  3         7  
  3         47  
10 3     3   19 use JSON::XS ();
  3         6  
  3         52  
11              
12 3     3   21 use Lim ();
  3         14  
  3         55  
13 3     3   17 use Lim::Util ();
  3         8  
  3         45  
14 3     3   1895 use Lim::RPC::Callback ();
  3         8  
  3         75  
15              
16 3     3   19 use base qw(Lim::RPC::Protocol);
  3         6  
  3         8994  
17              
18             =encoding utf8
19              
20             =head1 NAME
21              
22             ...
23              
24             =head1 VERSION
25              
26             See L for version.
27              
28             =cut
29              
30             our $VERSION = $Lim::VERSION;
31             our $JSON = JSON::XS->new->ascii->convert_blessed;
32             our %REST_CRUD = (
33             GET => 'READ',
34             POST => 'UPDATE',
35             PUT => 'CREATE',
36             DELETE => 'DELETE'
37             );
38              
39             =head1 SYNOPSIS
40              
41             ...
42              
43             =head1 SUBROUTINES/METHODS
44              
45             =head2 Init
46              
47             =cut
48              
49 0     0 1 0 sub Init {
50             }
51              
52             =head2 Destroy
53              
54             =cut
55              
56 0     0 1 0 sub Destroy {
57             }
58              
59             =head2 name
60              
61             =cut
62              
63             sub name {
64 2     2 1 10 'rest';
65             }
66              
67             =head2 serve
68              
69             =cut
70              
71 0     0 1   sub serve {
72             }
73              
74             =head2 handle
75              
76             =cut
77              
78             sub handle {
79 0     0 1   my ($self, $cb, $request) = @_;
80            
81 0 0 0       unless (blessed($request) and $request->isa('HTTP::Request')) {
82 0           return;
83             }
84              
85 0 0         if ($request->uri =~ /^\/([a-zA-Z]+)\/([a-zA-Z_]+)(?:\/([^\?]*)){0,1}/o) {
86 0           my ($module, $function, $parameters) = ($1, $2, $3);
87 0           my $response = HTTP::Response->new;
88 0           $response->request($request);
89 0           $response->protocol($request->protocol);
90            
91 0           $module = lc($module);
92 0           my $server = $self->server;
93 0 0 0       if (defined $server and $server->have_module($module)) {
94 0           my ($method, $call);
95            
96 0 0         if (exists $REST_CRUD{$request->method}) {
97 0           $method = lc($REST_CRUD{$request->method});
98             }
99             else {
100 0           $method = lc($request->method);
101             }
102 0           $function = lc($function);
103 0           $call = ucfirst($method).Lim::Util::Camelize($function);
104              
105 0           my $obj;
106 0 0         if ($server->have_module_call($module, $call)) {
107 0           $obj = $server->module_obj_by_protocol($module, $self->name);
108             }
109            
110 0           my ($query, $jsonp);
111 0 0         if (defined $obj) {
112 0 0         Lim::DEBUG and $self->{logger}->debug('API call ', $module, '->', $call, '()');
113            
114 0 0         if ($request->header('Content-Type') =~ /(?:^|\s)application\/x-www-form-urlencoded(?:$|\s|;)/o) {
    0          
115 0           my $query_str = $request->content;
116 0           $query_str =~ s/[\015\012]+$//o;
117              
118 0           $query = Lim::Util::QueryDecode($query_str);
119             }
120             elsif ($request->header('Content-Type') =~ /(?:^|\s)application\/json(?:$|\s|;)/o) {
121 0           eval {
122 0           $query = $JSON->decode($request->content);
123             };
124 0 0         if ($@) {
125 0           $response->code(HTTP_INTERNAL_SERVER_ERROR);
126 0           undef($query);
127 0           undef($obj);
128             }
129             }
130             else {
131 0           $query = Lim::Util::QueryDecode($request->uri->query);
132             }
133            
134 0           $jsonp = delete $query->{jsonpCallback};
135            
136 0 0         if (defined $parameters) {
137 0           my $redirect_call = $server->process_module_call_uri_map($module, $call, $parameters, $query);
138            
139 0 0 0       if (defined $redirect_call and $redirect_call) {
140 0 0         Lim::DEBUG and $self->{logger}->debug('API call redirected ', $call, ' => ', $redirect_call);
141 0           $call = $redirect_call;
142             }
143             }
144             }
145            
146 0 0         if (defined $obj) {
147 0           my $real_self = $self;
148 0           weaken($self);
149             $obj->$call(Lim::RPC::Callback->new(
150             cb => sub {
151 0     0     my ($result) = @_;
152            
153 0 0         unless (defined $self) {
154 0           return;
155             }
156            
157 0 0 0       if (blessed $result and $result->isa('Lim::Error')) {
    0          
158 0           $response->code($result->code);
159 0           eval {
160 0           $response->content($JSON->encode($result));
161             };
162 0 0         if ($@) {
163 0           $response->code(HTTP_INTERNAL_SERVER_ERROR);
164 0 0         Lim::WARN and $self->{logger}->warn('JSON encode error: ', $@);
165             }
166             else {
167 0           $response->header(
168             'Content-Type' => 'application/json; charset=utf-8',
169             'Cache-Control' => 'no-cache',
170             'Pragma' => 'no-cache'
171             );
172              
173 0 0         if (defined $jsonp) {
174 0           $response->content($jsonp.'('.$response->content().');');
175 0           $response->header('Content-Type' => 'application/javascript; charset=utf-8');
176             }
177             }
178             }
179             elsif (ref($result) eq 'HASH') {
180 0           eval {
181 0           $response->content($JSON->encode($result));
182             };
183 0 0         if ($@) {
184 0           $response->code(HTTP_INTERNAL_SERVER_ERROR);
185 0 0         Lim::WARN and $self->{logger}->warn('JSON encode error: ', $@);
186             }
187             else {
188 0           $response->header(
189             'Content-Type' => 'application/json; charset=utf-8',
190             'Cache-Control' => 'no-cache',
191             'Pragma' => 'no-cache'
192             );
193 0           $response->code(HTTP_OK);
194              
195 0 0         if (defined $jsonp) {
196 0           $response->content($jsonp.'('.$response->content().');');
197 0           $response->header('Content-Type' => 'application/javascript; charset=utf-8');
198             }
199             }
200             }
201             else {
202 0           $response->code(HTTP_INTERNAL_SERVER_ERROR);
203             }
204            
205 0           $cb->cb->($response);
206 0           return;
207             },
208             reset_timeout => sub {
209 0     0     $cb->reset_timeout;
210 0           }), $query);
211 0           return 1;
212             }
213             }
214             else {
215 0           return;
216             }
217              
218 0           $cb->cb->($response);
219 0           return 1;
220             }
221 0           return;
222             }
223              
224             =head1 AUTHOR
225              
226             Jerry Lundström, C<< >>
227              
228             =head1 BUGS
229              
230             Please report any bugs or feature requests to L.
231              
232             =head1 SUPPORT
233              
234             You can find documentation for this module with the perldoc command.
235              
236             perldoc Lim
237              
238             You can also look for information at:
239              
240             =over 4
241              
242             =item * Lim issue tracker (report bugs here)
243              
244             L
245              
246             =back
247              
248             =head1 ACKNOWLEDGEMENTS
249              
250             =head1 LICENSE AND COPYRIGHT
251              
252             Copyright 2012-2013 Jerry Lundström.
253              
254             This program is free software; you can redistribute it and/or modify it
255             under the terms of either: the GNU General Public License as published
256             by the Free Software Foundation; or the Artistic License.
257              
258             See http://dev.perl.org/licenses/ for more information.
259              
260              
261             =cut
262              
263             1; # End of Lim::RPC::Protocol::REST