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.
http://localhost:8000/dir/page?key1=value1&key2=value2
request.base == 'http://localhost:8000'
and
request.path == 'dir/page'
and
request.paramMap == {'key1': 'value1', 'key2': 'value2'}
"status": 200 "content-type": "text/html" "server": "CherryPy 0.1" "date": current date "set-cookie": [] "content-length": 0
| Static content | All content | Dynamic content |
|---|---|---|
| a. Request coming in | ||
| b. Set all member variables of request | ||
| c. Call initRequest (which may change request.path and request.paramMap) | ||
| d. Determine if this request corresponds to static or dynamic content (based on request.path and the staticContent section of the config file) | ||
| e. Call initNonStaticRequest (which may change request.path and request.paramMap) | ||
e. Read the static file and set response.headerMap values and response.body accordingly |
f. Call the method of the CherryClass instance, with some arguments (based on request.path and request.paramMap) and set response.headerMap values and response.body according to the result | |
f. Call initResponse (which may change response.headerMap and response.body) |
g. Call initResponse (which may change response.headerMap and response.body) | |
g. Send the response to the browser (based on response.headerMap and response.body) |
h. Send the response to the browser (based on response.headerMap and response.body) |
As you can see, initRequest and initNonStaticRequest can be used to tweak the URL or the parameters, or to perform any work that has to be done for each request.
initResponse and initNonStaticResponse can be used to change the response header or body, just before it is sent back to the client.
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).
initThread takes an argument called threadIndex containing the index of the thread that's being created. For instance, if you create 10 threads, threadIndex will take values from 0 to 9.
Same thing for initProcess and processIndex
initAfterBind 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 initAfterBind 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).
All you have to do is use the initNonStaticRequest to convert the URL http://host/customerName into http://host?customer=customerName. All that will be transparent to the user.
Just enter the following code:
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>
Compile the file, start the server, and try a few URls, like http://localhost:8000/customer1or http://localhost:8000/world
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
All we have to do is use initNonStaticRequest to store the start time, and use initNonStaticResponse to add the line containing the build time.
Here is the code:
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>
And voila
The following example shows how to set it up so it sends an email with the error everytime an error occurs:
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>
This example also shows you how to use the Mail standard module that comes with CherryPy.
See About this document... for information on suggesting changes.