File: node16.html

package info (click to toggle)
cherrypy 0.10-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 10,324 kB
  • ctags: 1,759
  • sloc: python: 14,411; sh: 6,915; perl: 2,472; makefile: 76
file content (464 lines) | stat: -rw-r--r-- 20,029 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>14. Special variables and functions</title>
<META NAME="description" CONTENT="14. Special variables and functions">
<META NAME="keywords" CONTENT="tut">
<META NAME="resource-type" CONTENT="document">
<META NAME="distribution" CONTENT="global">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="STYLESHEET" href="tut.css" type='text/css'>
<link rel="first" href="tut.html">
<link rel="contents" href="contents.html" title="Contents">

<LINK REL="next" HREF="node17.html">
<LINK REL="previous" HREF="node15.html">
<LINK REL="up" HREF="tut.html">
<LINK REL="next" HREF="node17.html">
<meta name='aesop' content='information'>
</head>
<body>
<DIV CLASS="navigation">
<table align="center" width="100%" cellpadding="0" cellspacing="2">
<tr>
<td><A HREF="node15.html"><img src="../icons/previous.gif"
  border="0" height="32"
  alt="Previous Page" width="32"></A></td>
<td><A HREF="tut.html"><img src="../icons/up.gif"
  border="0" height="32"
  alt="Up One Level" width="32"></A></td>
<td><A HREF="node17.html"><img src="../icons/next.gif"
  border="0" height="32"
  alt="Next Page" width="32"></A></td>
<td align="center" width="100%">CherryPy Tutorial</td>
<td><A HREF="node2.html"><img src="../icons/contents.gif"
  border="0" height="32"
  alt="Contents" width="32"></A></td>
<td><img src="../icons/blank.gif"
  border="0" height="32"
  alt="" width="32"></td>
<td><img src="../icons/blank.gif"
  border="0" height="32"
  alt="" width="32"></td>
</tr></table>
<b class="navlabel">Previous:</b> <a class="sectref" HREF="node15.html">13. Using your own</A>
<b class="navlabel">Up:</b> <a class="sectref" HREF="tut.html">CherryPy Tutorial</A>
<b class="navlabel">Next:</b> <a class="sectref" HREF="node17.html">15. Deploying your website</A>
<br><hr>
</DIV>
<!--End of Navigation Panel-->
<!--Table of Child-Links-->
<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></a>

<UL CLASS="ChildLinks">
<LI><A href="node16.html#SECTION0016100000000000000000">14.1 Special variables</a>
<UL>
<LI><A href="node16.html#SECTION0016110000000000000000">14.1.1 request</a>
<LI><A href="node16.html#SECTION0016120000000000000000">14.1.2 response</a>
</ul>
<LI><A href="node16.html#SECTION0016200000000000000000">14.2 Special functions</a>
<UL>
<LI><A href="node16.html#SECTION0016210000000000000000">14.2.1 initRequest, initNonStaticRequest, initResponse and initNonStaticResponse</a>
<LI><A href="node16.html#SECTION0016220000000000000000">14.2.2 onError</a>
<LI><A href="node16.html#SECTION0016230000000000000000">14.2.3 initThread, initProcess</a>
<LI><A href="node16.html#SECTION0016240000000000000000">14.2.4 initProgram, initServer, initAfterBind</a>
<LI><A href="node16.html#SECTION0016250000000000000000">14.2.5 initRequestBeforeParse (advanced usage only)</a>
</ul>
<LI><A href="node16.html#SECTION0016300000000000000000">14.3 Examples</a>
<UL>
<LI><A href="node16.html#SECTION0016310000000000000000">14.3.1 Playing with URLs</a>
<LI><A href="node16.html#SECTION0016320000000000000000">14.3.2 Sending back a redirect</a>
<LI><A href="node16.html#SECTION0016330000000000000000">14.3.3 Adding timing information to each page</a>
<LI><A href="node16.html#SECTION0016340000000000000000">14.3.4 Customizing the error message</a>
</ul></ul>
<!--End of Table of Child-Links-->
<HR>

<H1><A NAME="SECTION0016000000000000000000">
14. Special variables and functions</A>
</H1>

<P>
CherryPy sets and uses a few special variables and functions. They are very simple and easy to use, but
also very powerful. In this chapter, we'll see what these special variables and functions are, and we'll
learn how to use them in the next chapter.

<P>

<H1><A NAME="SECTION0016100000000000000000">
14.1 Special variables</A>
</H1>

<H2><A NAME="SECTION0016110000000000000000">
14.1.1 request</A>
</H2>
This is the most commonly used variable. It contains all the informations about the request that was sent by the client.
It's a class instance that contains several member variables that are set
by CherryPy for each request. The most commonly used member variables are:

<UL>
<LI><b>request.headerMap</b>: It's a Python map containing all keys and values sent by the client in the header of the request.
Note that all keys are always converted to lower case. For instance, to find out what browser the client is
using, use <var>request.headerMap['user-agent']</var> (note that this information may not be sent by the client)
</LI>
<LI><b>request.simpleCookie</b>: It's a <var>simpleCookie</var> object containing the cookies sent by the client. Note that this
information is also available in <var>request.headerMap['cookie']</var>. Check out the HowTo about cookies to learn more about how
to use cookie with CherryPy
</LI>
<LI><b>request.base</b>: String containing the base URL of the website. This is equivalent to <var>'http://'+request.headerMap['host']</var>
</LI>
<LI><b>request.path and request.paramMap</b>: The former contain the path of the page that's being requested.
Leading and trailing slashes are removed (if any). The latter is a map
containing a key and value for each parameter that the client sent (via GET or POST). For instance, if the URL is:
<div class="verbatim"><pre>
http://localhost:8000/dir/page?key1=value1&amp;key2=value2
</pre></div>
we'll have:
<div class="verbatim"><pre>
request.base == 'http://localhost:8000'
and
request.path == 'dir/page'
and
request.paramMap == {'key1': 'value1', 'key2': 'value2'}
</pre></div>
</LI>
<LI><b>request.originalPath and request.originalParamMap</b>: These variables are a copy of <var>request.path</var> and
<var>request.paramMap</var>. But we'll see in the next sections that it is possible to modify <var>request.path</var> and
<var>request.paramMap</var>. In this case, <var>request.originalPath</var> and <var>request.originalParamMap</var> keep the
original values.
</LI>
<LI><b>request.browserUrl</b>: String containing the URL as it appears in the browser window
</LI>
<LI><b>request.method</b>: String containing either <var>GET</var> or <var>POST</var>, to indicate what kind of request it was
</LI>
<LI><b>request.wfile</b> (advanced usage only): Check out the HowTo called "How to stream uploaded files directly to disk" for more information about this
</LI>
</UL>

<P>

<H2><A NAME="SECTION0016120000000000000000">
14.1.2 response</A>
</H2>
This is the second most commonly used variable (after <var>request</var>). It contains all informations about the response
that will be sent back to the client. It's a class instance that contains several member
variables that are set by CherryPy or by your program.

<UL>
<LI><b>response.headerMap</b>: It's a Python map that contains all keys and values that will be sent in the header of
the response. By default, CherryPy sets the following keys and values in the map:
<div class="verbatim"><pre>
"status": 200
"content-type": "text/html"
"server": "CherryPy 0.1"
"date": current date
"set-cookie": []
"content-length": 0
</pre></div>
In the next chapter, we'll learn how to use and modify these values
</LI>
<LI><b>response.body</b>: String containing the body of the response. This variable can only be used in 3 special functions (see below)
</LI>
<LI><b>response.simpleCookie</b>: <var>simpleCookie</var> object used to send cookies to the browser. Note that cookies
can also be sent by using <var>response.headerMap['cookie']</var>. Check out the HowTo about cookies to learn more about how
to use cookie with CherryPy
</LI>
<LI><b>response.sendResponse and response.wfile</b> (advanced usage only): Used for streaming. Check out the HowTo called "How to use streaming with CherryPy" for more information.
</LI>
</UL>

<P>

<H1><A NAME="SECTION0016200000000000000000">
14.2 Special functions</A>
</H1>
In your code, you can define special functions that will change the server's behavior. To define these functions, just
use Python's regular syntax and define them outside all CherryClasses. When you use different modules, you can define
the same function in different modules. In this case, CherryPy will just concatenate the bodies of all functions, in
the same order it reads the files.

<P>

<H2><A NAME="SECTION0016210000000000000000">
14.2.1 initRequest, initNonStaticRequest, initResponse and initNonStaticResponse</A>
</H2>
Here is the algorithm that the server uses when it receives a request:

<P>
<table border align="center" style="border-collapse: collapse">
  <thead>
    <tr class="tableheader">
      <th align="left"><b>Static content</b>&nbsp;</th>
      <th align="left"><b>All content</b>&nbsp;</th>
      <th align="left"><b>Dynamic content</b>&nbsp;</th>
      </tr>
    </thead>
  <tbody valign="baseline">
    <tr><td align="left" valign="baseline">&nbsp;</td>
        <td align="left">a. Request coming in</td>
        <td align="left">&nbsp;</td>
    <tr><td align="left" valign="baseline">&nbsp;</td>
        <td align="left">b. Set all member variables of <var>request</var></td>
        <td align="left">&nbsp;</td>
    <tr><td align="left" valign="baseline">&nbsp;</td>
        <td align="left">c. Call <var>initRequest</var> (which may change <var>request.path</var> and <var>request.paramMap</var>)</td>
        <td align="left">&nbsp;</td>
    <tr><td align="left" valign="baseline">&nbsp;</td>
        <td align="left">d. Determine if this request corresponds to static or dynamic content (based on <var>request.path</var>
        and the <var>staticContent</var> section of the config file)</td>
        <td align="left">&nbsp;</td>
    <tr><td align="left" valign="baseline">&nbsp;</td>
        <td align="left"> </td>
        <td align="left">e. Call <var>initNonStaticRequest</var> (which may change <var>request.path</var> and <var>request.paramMap</var>)</td>
    <tr><td align="left" valign="baseline"><code>e. Read the static file and set <var>response.headerMap</var> values and <var>response.body</var> accordingly</code></td>
        <td align="left"> </td>
        <td align="left">f. Call the method of the CherryClass instance, with some arguments (based on <var>request.path</var> and
        <var>request.paramMap</var>) and set <var>response.headerMap</var> values and <var>response.body</var> according to the result</td>
    <tr><td align="left" valign="baseline"><code>f. Call <var>initResponse</var> (which may change <var>response.headerMap</var> and <var>response.body</var>)</code></td>
        <td align="left"> </td>
        <td align="left">g. Call <var>initResponse</var> (which may change <var>response.headerMap</var> and <var>response.body</var>)</td>
    <tr><td align="left" valign="baseline"><code>g. Send the response to the browser (based on <var>response.headerMap</var> and <var>response.body</var>)</code></td>
        <td align="left"> </td>
        <td align="left">h. Send the response to the browser (based on <var>response.headerMap</var> and <var>response.body</var>)</td></tbody>
</table>

<P>
As you can see, <var>initRequest</var> and <var>initNonStaticRequest</var> can be used to tweak the URL or the parameters, or to
perform any work that has to be done for each request.

<P>
<var>initResponse</var> and <var>initNonStaticResponse</var> can be used to change the response header or body, just before
it is sent back to the client.

<P>

<H2><A NAME="SECTION0016220000000000000000">
14.2.2 onError</A>
</H2>
That function is called by CherryPy when an error occured while building the page. See next section for an example.

<P>

<H2><A NAME="SECTION0016230000000000000000">
14.2.3 initThread, initProcess</A>
</H2>
If you use a thread-pool server or process-pool server, then the corresponding
special function (respectively <var>initThread</var> or <var>initProcess</var>) will
be called  by each newly created thread/process.

<P>
These functions can be used for instance if you want each thread/process to
have its own database connection (the HowTo called "Sample deployment
configuration for a real-world website" explains how to do that).

<P>
<var>initThread</var> takes an argument called <var>threadIndex</var> containing the index of the thread that's being created. For instance, if you create 10 threads, <var>threadIndex</var> will take values from 0 to 9.

<P>
Same thing for <var>initProcess</var> and <var>processIndex</var>

<P>

<H2><A NAME="SECTION0016240000000000000000">
14.2.4 initProgram, initServer, initAfterBind</A>
</H2>
The code you put in <var>initProgram</var> is copied at the very beginning of the
generated file, so it's the first thing that will be executed. You can use
that special function if you need to run some code before the CherryClasses
are instanciated.
Then, the server creates all instances of the CherryClasses and then it calls the special function <var>initServer</var>. This is basically where you perform some
initialization tasks if some are needed.

<P>
<var>initAfterBind</var> is called after the socket "bind" has been made. For instance, on Unix-based systems, you need start CherryPy as root is you want it to
bind its socket to port 80. The <var>initAfterBind</var> special function can be used
to change the user back to an unpriviledged user after the "bind" has been done.
(the HowTo called "Sample deployment
configuration for a real-world website" explains how to do that).

<P>

<H2><A NAME="SECTION0016250000000000000000">
14.2.5 initRequestBeforeParse (advanced usage only)</A>
</H2>
This special function is called by the server when it receives a POST request, before it parses
the POST data. This allows you for instance to tell the server not to parse the POST data (by
setting <var>request.parsePostData</var> to <var>0</var>) and then you can parse the POST data yourself
(by reading on <var>request.rfile</var>). Check out the HowTo called "How to stream uploaded files directly to disk" for more information about this

<P>

<H1><A NAME="SECTION0016300000000000000000">
14.3 Examples</A>
</H1>

<H2><A NAME="SECTION0016310000000000000000">
14.3.1 Playing with URLs</A>
</H2>
Let's say you want to set up a website for your customers. You want your customers to have their own URL:
<a class="url" href="http://host/customerName">http://host/customerName</a>, but the page is almost the same for each customer, so you don't want to
create a method for each customer.

<P>
All you have to do is use the <var>initNonStaticRequest</var> to convert the URL <a class="url" href="http://host/customerName">http://host/customerName</a> into
<a class="url" href="http://host?customer=customerName">http://host?customer=customerName</a>. All that will be transparent to the user.

<P>
Just enter the following code:
<div class="verbatim"><pre>
def initNonStaticRequest():
    if request.path:
        request.paramMap['customer']=request.path
        request.path=""
CherryClass Root:
mask:
    def index(self, customer=""):
        &lt;html&gt;&lt;body&gt;
            Hello, &lt;py-eval="customer"&gt;
        &lt;/body&gt;&lt;/html&gt;
</pre></div>
And that's it !

<P>
Compile the file, start the server, and try a few URls, like <a class="url" href="http://localhost:8000/customer1">http://localhost:8000/customer1</a>or <a class="url" href="http://localhost:8000/world">http://localhost:8000/world</a>
<P>

<H2><A NAME="SECTION0016320000000000000000">
14.3.2 Sending back a redirect</A>
</H2>
To send a <var>redirect</var> to the browser, all you have to do is send back a status code of <var>302</var> (instead
of 200), and set a <var>location</var> value in the response header. This can be done easily using the <var>response.headerMap</var>
special variable:
<div class="verbatim"><pre>
CherryClass Root:
mask:
    def index(self):
        &lt;html&gt;&lt;body&gt;
            &lt;a href="loop"&gt;Click here to come back to this page&lt;/a&gt;
        &lt;/body&gt;&lt;/html&gt;
view:
    def loop(self):
        response.headerMap['status']=302
        response.headerMap['location']=request.base
        return "" # A view should always return a string
</pre></div>

<P>

<H2><A NAME="SECTION0016330000000000000000">
14.3.3 Adding timing information to each page</A>
</H2>
In this example, we'll add one line at the end of each page that's served by the server. This line will
contain the time it took to build the page. Of course, we only want this line for dynamic HTML pages.

<P>
All we have to do is use <var>initNonStaticRequest</var> to store the start time, and use <var>initNonStaticResponse</var>
to add the line containing the build time.

<P>
Here is the code:
<div class="verbatim"><pre>
import time
def initNonStaticRequest():
    request.startTime=time.time()
def initNonStaticResponse():
    if response.headerMap['content-type']=='text/html':
        response.body+='&lt;br&gt;Time: %.04fs'%(time.time()-request.startTime)
CherryClass Root:
mask:
    def index(self):
        &lt;html&gt;&lt;body&gt;
            Hello, world
        &lt;/body&gt;&lt;/html&gt;
</pre></div>

<P>
And voila

<P>

<H2><A NAME="SECTION0016340000000000000000">
14.3.4 Customizing the error message</A>
</H2>
This is done through the <var>onError</var> special function. Just use <var>response.headerMap</var> and <var>response.body</var>
to do what you want.

<P>
The following example shows how to set it up so it sends an email with the error everytime an error occurs:
<div class="verbatim"><pre>
use Mail

def onError():
    # Get the error in a string
    import traceback, StringIO
    bodyFile=StringIO.StringIO()
    traceback.print_exc(file=bodyFile)
    errorBody=bodyFile.getvalue()
    bodyFile.close()
    # Send an email with the error
    myMail.sendMail("erreur@site.com", "webmaster@site.com", "", "text/plain", "An error occured on your site", errorBody)
    # Set the body of the response
    response.body="&lt;html&gt;&lt;body&gt;&lt;br&gt;&lt;br&gt;&lt;center&gt;"
    response.body+="Sorry, an error occured&lt;br&gt;"
    response.body+="An email has been sent to the webmaster"
    response.body+="&lt;/center&gt;&lt;/body&gt;&lt;/html&gt;"


CherryClass MyMail(Mail):
function:
    def __init__(self):
        self.smtpServer='smtp.site.com'

CherryClass Root:
mask:
    def index(self):
        &lt;html&gt;&lt;body&gt;
            &lt;a py-attr="request.base+'/generateError'" href=""&gt;Click here to generate an error&lt;/a&gt;
        &lt;/body&gt;&lt;/html&gt;
    def generateError(self):
        &lt;html&gt;&lt;body&gt;
            You'll never see this: &lt;py-eval="1/0"&gt;
        &lt;/body&gt;&lt;/html&gt;
</pre></div>

<P>
This example also shows you how to use the <var>Mail</var> standard module that comes with CherryPy.

<P>

<DIV CLASS="navigation">
<p><hr>
<table align="center" width="100%" cellpadding="0" cellspacing="2">
<tr>
<td><A HREF="node15.html"><img src="../icons/previous.gif"
  border="0" height="32"
  alt="Previous Page" width="32"></A></td>
<td><A HREF="tut.html"><img src="../icons/up.gif"
  border="0" height="32"
  alt="Up One Level" width="32"></A></td>
<td><A HREF="node17.html"><img src="../icons/next.gif"
  border="0" height="32"
  alt="Next Page" width="32"></A></td>
<td align="center" width="100%">CherryPy Tutorial</td>
<td><A HREF="node2.html"><img src="../icons/contents.gif"
  border="0" height="32"
  alt="Contents" width="32"></A></td>
<td><img src="../icons/blank.gif"
  border="0" height="32"
  alt="" width="32"></td>
<td><img src="../icons/blank.gif"
  border="0" height="32"
  alt="" width="32"></td>
</tr></table>
<b class="navlabel">Previous:</b> <a class="sectref" HREF="node15.html">13. Using your own</A>
<b class="navlabel">Up:</b> <a class="sectref" HREF="tut.html">CherryPy Tutorial</A>
<b class="navlabel">Next:</b> <a class="sectref" HREF="node17.html">15. Deploying your website</A>
<hr>
<span class="release-info">Release 0.10, documentation updated on 19 March 2004.</span>
</DIV>
<!--End of Navigation Panel-->
<ADDRESS>
See <i><a href="about.html">About this document...</a></i> for information on suggesting changes.
</ADDRESS>
</BODY>
</HTML>