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&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> </th>
<th align="left"><b>All content</b> </th>
<th align="left"><b>Dynamic content</b> </th>
</tr>
</thead>
<tbody valign="baseline">
<tr><td align="left" valign="baseline"> </td>
<td align="left">a. Request coming in</td>
<td align="left"> </td>
<tr><td align="left" valign="baseline"> </td>
<td align="left">b. Set all member variables of <var>request</var></td>
<td align="left"> </td>
<tr><td align="left" valign="baseline"> </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"> </td>
<tr><td align="left" valign="baseline"> </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"> </td>
<tr><td align="left" valign="baseline"> </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=""):
<html><body>
Hello, <py-eval="customer">
</body></html>
</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):
<html><body>
<a href="loop">Click here to come back to this page</a>
</body></html>
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+='<br>Time: %.04fs'%(time.time()-request.startTime)
CherryClass Root:
mask:
def index(self):
<html><body>
Hello, world
</body></html>
</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="<html><body><br><br><center>"
response.body+="Sorry, an error occured<br>"
response.body+="An email has been sent to the webmaster"
response.body+="</center></body></html>"
CherryClass MyMail(Mail):
function:
def __init__(self):
self.smtpServer='smtp.site.com'
CherryClass Root:
mask:
def index(self):
<html><body>
<a py-attr="request.base+'/generateError'" href="">Click here to generate an error</a>
</body></html>
def generateError(self):
<html><body>
You'll never see this: <py-eval="1/0">
</body></html>
</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>
|