File Coverage

blib/lib/Mojolicious/Plugin/JSONRPC2.pm
Criterion Covered Total %
statement 58 58 100.0
branch 14 14 100.0
condition 8 9 88.8
subroutine 16 16 100.0
pod 1 1 100.0
total 97 98 98.9


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::JSONRPC2;
2              
3 3     3   142170 use Mojo::Base 'Mojolicious::Plugin';
  3         408377  
  3         30  
4 3     3   2565 use Carp;
  3         8  
  3         240  
5              
6             our $VERSION = 'v2.0.2';
7              
8 3     3   2167 use JSON::XS;
  3         13006  
  3         214  
9             # to ensure callback runs on notification
10 3     3   1013 use JSON::RPC2::Server 0.004000;
  3         6067  
  3         116  
11              
12 3     3   23 use constant TIMEOUT => 5*60; # sec
  3         6  
  3         190  
13 3     3   17 use constant HTTP_200 => 200;
  3         7  
  3         136  
14 3     3   18 use constant HTTP_204 => 204;
  3         7  
  3         132  
15 3     3   18 use constant HTTP_415 => 415;
  3         7  
  3         2158  
16              
17             my $Type = 'application/json';
18             my %HEADERS = (
19             'Content-Type' => qr{\A\s*\Q$Type\E\s*(?:;|\z)}msi,
20             'Accept' => qr{(?:\A|,)\s*\Q$Type\E\s*(?:[;,]|\z)}msi,
21             );
22              
23              
24             sub register {
25 1     1 1 45 my ($self, $app, $conf) = @_;
26              
27 1     1   12 $app->helper(jsonrpc2_headers => sub { return %HEADERS });
  1         497  
28              
29 1     6   150 $app->routes->add_shortcut(jsonrpc2 => sub { _shortcut('POST', @_) });
  6         2088  
30 1     3   89 $app->routes->add_shortcut(jsonrpc2_get => sub { _shortcut('GET', @_) });
  3         1703  
31              
32 1         48 return;
33             }
34              
35             sub _shortcut {
36 9     9   24 my ($method, $r, $path, $server) = @_;
37 9 100 100     124 croak 'usage: $r->jsonrpc2'.($method eq 'GET' ? '_get' : q{}).'("/rpc/path", JSON::RPC2::Server->new)'
    100          
38             if !(ref $server && $server->isa('JSON::RPC2::Server'));
39 5     15   32 return $r->any([$method] => $path, [format => 0], sub { _srv($server, @_) });
  15         239938  
40             }
41              
42             sub _srv {
43 15     15   44 my ($server, $c) = @_;
44              
45 15 100 100     56 if (($c->req->headers->content_type // q{}) !~ /$HEADERS{'Content-Type'}/ms) {
46 5         169 return $c->render(status => HTTP_415, data => q{});
47             }
48 10 100 50     373 if (($c->req->headers->accept // q{}) !~ /$HEADERS{'Accept'}/ms) {
49 2         58 return $c->render(status => HTTP_415, data => q{});
50             }
51              
52 8         240 $c->res->headers->content_type($Type);
53 8         248 $c->render_later;
54              
55 8   100     230 my $timeout = $c->stash('jsonrpc2.timeout') || TIMEOUT;
56 8         173 $c->inactivity_timeout($timeout);
57              
58 8         634 my $request;
59 8 100       28 if ($c->req->method eq 'GET') {
60 2         37 $request = $c->req->query_params->to_hash;
61 2 100       525 if (exists $request->{params}) {
62 1         3 $request->{params} = eval { decode_json($request->{params}) };
  1         16  
63             }
64             } else {
65 6         85 $request = eval { decode_json($c->req->body) };
  6         19  
66             }
67              
68             $server->execute($request, sub {
69 7     7   501614 my ($json_response) = @_;
70 7 100       31 my $status = $json_response ? HTTP_200 : HTTP_204;
71 7         37 $c->render(status => $status, data => $json_response);
72 8         311 });
73              
74 8         2535 return;
75             }
76              
77              
78             1; # Magic true value required at end of module
79             __END__