1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
<title>CGILua: Building Web Scripts with Lua</title>
6
<link rel="stylesheet" href="http://www.keplerproject.org/doc.css" type="text/css"/>
7
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
14
<div id="product_logo"><a href="http://www.keplerproject.org">
15
<img alt="CGILua logo" src="cgi-128.gif"/>
17
<div id="product_name"><big><strong>CGILua</strong></big></div>
18
<div id="product_description">Building Web Scripts with Lua</div>
19
</div> <!-- id="product" -->
26
<li><a href="index.html">Home</a>
28
<li><a href="index.html#overview">Overview</a></li>
29
<li><a href="index.html#status">Status</a></li>
30
<li><a href="index.html#download">Download</a></li>
31
<li><a href="index.html#history">History</a></li>
32
<li><a href="index.html#incompatibility">Incompatibilities</a></li>
33
<li><a href="index.html#credits">Credits</a></li>
34
<li><a href="index.html#contact">Contact us</a></li>
37
<li><strong>Manual</strong>
39
<li><a href="manual.html#intro">Introduction</a></li>
40
<li><a href="manual.html#installation">Installation</a></li>
41
<li><a href="manual.html#config">Configuration</a></li>
42
<li><a href="manual.html#scripts">Lua Scripts</a></li>
43
<li><a href="manual.html#templates">Lua Pages</a></li>
44
<li><a href="manual.html#parameters">Parameters</a></li>
45
<li><a href="manual.html#dispatching">Dispatching</a></li>
46
<li><a href="manual.html#authentication">Authentication</a></li>
47
<li><a href="manual.html#error_handling">Error Handling</a></li>
50
<li><a href="reference.html">Reference</a>
52
<li><a href="reference.html#headers">Headers</a></li>
53
<li><a href="reference.html#contents">Content Generation</a></li>
54
<li><a href="reference.html#prep">Lua Pages</a></li>
55
<li><a href="reference.html#variables">CGILua Variables</a></li>
56
<li><a href="reference.html#error_handling">Error Handling</a></li>
57
<li><a href="reference.html#behavior">CGILua Behavior</a></li>
58
<li><a href="reference.html#urlcode">URL Encoding</a></li>
59
<li><a href="reference.html#auxiliar">Auxiliary functions</a></li>
60
<li><a href="reference.html#index">Alphabetic Index</a></li>
63
<li><a href="libraries.html">Libraries</a>
65
<li><a href="libraries.html#authentication">Authentication</a></li>
66
<li><a href="libraries.html#cookies">Cookies</a></li>
67
<li><a href="libraries.html#dispatcher">Dispatcher</a></li>
68
<li><a href="libraries.html#serialize">Serialize</a></li>
69
<li><a href="libraries.html#session">Session</a></li>
72
<li><a href="sapi.html">SAPI</a></li>
73
<li><a href="license.html">License</a></li>
75
</div> <!-- id="navigation" -->
79
<h2><a name="intro"></a>Introduction</h2>
82
CGILua uses <a href="http://www.lua.org">Lua</a> as a server-side scripting
83
language for creating dynamic Web pages. Both pure
84
<a href="manual.html#scripts">Lua Scripts</a> and
85
<a href="manual.html#templates">Lua Pages</a> (LP) are supported by CGILua.
86
A Lua Script is essentially a Lua program that creates the whole contents of
87
a web page and returns it to the client. A Lua Page is a conventional
88
markup text (HTML, XML etc) file that embeds Lua code using some special
89
tags. Those tags are processed by CGILua and resulting page is returned to the
92
<p>Lua Scripts and Lua Pages are equally easy to use, and choosing one of them
93
basically depends on the characteristics of the resulting page. While Lua
94
Pages are more convenient for the separation of logic and format, Lua Scripts
95
are more adequate for creating pages that are simpler in terms of its structure,
96
but require a more significative amount of internal processing.</p>
98
<p>Allowing these two methods to be intermixed, CGILua provides Web applications
99
developers with great flexibility when both requirements are present. For a
100
detailed description of both scripting methods and some examples of
101
their use see <a href="#scripts">Lua Scripts</a> and
102
<a href="#templates">Lua Pages</a>.</p>
104
<h4>Architecture</h4>
107
CGILua architecture is divided in two layers. The lower level is represented
108
by the Server API (<a href="sapi.html">SAPI</a>) and the higher level is
109
represented by the CGILua API itself. SAPI is the interface between the web server
110
and the CGILua API, so it needs to be implemented for each Web server and launching
115
A launcher is responsible for the interaction of CGILua and the Web server,
116
implementing SAPI for example using ISAPI on IIS or mod_lua on Apache.
117
The reference implementation of CGILua launchers is
118
<a href="http://www.keplerproject.org/kepler/">Kepler</a>.
122
The CGILua API is implemented using only SAPI and is totally portable
123
over different launchers and their supporting Web servers. This way any Lua Script
124
or Lua Page can be used by any launcher.
127
<h4><a name="lifecycle"></a>Request life cycle</h4>
130
CGILua processes requests using a CGI metaphor (even if the launcher is not based
131
on CGI) and requests have a life cycle that can be customized by the programmer.
132
The CGILua request life cycle consists in the following sequence of steps for each
137
<li>Add default handlers such as LuaScripts and Lua Pages and commom file formats.</li>
138
<li>Execute the <code>config.lua</code> file, allowing the customization of the next steps.</li>
139
<li>Build the <code>cgilua.POST</code> and <code>cgilua.QUERY</code> tables (processing POST and QUERY data).</li>
140
<li>Change to user script directory.</li>
141
<li>Execute the registered <em>open</em> functions.</li>
142
<li>Execute the requested script with the correct environment.</li>
143
<li>Execute the registered <em>close</em> functions.</li>
144
<li>Change back to the original directory</li>
148
Editing the <code>config.lua</code> file one can customize the CGILua behaviour.
149
One typical use would be registering the <em>open</em> and <em>close</em> functions
150
in order to change the request processing behavior.
151
With this customization it is possible to implement new features like
152
session management and private library directories as shown in section
153
<a href="#config">Configuration</a>, or even to implement new
154
abstractions over the whole CGILua way of live, like MVC-frameworks such as Orbit.
157
<h2><a name="installation"></a>Installation</h2>
161
<a href="http://www.inf.puc-rio.br/~roberto/pil2/chapter15.pdf">package model</a>
162
for Lua 5.1, therefore it should be "installed" in your <code>package.path</code>.
165
<p>You can also install CGILua using <a href="http://www.luarocks.org">LuaRocks</a>:</p>
167
<pre class="example">
168
luarocks install cgilua
171
<h2><a name="config"></a>Configuration</h2>
174
The Kepler distribution of CGILua 5.1 offers a single configuration file, called <code>config.lua</code>.
175
This file can be used to alter the default CGILua behaviour and is located in the Kepler configuration directory.
178
<p>Some of the uses of <code>config.lua</code> customization are:</p>
181
<dt><strong>Script Handlers</strong></dt>
182
<dd>A handler is responsible for the response of a request.
183
You can add new CGILua handlers using
184
<a href="reference.html#addscripthandler"><code>cgilua.addscripthandler</code></a>
185
(see also <a href="reference.html#buildplainhandler"><code>cgilua.buildplainhandler</code></a>
186
and <a href="reference.html#buildprocesshandler"><code>cgilua.buildprocesshandler</code></a>
187
for functions that build simple handlers).
190
<dt><strong>POST Data Sizes</strong></dt>
191
<dd>You can change the POST data size limits using
192
<a href="reference.html#setmaxinput"><code>cgilua.setmaxinput</code></a> and
193
<a href="reference.html#setmaxfilesize"><code>cgilua.setmaxfilesize</code></a>.
196
<dt><strong>Opening and Closing Functions</strong></dt>
197
<dd>You can add your functions to the life cycle of CGILua using
198
<a href="reference.html#addopenfunction"><code>cgilua.addopenfunction</code></a> and
199
<a href="reference.html#addclosefunction"><code>cgilua.addclosefunction</code></a>.
200
These functions are executed just before and just after the script execution,
201
even when an error occurs in the script processing.</dd>
206
In particular, the opening and closing functions are useful for different things.
207
Some examples of the use of such functions in <code>config.lua</code> are shown next.
211
Previous versions of CGILua loaded a <code>env.lua</code> file from the
212
script directory before processing it. To emulate this with CGILua 5.1 you can
216
<pre class="example">
217
cgilua.addopenfunction (function ()
218
cgilua.doif ("env.lua")
223
If every script needs to load a module (such as the sessions library), you can do:
226
<pre class="example">
227
require"cgilua.session"
228
cgilua.session.setsessiondir(CGILUA_TMP)
229
cgilua.addopenfunction (cgilua.session.open)
230
cgilua.addclosefunction (cgilua.session.close)
234
<em>Note</em> that the function <code>cgilua.addopenfunction</code>
235
must be used to call <code>cgilua.session.open</code> because this function
236
needs to change the <code>cgi</code> table (see section
237
<a href="#parameters">Receiving parameters</a>
238
for more information on this special table)
239
which is not yet available during the execution of the <code>config.lua</code>
240
file (see the <a href="#lifecycle">Request life cycle</a>).
244
When some scripts may use the library but others may not,
245
you could define an "enabling" function (which should be called at the
246
very beginning of each script that needs to use sessions):
249
<pre class="example">
250
require"cgilua.session"
251
cgilua.session.setsessiondir(CGILUA_TMP)
252
cgilua.enablesession = function ()
253
cgilua.session.open ()
254
cgilua.addclosefunction (cgilua.session.close)
259
Sometimes you need to configure a private libraries directory for each application
260
hosted in the server. This configuration allows the function <code>require</code>
261
to find packages installed in the private directory and in the system directory
262
but not in other application's private directory. To implement this you could do:
265
<pre class="example">
266
local app_lib_dir = {
267
["/virtual/path/"] = "/absolute/path/lib/",
269
local package = package
270
cgilua.addopenfunction (function ()
271
local app = app_lib_dir[cgilua.script_vdir]
273
package.path = app..'/?.lua'..';'..package.path
278
<h2><a name="scripts"></a>Lua Scripts</h2>
281
Lua Scripts are text files containing valid Lua code. This style of usage
282
adopts a more "raw" form of web programming, where a program is responsible
283
for the entire generation of the resulting page. Lua Scripts have a default
284
<code>.lua</code> extension.
288
To generate a valid web document (HTML, XML, WML, CSS etc) the Lua Script
289
must follow the expected HTTP order to produce its output, first sending the
290
correct <a href="reference.html#headers">headers</a> and then sending the
291
actual document <a href="reference.html#contents">contents</a>.
295
CGILua offers some functions to ease these tasks, such as
296
<a href="reference.html#htmlheader"><code>cgilua.htmlheader</code></a> to
297
produce the header for a HTML document and
298
<a href="reference.html#put"><code>cgilua.put</code></a> to send the document
299
contents (or part of it).
303
For example, a HTML document which displays the sentence "Hello World!" can
304
be generated with the following Lua Script:
307
<pre class="example">
312
<title>Hello World</title>
315
<strong>Hello World!</strong>
321
It should be noted that the above example generates a "fixed" page: even
322
though the page is generated at execution time there is no "variable"
323
information. That means that the very same document could be generated directly
324
with a simple static HTML file. However, Lua Scripts become especially useful
325
when the document contains information which is not known beforehand or changes
326
according to passed parameters, and it is necessary to generate a "dynamic" page.
330
Another easy example can be shown, this time using a Lua control structure,
331
variables, and the concatenation operator:
334
<pre class="example">
337
if cgilua.QUERY.language == 'english' then
338
greeting = 'Hello World!'
339
elseif cgilua.QUERY.language == 'portuguese' then
340
greeting = 'Olá Mundo!'
342
greeting = '[unknown language]'
345
cgilua.put('<html>')
346
cgilua.put('<head>')
347
cgilua.put(' <title>'..greeting..'</title>')
348
cgilua.put('</head>')
349
cgilua.put('<body>')
350
cgilua.put(' <strong>'..greeting..'</strong>')
351
cgilua.put('</body>')
352
cgilua.put('</html>')
356
In the above example the use of <code><em>cgilua.QUERY.language</em></code> indicates
357
that <em>language</em> was passed to the Lua Script as a
358
<a href="manual.html#parameters">CGILua parameter</a>, coming from the URL used to activate it
359
(via GET). If you were using a form, the parameter would be available in
360
<code><em>cgilua.POST.language</em></code>. CGILua automatically decodes such
361
QUERY and POST parameters so you can use them at will on your
362
Lua Scripts and Lua Pages.
365
<h2><a name="templates"></a>Lua Pages</h2>
368
A Lua Page is a text template file which will be processed by CGILua
369
before the HTTP server sends it to the client. CGILua does not
370
process the text itself but look for some special markups that include Lua
371
code into the file. After all those markups are processed and merged with the
372
template file, the results are sent to the client.
376
Lua Pages have a default <code>.lp</code> extension. They are a simpler
377
way to make a dynamic page because there is no need to send the HTTP headers.
378
Usually Lua Pages are HTML pages so CGILua sends the HTML header automatically.
382
Since there are some restrictions on the uses of HTTP headers sometimes
383
a Lua Script will have to be used instead of a Lua Page.
386
<p>The fundamental Lua Page markups are:</p>
389
<dt><strong><code><?lua <em>chunk</em> ?></code></strong></dt>
390
<dd>Processes and merges the Lua <em>chunk</em> execution results where
391
the markup is located in the template. The alternative form
392
<code><% <em>chunk</em> %></code> can also be used.</dd>
394
<dt><strong><code><?lua= <em>expression</em> ?></code></strong></dt>
395
<dd>Processes and merges the Lua <em>expression</em> evaluation where the
396
markup is located in the template. The alternative form
397
<code><%= <em>expression</em> %></code> can also be used.</dd>
401
Note that the ending mark could not appear inside a Lua chunk or Lua
402
expression even inside quotes. The Lua Pages pre-processor just makes global
403
substitutions on the template, searching for a matching pair of markups and
404
generating the corresponding Lua code to achieve the same result as the
405
equivalent Lua Script.
409
The second example on the previous section could be written using a
413
<pre class="example">
416
if cgilua.QUERY.language == 'english' then
417
greeting = 'Hello World!'
418
elseif cgilua.QUERY.language == 'portuguese' then
419
greeting = 'Olá Mundo!'
421
greeting = '[unknown language]'
425
<title><%= greeting %></title>
428
<strong><%= greeting %></strong>
434
HTML tags and Lua Page tags can be freely intermixed. However, as on other
435
template languages, it's considered a best practice to not use explicit
436
Lua logic on templates.
437
The recommended aproach is to use only function calls that returns content
438
chunks, so in this example, assuming that function <code>getGreeting</code>
439
was definied in file <code>functions.lua</code> as follows:
442
<pre class="example">
443
function getGreeting()
445
if cgilua.QUERY.language == 'english' then
446
greeting = 'Hello World!'
447
elseif cgilua.QUERY.language == 'portuguese' then
448
greeting = 'Olá Mundo!'
450
greeting = '[unknown language]'
456
<p>the Lua Page could be rewriten as:</p>
458
<pre class="example">
460
assert (loadfile"functions.lua")()
464
<title><%= getGreeting() %></title>
467
<strong><%= getGreeting() %></strong>
473
Another interesting feature of Lua Pages is the intermixing of Lua and HTML.
474
It is very usual to have a list of values in a table, iterate over the list
475
and show the items on the page.
479
A Lua Script could do that using a loop like:
482
<pre class="example">
483
cgilua.put("<ul>")
484
for i, item in ipairs(list) do
485
cgilua.put("<li>"..item.."</li>")
487
cgilua.put("</ul>")
491
The equivalent loop in Lua Page would be:
494
<pre class="example">
496
<% for i, item in ipairs(list) do %>
497
<li><%= item %></li>
502
<h2><a name="parameters"></a>Receiving parameters: the <code>QUERY</code> and <code>POST</code> tables</h2>
505
CGILua offers both types of request parameters (QUERY strings and POST data) in the
506
<code>cgilua.QUERY</code> and <code>cgilua.POST</code> tables.
510
Usually all types of parameters will be available as strings. If the value of
511
a parameter is a number, it will be converted to its string representation.
515
There are only two exceptions where the value will be a Lua table. The first
516
case occurs on file uploads, where the corresponding table will have the
521
<dt><strong>filename</strong></dt>
522
<dd>the file name as given by the client.</dd>
524
<dt><strong>filesize</strong></dt>
525
<dd>the file size in bytes.</dd>
527
<dt><strong>file</strong></dt>
528
<dd>the temporary file handle. The file must be copied
529
because CGILua will remove it after the script ends.</dd>
533
The other case that uses Lua tables occurs when
534
there is more than one value associated with the same parameter
535
name. This happens in the case of a selection list with multiple values; but it
536
also occurs when the form (of the referrer) had two or more
537
elements with the same <code>name</code> attribute (maybe because one was on a
538
form and another was in the query string). All values will be inserted
539
in an indexed table in the order in which they are handled.
542
<h2><a name="dispatching"></a>Dispatching</h2>
545
If you want to use more sophisticated URLs, the Kepler distribution includes a dispatching script
546
called <code>app.lua</code> that can be used to handle URLs in the format
547
<code>.../app.lua/<em>app_name</em>/<em>path_info</em></code> in a standard way.
548
URLs in this format are said to refer to CGILua spplications, which consists in a standard loading
549
sequence for web applications using CGILua and <code>app.lua</code> as their dispatcher:
553
<li>there is an <em>app_name</em> as the start of <em>path_info</em></li>
554
<li>there is an <code>init.lua</code> file in <code><em>CGILUA_APPS</em>/<em>app_name</em></code></li>
555
<li>changes the current directory to <code><em>CGILUA_APPS</em>/<em>app_name</em></code></li>
556
<li>sets <code>cgilua.app_name</code> to <em>app_name</em></li>
557
<li>adds <code><em>CGILUA_APPS</em>/<em>app_name</em>/lua</code> to the start of <code>package.path</code></li>
558
<li>executes <code>init.lua</code></li>
562
CGILua applications usually need to dispatch their actions using the remaining <em>path_info</em> and for that
563
they can use <code>cgilua.dispatcher</code> as a helper library. The example below uses it to dispatch URLs that
564
follow a convention similar to <a href="http://www.rubyonrails.org/">Rails</a>. Let's assume that this is a
565
<code>init.lua</code> file in the <code><em>CGILUA_APPS</em>/blog</code> directory:
568
<pre class="example">
569
require"cgilua.dispatcher"
570
return cgilua.dispatcher.route{"/$controller/$action/$ID", handle, "rails"}
574
In this example URLs like <code>.../app.lua/blog/post/edit/2</code> would result in the function <code>handle</code>
578
<pre class="example">
579
handle({controller="post", action="edit", ID="2"})
583
the <code>handle</code> function would then decide how to proceed depending on the parameters received and generate
584
the corresponding response using CGILua functions or a template engine like Lua Pages or Cosmo.
588
Note that this example does not include error handling for invalid URLs or default values.
591
<h2><a name="authentication"></a>Authentication</h2>
594
CGILua offers a simple but useful authentication mechanism that can be shared by different CGILua applications
595
or even applications developed in other platforms. The authentication mechanism is based on HTTP redirections
596
and assumes three different participants.
600
The first one is the controller script, which is responsible for centralizing the user authentication control
601
and deciding if the application should continue depending on a user being logged in or not. An example of such
602
controller would be the <code>app.lua</code> dispatcher script distributed with Kepler. As most of the controllers
603
would do, it checks for the presence of an authenticated user and redirects to the checking script when that fails:
606
<pre class="example">
607
-- checks for authenticated users
608
if not cgilua.authentication.username() then
609
cgilua.redirect(cgilua.authentication.checkURL())
611
-- continues with the application flow
615
<p>If your application is not handled by a single script like one using <code>app.lua</code> then you would need
616
to repeat this check in every script that requires authenticated users.
619
<p>The second participant in the authentication mechanism is the checking script. This script should ask for user
620
credentials, check them using the adequate method and redirect back to the original URL if the user was succesfully
625
One simple example of such a checking script is the one found in <code>/examples/check.lua</code> in CGILua CVS,
626
but usually a checking script implemented in CGILua would do the following:
629
<pre class="example">
630
-- Checking script example
631
-- Assumes that the login form will use two fields called username and pass
633
local username = cgilua.POST.username
634
local pass = cgilua.POST.pass
635
local logged, err, logoutURL
637
if cgilua.authentication then
638
logged, err = cgilua.authentication.check(username, pass)
639
username = cgilua.authentication.username() or ""
640
logoutURL = cgilua.authentication.logoutURL()
643
err = "No authentication configured!"
647
if logged and username then
648
-- goes back to the application
649
cgilua.redirect(cgilua.authentication.refURL())
652
-- displays the login form which submits to this same script
654
cgilua.lp.include ("login.lp", {
655
logged = logged, errorMsg = err, username = username,
656
cgilua = cgilua, logoutURL = logoutURL})
661
The login form for this example can be fount at <code>/examples/login.lp</code> in CGILua CVS and consists of:
664
<pre class="example">
665
<% if logged then %>
666
<p>User <%= username %> logged in</p>
667
<a href="<%= logoutURL %>">Logout</a>
669
<p style="color:#ff0000"><%= errorMsg %> </p>
670
<form method="post" action="" >
671
User name: <input name="username" maxlength="20" size="20" value="<%= username %>" ><br />
672
Password: <input name="pass" type="password" maxlength="20" size="20"><br />
673
<input type="submit" value="Login">
674
<input type="reset" value="Reset">
680
Finally the third participant in the authentication process is the configuration file. This file is used to
681
set the authentication method and other details. Each method has it's set of parameters and defines a
682
<code>check</code> callback used by CGILua during the authentication process.
683
See <code>/examples/authentication_conf.lua</code> for configuration examples using database, LDAP and Web server
684
authentication methods.
687
<h2><a name="error_handling"></a>Error Handling</h2>
689
<p>There are three functions for error handling in CGILua:</p>
693
<a href="reference.html#seterrorhandler"><code>cgilua.seterrorhandler</code></a>
694
defines the <em>error handler</em>, a function called by Lua when an error has
695
just occurred. The error handler has access to the execution stack before the
696
error is thrown so it can build an error message using stack information.
697
Lua also provides a function to do that: <code>debug.traceback</code>.
702
<a href="reference.html#seterroroutput"><code>cgilua.seterroroutput</code></a>
703
defines the function that decides what to do with the error message. It could
704
be sent to the client's browser, written to a log file or sent to an e-mail
705
address (with the help of
706
<a href="http://luasocket.luaforge.net/">LuaSocket</a> or
707
<a href="http://www.keplerproject.org/lualogging/">LuaLogging</a> for example).
712
<a href="reference.html#errorlog"><code>cgilua.errorlog</code></a>
713
is provided to write directly to the http server error log file.
717
An useful example of its use could be handling unexpected errors.
718
Customizing unexpected error messages to the end user but giving all the
719
information to the application's developers is the goal of the following
723
<pre class="example">
724
local ip = cgilua.servervariable"REMOTE_ADDR"
725
local developers_machines = {
726
["192.168.0.20"] = true,
727
["192.168.0.27"] = true,
728
["192.168.0.30"] = true,
730
local function mail (s)
731
require"cgilua.serialize"
735
table.insert (msg, tostring(s))
736
-- Tries to obtain the REFERER URL
737
table.insert (msg, tostring (cgilua.servervariable"HTTP_REFERER"))
738
table.insert (msg, cgilua.servervariable"SERVER_NAME"..
739
cgilua.servervariable"SCRIPT_NAME")
741
table.insert (msg, "CGI")
742
cgilua.serialize(cgi, function (s) table.insert (msg, s) end)
743
table.insert (msg, tostring (os.date()))
744
table.insert (msg, tostring (ip))
745
table.insert (msg, "Cookies:")
746
table.insert (msg, tostring (cgilua.servervariable"HTTP_COOKIE" or "no cookies"))
747
-- Formats message according to LuaSocket-2.0b3
748
local source = socket.smtp.message {
749
headers = { subject = "Script Error", },
750
body = table.concat (msg, '\n'),
753
local r, e = socket.smtp.send {
754
from = "sender@my.domain.net",
755
rcpt = "developers@my.domain.net",
759
if developers_machines[ip] then
760
-- Developer's error treatment: write to the display
761
cgilua.seterroroutput (function (msg)
762
cgilua.errorlog (msg)
763
cgilua.errorlog (cgilua.servervariable"REMOTE_ADDR")
764
cgilua.errorlog (os.date())
766
msg = string.gsub (string.gsub (msg, "\n", "<br>\n"), "\t", " ")
770
-- User's error treatment: shows a standard page and sends an e-mail to
772
cgilua.seterroroutput (function (s)
774
cgilua.put"<h1>An error occurred</h1>\n"
775
cgilua.put"The responsible is being informed."
782
The message is written to the browser if the request comes from one of
783
the developer's machines. If it is not the case, a simple polite message
784
is given to the user and a message is sent to the developer's e-mail account
785
containing all possible information to help reproduce the situation.
788
</div> <!-- id="content" -->
790
</div> <!-- id="main" -->
793
<p><a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.0!</a></p>
794
<p><small>$Id: manual.html,v 1.27 2008/05/19 18:13:36 carregal Exp $</small></p>
795
</div> <!-- id="about" -->
797
</div> <!-- id="container" -->