Subsections
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.
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:
- request.headerMap: 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 request.headerMap['user-agent'] (note that this information may not be sent by the client)
- request.simpleCookie: It's a simpleCookie object containing the cookies sent by the client. Note that this
information is also available in request.headerMap['cookie']. Check out the HowTo about cookies to learn more about how
to use cookie with CherryPy
- request.base: String containing the base URL of the website. This is equivalent to 'http://'+request.headerMap['host']
- request.path and request.paramMap: 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:
http://localhost:8000/dir/page?key1=value1&key2=value2
we'll have:
request.base == 'http://localhost:8000'
and
request.path == 'dir/page'
and
request.paramMap == {'key1': 'value1', 'key2': 'value2'}
- request.originalPath and request.originalParamMap: These variables are a copy of request.path and
request.paramMap. But we'll see in the next sections that it is possible to modify request.path and
request.paramMap. In this case, request.originalPath and request.originalParamMap keep the
original values.
- request.browserUrl: String containing the URL as it appears in the browser window
- request.method: String containing either GET or POST, to indicate what kind of request it was
- request.wfile (advanced usage only): Check out the HowTo called "How to stream uploaded files directly to disk" for more information about this
This is the second most commonly used variable (after request). 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.
- response.headerMap: 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:
"status": 200
"content-type": "text/html"
"server": "CherryPy 0.1"
"date": current date
"set-cookie": []
"content-length": 0
In the next chapter, we'll learn how to use and modify these values
- response.body: String containing the body of the response. This variable can only be used in 3 special functions (see below)
- response.simpleCookie: simpleCookie object used to send cookies to the browser. Note that cookies
can also be sent by using response.headerMap['cookie']. Check out the HowTo about cookies to learn more about how
to use cookie with CherryPy
- response.sendResponse and response.wfile (advanced usage only): Used for streaming. Check out the HowTo called "How to use streaming with CherryPy" for more information.
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.
Here is the algorithm that the server uses when it receives a request:
|
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.
That function is called by CherryPy when an error occured while building the page. See next section for an example.
If you use a thread-pool server or process-pool server, then the corresponding
special function (respectively initThread or initProcess) will
be called by each newly created thread/process.
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
The code you put in initProgram 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 initServer. This is basically where you perform some
initialization tasks if some are needed.
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).
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 request.parsePostData to 0) and then you can parse the POST data yourself
(by reading on request.rfile). Check out the HowTo called "How to stream uploaded files directly to disk" for more information about this
Let's say you want to set up a website for your customers. You want your customers to have their own URL:
http://host/customerName, but the page is almost the same for each customer, so you don't want to
create a method for each customer.
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>
And that's it !
Compile the file, start the server, and try a few URls, like http://localhost:8000/customer1or http://localhost:8000/world
To send a redirect to the browser, all you have to do is send back a status code of 302 (instead
of 200), and set a location value in the response header. This can be done easily using the response.headerMap
special variable:
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
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.
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
This is done through the onError special function. Just use response.headerMap and response.body
to do what you want.
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.