From: <Sve...@nt...> - 2005-12-19 03:41:29
|
Author: SvenDowideit Date: 2005-12-18 19:38:25 -0800 (Sun, 18 Dec 2005) New Revision: 7881 Added: twiki/branches/DEVELOP/bin/rest Modified: twiki/branches/DEVELOP/data/TWiki/TWikiScripts.txt twiki/branches/DEVELOP/data/TestCases/TestCaseRestTest.txt twiki/branches/DEVELOP/lib/TWiki.pm twiki/branches/DEVELOP/lib/TWiki/Func.pm twiki/branches/DEVELOP/lib/TWiki/Plugins/EmptyPlugin.pm twiki/branches/DEVELOP/lib/TWiki/UI/Rest.pm twiki/branches/DEVELOP/tools/MANIFEST Log: Item115: applied RafaelAlvarez's patch to only call registered functions, and added more documentation Copied: twiki/branches/DEVELOP/bin/rest (from rev 7610, twiki/branches/DEVELOP/bin/rest) Modified: twiki/branches/DEVELOP/data/TWiki/TWikiScripts.txt =================================================================== --- twiki/branches/DEVELOP/data/TWiki/TWikiScripts.txt 2005-12-18 17:49:11 UTC (rev 7880) +++ twiki/branches/DEVELOP/data/TWiki/TWikiScripts.txt 2005-12-19 03:38:25 UTC (rev 7881) @@ -1,3 +1,4 @@ +%META:TOPICINFO{author="TWikiContributor" date="1111929255" format="1.0" version="$Rev: 7555 $"}% ---+ TWiki CGI Scripts TWiki uses a set of scripts in the =bin= directory. This topic describes the interfaces to some of those scripts. @@ -133,6 +134,37 @@ ---++ =preview= This script is _deprecated_. Its functions are covered by the =save= script. + +---++ =rest= +This script can be invoked via http in a similar way as the view script (see *Invocation Examples*, bellow) to execute a function that it's associated to a "subject" and a "verb" (see bellow). It'll print the result directly to the stream unless the =endPoint= parameter is specified, in which case the control is redirected to the given topic. + +The =rest= script itself uses one parameter: + +| =endPoint= | Where to redirect the response once the request is served, in the form "Web.Topic" | + +Any additional parameters are passed directly to the function (i.e: The function can get any other parameter using the CGI $query object) + +---+++ Invocation Examples: + +The =rest= script assumes that it will be called with URL in the form: + +=http://my.host/bin/rest/<subject>/<verb>= + +where <subject> must be the WikiWord name of the Plugin, and the <verb> is the alias for the function registered using the registerRESTHandler. The <subject> and <verb> are then used to lookup and call the registered function. + +Functions outside the plugins also can be registered, but please consider the security implications of allowing URL access, as functions can sidestep TWiki Authentication & Authorisation settings. + +=<subject>= and =<verb>= are checked for illegal characters exactly in the same way as the web and topic names. + +As an example, the EmptyPlugin has registered a function to be used with the =rest= script under the subject *EmptyPlugin* and the verb *example*. Click below to see the =rest= script in action (run as Main.TWikiGuest). + +[[%SCRIPTURL%/rest%SCRIPTSUFFIX%/EmptyPlugin/example?debugenableplugin=EmptyPlugin][Call the Plugin]] + +You can also call the function from the command line, but this will be run as the Main.TWikiAdminGroup (as it is assumed that shell access is secure) - eg: <verbatim>./rest EmptyPlugin.example</verbatim> + +Note that for calls to plugins, they must be enabled in =configure=. + + ---++ =configure= =configure= is the browser script used for inspection and configuration of the TWiki configuration. None of the parameters to this script are useable for any purpose except =configure=. Modified: twiki/branches/DEVELOP/data/TestCases/TestCaseRestTest.txt =================================================================== --- twiki/branches/DEVELOP/data/TestCases/TestCaseRestTest.txt 2005-12-18 17:49:11 UTC (rev 7880) +++ twiki/branches/DEVELOP/data/TestCases/TestCaseRestTest.txt 2005-12-19 03:38:25 UTC (rev 7881) @@ -7,7 +7,7 @@ Click the link below. If the script is working, a page with the text "This is an example of a REST invocation" should appear. -[[%SCRIPTURL%/rest%SCRIPTSUFFIX%/EmptyPlugin/restExample?debugenableplugin=EmptyPlugin][Call the Plugin]] +[[%SCRIPTURL%/rest%SCRIPTSUFFIX%/EmptyPlugin/example?debugenableplugin=EmptyPlugin][Call the Plugin]] Modified: twiki/branches/DEVELOP/lib/TWiki/Func.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Func.pm 2005-12-18 17:49:11 UTC (rev 7880) +++ twiki/branches/DEVELOP/lib/TWiki/Func.pm 2005-12-19 03:38:25 UTC (rev 7881) @@ -1780,6 +1780,72 @@ ---++ Functions: System and I18N related +=cut + +=pod= + +---+++ registerRESTHandler( $alias, \&fn, ) +Should only be called from initPlugin. + +Adds a function to the dispatch table of the REST interface + * =$alias= - The name . + * =\&fn= - Reference to the function. + +*Since:* TWiki::Plugins::VERSION 1.1 + +The handler function must be of the form: +<verbatim> +sub handler(\%session) +</verbatim> +where: + * =\%session= - a reference to the TWiki session object (may be ignored) + +From the REST interface, the name of the plugin must be used +as the subject of the invokation. + +Example +------- + +The EmptyPlugin has the following call in the initPlugin handler: +<verbatim> + TWiki::Func::registerRESTHandler('example', \&restExample); +</verbatim> + +This adds the =restExample= function to the REST dispatch table +for the EmptyPlugin under the 'example' alias, and allows it +to be invoked using the URL + +=http://server:port/bin/rest/EmptyPlugin/example= + +note that the URL + +=http://server:port/bin/rest/EmptyPlugin/restExample= + +(ie, with the name of the function instead of the alias) will not work. + +=cut + +sub registerRESTHandler { + my( $alias, $function) = @_; + ASSERT($TWiki::Plugins::SESSION) if DEBUG; + my $plugin = caller; + $plugin =~ s/.*:://; # strip off TWiki::Plugins:: prefix + + # Use an anonymous function so it gets inlined at compile time. + # Make sure we don't mangle the session reference. + TWiki::registerRESTHandler( $plugin, + $alias, + sub { + my $record = $TWiki::Plugins::SESSION; + $TWiki::Plugins::SESSION = $_[0]; + my $result = &$function( @_ ); + $TWiki::Plugins::SESSION = $record; + return $result; + } + ); +} + +=pod ---+++ getRegularExpression( $name ) -> $expr Retrieves a TWiki predefined regular expression or character class. Modified: twiki/branches/DEVELOP/lib/TWiki/Plugins/EmptyPlugin.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Plugins/EmptyPlugin.pm 2005-12-18 17:49:11 UTC (rev 7880) +++ twiki/branches/DEVELOP/lib/TWiki/Plugins/EmptyPlugin.pm 2005-12-19 03:38:25 UTC (rev 7881) @@ -125,6 +125,10 @@ # register the _EXAMPLETAG function to handle %EXAMPLETAG{...}% TWiki::Func::registerTagHandler( 'EXAMPLETAG', \&_EXAMPLETAG ); + # Allow a sub to be called from the REST interface + # using the provided alias + TWiki::Func::registerRESTHandler('example', \&restExample); + # Plugin correctly initialized return 1; } @@ -617,7 +621,8 @@ =cut sub restExample { - return "This is an example of a REST invocation"; + #my ($session) = @_; + return "This is an example of a REST invocation\n\n"; } 1; Modified: twiki/branches/DEVELOP/lib/TWiki/UI/Rest.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/UI/Rest.pm 2005-12-18 17:49:11 UTC (rev 7880) +++ twiki/branches/DEVELOP/lib/TWiki/UI/Rest.pm 2005-12-19 03:38:25 UTC (rev 7881) @@ -45,68 +45,47 @@ ---++ StaticMethod gateway( $session, $pluginName, $,methodName, $scriptUrl, $query ) =rest= command handler. -This method is designed to be invoked via the =TWiki::UI::run= method, -and will invoke a method in a plugin. - -It'll print the result directly to the stream unless the =endPoint= parameter is specified -(via que $query object), in which case the control is redirected to the given topic. - - -Additional parameters can be queries using the $query object. - ----+++ Invocation Examples: - -=http://my.host/bin/rest/EmptyPlugin/testRest= - -Will invoke =TWiki::Plugin::EmptyPlugin::testRest=, and print the result directly to the stream. - -=http://my.host/bin/rest/EmptyPlugin/testRest?endPoint=SomeWeb.SomeTopic= - -Will invoke =TWiki::Plugin::EmptyPlugin::testRest=, and redirect the control to <nop>SomeWeb.SomeTopic - +This method is designed to be invoked via the =TWiki::UI::run= method. +It'll lookup in the dispatch table for a function associated with +the given subject and verb, and execute it if one is found. + =cut sub gateway { - my $session = shift; - $session->enterContext( 'rest' ); - - my $query = $session->{cgiQuery}; - my $web = $session->{webName}; - my $topic = $session->{topicName}; - - my $endPoint = $query->param( 'endPoint' ); + my $session = shift; + $session->enterContext( 'rest' ); - - my $method = $topic; - my $plugin = $web; - - - if (TWiki::isValidWikiWord($plugin)) { - my $class = TWiki::Sandbox::untaintUnchecked('TWiki::Plugins::'.$plugin); - - my $m = TWiki::Sandbox::untaintUnchecked($class.'::'.$method); - eval "use $class"; - if( $@ ) { - die "$class compile failed: $@"; - } + my $query = $session->{cgiQuery}; + my $web = $session->{webName}; + my $topic = $session->{topicName}; - if (defined(&$m)) { - no strict 'refs'; - local $TWiki::Plugins::SESSION=$session; - my $result=''; - $result=&$m($session); - use strict 'refs'; - if (defined($endPoint)) { - $session->redirect($session->getScriptUrl( '', $endPoint, 'view' )); - } - $session->writeCompletePage( $result ); - } else { - $session->writeCompletePage( 'Unknown Command'.$plugin.'::'.$method); - } - } else { - $session->writeCompletePage( 'Invalid Command'.$plugin.'::'.$method); - } + my $endPoint = $query->param( 'endPoint' ); - $session->leaveContext( 'rest' ); + my $verb= $topic; + my $subject = $web; + + $session->writeLog( 'rest', $web.'.'.$topic ); + + if (TWiki::isValidWikiWord($subject)) { + my $function=TWiki::restDispatch($subject,$verb); + if (defined($function)) { + no strict 'refs'; + local $TWiki::Plugins::SESSION=$session; + my $result=''; + $result=&$function($session,$subject,$verb); + use strict 'refs'; + if (defined($endPoint)) { + $session->redirect($session->getScriptUrl( '', $endPoint, 'view' )); + } else { + $session->writeCompletePage( $result ); + } + } else { + $session->writeCompletePage( 'Unknown Action '.$subject.'/'.$verb); + } + } else { + $session->writeCompletePage( 'Invalid Command '.$subject); + } + + $session->leaveContext( 'rest' ); } 1; Modified: twiki/branches/DEVELOP/lib/TWiki.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki.pm 2005-12-18 17:49:11 UTC (rev 7880) +++ twiki/branches/DEVELOP/lib/TWiki.pm 2005-12-19 03:38:25 UTC (rev 7881) @@ -64,6 +64,7 @@ %constantTags %functionTags %contextFreeSyntax + %restDispatch $VERSION $RELEASE $TRUE $FALSE @@ -2300,6 +2301,51 @@ } } +=pod= + +---+++ registerRESTHandler( $subject, $verb, \&fn ) +Adds a function to the dispatch table of the REST interface +for a given subject. See TWikiScripts#rest for more info. + + * =$subject= - The subject under which the function will be registered. + * =$verb= - The verb under which the function will be registered. + * =\&fn= - Reference to the function. + +The handler function must be of the form: +<verbatim> +sub handler(\%session,$subject,$verb) -> $text +</verbatim> +where: + * =\%session= - a reference to the TWiki session object (may be ignored) + * =$subject= - The invoked subject (may be ignored) + * =$verb= - The invoked verb (may be ignored) + +*Since:* TWiki::Plugins::VERSION 1.1 +=cut= + +sub registerRESTHandler { + my ( $subject, $verb, $fnref) = @_; + $restDispatch{$subject}{$verb} = \&$fnref; +} + +=pod= + +---+++ restDispatch( $subject, $verb) => \&fn +Returns the handler function associated to the given $subject and $werb, +or undef if none is found. + +*Since:* TWiki::Plugins::VERSION 1.1 +=cut= +sub restDispatch { + my ( $subject, $verb) = @_; + my $s=$restDispatch{$subject}; + if (defined($s)) { + return $restDispatch{$subject}{$verb}; + } else { + return undef; + } +} + =pod ---++ ObjectMethod handleCommonTags( $text, $web, $topic ) -> $text Modified: twiki/branches/DEVELOP/tools/MANIFEST =================================================================== --- twiki/branches/DEVELOP/tools/MANIFEST 2005-12-18 17:49:11 UTC (rev 7880) +++ twiki/branches/DEVELOP/tools/MANIFEST 2005-12-19 03:38:25 UTC (rev 7881) @@ -15,6 +15,7 @@ bin/register 0550 bin/rename 0550 bin/resetpasswd 0550 +bin/rest 0550 bin/save 0550 bin/search 0550 bin/setlib.cfg 0550 |