tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: CGI scripts



Am 08.05.11 11:44, schrieb Jukka Ruohonen:
> Hello.
> 
> Now that lua(1) and httpd(8) are in the base system, what people think about
> distributing some CGI scripts for instance via /usr/share/examples? Examples
> could include for instance some system or server monitoring scripts that are
> often seen in commercial products.

(caution, long reply...)

I like the idea of generating content dynamically, CGI, however, looks
like the wrong path to me.  There exist more elegant ways, FastCGI comes
to my mind, or any approach where there is not the overhead of starting
the CGI program.

In our commercial products we use sth we call Lua Templates, a page
template engine that uses Lua:

- Normal text gets rendered as is
- text enclosed in <% ... %> brackets is executed as Lua code
- text enclosed in <%= ... %> brackets is evaluated as a Lua expression
and the resulting value is inserted here
- <%=FMT ... %> is a special version that allows for formatting the
output like in string.format()
- text enclosed in <%! ... %> is a processing directive, currently only
'include' is supported

Upon first use, a template gets converted to Lua bytecode in one step,
subsequent usages are considerable faster, i.e. each template ends up as
a Lua function in the rendering state.

Apropos rendering: we use two Lua states:  One state is the application
logic, i.e. the data processing parts.  For rendering, we use a second
state which is only used to produce the web-pages.  The two states are
"linked" by a proxy module, which allows us to use variables from one
Lua state in another Lua state.  All the core code for this is written
in C, making extensive use of the Lua C-API.  To test a template, there
is a binary 'lt' which can be used from the commandline.

An application program roughly looks like this:

require 'proxy'

function doSth ()
  p = lt.proxy()

  p.data = {
    name = 'mbalmer',
    age = '42'
  }

  lt.render('template.lt')
end

As the code implies, p.data is a table that is actually created in the
render state, not in the processing state.  p is the proxy object that
allows me to manipulate the other state.

lt.render is a function in the render state and template.lt could look
like this:

<%! include header.lt %>

<h1>Example template</h1>

Name: <%= data.name %><br>
Age: <%= data.age %><br>

<% for n = 1, 10 do %>
Number <%=02d n %><br>
<% end %>

The idea behind this slight complication is to prevent the rendering
state from acessing application internals, thus strongly separating
application logic from presentation.  Of course for simple applications
this is not needed. ymmv.

We link URLs to Lua functions in a RESTful way, Lua functions register
themselves for a certain request, and a dispatcher (written in C) that
handles authorization and such will dispatch incoming HTTP requests to
the right Lua function.

As for the web interface we use lighttpd and FastCGI currently, but
having this somehow using the in-tree httpd would be nice.  Dunno of
much use this system is, but if there is interest in this Lua Template /
proxy stuff, we could consider making it available some time in the
future.  But it would need some work, since at the moment we don't have
code to decode the HTTP request (we still use ClearSilver for this part).





Home | Main Index | Thread Index | Old Index