~ubuntu-branches/ubuntu/karmic/libapache2-mod-python/karmic-updates

« back to all changes in this revision

Viewing changes to Doc/modpython3.tex

  • Committer: Bazaar Package Importer
  • Author(s): Thom May
  • Date: 2004-09-06 20:27:57 UTC
  • Revision ID: james.westby@ubuntu.com-20040906202757-yzpyu1bcabgpjtiu
Tags: upstream-3.1.3
ImportĀ upstreamĀ versionĀ 3.1.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
\chapter{Tutorial\label{tutorial}}
 
2
 
 
3
\begin{flushright}
 
4
  \emph{So how can I make this work?}
 
5
\end{flushright}
 
6
 
 
7
\emph{This is a quick guide to getting started with mod_python 
 
8
  programming once you have it installed. This is \textbf{not} an
 
9
  installation manual!}
 
10
 
 
11
\emph{It is also highly recommended to read (at least the top part of)
 
12
  Section \ref{pythonapi}, \citetitle[pythonapi.html]{Python API} after
 
13
  completing this tutorial.}
 
14
 
 
15
\section{A Quick Start with the Publisher Handler\label{tut-pub}}
 
16
 
 
17
This section provides a quick overview of the Publisher handler for
 
18
those who would like to get started without getting into too much
 
19
detail. A more thorough explanation of how mod_python handlers work
 
20
and what a handler actually is follows on in the later sections of the
 
21
tutorial.
 
22
 
 
23
The \code{publisher} handler is provided as one of the standard
 
24
mod_python handlers. To get the publisher handler working, you will
 
25
need the following lines in your config:
 
26
 
 
27
\begin{verbatim}
 
28
  AddHandler mod_python .py
 
29
  PythonHandler mod_python.publisher
 
30
  PythonDebug On
 
31
\end{verbatim}
 
32
 
 
33
The following example will demonstrate a simple feedback form. The
 
34
form will ask for the name, e-mail address and a comment and construct
 
35
an e-mail to the webmaster using the information submitted by the
 
36
user. This simple application consists of two files:
 
37
\filenq{form.html} - the form to collect the data, and
 
38
\filenq{form.py} - the target of the form's action.
 
39
 
 
40
Here is the html for the form:
 
41
 
 
42
\begin{verbatim}
 
43
  <html>
 
44
      Please provide feedback below:
 
45
  <p>                           
 
46
  <form action="form.py/email" method="POST">
 
47
 
 
48
      Name:    <input type="text" name="name"><br>
 
49
      Email:   <input type="text" name="email"><br>
 
50
      Comment: <textarea name="comment" rows=4 cols=20></textarea><br>
 
51
      <input type="submit">
 
52
 
 
53
  </form>
 
54
  </html>  
 
55
\end{verbatim}
 
56
 
 
57
Note the \code{action} element of the \code{<form>} tag points to
 
58
\code{form.py/email}. We are going to create a file called
 
59
\filenq{form.py}, like this:
 
60
 
 
61
\begin{verbatim}
 
62
import smtplib
 
63
 
 
64
WEBMASTER = "webmaster"   # webmaster e-mail
 
65
SMTP_SERVER = "localhost" # your SMTP server
 
66
 
 
67
def email(req, name, email, comment):
 
68
 
 
69
    # make sure the user provided all the parameters
 
70
    if not (name and email and comment):
 
71
        return "A required parameter is missing, \
 
72
               please go back and correct the error"
 
73
 
 
74
    # create the message text
 
75
    msg = """\
 
76
From: %s                                                                                                                                           
 
77
Subject: feedback
 
78
To: %s
 
79
 
 
80
I have the following comment:
 
81
 
 
82
%s
 
83
 
 
84
Thank You,
 
85
 
 
86
%s
 
87
 
 
88
""" % (email, WEBMASTER, comment, name)
 
89
 
 
90
    # send it out
 
91
    conn = smtplib.SMTP(SMTP_SERVER)
 
92
    conn.sendmail(email, [WEBMASTER], msg)
 
93
    conn.quit()
 
94
 
 
95
    # provide feedback to the user
 
96
    s = """\
 
97
<html>
 
98
 
 
99
Dear %s,<br>                                                                                                                                       
 
100
Thank You for your kind comments, we
 
101
will get back to you shortly.
 
102
 
 
103
</html>""" % name
 
104
 
 
105
    return s
 
106
\end{verbatim}
 
107
 
 
108
When the user clicks the Submit button, the publisher handler will
 
109
load the \function{email} function in the \module{form} module,
 
110
passing it the form fields as keyword arguments. It will also pass the
 
111
request object as \code{req}.
 
112
 
 
113
Note that you do not have to have \code{req} as one of the arguments
 
114
if you do not need it. The publisher handler is smart enough to pass
 
115
your function only those arguments that it will accept.
 
116
 
 
117
The data is sent back to the browser via the return value of the
 
118
function.
 
119
 
 
120
Even though the Publisher handler simplifies mod_python programming a
 
121
great deal, all the power of mod_python is still available to this
 
122
program, since it has access to the request object. You can do all the
 
123
same things you can do with a ``native'' mod_python handler, e.g. set
 
124
custom headers via \code{req.headers_out}, return errors by raising
 
125
\exception{apache.SERVER_ERROR} exceptions, write or read directly to
 
126
and from the client via \method{req.write()} and \method{req.read()},
 
127
etc.
 
128
 
 
129
Read Section \ref{hand-pub} \citetitle[hand-pub.html]{Publisher Handler}
 
130
for more information on the publisher handler. 
 
131
 
 
132
\section{Quick Overview of how Apache Handles Requests\label{tut-overview}}
 
133
 
 
134
If you would like delve in deeper into the functionality of
 
135
mod_python, you need to understand what a handler is.  
 
136
 
 
137
Apache processes requests in \dfn{phases}. For example, the first
 
138
phase may be to authenticate the user, the next phase to verify
 
139
whether that user is allowed to see a particular file, then (next
 
140
phase) read the file and send it to the client. A typical static file
 
141
request involves three phases: (1) translate the requested URI to a
 
142
file location (2) read the file and send it to the client, then (3)
 
143
log the request. Exactly which phases are processed and how varies
 
144
greatly and depends on the configuration.
 
145
 
 
146
A \dfn{handler} is a function that processes one phase. There may be
 
147
more than one handler available to process a particular phase, in
 
148
which case they are called by Apache in sequence. For each of the
 
149
phases, there is a default Apache handler (most of which by default
 
150
perform only very basic functions or do nothing), and then there are
 
151
additional handlers provided by Apache modules, such as mod_python.
 
152
 
 
153
Mod_python provides every possible handler to Apache. Mod_python
 
154
handlers by default do not perform any function, unless specifically
 
155
told so by a configuration directive. These directives begin with
 
156
\samp{Python} and end with \samp{Handler}
 
157
(e.g. \code{PythonAuthenHandler}) and associate a phase with a Python
 
158
function. So the main function of mod_python is to act as a dispatcher
 
159
between Apache handlers and Python functions written by a developer
 
160
like you.
 
161
 
 
162
The most commonly used handler is \code{PythonHandler}. It handles the
 
163
phase of the request during which the actual content is
 
164
provided. Because it has no name, it is sometimes referred to as as
 
165
\dfn{generic} handler. The default Apache action for this handler is
 
166
to read the file and send it to the client. Most applications you will
 
167
write will override this one handler. To see all the possible
 
168
handlers, refer to Section \ref{directives},
 
169
\citetitle[directives.html]{Apache Directives}.
 
170
 
 
171
\section{So what Exactly does Mod-python do?\label{tut-what-it-do}}
 
172
 
 
173
Let's pretend we have the following configuration: 
 
174
\begin{verbatim}
 
175
  <Directory /mywebdir>
 
176
      AddHandler mod_python .py
 
177
      PythonHandler myscript
 
178
      PythonDebug On
 
179
  </Directory>
 
180
\end{verbatim}
 
181
 
 
182
\strong{NB:} \filenq{/mywebdir} is an absolute physical path. 
 
183
 
 
184
And let's say that we have a python program (Windows users: substitute
 
185
forward slashes for backslashes) \file{/mywedir/myscript.py} that looks like
 
186
this:
 
187
 
 
188
\begin{verbatim}
 
189
from mod_python import apache
 
190
 
 
191
def handler(req):
 
192
 
 
193
    req.content_type = "text/plain"
 
194
    req.write("Hello World!")
 
195
 
 
196
    return apache.OK
 
197
\end{verbatim}    
 
198
 
 
199
Here is what's going to happen: The \code{AddHandler} directive tells
 
200
Apache that any request for any file ending with \file{.py} in the
 
201
\file{/mywebdir} directory or a subdirectory thereof needs to be
 
202
processed by mod_python. The \samp{PythonHandler myscript} directive
 
203
tells mod_python to process the generic handler using the
 
204
\code{myscript} script. The \samp{PythonDebug On} directive instructs
 
205
mod_python in case of an Python error to send error output to the
 
206
client (in addition to the logs), very useful during development.
 
207
 
 
208
When a request comes in, Apache starts stepping through its request
 
209
processing phases calling handlers in mod_python. The mod_python
 
210
handlers check whether a directive for that handler was specified in
 
211
the configuration. (Remember, it acts as a dispatcher.)  In our
 
212
example, no action will be taken by mod_python for all handlers except
 
213
for the generic handler. When we get to the generic handler,
 
214
mod_python will notice \samp{PythonHandler myscript} directive and do
 
215
the following:
 
216
 
 
217
\begin{enumerate}
 
218
 
 
219
\item
 
220
  If not already done, prepend the directory in which the
 
221
  \code{PythonHandler} directive was found to \code{sys.path}.
 
222
 
 
223
\item
 
224
  Attempt to import a module by name \code{myscript}. (Note that if
 
225
  \code{myscript} was in a subdirectory of the directory where
 
226
  \code{PythonHandler} was specified, then the import would not work
 
227
  because said subdirectory would not be in the \code{sys.path}. One
 
228
  way around this is to use package notation, e.g. \samp{PythonHandler
 
229
  subdir.myscript}.)
 
230
 
 
231
\item 
 
232
  Look for a function called \code{handler} in \code{myscript}.
 
233
 
 
234
\item
 
235
  Call the function, passing it a request object. (More on what a
 
236
  request object is later)
 
237
 
 
238
\item
 
239
  At this point we're inside the script: 
 
240
 
 
241
  \begin{itemize}
 
242
 
 
243
  \item
 
244
    \begin{verbatim}
 
245
from mod_python import apache
 
246
    \end{verbatim}
 
247
 
 
248
    This imports the apache module which provides us the interface to
 
249
    Apache. With a few rare exceptions, every mod_python program will have
 
250
    this line.
 
251
 
 
252
  \item
 
253
    \begin{verbatim}
 
254
def handler(req):
 
255
    \end{verbatim}
 
256
 
 
257
    \index{handler} This is our \dfn{handler} function declaration. It
 
258
    is called \samp{handler} because mod_python takes the name of the
 
259
    directive, converts it to lower case and removes the word
 
260
    \samp{python}. Thus \samp{PythonHandler} becomes
 
261
    \samp{handler}. You could name it something else, and specify it
 
262
    explicitly in the directive using \samp{::}. For example, if the
 
263
    handler function was called \samp{spam}, then the directive would
 
264
    be \samp{PythonHandler myscript::spam}.
 
265
 
 
266
    Note that a handler must take one argument - the request
 
267
    object. The request object is an object that provides all of the
 
268
    information about this particular request - such as the IP of
 
269
    client, the headers, the URI, etc. The communication back to the
 
270
    client is also done via the request object, i.e. there is no
 
271
    ``response'' object.
 
272
 
 
273
  \item
 
274
    \begin{verbatim}
 
275
req.content_type = "text/plain"
 
276
    \end{verbatim}
 
277
 
 
278
    This sets the content type to \samp{text/plain}. The default is usually
 
279
    \samp{text/html}, but since our handler doesn't produce any html,
 
280
    \samp{text/plain} is more appropriate.
 
281
 
 
282
  \item
 
283
    \begin{verbatim}
 
284
req.write("Hello World!")
 
285
    \end{verbatim}
 
286
 
 
287
    This writes the \samp{Hello World!} string to the client. (Did I really
 
288
    have to explain this one?)
 
289
 
 
290
  \item
 
291
    \begin{verbatim}
 
292
return apache.OK
 
293
    \end{verbatim}
 
294
 
 
295
    This tells Apache that everything went OK and that the request has
 
296
    been processed. If things did not go OK, that line could be return
 
297
    \constant{apache.HTTP_INTERNAL_SERVER_ERROR} or return
 
298
    \constant{apache.HTTP_FORBIDDEN}. When things do not go OK, Apache
 
299
    will log the error and generate an error message for the client.
 
300
  \end{itemize}
 
301
\end{enumerate}
 
302
 
 
303
\strong{Some food for thought:} If you were paying attention, you
 
304
noticed that the text above didn't specify that in order for the
 
305
handler code to be executed, the URL needs to refer to
 
306
\filenq{myscript.py}. The only requirement was that it refers to a
 
307
\filenq{.py} file. In fact the name of the file doesn't matter, and
 
308
the file referred to in the URL doesn't have to exist. So, given the
 
309
above configuration, \samp{http://myserver/mywebdir/myscript.py} and
 
310
\samp{http://myserver/mywebdir/montypython.py} would give the exact
 
311
same result. The important thing to understand here is that a handler
 
312
augments the server behaviour when processing a specific type of file,
 
313
not an individual file.
 
314
 
 
315
\emph{At this point, if you didn't understand the above paragraph, go
 
316
  back and read it again, until you do.}
 
317
 
 
318
\section{Now something More Complicated - Authentication\label{tut-more-complicated}}
 
319
 
 
320
Now that you know how to write a primitive handler, let's try
 
321
something more complicated.
 
322
 
 
323
Let's say we want to password-protect this directory. We want the
 
324
login to be \samp{spam}, and the password to be \samp{eggs}.
 
325
 
 
326
First, we need to tell Apache to call our \emph{authentication}
 
327
handler when authentication is needed. We do this by adding the
 
328
\code{PythonAuthenHandler}. So now our config looks like this:
 
329
 
 
330
\begin{verbatim}
 
331
  <Directory /mywebdir>
 
332
      AddHandler mod_python .py
 
333
      PythonHandler myscript
 
334
      PythonAuthenHandler myscript
 
335
      PythonDebug On
 
336
  </Directory>
 
337
\end{verbatim}
 
338
 
 
339
Notice that the same script is specified for two different
 
340
handlers. This is fine, because if you remember, mod_python will look
 
341
for different functions within that script for the different handlers.
 
342
 
 
343
Next, we need to tell Apache that we are using Basic HTTP
 
344
authentication, and only valid users are allowed (this is fairly basic
 
345
Apache stuff, so we're not going to go into details here). Our config
 
346
looks like this now:
 
347
 
 
348
\begin{verbatim}
 
349
  <Directory /mywebdir>
 
350
     AddHandler mod_python .py
 
351
     PythonHandler myscript
 
352
     PythonAuthenHandler myscript
 
353
     PythonDebug On
 
354
     AuthType Basic
 
355
     AuthName "Restricted Area"
 
356
     require valid-user
 
357
  </Directory>
 
358
\end{verbatim}          
 
359
 
 
360
Now we need to write an authentication handler function in
 
361
\file{myscript.py}. A basic authentication handler would look like
 
362
this:
 
363
 
 
364
\begin{verbatim}
 
365
 
 
366
from mod_python import apache
 
367
 
 
368
def authenhandler(req):
 
369
 
 
370
    pw = req.get_basic_auth_pw()
 
371
    user = req.user
 
372
 
 
373
    if user == "spam" and pw == "eggs":
 
374
       return apache.OK
 
375
    else:
 
376
       return apache.HTTP_UNAUTHORIZED
 
377
\end{verbatim}  
 
378
 
 
379
Let's look at this line by line: 
 
380
 
 
381
\begin{itemize}
 
382
 
 
383
\item
 
384
  \begin{verbatim}
 
385
def authenhandler(req):
 
386
  \end{verbatim}
 
387
 
 
388
  This is the handler function declaration. This one is called
 
389
  \code{authenhandler} because, as we already described above,
 
390
  mod_python takes the name of the directive
 
391
  (\code{PythonAuthenHandler}), drops the word \samp{Python} and converts
 
392
  it lower case.
 
393
 
 
394
\item
 
395
  \begin{verbatim}
 
396
    pw = req.get_basic_auth_pw()
 
397
  \end{verbatim}
 
398
  
 
399
  This is how we obtain the password. The basic HTTP authentication
 
400
  transmits the password in base64 encoded form to make it a little
 
401
  bit less obvious. This function decodes the password and returns it
 
402
  as a string. Note that we have to call this function before obtaining
 
403
  the user name.
 
404
 
 
405
\item
 
406
  \begin{verbatim}
 
407
    user = req.user
 
408
  \end{verbatim}
 
409
  
 
410
  This is how you obtain the username that the user entered. 
 
411
 
 
412
\item
 
413
  \begin{verbatim}
 
414
    if user == "spam" and pw == "eggs":
 
415
        return apache.OK
 
416
  \end{verbatim}
 
417
 
 
418
  We compare the values provided by the user, and if they are what we
 
419
  were expecting, we tell Apache to go ahead and proceed by returning
 
420
  \constant{apache.OK}. Apache will then consider this phase of the
 
421
  request complete, and proceed to the next phase. (Which in this case
 
422
  would be \function{handler()} if it's a \code{.py} file).
 
423
 
 
424
\item
 
425
  \begin{verbatim}
 
426
    else:
 
427
        return apache.HTTP_UNAUTHORIZED 
 
428
  \end{verbatim}
 
429
 
 
430
  Else, we tell Apache to return \constant{HTTP_UNAUTHORIZED} to the
 
431
  client, which usually causes the browser to pop a dialog box asking
 
432
  for username and password.
 
433
 
 
434
\end{itemize}
 
435