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   143868 use Mojo::Base 'Mojolicious::Plugin';
  3         402743  
  3         22  
4 3     3   2284 use Carp;
  3         6  
  3         241  
5              
6             our $VERSION = 'v2.0.3';
7              
8 3     3   2140 use JSON::XS;
  3         12459  
  3         208  
9             # to ensure callback runs on notification
10 3     3   1043 use JSON::RPC2::Server 0.004000;
  3         6066  
  3         106  
11              
12 3     3   20 use constant TIMEOUT => 5*60; # sec
  3         6  
  3         179  
13 3     3   19 use constant HTTP_200 => 200;
  3         6  
  3         132  
14 3     3   16 use constant HTTP_204 => 204;
  3         6  
  3         129  
15 3     3   17 use constant HTTP_415 => 415;
  3         7  
  3         2265  
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 44 my ($self, $app, $conf) = @_;
26              
27 1     1   12 $app->helper(jsonrpc2_headers => sub { return %HEADERS });
  1         490  
28              
29 1     6   147 $app->routes->add_shortcut(jsonrpc2 => sub { _shortcut('POST', @_) });
  6         2137  
30 1     3   90 $app->routes->add_shortcut(jsonrpc2_get => sub { _shortcut('GET', @_) });
  3         1643  
31              
32 1         65 return;
33             }
34              
35             sub _shortcut {
36 9     9   24 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   32 return $r->any([$method] => $path, [format => 0], sub { _srv($server, @_) });
  15         252465  
40             }
41              
42             sub _srv {
43 15     15   40 my ($server, $c) = @_;
44              
45 15 100 100     67 if (($c->req->headers->content_type // q{}) !~ /$HEADERS{'Content-Type'}/ms) {
46 5         177 return $c->render(status => HTTP_415, data => q{});
47             }
48 10 100 50     401 if (($c->req->headers->accept // q{}) !~ /$HEADERS{'Accept'}/ms) {
49 2         71 return $c->render(status => HTTP_415, data => q{});
50             }
51              
52 8         247 $c->res->headers->content_type($Type);
53 8         190 $c->render_later;
54              
55 8   100     191 my $timeout = $c->stash('jsonrpc2.timeout') || TIMEOUT;
56 8         146 $c->inactivity_timeout($timeout);
57              
58 8         743 my $request;
59 8 100       28 if ($c->req->method eq 'GET') {
60 2         33 $request = $c->req->query_params->to_hash;
61 2 100       530 if (exists $request->{params}) {
62 1         3 $request->{params} = eval { decode_json($request->{params}) };
  1         12  
63             }
64             } else {
65 6         93 $request = eval { decode_json($c->req->body) };
  6         23  
66             }
67              
68             $server->execute($request, sub {
69 7     7   501554 my ($json_response) = @_;
70 7 100       24 my $status = $json_response ? HTTP_200 : HTTP_204;
71 7         41 $c->render(status => $status, data => $json_response);
72 8         347 });
73              
74 8         2719 return;
75             }
76              
77              
78             1; # Magic true value required at end of module
79             __END__