1. Bill Welliver
  2. scriptrunner

Overview

In yet another in a long string of rapid-fire ideas turned into alpha
quality code, I'd like to annouce the availability of the Pike
ScriptRunner. ScriptRunner is a FastCGI application that will
(hopefully) run under pretty much any web server that supports FastCGI.
The ScriptRunner allow you to run pike scripts under non-pike based web
servers. Because ScriptRunner uses FastCGI, its performance should be
close to embedded language solutions like mod_perl, but with a lot
less worries about security and overflows. With ScriptRunner you can
introduce all of your friends to Pike without forcing them to suffer
bad performance or the (more likely) attachment to Apache. In addition,
ScriptRunner does a lot of the unpleasant work of parsing incoming
requests, allowing you to get right to the task of writing your code.

Right now, it's pretty early on in its development, so there are a lot of
niceties present in Roxen or Caudium that aren't available, and it's not
terribly well tested, so it could have some nasty bugs. Enough raw
functionality is available to be highly useful; hopefully there will be
interest in improving things in this area. ScriptRunner contains code
written by others over the years; this is really more of a gathering of
snippets into something more readily useful to others.

Requirements:

Pike 7.6+
libfastcgi (available from http://www.fastcgi.com)
Public.Web.FastCGI (available from
http://www.siriushosting.com/pike/fastcgi.html)

Features:

- Multi-threaded request handling
- Session persistence
- Persistent interpreter
- Compiled object caching
- Incoming requests are parsed and passed to you in a request id object.
- Handles FCGI processing for you. Just return a string or control mapping
  from your parse() method.

Installation:

Please visit the ScriptRunner page for more updated information:

http://www.gotpike.org/PikeWiki/index.pike?page=PikeApps/Pike+ScriptRunner

Basic installation instructions are located in the file INSTALL.

Apache users: see the file INSTALL.Apache for information on configuring 
Apache support for FastCGI.

Get the snapshot tarball here:

http://buoy.riverweb.com:8080/viewrep/cvs/scriptrunner

Add a redirect to convert all requests to (*.pike) to
/path/to/scriptrunner.fcgi($1) (actual syntax will vary based on the
redirector you're using.

For example, if I've installed ScriptRunner so that the ScriptRunner.fcgi 
is called by the following request:

http://www.mysite.com/path/to/ScriptRunner.fcgi

and I put a pike script in /some/other/path.pike on my website, I need my 
redirect to internally change

http://www.mysite.com/some/other/path.pike

to

http://www.mysite.com/path/to/ScriptRunner.fcgi/some/other/path.pike

This is a common technique used by PHP and other languages. Alternately, 
you could use mod_actions to do the same thing:

   AddHandler scriptrunner-pike-script .pike
   Action scriptrunner-pike-script /path/to/ScriptRunner.fcgi

In the long run, this may be a simpler option.

Some example scripts are included to give you a head start. 

Writing Pike Scripts:

First of all, you should know how to write code in the Pike language. It's 
pretty easy, and if you're accustomed to C-like languages, such as C or 
Java, you should be able to pick things up in a few minutes.

A pike script must impliment the following method:

string|mapping parse(RequestID request_id);

request_id is an object that contains the request information, all broken 
down into the most important components. Accessing the scriptrunner 
application without providing a script file will give you an example of 
what's contained in the RequestID object.

Some important members of a RequestID object:

variables: a mapping containing key-value pairs for all passed query and 
POST variables. ScriptRunner does not differentiate between GET and POST 
variables.

cookies: a mapping containing key-value pairs for all cookies provided to 
the server during the request.

query: the contents of the request string following the ?

method: the HTTP method sent by the client.

client: an array containing elements of the client agent being used.

pragma: a multiset containing any pragma keys sent by the client agent. 
the most common of these is "no-cache".

prot: the http protocol and version, for example: HTTP/1.0.

referrer: an array containing the referrer.

remoteaddr: the client's ip address

remotehost: the client's remote hostname, if available.

misc: a mapping containing miscellaneous information about the request. 

misc->session_variables: if set to use sessions, your script or psp page 
will have a mapping here that you can add to and which will be maintained 
across requests. Currently, this can not contain programs or objects.

misc->session_id: if set to use sessions, this will be a string containing 
the current session identifier.

Your parse() function can run any pike code you'd like, and when you're 
done, it should return either a string containing the HTML content to 
return to the browser, or a "control" mapping. A control mapping is a 
mapping that contains certain indices that control the response returned 
to the browser. You'd want to return a mapping if you need to alter the 
content type of the result, or if you want to add special headers or 
change the status code. example2.pike gives you an example of a control 
mapping used to perform a HTTP redirect. Future releases of ScriptRunner 
will provide convenience functions that will generate appropriate control 
mappings for you. Until then, Here are the contents (and default falues):

([
    /* the result code to return, 200 is "OK" */
    "error" : 200    

    /* the mime content type to return */
    "type" : "content/html"  

    /* a string or Stdio.File object containing the data to return. If a 
       File object, the data will be read() from the object. Not required,
       strictly speaking, but it is normally important to provide. */
    "data" : UNDEFINED  

    /* a mapping containing response headers to provide */
    "_headers" : UNDEFINED
])

Do note that the contents of this mapping may change once convenience 
functions arrive. If you find yourself performing a large number of string 
concatenations to create the result string, you may want to consider using 
String.Buffer, which can improve the performance of your application in 
these situations. See the Pike module reference for more information on 
String.Buffer.

Upon successful compilation of your script, it will be instantiated into 
an object, so you can provide create() and destroy() methods to control 
startup and shutdown of services required by parse(). Note that upon 
compilation, scripts are cached. Scripts can currently be reloaded by 
sending the Pragma: no-cache header (by doing a "super reload" using 
mozilla based browsers). Do not count on destroy() to be called 
immediately upon destruction, as there may be a delay between the script 
being recompiled and garbage collection, which forces destroy() to be 
called. 

In the event of a compilation failure, the error will be displayed to the 
client and written to a log file. Compilation retries will occurr on 
subsequent requests. In the event of an uncaught error exception, an 
error and stacktrace will be returned to the browser, as well as written 
to the log file. 

Comments, Feedback and Participation:

I welcome all of these, especially if you're interested in helping to
debug and enhance the code. Contact me if you'd like to help out.