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:
Cgi.cgi, a class which deals with parsing parameters.Cgi.Template which is a module which provides HTML templates to separate code from presentation.Cgi.escape*, functions for escaping strings in HTML documents.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.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.
The template library also offers a way to automatically HTML-escape tags (this means, for example, replacing < with <). Any tag written as ::name_html:: refers to the tag named name, but with HTML escapes applied.
The possible escape types are:
::name_url:: for URL-encoding.::name_html:: - Escapes & < > " with the appropriate HTML escape sequence. It also turns end of lines into <br>.::name_html_tag:: - Escapes & < > " with the appropriate HTML escape sequence. It also turns end of lines into 
. This function is suitable when placing text between the quotes in an HTML tag, eg. <input value="::text_html_tag::">.::name_html_textarea:: Escapes & < > " with the appropriate HTML escape sequence. It leaves everything else unchanged. This is a suitable function to use when placing text in an HTML <textarea>...</textarea>.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:
q#param name - Returns the value of the parameter named name.q#param_all name - Returns a list of all values of a parameter. Note that a CGI script can have the same named parameter several times, eg. if it is called as script.cmo?foo=1&foo=2q#params - Returns a hash of name to value pairs containing all parameters passed to the script.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.
(This section not written yet. Instead, see the examples in the source distribution).
Merjis specialises in finding interested visitors and helping them to convert into leads or purchases. We use PPC, SEO, Social Media, Analytics, Usability, Design, etc.