~ubuntu-branches/ubuntu/gutsy/libapache2-mod-python/gutsy

« back to all changes in this revision

Viewing changes to Doc/modpython6.tex

  • Committer: Bazaar Package Importer
  • Author(s): Piotr Ożarowski
  • Date: 2007-04-12 20:52:05 UTC
  • mfrom: (1.2.4 upstream) (1.1.2 etch)
  • Revision ID: james.westby@ubuntu.com-20070412205205-j4qlsw3o4tl615iq
Tags: 3.3.1-1
* New upstream release
* Remove configure and mod_python.h files in clean rule to make the diff.gz
  file smaller
* Current Python version in libapache2-mod-pythonX.Y package name (Provides:
  field) filled in automatically.
* Added XS-Vcs-Browser field

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
\chapter{Server Side Includes\label{ssi}}
 
2
 
 
3
\section{Overview of SSI\label{ssi-overview}}
 
4
 
 
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.
 
10
 
 
11
SSI directives have the following syntax:
 
12
 
 
13
\begin{verbatim}
 
14
<!--#element attribute=value attribute=value ... -->
 
15
\end{verbatim}
 
16
 
 
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.
 
21
 
 
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.
 
25
 
 
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
 
30
not be executed.
 
31
 
 
32
\section{Using Python Code\label{ssi-python-code}}
 
33
 
 
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.
 
39
 
 
40
\begin{verbatim}
 
41
<!--#python eval="10*'HELLO '" -->
 
42
<!--#python eval="len('HELLO')" -->
 
43
\end{verbatim}
 
44
 
 
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.
 
47
 
 
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
 
53
the code.
 
54
 
 
55
\begin{verbatim}
 
56
<!--#python exec="
 
57
filter.write(10*'HELLO ')
 
58
filter.write(str(len('HELLO')))
 
59
" -->
 
60
\end{verbatim}
 
61
 
 
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
 
65
elements.
 
66
 
 
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.
 
71
 
 
72
\begin{verbatim}
 
73
<!--#python exec="
 
74
print >> filter, len('HELLO')
 
75
" -->
 
76
\end{verbatim}
 
77
 
 
78
\section{Scope of Global Data\label{ssi-data-scope}}
 
79
 
 
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
 
84
class definitions.
 
85
 
 
86
\begin{verbatim}
 
87
<!--#python exec="
 
88
import cgi, time, os
 
89
def _escape(object):
 
90
    return cgi.escape(str(object))
 
91
now = time.time() 
 
92
" -->
 
93
<html>
 
94
<body>
 
95
<pre>
 
96
<!--#python eval="_escape(time.asctime(time.localtime(now)))"-->
 
97
 
 
98
<!--#python exec="
 
99
keys = os.environ.keys()
 
100
keys.sort()
 
101
for key in keys:
 
102
    print >> filter, _escape(key),
 
103
    print >> filter, '=',
 
104
    print >> filter, _escape(repr(os.environ.get(key)))
 
105
" -->
 
106
</pre>
 
107
</body>
 
108
</html>
 
109
\end{verbatim}
 
110
 
 
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.
 
115
 
 
116
\section{Pre-propulating Globals\label{ssi-globals}}
 
117
 
 
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.
 
124
 
 
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
 
127
handler.
 
128
 
 
129
\begin{verbatim}
 
130
PythonFixupHandler _handlers
 
131
\end{verbatim}
 
132
 
 
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
 
137
within the page.
 
138
 
 
139
\begin{verbatim}
 
140
from mod_python import apache
 
141
 
 
142
import cgi, time
 
143
 
 
144
def _escape(object):
 
145
    return cgi.escape(str(object))
 
146
 
 
147
def _header(filter):
 
148
    print >> filter, '...'
 
149
 
 
150
def _footer(filter):
 
151
    print >> filter, '...'
 
152
 
 
153
def fixuphandler(req):
 
154
    req.ssi_globals = {}
 
155
    req.ssi_globals['time'] = time
 
156
    req.ssi_globals['_escape'] = _escape
 
157
    req.ssi_globals['_header'] = _header
 
158
    req.ssi_globals['_footer'] = _footer
 
159
    return apache.OK
 
160
\end{verbatim}
 
161
 
 
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
 
164
pages.
 
165
 
 
166
\begin{verbatim}
 
167
<!--#python exec="
 
168
now = time.time()
 
169
" -->
 
170
<html>
 
171
<body>
 
172
<!--#python exec="_header(filter)" -->
 
173
<pre>
 
174
<!--#python eval="_escape(time.asctime(time.localtime(now)))"-->
 
175
</pre>
 
176
<!--#python exec="_footer(filter)" -->
 
177
</body>
 
178
</html>
 
179
\end{verbatim}
 
180
 
 
181
\section{Conditional Expressions\label{ssi-conditionals}}
 
182
 
 
183
SSI allows for some programmability in its own right through the use of
 
184
conditional expressions. The structure of this conditional construct is:
 
185
 
 
186
\begin{verbatim}
 
187
<!--#if expr="test_condition" -->
 
188
<!--#elif expr="test_condition" -->
 
189
<!--#else -->
 
190
<!--#endif -->
 
191
\end{verbatim}
 
192
 
 
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.
 
195
 
 
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}.
 
203
 
 
204
To set these variables from within a mod_python handler, the
 
205
\code{subprocess_env} table object would be manipulated directly through
 
206
the request object.
 
207
 
 
208
\begin{verbatim}
 
209
from mod_python import apache
 
210
 
 
211
def fixuphandler(req):
 
212
    debug = req.get_config().get('PythonDebug', '0')
 
213
    req.subprocess_env['DEBUG'] = debug
 
214
    return apache.OK
 
215
\end{verbatim}
 
216
 
 
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.
 
219
 
 
220
\begin{verbatim}
 
221
<!--#python exec="
 
222
debug = filter.req.get_config().get('PythonDebug', '0')
 
223
filter.req.subprocess_env['DEBUG'] = debug
 
224
" -->
 
225
<html>
 
226
<body>
 
227
<!--#if expr="${DEBUG} != 0" -->
 
228
DEBUG ENABLED
 
229
<!--#else -->
 
230
DEBUG DISABLED
 
231
<!--#endif -->
 
232
</body>
 
233
</html>
 
234
\end{verbatim}
 
235
 
 
236
\section{Enabling INCLUDES Filter\label{ssi-output-filter}}
 
237
 
 
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.
 
241
 
 
242
\begin{verbatim}
 
243
AddOutputFilter INCLUDES .shtml
 
244
\end{verbatim}
 
245
 
 
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
 
252
used.
 
253
 
 
254
\begin{verbatim}
 
255
from mod_python import apache
 
256
 
 
257
def fixuphandler(req):
 
258
    req.add_output_filter('INCLUDES')
 
259
    return apache.OK
 
260
\end{verbatim}
 
261
 
1
262
\chapter{Standard Handlers\label{handlers}}
2
263
 
3
264
\section{Publisher Handler\label{hand-pub}}
13
274
  <Directory /some/path>
14
275
    SetHandler mod_python 
15
276
    PythonHandler mod_python.publisher
16
 
    </Directory>
 
277
  </Directory>
17
278
\end{verbatim}
18
279
 
19
280
This handler allows access to functions and variables within a module
24
285
  """ Publisher example """
25
286
 
26
287
  def say(req, what="NOTHING"):
27
 
  return "I am saying %s" % what
 
288
      return "I am saying %s" % what
28
289
 
29
290
\end{verbatim}
30
291
 
87
348
  DocumentRoot /some/dir
88
349
 
89
350
  <Directory /some/dir>
90
 
  SetHandler mod_python
91
 
  PythonHandler mod_python.publisher
 
351
    SetHandler mod_python
 
352
    PythonHandler mod_python.publisher
92
353
  </Directory>
93
354
\end{verbatim}
94
355
 
96
357
 
97
358
\begin{verbatim}
98
359
  def index(req):
99
 
 
100
 
  return "We are in index()"
 
360
      return "We are in index()"
101
361
 
102
362
  def hello(req):
 
363
      return "We are in hello()"
103
364
 
104
 
  return "We are in hello()"
105
365
\end{verbatim}
106
366
 
107
367
Then:
183
443
 
184
444
  def __auth__(req, user, passwd):
185
445
 
186
 
  if user == "eggs" and passwd == "spam" or \
187
 
  user == "joe" and passwd == "eoj":
188
 
  return 1
189
 
  else:
190
 
  return 0
 
446
      if user == "eggs" and passwd == "spam" or \
 
447
          user == "joe" and passwd == "eoj":
 
448
          return 1
 
449
      else:
 
450
          return 0
191
451
 
192
452
  def __access__(req, user):
193
 
  if user == "eggs":
194
 
  return 1
195
 
  else:
196
 
  return 0
 
453
      if user == "eggs":
 
454
          return 1
 
455
      else:
 
456
          return 0
197
457
 
198
458
  def hello(req):
199
 
  return "hello"
 
459
      return "hello"
200
460
 
201
461
\end{verbatim}
202
462
 
209
469
  __access__ = ["eggs"]
210
470
 
211
471
  def hello(req):
212
 
  return "hello"
 
472
      return "hello"
213
473
 
214
474
\end{verbatim}
215
475
 
220
480
\begin{verbatim}
221
481
  def sensitive(req):
222
482
 
223
 
  def __auth__(req, user, password):
224
 
  if user == 'spam' and password == 'eggs':
225
 
  # let them in
226
 
  return 1
227
 
  else:
228
 
  # no access
229
 
  return 0
 
483
      def __auth__(req, user, password):
 
484
          if user == 'spam' and password == 'eggs':
 
485
              # let them in
 
486
              return 1
 
487
          else:
 
488
              # no access
 
489
              return 0
230
490
 
231
 
  # something involving sensitive information
232
 
  return 'sensitive information`
 
491
      # something involving sensitive information
 
492
      return 'sensitive information`
233
493
\end{verbatim}
234
494
 
235
495
Note that this technique will also work if \code{__auth__} or
284
544
appending an underscore (\samp{_}) to the end of the url you can get a
285
545
nice side-by-side listing of original PSP code and resulting Python
286
546
code generated by the \code{psp} module. This is very useful for
287
 
debugging.
 
547
debugging. You'll need to adjust your httpd configuration:
 
548
 
 
549
\begin{verbatim}
 
550
  AddHandler mod_python .psp .psp_
 
551
  PythonHandler mod_python.psp
 
552
  PythonDebug On
 
553
\end{verbatim}
288
554
 
289
555
\begin{notice}
290
556
Leaving debug on in a production environment will allow remote users