Developers » mod_caml for beginners

(Redirected from mod_caml_for_beginners)

Writing CGI scripts in OCaml

mod_caml lets you write CGI "scripts" in OCaml. These are bytecode compiled into .cmo files and linked into the webserver at runtime using Dynlink. The upshot is that the scripts run inside the Apache webserver process, and are cached there (unless you restart Apache of course). You avoid the overhead of forking and starting up the OCaml runtime on each invocation, and you can cache data such as database handles and compiled templates in the script.

OCaml CGI programs can make raw Apache API calls (see the section on writing Apache handlers below). However normally CGI programs will use the Cgi library which contains high-level classes, functions and modules:

Loading and registering scripts

mod_caml provides a handler called Registry which loads and calls CGI scripts. Registry loads the CGI script once when it is first requested using Dynlink, or reloads it if the .cmo file on disk changes. When the script is loaded/reloaded it must register itself with the Registry, passing a "run" function. Each time the script runs this function is called:

open Registry

let run r =
  (* The run function. See below for details. *)

  (* ... *)

let () =
  register_script run

Note that the top level code is only called once (on each load/reload) and the run function is called each time the script is invoked. You can use this to your advantage, for example by performing expensive initializations or opening a database connection in the top level, and using the (cached) results in the run function.

Cgi and templates

Cgi.cgi and Cgi.Template.template are two classes which are normally used together to write CGI scripts. Here is a simple "hello, world" example:

open Registry
open Cgi

let template = "
<html>
  <head><title>::title_html::</title></head>
  <body bgcolor=\"#ffffff\">
    <h1>::title_html::</h1>
    <p>
      <b>If you see this message, then everything looks like it's installed
      and working fine!</b>
    </p>
  </body>
</html>"

let template = Template.template_from_string template;;
template#set "title" "Hello, world."

let run r =
  let q = new cgi r in

  (* Display the page. *)
  q#template template

let () =
  register_script run

This example demonstrates both the Cgi.cgi and Cgi.Template.template classes, and the separation of code and presentation. (In this instance presentation isn't actually very separated: normally you would place the template into a separate file for your web designers to edit).

new cgi r creates the Cgi.cgi class from r which is an Apache.Request.t object (corresponds to the internal Apache request_rec). Cgi.cgi has functions for reading parameters passed to the script and also for generating the HTTP headers (q#header ()).

Cgi.Template.template_from_string compiles the template from the source string and returns a template object. Templates contain simple tags such as ::title:: which can be replaced using template#set "title" text.

Escaping in templates

The template library also offers a way to automatically HTML-escape tags (this means, for example, replacing < with &lt;). Any tag written as ::name_html:: refers to the tag named name, but with HTML escapes applied.

The possible escape types are:

Parameters

Cgi.cgi provides methods for reading the parameters passed to the script (either as a query string such as script.cmo?foo=1&bar=2 or using the POST method). The constructor does all the parsing and unescaping for you. You read parameters using the methods:

Here is an example script which just displays the parameters passed to it:

open Registry
open Cgi

let template = "
<html>
 <head><title>::title_html::</title></head>
  <body bgcolor=\"#ffffff\">
  <h1>::title_html::</h1>
  <h2>Parameters passed into the script</h2>
  <table border=\"1\"><tr><th>Name</th><th>Value</th></tr>
   ::table(params)::
   <tr><td>::name_html::</td><td>::value_html::</td></tr>
   ::end::
  </table>
  <h2>Form</h2>
  <p>
   This is a simple form which POSTs data to the script:
  </p>
  <form method=\"post\" action=\"params.cmo\">
   Name: <input name=\"name\" value=\"\">
   <input type=\"submit\" name=\"submit\" value=\"Send\">
  </form>
 </body>
</html>"

let template = Template.template_from_string template;;
template#set "title" "Params demonstration CGI script"

let run r =
  let q = new cgi r in

  (* Get each parameter (gets [ name, value; name, value; ... ]). *)
  let params_list = q#params_list in
  let table = List.map (fun (name, value) ->
    [ "name", Template.VarString name;
      "value", Template.VarString value ]) params_list in

  (* Set up the table. *)
  template#table "params" table;

  (* Display the page. *)
  q#template template

(* Register the script's run function. *)
let () =
  register_script run

The only really complex part of this script is the list mapping which changes the parameter list as returned from the q (query) into the form required by the template's table. It has to convert each parameter into a row in the table represented by an assoc-list.

Writing Apache handlers in OCaml

(This section not written yet. Instead, see the examples in the source distribution).

Merjis

effective marketing for the web

Merjis specialises in innovative marketing,
accessibility, search engine optimisation (SEO),
and development for the web.