6.3. Your first Pike script

A Pike script is quite like a Perl script. It is executed when the user tries to access it. So a Pike script is usually where your public web files are. This is a good choice if you already have a Perl background and want to try Pike.

You have two choices when doing this. You can execute Pike as a CGI script or internally within the server. If you don't know what CGI is, look up the Apache-Overview-HOWTO at http://www.tldp.org/.

Here, we will run Pike scripts internally within Caudium. To achieve this, you have to load another module in your server by selecting Load module in the CIF.. You now have the list of all modules available in Caudium. As you see, there are a lot of modules and reading this page should give you some ideas for future development. To select the Pike script module, just click on the image named "Pike script support" if you use a graphical browser.

You can now create a .pike file containing, for example,

Example 6-3. A basic Pike script.


// you have to inherit caudiumlib to have some basic things
// like the id object and response mapping
inherit "caudiumlib";

// the same as the main
// if you modify this script and you see that Caudium don't take your
// modification into account, reload the Pike script support module
// This is because Caudium uses a cache for performance reasons
string parse(object id)
{
  string html = "<html><body>The id object contain some "
  "very useful information<br />";
  html += sprintf("The id->variables contain a list of "
  "arguments given to this script %O\n", id->variables);
  return html;
}  
      

Pike scripts are usually used for little internal development. Pike scripts can be very useful in this case because you can create something with very little lines. Here is an example of such a script:

Example 6-4. A real world script.


/* Here is a Pike script (not a Caudium module).
   This script is less than 20 lines (comments
   and blank lines excluded) and will randomly
   return one file to the web browser from a list of files.
   This script was kindly provided by Xavier Beaudouin */

// first we need to inherit from caudiumlib in order to get
// the parse, http_redirect functions and id object
// recognized.
inherit "caudiumlib";

// we declare an array of files
array (string)files;

// an ASCII text containing the name of a file
// on the real filesystem.
// Each file name in this file will be
// randomly return (the files name have to be on
// a separate line).
#define FILELIST "/list"

#define BASEDIR "/thepath2yourfiles/"

// this function is the constructor, it will be loaded first
void create () {
 // the array of strings 'files' will contain
 // all the files we serve provided the file
 // FILELIST list each file name on one line.
 files = Stdio.read_bytes(FILELIST)/"\n";
}

// if no_reload return 1, Caudium will cache the
// result of this script for maximum performances
// and will not execute it a second time.
// As a result, If you give the argument 
// ?reload=1 to your script, Caudium will 
// reload it. 
// This is useful to use cache for average
// content delivery unless you are doing
// developpement
int no_reload(object id)
{
 if(!id->variables->reload)
   return 1;
 return 0;
}

// As this is a simple pike script (CGI like), this function
// will be called by Caudium and should return a string that
// will be display to the client's browser.
// It can also return a mapping containing all the HTTP response
// (headers + text)
mapping parse(object id)
{
 // We randomly return one of the file we list in the FILELIST file
 // (relative to BASEDIR directory).
 // http_redirect will send a HTTP 301 header telling the browser
 // where to get randomly selected file.
 return http_redirect(BASEDIR + files[random(sizeof(files))],id);
}
      

But you can also create some powerful scripts:

Example 6-5. A script for the power user.


inherit "caudiumlib";

string|mapping|object parse( object id )
{
  id->my_fd->write(id->clientprot + " 200 Ok\r\n");
  id->my_fd->write("Server: Caudium !\r\n");
  id->my_fd->write("Expires: 0\r\n");
  id->my_fd->write("Content-Type: text/html\r\n");
  id->my_fd->write("pragma: no-cache\r\n\r\n");
  id->my_fd->set_id( ({ id->my_fd }) );
  id->my_fd->set_nonblocking(0,send_data);
  return http_pipe_in_progress();
}

void send_data(array (object) id)
{

  id[0]->write("<pre>");
  id[0]->write("test......................\n");
  id[0]->write("test......................\n");
  id[0]->write("test......................\n");
  id[0]->write("sleep for 10 sec\n");
  sleep(10);
  id[0]->write("Done</pre>");
  id[0]->close();
  destruct(id[0]);
}
      

This example uses non-blocking sockets. my_fd is the file descriptor of the HTTP socket. Here we change the type of the HTTP socket from blocking sockets (default type) to non-blocking sockets. Non-blocking sockets are sockets that won't block the program waiting for data. Instead, a read and write function (the so-called callback functions) will be called automatically when there is some data to read or write to the HTTP socket. Moreover, we return here a special function, http_pipe_in_progress. This is because as the HTTP socket is set to non-blocking, Caudium won't be able to wait for processing the HTTP stuff like headers and so on. So we have to tell it not to wait for us and send a http_pipe_in_progress.

This mechanism is very useful when you have to do some communication with slow sockets on a single process server (multi-threaded one). In the case of a single process, when you wait for a socket it is all the server, which will wait. So all your users will be stalled. With non blocking sockets there is no problem anymore; the server won't wait for each socket. Example of such code includes CAMAS IMAP/NNTP clients. If you don't understand, don't worry, you usually don't have to understand these mechanisms.

However, the Pike script allows you to write some complex code it is not well suited for big projects. If this is the case, read the next paragraph and enjoy.

Note

The Caudium API is available at http://caudium.net/. You should also read the Roxen 1.3 PDF available at http://caudium.info/. Pike scripts are blocking, and allow your users to run scripts with the same privilege as the server. Blocking means that the server will be stalled if a socket from a pike script is stalled (usually waiting for something). This applies even if you use non-blocking sockets in your script. You don't have this problem with modules.