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   147951 use Mojo::Base 'Mojolicious::Plugin';
  3         412043  
  3         81  
4 3     3   2387 use Carp;
  3         7  
  3         226  
5              
6             our $VERSION = 'v2.0.4';
7              
8 3     3   2186 use JSON::XS;
  3         13087  
  3         213  
9             # to ensure callback runs on notification
10 3     3   1081 use JSON::RPC2::Server 0.004000;
  3         6265  
  3         166  
11              
12 3     3   25 use constant TIMEOUT => 5*60; # sec
  3         7  
  3         192  
13 3     3   20 use constant HTTP_200 => 200;
  3         7  
  3         128  
14 3     3   17 use constant HTTP_204 => 204;
  3         8  
  3         131  
15 3     3   18 use constant HTTP_415 => 415;
  3         6  
  3         2262  
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 47 my ($self, $app, $conf) = @_;
26              
27 1     1   11 $app->helper(jsonrpc2_headers => sub { return %HEADERS });
  1         487  
28              
29 1     6   150 $app->routes->add_shortcut(jsonrpc2 => sub { _shortcut('POST', @_) });
  6         2072  
30 1     3   89 $app->routes->add_shortcut(jsonrpc2_get => sub { _shortcut('GET', @_) });
  3         1533  
31              
32 1         51 return;
33             }
34              
35             sub _shortcut {
36 9     9   26 my ($method, $r, $path, $server) = @_;
37 9 100 100     122 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   30 return $r->any([$method] => $path, [format => 0], sub { _srv($server, @_) });
  15         229451  
40             }
41              
42             sub _srv {
43 15     15   36 my ($server, $c) = @_;
44              
45 15 100 100     44 if (($c->req->headers->content_type // q{}) !~ /$HEADERS{'Content-Type'}/ms) {
46 5         158 return $c->render(status => HTTP_415, data => q{});
47             }
48 10 100 50     337 if (($c->req->headers->accept // q{}) !~ /$HEADERS{'Accept'}/ms) {
49 2         65 return $c->render(status => HTTP_415, data => q{});
50             }
51              
52 8         230 $c->res->headers->content_type($Type);
53 8         184 $c->render_later;
54              
55 8   100     160 my $timeout = $c->stash('jsonrpc2.timeout') || TIMEOUT;
56 8         128 $c->inactivity_timeout($timeout);
57              
58 8         537 my $request;
59 8 100       26 if ($c->req->method eq 'GET') {
60 2         32 $request = $c->req->query_params->to_hash;
61 2 100       518 if (exists $request->{params}) {
62 1         3 $request->{params} = eval { decode_json($request->{params}) };
  1         12  
63             }
64             } else {
65 6         76 $request = eval { decode_json($c->req->body) };
  6         15  
66             }
67              
68             $server->execute($request, sub {
69 7     7   501372 my ($json_response) = @_;
70 7 100       24 my $status = $json_response ? HTTP_200 : HTTP_204;
71 7         36 $c->render(status => $status, data => $json_response);
72 8         256 });
73              
74 8         2398 return;
75             }
76              
77              
78             1; # Magic true value required at end of module
79             __END__