line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
package JRPC::Apache2; |
3
|
1
|
|
|
1
|
|
860
|
use JRPC; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
32
|
|
4
|
1
|
|
|
1
|
|
4
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
25
|
|
5
|
1
|
|
|
1
|
|
3
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
17
|
|
6
|
1
|
|
|
1
|
|
218
|
use Apache2::RequestRec (); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
use Apache2::RequestIO (); |
8
|
|
|
|
|
|
|
# qw(OK) |
9
|
|
|
|
|
|
|
use Apache2::Const -compile => qw(:common); # 'OK', 'DECLINED' |
10
|
|
|
|
|
|
|
use APR::Table (); |
11
|
|
|
|
|
|
|
use JSON::XS; |
12
|
|
|
|
|
|
|
use JRPC; # Import ... ? |
13
|
|
|
|
|
|
|
*jdie = JRPC::createfault; |
14
|
|
|
|
|
|
|
#use Storable (); # Would import store - do not want that. |
15
|
|
|
|
|
|
|
# For Global Request (PerlOptions +GlobalRequest) |
16
|
|
|
|
|
|
|
#use Apache2::RequestUtil; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 NAME |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
JRPC::Apache2 - JSON-RPC Services in Apache2 / mod_perl runtime |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 DESCRIPTION |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
This package is a mod_perl JSON-RPC handler / dispatcher. It only contains the conventional mod_perl handler($r) callback method |
25
|
|
|
|
|
|
|
(see mod_perl documentation for details: http://perl.apache.org/docs/2.0/user/config/config.html ). |
26
|
|
|
|
|
|
|
Do not call the handler() method directly, but assign it to be used as a mod_perl handler (Servicpackage "Math" is used here for an example): |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# Load Service Package (for JRPC::Apache2 to use) |
29
|
|
|
|
|
|
|
PerlModule Math; |
30
|
|
|
|
|
|
|
# Assign directly to a URL Location / path by |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
SetHandler modperl |
33
|
|
|
|
|
|
|
PerlResponseHandler JRPC::Apache2 |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=cut |
37
|
|
|
|
|
|
|
# Parse and handle JSON-RPC Request. |
38
|
|
|
|
|
|
|
# reads POST body by $r->read($buffer, $len). |
39
|
|
|
|
|
|
|
# if/else dispatching (of 3 meth) gives slight edge compared to |
40
|
|
|
|
|
|
|
# non-cached brute force method resolution (~770 vs. ~740) |
41
|
|
|
|
|
|
|
#if ($m eq 'add') {$resp = add($p);} |
42
|
|
|
|
|
|
|
#elsif ($m eq 'store') {$resp = store($p);} |
43
|
|
|
|
|
|
|
#elsif ($m eq 'multiply') {$resp = multiply($p);} |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub handler { |
46
|
|
|
|
|
|
|
my ($r) = @_; |
47
|
|
|
|
|
|
|
if ($r->method() ne 'POST') {return(Apache2::Const::DECLINED);} # 1 illegal |
48
|
|
|
|
|
|
|
my $hdrs_in = $r->headers_in(); |
49
|
|
|
|
|
|
|
my $hdrs_out = $r->headers_out(); |
50
|
|
|
|
|
|
|
my $buffer = '';my $len = 8000; # TODO: Grab _actual_ content-length |
51
|
|
|
|
|
|
|
my $cnt = $r->read($buffer, $len); |
52
|
|
|
|
|
|
|
#NA:my $hdlr = $r->handler(); # Returns String ("modperl") |
53
|
|
|
|
|
|
|
$r->content_type('text/plain'); |
54
|
|
|
|
|
|
|
##################################### |
55
|
|
|
|
|
|
|
my $jresp = {'id' => $$, 'jsonrpc' => '2.0', }; # Set up dummy |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
eval { |
58
|
|
|
|
|
|
|
if (!$cnt) {die("JSON-RPC Request body is Empty (-32700)");} |
59
|
|
|
|
|
|
|
# Parse Request |
60
|
|
|
|
|
|
|
my $j = eval { JRPC::parse($buffer); }; # |
61
|
|
|
|
|
|
|
if ($@) {die("Error Parsing JSON-RPC Request: $@");} |
62
|
|
|
|
|
|
|
if (defined($JRPC::prelogger) && (ref($JRPC::prelogger) eq 'CODE')) {$JRPC::prelogger->($j);} |
63
|
|
|
|
|
|
|
my $p = $j->{'params'}; |
64
|
|
|
|
|
|
|
my $m = $j->{'method'}; |
65
|
|
|
|
|
|
|
$jresp->{'id'} = $j->{'id'}; |
66
|
|
|
|
|
|
|
#my $res = {}; # Result |
67
|
|
|
|
|
|
|
my $f;my $mid = 0; |
68
|
|
|
|
|
|
|
if ($m =~ /\./) {$f = JRPC::methresolve_dotnot($r, $m);$mid=1;} |
69
|
|
|
|
|
|
|
else {my $f = JRPC::methresolve($r, $m);} |
70
|
|
|
|
|
|
|
if (!$f) {die("method '$m' not resolved (-32601) mid=$mid");} |
71
|
|
|
|
|
|
|
##### reqinit |
72
|
|
|
|
|
|
|
#if (my $f = $pkg->can('reqinit')) {$f->($p, $j);} |
73
|
|
|
|
|
|
|
##### Execute, store result |
74
|
|
|
|
|
|
|
my $res = eval { $f->($p); }; # Dispatch (catching any exceptions) |
75
|
|
|
|
|
|
|
if ($@) {die("Error in processing JRPC method '$m' (-32603): $@");} |
76
|
|
|
|
|
|
|
# Definite Success - serialize response ? |
77
|
|
|
|
|
|
|
$jresp->{'result'} = $res; |
78
|
|
|
|
|
|
|
###### Respond |
79
|
|
|
|
|
|
|
#my $clen = $hdrs_in->get('content-length'); # Double verify read() |
80
|
|
|
|
|
|
|
# 'clen' => $clen, 'postread' => $cnt, |
81
|
|
|
|
|
|
|
# There could be blessed nodes in $res ('result' now) that do not serialize |
82
|
|
|
|
|
|
|
# well. Be ready to encounter exceptions here. |
83
|
|
|
|
|
|
|
DEBUG: $jresp->{'APAOK'} = Apache2::Const::OK; |
84
|
|
|
|
|
|
|
my $out = eval { encode_json($jresp); }; # Serialize as a separate step to know length |
85
|
|
|
|
|
|
|
if ($@) {die("Error Forming the response: $@");} |
86
|
|
|
|
|
|
|
########################## |
87
|
|
|
|
|
|
|
$hdrs_out->{'content-length'} = length($out); # Raw assignment ? |
88
|
|
|
|
|
|
|
$r->print($out); |
89
|
|
|
|
|
|
|
}; |
90
|
|
|
|
|
|
|
if ($@) { |
91
|
|
|
|
|
|
|
$r->print( JRPC::createfault($jresp, $@, 500) ); |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
return Apache2::Const::OK; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
#$r->err_headers_out->add('Set-Cookie' => $cookie); |
96
|
|
|
|
|
|
|
#$r->print(encode_json($j)); |
97
|
|
|
|
|
|
|
1; |
98
|
|
|
|
|
|
|
|