1
\chapter{Server Side Includes\label{ssi}}
3
\section{Overview of SSI\label{ssi-overview}}
5
SSI (Server Side Includes) are directives that are placed in HTML pages,
6
and evaluated on the server while the pages are being served. They let you
7
add dynamically generated content to an existing HTML page, without having
8
to serve the entire page via a CGI program, or other dynamic technology
9
such as a mod_python handler.
11
SSI directives have the following syntax:
14
<!--#element attribute=value attribute=value ... -->
17
It is formatted like an HTML comment, so if you don't have SSI correctly
18
enabled, the browser will ignore it, but it will still be visible in the
19
HTML source. If you have SSI correctly configured, the directive will be
20
replaced with its results.
22
For a more thorough description of the SSI mechanism and how to enable it,
23
see the \citetitle[http://httpd.apache.org/docs/2.0/howto/ssi.html]{SSI
24
tutorial} provided with the Apache documentation.
26
Version 3.3 of mod_python introduces support for using Python code within
27
SSI files. Note that mod_python honours the intent of the Apache
28
\code{IncludesNOEXEC} option to the \code{Options} directive. That is, if
29
\code{IncludesNOEXEC} is enabled, then Python code within a SSI file will
32
\section{Using Python Code\label{ssi-python-code}}
34
The extensions to mod_python to allow Python code to be used in conjunction
35
with SSI introduces the new SSI directive called 'python'. This directive
36
can be used in two forms, these being 'eval' and 'exec' modes. In the case
37
of 'eval', a Python expression is used and it is the result of that
38
expression which is substituted in place into the page.
41
<!--#python eval="10*'HELLO '" -->
42
<!--#python eval="len('HELLO')" -->
45
Where the result of the expression is not a string, the value will be
46
automatically converted to a string by applying \code{str()} to the value.
48
In the case of 'exec' a block of Python code may be included. For any
49
output from this code to appear in the page, it must be written back
50
explicitly as being part of the response. As SSI are processed by an Apache
51
output filter, this is done by using an instance of the mod_python
52
\code{filter} object which is pushed into the global data set available to
57
filter.write(10*'HELLO ')
58
filter.write(str(len('HELLO')))
62
Any Python code within the 'exec' block must have a zero first level
63
indent. You cannot start the code block with an arbitrary level of indent
64
such that it lines up with any indenting used for surrounding HTML
67
Although the mod_python \code{filter} object is not a true file object, that
68
it provides the \code{write()} method is sufficient to allow the \code{print}
69
statement to be used on it directly. This will avoid the need to explicitly
70
convert non string objects to a string before being output.
74
print >> filter, len('HELLO')
78
\section{Scope of Global Data\label{ssi-data-scope}}
80
Multiple instances of 'eval' or 'exec' code blocks may be used within the
81
one page. Any changes to or creation of global data which is performed
82
within one code block will be reflected in any following code blocks.
83
Global data constitutes variables as well as module imports, function and
90
return cgi.escape(str(object))
96
<!--#python eval="_escape(time.asctime(time.localtime(now)))"-->
99
keys = os.environ.keys()
102
print >> filter, _escape(key),
103
print >> filter, '=',
104
print >> filter, _escape(repr(os.environ.get(key)))
111
The lifetime of any global data is for the current request only. If data
112
must persist between requests, it must reside in external modules and as
113
necessary be protected against multithreaded access in the event that a
114
multithreaded Apache MPM is used.
116
\section{Pre-propulating Globals\label{ssi-globals}}
118
Any Python code which appears within the page has to be compiled each time
119
the page is accessed before it is executed. In other words, the compiled
120
code is not cached between requests. To limit such recompilation and to
121
avoid duplication of common code amongst many pages, it is preferable to
122
pre-populate the global data from within a mod_python handler prior to the
123
page being processed.
125
In most cases, a fixup handler would be used for this purpose. For this to
126
work, first need to configure Apache so that it knows to call the fixup
130
PythonFixupHandler _handlers
133
The implementation of the fixup handler contained in \code{_handlers.py}
134
then needs to create an instance of a Python dictionary, store that in the
135
mod_python request object as \code{ssi_globals} and then populate that
136
dictionary with any data to be available to the Python code executing
140
from mod_python import apache
145
return cgi.escape(str(object))
148
print >> filter, '...'
151
print >> filter, '...'
153
def fixuphandler(req):
155
req.ssi_globals['time'] = time
156
req.ssi_globals['_escape'] = _escape
157
req.ssi_globals['_header'] = _header
158
req.ssi_globals['_footer'] = _footer
162
This is most useful where it is necessary to insert common information such
163
as headers, footers or menu panes which are dynamically generated into many
172
<!--#python exec="_header(filter)" -->
174
<!--#python eval="_escape(time.asctime(time.localtime(now)))"-->
176
<!--#python exec="_footer(filter)" -->
181
\section{Conditional Expressions\label{ssi-conditionals}}
183
SSI allows for some programmability in its own right through the use of
184
conditional expressions. The structure of this conditional construct is:
187
<!--#if expr="test_condition" -->
188
<!--#elif expr="test_condition" -->
193
A test condition can be any sort of logical comparison, either comparing
194
values to one another, or testing the 'truth' of a particular value.
196
The source of variables used in conditional expressions is distinct from
197
the set of global data used by the Python code executed within a page.
198
Instead, the variables are sourced from the \code{subprocess_env} table
199
object contained within the request object. The values of these variables
200
can be set from within a page using the SSI 'set' directive, or by a range
201
of other Apache directives within the Apache configuration files such as
202
\code{BrowserMatchNoCase} and \code{SetEnvIf}.
204
To set these variables from within a mod_python handler, the
205
\code{subprocess_env} table object would be manipulated directly through
209
from mod_python import apache
211
def fixuphandler(req):
212
debug = req.get_config().get('PythonDebug', '0')
213
req.subprocess_env['DEBUG'] = debug
217
If being done from within Python code contained within the page itself, the
218
request object would first have to be accessed via the filter object.
222
debug = filter.req.get_config().get('PythonDebug', '0')
223
filter.req.subprocess_env['DEBUG'] = debug
227
<!--#if expr="${DEBUG} != 0" -->
236
\section{Enabling INCLUDES Filter\label{ssi-output-filter}}
238
SSI is traditionally enabled using the \code{AddOutputFilter} directive in
239
the Apache configuration files. Normally this would be where the request
240
mapped to a static file.
243
AddOutputFilter INCLUDES .shtml
246
When mod_python is being used, the ability to dynamically enable output
247
filters for the current request can instead be used. This could be done
248
just for where the request maps to a static file, but may just as easily be
249
carried out where the content of a response is generated dynamically. In
250
either case, to enable SSI for the current request, the
251
\code{add_output_filter()} method of the mod_python request object would be
255
from mod_python import apache
257
def fixuphandler(req):
258
req.add_output_filter('INCLUDES')
1
262
\chapter{Standard Handlers\label{handlers}}
3
264
\section{Publisher Handler\label{hand-pub}}