Filename | /var/www/foswikidev/core/lib/Foswiki/Contrib/JsonRpcContrib/Server.pm |
Statements | Executed 34 statements in 1.37ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 1.10ms | 1.31ms | BEGIN@25 | Foswiki::Contrib::JsonRpcContrib::Server::
1 | 1 | 1 | 614µs | 734µs | BEGIN@26 | Foswiki::Contrib::JsonRpcContrib::Server::
1 | 1 | 1 | 16µs | 29µs | BEGIN@19 | Foswiki::Contrib::JsonRpcContrib::Server::
5 | 1 | 1 | 16µs | 16µs | registerMethod | Foswiki::Contrib::JsonRpcContrib::Server::
1 | 1 | 1 | 11µs | 11µs | new | Foswiki::Contrib::JsonRpcContrib::Server::
1 | 1 | 1 | 10µs | 14µs | BEGIN@20 | Foswiki::Contrib::JsonRpcContrib::Server::
1 | 1 | 1 | 10µs | 45µs | BEGIN@28 | Foswiki::Contrib::JsonRpcContrib::Server::
1 | 1 | 1 | 10µs | 22µs | BEGIN@164 | Foswiki::Contrib::JsonRpcContrib::Server::
1 | 1 | 1 | 9µs | 19µs | BEGIN@173 | Foswiki::Contrib::JsonRpcContrib::Server::
1 | 1 | 1 | 9µs | 106µs | BEGIN@22 | Foswiki::Contrib::JsonRpcContrib::Server::
1 | 1 | 1 | 4µs | 4µs | BEGIN@23 | Foswiki::Contrib::JsonRpcContrib::Server::
1 | 1 | 1 | 4µs | 4µs | BEGIN@24 | Foswiki::Contrib::JsonRpcContrib::Server::
0 | 0 | 0 | 0s | 0s | __ANON__[:174] | Foswiki::Contrib::JsonRpcContrib::Server::
0 | 0 | 0 | 0s | 0s | __ANON__[:179] | Foswiki::Contrib::JsonRpcContrib::Server::
0 | 0 | 0 | 0s | 0s | __ANON__[:184] | Foswiki::Contrib::JsonRpcContrib::Server::
0 | 0 | 0 | 0s | 0s | __ANON__[:82] | Foswiki::Contrib::JsonRpcContrib::Server::
0 | 0 | 0 | 0s | 0s | __ANON__[:90] | Foswiki::Contrib::JsonRpcContrib::Server::
0 | 0 | 0 | 0s | 0s | dispatch | Foswiki::Contrib::JsonRpcContrib::Server::
0 | 0 | 0 | 0s | 0s | getHandler | Foswiki::Contrib::JsonRpcContrib::Server::
0 | 0 | 0 | 0s | 0s | writeDebug | Foswiki::Contrib::JsonRpcContrib::Server::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # JSON-RPC for Foswiki | ||||
2 | # | ||||
3 | # Copyright (C) 2011-2015 Michael Daum http://michaeldaumconsulting.com | ||||
4 | # | ||||
5 | # This program is free software; you can redistribute it and/or | ||||
6 | # modify it under the terms of the GNU General Public License | ||||
7 | # as published by the Free Software Foundation; either version 2 | ||||
8 | # of the License, or (at your option) any later version. For | ||||
9 | # more details read LICENSE in the root of this distribution. | ||||
10 | # | ||||
11 | # This program is distributed in the hope that it will be useful, | ||||
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||||
14 | # | ||||
15 | # As per the GPL, removal of this notice is prohibited. | ||||
16 | |||||
17 | package Foswiki::Contrib::JsonRpcContrib::Server; | ||||
18 | |||||
19 | 2 | 29µs | 2 | 41µs | # spent 29µs (16+13) within Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@19 which was called:
# once (16µs+13µs) by Foswiki::Contrib::JsonRpcContrib::getServer at line 19 # spent 29µs making 1 call to Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@19
# spent 13µs making 1 call to strict::import |
20 | 2 | 28µs | 2 | 18µs | # spent 14µs (10+4) within Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@20 which was called:
# once (10µs+4µs) by Foswiki::Contrib::JsonRpcContrib::getServer at line 20 # spent 14µs making 1 call to Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@20
# spent 4µs making 1 call to warnings::import |
21 | |||||
22 | 2 | 29µs | 2 | 204µs | # spent 106µs (9+98) within Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@22 which was called:
# once (9µs+98µs) by Foswiki::Contrib::JsonRpcContrib::getServer at line 22 # spent 106µs making 1 call to Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@22
# spent 98µs making 1 call to Error::import |
23 | 2 | 20µs | 1 | 4µs | # spent 4µs within Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@23 which was called:
# once (4µs+0s) by Foswiki::Contrib::JsonRpcContrib::getServer at line 23 # spent 4µs making 1 call to Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@23 |
24 | 2 | 19µs | 1 | 4µs | # spent 4µs within Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@24 which was called:
# once (4µs+0s) by Foswiki::Contrib::JsonRpcContrib::getServer at line 24 # spent 4µs making 1 call to Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@24 |
25 | 2 | 101µs | 1 | 1.31ms | # spent 1.31ms (1.10+215µs) within Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@25 which was called:
# once (1.10ms+215µs) by Foswiki::Contrib::JsonRpcContrib::getServer at line 25 # spent 1.31ms making 1 call to Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@25 |
26 | 2 | 103µs | 1 | 734µs | # spent 734µs (614+120) within Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@26 which was called:
# once (614µs+120µs) by Foswiki::Contrib::JsonRpcContrib::getServer at line 26 # spent 734µs making 1 call to Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@26 |
27 | |||||
28 | 2 | 501µs | 2 | 80µs | # spent 45µs (10+35) within Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@28 which was called:
# once (10µs+35µs) by Foswiki::Contrib::JsonRpcContrib::getServer at line 28 # spent 45µs making 1 call to Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@28
# spent 35µs making 1 call to constant::import |
29 | |||||
30 | # Error codes for json-rpc response | ||||
31 | # -32700: Parse error - Invalid JSON was received by the server. | ||||
32 | # -32600: Invalid Request - The JSON sent is not a valid Request object. | ||||
33 | # -32601: Method not found - The method does not exist / is not available. | ||||
34 | # -32602: Invalid params - Invalid method parameter(s). | ||||
35 | # -32603: Internal error - Internal JSON-RPC error. | ||||
36 | # -32099 to -32000: Server error - Reserved for implementation-defined server-errors. | ||||
37 | # 0: ok | ||||
38 | # 1: unknown error | ||||
39 | # 401: access denied | ||||
40 | # 404: topic not found | ||||
41 | |||||
42 | ################################################################################ | ||||
43 | # static | ||||
44 | sub writeDebug { | ||||
45 | Foswiki::Func::writeDebug '- JsonRpcContrib::Server - ' . $_[0]; | ||||
46 | } | ||||
47 | |||||
48 | ################################################################################ | ||||
49 | # constructor | ||||
50 | # spent 11µs within Foswiki::Contrib::JsonRpcContrib::Server::new which was called:
# once (11µs+0s) by Foswiki::Contrib::JsonRpcContrib::getServer at line 42 of /var/www/foswikidev/core/lib/Foswiki/Contrib/JsonRpcContrib.pm | ||||
51 | 1 | 700ns | my $class = shift; | ||
52 | |||||
53 | 1 | 8µs | my $this = bless( {}, $class ); | ||
54 | |||||
55 | 1 | 6µs | return $this; | ||
56 | } | ||||
57 | |||||
58 | ################################################################################ | ||||
59 | # spent 16µs within Foswiki::Contrib::JsonRpcContrib::Server::registerMethod which was called 5 times, avg 3µs/call:
# 5 times (16µs+0s) by Foswiki::Contrib::JsonRpcContrib::registerMethod at line 31 of /var/www/foswikidev/core/lib/Foswiki/Contrib/JsonRpcContrib.pm, avg 3µs/call | ||||
60 | 5 | 4µs | my ( $this, $namespace, $method, $fnref, $options ) = @_; | ||
61 | |||||
62 | writeDebug("registerMethod($namespace, $method, $fnref)") if TRACE; | ||||
63 | |||||
64 | 5 | 18µs | $this->{handler}{$namespace}{$method} = { | ||
65 | function => $fnref, | ||||
66 | options => $options | ||||
67 | }; | ||||
68 | } | ||||
69 | |||||
70 | ################################################################################ | ||||
71 | sub dispatch { | ||||
72 | my ( $this, $session ) = @_; | ||||
73 | |||||
74 | writeDebug("called dispatch") if TRACE; | ||||
75 | |||||
76 | $Foswiki::Plugins::SESSION = $session; | ||||
77 | $this->{session} = $session; | ||||
78 | |||||
79 | my $request; | ||||
80 | try { | ||||
81 | $request = new Foswiki::Contrib::JsonRpcContrib::Request($session); | ||||
82 | } | ||||
83 | catch Foswiki::Contrib::JsonRpcContrib::Error with { | ||||
84 | my $error = shift; | ||||
85 | Foswiki::Contrib::JsonRpcContrib::Response->print( | ||||
86 | $session, | ||||
87 | code => $error->{code}, | ||||
88 | message => $error->{message} | ||||
89 | ); | ||||
90 | }; | ||||
91 | return unless defined $request; | ||||
92 | |||||
93 | # get topic parameter and set the location overriding any | ||||
94 | # other value derived from the namespace param | ||||
95 | my $topic = $request->param('topic') | ||||
96 | || $Foswiki::cfg{HomeTopicName}; | ||||
97 | ( $session->{webName}, $session->{topicName} ) = | ||||
98 | Foswiki::Func::normalizeWebTopicName( $Foswiki::cfg{UsersWebName}, | ||||
99 | $topic ); | ||||
100 | writeDebug("topic=$topic") if TRACE; | ||||
101 | |||||
102 | # get handler for this namespace | ||||
103 | my $handler = $this->getHandler($request); | ||||
104 | unless ( defined $handler ) { | ||||
105 | Foswiki::Contrib::JsonRpcContrib::Response->print( | ||||
106 | $session, | ||||
107 | code => -32601, | ||||
108 | message => "Invalid invocation - unknown handler for " | ||||
109 | . $request->namespace() . "." | ||||
110 | . $request->method(), | ||||
111 | id => $request->id() | ||||
112 | ); | ||||
113 | return; | ||||
114 | } | ||||
115 | |||||
116 | # if there's login info, try and apply it | ||||
117 | my $userName = $request->param('username'); | ||||
118 | if ($userName) { | ||||
119 | writeDebug("checking password for $userName") if TRACE; | ||||
120 | my $pass = $request->param('password') || ''; | ||||
121 | unless ( $session->{users}->checkPassword( $userName, $pass ) ) { | ||||
122 | Foswiki::Contrib::JsonRpcContrib::Response->print( | ||||
123 | $session, | ||||
124 | code => 401, | ||||
125 | message => "Access denied", | ||||
126 | id => $request->id() | ||||
127 | ); | ||||
128 | return; | ||||
129 | } | ||||
130 | |||||
131 | my $cUID = $session->{users}->getCanonicalUserID($userName); | ||||
132 | my $wikiName = $session->{users}->getWikiName($cUID); | ||||
133 | $session->{users}->getLoginManager() | ||||
134 | ->userLoggedIn( $userName, $wikiName ); | ||||
135 | } | ||||
136 | |||||
137 | # validate the request | ||||
138 | if ( $handler->{validate} ) { | ||||
139 | my $nonce = $request->param('validation_key'); | ||||
140 | if ( | ||||
141 | !defined($nonce) | ||||
142 | || !Foswiki::Validation::isValidNonce( | ||||
143 | $session->getCGISession(), $nonce | ||||
144 | ) | ||||
145 | ) | ||||
146 | { | ||||
147 | Foswiki::Contrib::JsonRpcContrib::Response->print( | ||||
148 | $session, | ||||
149 | code => -32600, | ||||
150 | message => "Invalid validation code", | ||||
151 | id => $request->id() | ||||
152 | ); | ||||
153 | return; | ||||
154 | } | ||||
155 | } | ||||
156 | |||||
157 | Foswiki::Func::writeEvent( 'jsonrpc', | ||||
158 | $request->namespace() . ' ' . $request->method() ); | ||||
159 | |||||
160 | # call | ||||
161 | my $code = 0; | ||||
162 | my $result; | ||||
163 | try { | ||||
164 | 2 | 69µs | 2 | 34µs | # spent 22µs (10+12) within Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@164 which was called:
# once (10µs+12µs) by Foswiki::Contrib::JsonRpcContrib::getServer at line 164 # spent 22µs making 1 call to Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@164
# spent 12µs making 1 call to strict::unimport |
165 | my $function = $handler->{function}; | ||||
166 | writeDebug( "calling handler for " | ||||
167 | . $request->namespace . "." | ||||
168 | . $request->method ) | ||||
169 | if TRACE; | ||||
170 | $result = | ||||
171 | &$function( $session, $request, $session->{response}, | ||||
172 | $handler->{options} ); | ||||
173 | 2 | 435µs | 2 | 28µs | # spent 19µs (9+9) within Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@173 which was called:
# once (9µs+9µs) by Foswiki::Contrib::JsonRpcContrib::getServer at line 173 # spent 19µs making 1 call to Foswiki::Contrib::JsonRpcContrib::Server::BEGIN@173
# spent 10µs making 1 call to strict::import |
174 | } | ||||
175 | catch Foswiki::Contrib::JsonRpcContrib::Error with { | ||||
176 | my $error = shift; | ||||
177 | $result = $error->{message}; | ||||
178 | $code = $error->{code}; | ||||
179 | } | ||||
180 | catch Error::Simple with { | ||||
181 | my $error = shift; | ||||
182 | $result = $error->{-text}; | ||||
183 | $code = 1; # unknown error | ||||
184 | }; | ||||
185 | |||||
186 | # finally | ||||
187 | my $redirectto = $request->param('redirectto'); | ||||
188 | if ( $code == 0 && defined $redirectto ) { | ||||
189 | my $url; | ||||
190 | if ( $redirectto =~ /^https?:/ ) { | ||||
191 | $url = $redirectto; | ||||
192 | } | ||||
193 | else { | ||||
194 | $url = | ||||
195 | $session->getScriptUrl( 1, 'view', $session->{webName}, | ||||
196 | $redirectto ); | ||||
197 | } | ||||
198 | $session->redirect($url); | ||||
199 | } | ||||
200 | else { | ||||
201 | Foswiki::Contrib::JsonRpcContrib::Response->print( | ||||
202 | $session, | ||||
203 | code => $code, | ||||
204 | message => $result, | ||||
205 | id => $request->id() | ||||
206 | ); | ||||
207 | } | ||||
208 | |||||
209 | return; | ||||
210 | } | ||||
211 | |||||
212 | ################################################################################ | ||||
213 | sub getHandler { | ||||
214 | my ( $this, $request ) = @_; | ||||
215 | |||||
216 | my $namespace = $request->namespace(); | ||||
217 | return unless $namespace; | ||||
218 | |||||
219 | my $method = $request->method(); | ||||
220 | return unless $method; | ||||
221 | |||||
222 | unless ( defined $this->{handler}{$namespace} ) { | ||||
223 | |||||
224 | # lazy register handler | ||||
225 | if ( defined $Foswiki::cfg{JsonRpcContrib}{Handler} | ||||
226 | && defined $Foswiki::cfg{JsonRpcContrib}{Handler}{$namespace} | ||||
227 | && defined $Foswiki::cfg{JsonRpcContrib}{Handler}{$namespace} | ||||
228 | {$method} ) | ||||
229 | { | ||||
230 | |||||
231 | my $def = | ||||
232 | $Foswiki::cfg{JsonRpcContrib}{Handler}{$namespace}{$method}; | ||||
233 | |||||
234 | writeDebug("compiling $def->{package} for $namespace.$method") | ||||
235 | if TRACE; | ||||
236 | eval qq(use $def->{package}); | ||||
237 | |||||
238 | # disable on error | ||||
239 | if ($@) { | ||||
240 | print STDERR "JsonRPC handler compile error: $@\n"; | ||||
241 | $Foswiki::cfg{JsonRpcContrib}{Handler}{$namespace}{$method} = | ||||
242 | undef; | ||||
243 | return; | ||||
244 | } | ||||
245 | |||||
246 | my $sub = $def->{package} . "::" . $def->{function}; | ||||
247 | $this->registerMethod( $namespace, $method, \&$sub, | ||||
248 | $def->{options} ); | ||||
249 | } | ||||
250 | } | ||||
251 | |||||
252 | return unless defined $this->{handler}{$namespace}; | ||||
253 | |||||
254 | return $this->{handler}{$namespace}{$method}; | ||||
255 | } | ||||
256 | |||||
257 | 1 | 2µs | 1; | ||
258 |