Changeset 637
- Timestamp:
- 09/13/05 17:03:33
- Files:
-
- branches/mikerobi-experimental/CHANGELOG.txt (modified) (1 diff)
- branches/mikerobi-experimental/cherrypy/_cperror.py (modified) (2 diffs)
- branches/mikerobi-experimental/cherrypy/test/helper.py (modified) (2 diffs)
- branches/mikerobi-experimental/cherrypy/test/webtest.py (modified) (1 diff)
- branches/mikerobi-experimental/docs/book/xml/adminreference.xml (modified) (1 diff)
- branches/mikerobi-experimental/docs/book/xml/appdeveloperreference.xml (modified) (1 diff)
- branches/mikerobi-experimental/docs/book/xml/configsystemoverview.xml (modified) (2 diffs)
- branches/mikerobi-experimental/docs/book/xml/fileuploadbehavior.xml (modified) (1 diff)
- branches/mikerobi-experimental/docs/book/xml/globaloverviewcherrypy.xml (modified) (3 diffs)
- branches/mikerobi-experimental/docs/book/xml/sessions.xml (modified) (4 diffs)
- branches/mikerobi-experimental/docs/book/xml/staticcontenthandling.xml (modified) (2 diffs)
- branches/mikerobi-experimental/docs/book/xml/templateindependant.xml (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/mikerobi-experimental/CHANGELOG.txt
r615 r637 1 2005-09-04: 2 * Generalized mechanism for handling HTTP errors 3 * raising a HTTPStatusError will automatically send an appropriate error page 4 * All errors in production mode will cause CP to respond with a http error 5 1 6 2005-08-17: 2 7 * The session filter has been simplified, the mechanism for creating multiple sessions has been removed. However .. (mikerobi) branches/mikerobi-experimental/cherrypy/_cperror.py
r634 r637 174 174 175 175 class HTTPError(Error): 176 """Exception raised when the client has made an error in its request.""" 176 """ Exception raised when the client has made an error in its request. 177 This exception will automatically set the response status and body. 178 179 A custom body can be pased to the init method in place of the standard error page. 180 """ 177 181 178 182 def __init__(self, status=500, body=_missing): … … 187 191 188 192 if body is _missing: 193 # because the init method is called before the exception is raised 194 # it is impossible to embed the traceback in the error page at this point. 195 # We use a generator so that the error page is generated at a later point ( 196 # after the exception is raised). 189 197 cherrypy.response.body = self.pageGenerator() 190 198 else: branches/mikerobi-experimental/cherrypy/test/helper.py
r615 r637 37 37 import webtest 38 38 import types 39 import re 40 39 41 for _x in dir(cherrypy): 40 42 y = getattr(cherrypy, _x) … … 127 129 else: 128 130 webtest.WebCase.getPage(self, url, headers, method, body) 131 132 def assertErrorPage(self, errorCode, pattern = ''): 133 """ Compare the response body with a built in error page. 134 The function will optionally look for the regexp pattern, 135 within the exception embedded in the error page. 136 """ 137 138 from cherrypy._cputil import getErrorStatusAndPage 139 page = getErrorStatusAndPage(errorCode, '')[1] 140 141 # escape the question marks 142 page = page.replace('?', r'\?') 143 144 # re to find the traceback in the page 145 traceRe = re.compile('(<pre id="traceback">)(</pre>)') 146 147 # stick the pattern in the page so we can match everythign 148 # at once 149 page = traceRe.sub( '\g<1>.*%s.*\g<2>' % pattern, page) 150 151 # check if there is no exception 152 if pattern and traceRe.search(self.body): 153 msg = 'No match for %s in body' % `pattern` 154 self._handlewebError(msg) 155 else: 156 if not re.search(page, self.body, re.DOTALL): 157 msg = 'Error page does not match' 158 self._handlewebError(msg) 129 159 130 160 CPTestLoader = webtest.ReloadingTestLoader() branches/mikerobi-experimental/cherrypy/test/webtest.py
r634 r637 286 286 msg = 'No match for %s in body' % `pattern` 287 287 self._handlewebError(msg) 288 289 def assertErrorPage(self, errorCode, pattern = ''): 290 from cherrypy._cputil import getErrorStatusAndPage 291 page = getErrorStatusAndPage(errorCode, '')[1] 292 293 # escape the question marks 294 page = page.replace('?', r'\?') 295 296 # re to find the traceback in the page 297 traceRe = re.compile('(<pre id="traceback">)(</pre>)') 298 299 # stick the pattern in the page so we can match everythign 300 # at once 301 page = traceRe.sub( '\g<1>.*%s.*\g<2>' % pattern, page) 302 303 # check if there is no exception 304 if pattern and traceRe.search(self.body): 305 msg = 'No match for %s in body' % `pattern` 306 self._handlewebError(msg) 307 else: 308 if not re.search(page, self.body, re.DOTALL): 309 msg = 'Error page does not match' 310 self._handlewebError(msg) 311 288 312 289 313 290 def cleanHeaders(headers, method, body, host, port): branches/mikerobi-experimental/docs/book/xml/adminreference.xml
r325 r637 7 7 8 8 <xi:include href="installapplication.xml"/> 9 <xi:include href="configreference.xml"/> 9 10 <xi:include href="configureapplication.xml"/> 10 11 <xi:include href="productionsetup.xml"/> branches/mikerobi-experimental/docs/book/xml/appdeveloperreference.xml
r615 r637 1 <?xml version="1.0" encoding="utf-8"?> 2 <section xmlns:db="http://docbook.org/docbook-ng" xmlns:xi="http://www.w3.org/2001/XInclude" 3 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xml:id="appdeveloperreference"> 4 <title>Application developer reference</title> 5 <abstract>CherryPy tries to bring to Python developers a system that let them use their language 6 to develop web application as they would use it for any other type of environment. Therefore, 7 building a web application with CherryPy is very straightforward and does not require the 8 developer to change his/her habits, nor to learn many features before being able to pull out a 9 working application. This section will review the basic bricks offered by CherryPy to build an 10 application.</abstract> 11 <xi:include href="globaloverviewcherrypy.xml"/> 12 <xi:include href="configsystemoverview.xml"/> 13 <xi:include href="sessions.xml"/> 14 <xi:include href="templateindependant.xml"/> 15 <xi:include href="staticcontenthandling.xml"/> 16 <xi:include href="fileuploadbehavior.xml"/> 1 <?xml version="1.0" encoding="UTF-8"?> 2 <section xmlns:db="http://docbook.org/docbook-ng" 3 xmlns:xi="http://www.w3.org/2001/XInclude" 4 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 5 xml:id="appdeveloperreference"> 6 <title>Application developer reference</title> 7 <abstract>CherryPy lets developers use Python to develop web applications, 8 just as they would use Python for any other type of application. Building a 9 web application with CherryPy is very straightforward and does not require 10 the developer to change habits, or learn many features, before being able to 11 produce a working application. This section will review the basic components 12 which CherryPy provides to build an application.</abstract> 13 <xi:include href="globaloverviewcherrypy.xml" /> 14 <xi:include href="configsystemoverview.xml" /> 15 <xi:include href="sessions.xml" /> 16 <xi:include href="templateindependant.xml" /> 17 <xi:include href="staticcontenthandling.xml" /> 18 <xi:include href="fileuploadbehavior.xml" /> 17 19 </section> branches/mikerobi-experimental/docs/book/xml/configsystemoverview.xml
r615 r637 1 <?xml version="1.0" encoding="utf-8"?> 2 <section xmlns:db="http://docbook.org/docbook-ng" xmlns:xi="http://www.w3.org/2001/XInclude" 3 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xml:id="configsystemoverview"> 4 <title>Configuration system overview</title> 5 <para>The CherryPy configuration system specifies with a fine grain how each part of the 6 application should react. You will use it for two reason: </para> 7 <itemizedlist> 8 <listitem>Web server settings</listitem> 9 <listitem>Enabling filters per path</listitem> 10 </itemizedlist> 11 <para>You will be able to declare the configuration settings either from a file or from a Python 12 dictionnary.</para> 13 <para>First of all, let's see how a typical configuration file is defined.</para> 14 <example> 15 <title>Configuration file</title> 16 <programlisting linenumbering="numbered"> 17 #The configuration file called myconfigfile.conf 1 <?xml version="1.0" encoding="UTF-8"?> 2 <section xmlns:db="http://docbook.org/docbook-ng" 3 xmlns:xi="http://www.w3.org/2001/XInclude" 4 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 5 xml:id="configsystemoverview"> 6 <title>Configuration system overview</title> 7 <para>The CherryPy configuration system provides fine-grained control over 8 how each part of the application should react. You will use it for two 9 reasons:</para> 10 <itemizedlist> 11 <listitem>Web server settings</listitem> 12 <listitem>Enabling filters per path</listitem> 13 </itemizedlist> 14 <para>You will be able to declare the configuration settings either from a 15 file or from a Python dictionary.</para> 16 <para>First of all, let's see how a typical configuration file is 17 defined.</para> 18 <example> 19 <title>Configuration file</title> 20 <programlisting linenumbering="numbered"> 21 # The configuration file called myconfigfile.conf 18 22 [global] 19 23 server.socketPort=8080 … … 41 45 cherrypy.config.update(file="myconfigfile.conf") 42 46 </programlisting> 43 </example> 44 <para>The settings can also be defined using a python dictionnary instead of a file as follow :</para> 45 <example> 46 <title>Configuration dictionnary</title> 47 <programlisting linenumbering="numbered"> 47 </example> 48 <para>The settings can also be defined using a python dictionary instead of 49 a file as follows:</para> 50 <example> 51 <title>Configuration dictionary</title> 52 <programlisting linenumbering="numbered"> 48 53 settings = { 49 'global': {50 'server.socketPort': 8080,51 'server.socketHost': "",52 'server.socketFile': "",53 'server.socketQueueSize': 5,54 'server.protocolVersion': "HTTP/1.0",55 'server.logToScreen': True,56 'server.logFile': "",57 'server.reverseDNS': False,58 'server.threadPool': 10,59 'server.environment': "development"54 'global': { 55 'server.socketPort' : 8080, 56 'server.socketHost': "", 57 'server.socketFile': "", 58 'server.socketQueueSize': 5, 59 'server.protocolVersion': "HTTP/1.0", 60 'server.logToScreen': True, 61 'server.logFile': "", 62 'server.reverseDNS': False, 63 'server.threadPool': 10, 64 'server.environment': "development" 60 65 }, 61 '/service/xmlrpc': {62 'xmlRpcFilter.on': True66 '/service/xmlrpc' : { 67 'xmlRpcFilter.on': True 63 68 }, 64 '/admin': {65 'sessionAuthenticateFilter.on':True69 '/admin': { 70 'sessionAuthenticateFilter.on' :True 66 71 }, 67 '/css/default.css': {68 'staticFilter.on': True,69 'staticFilter.file': "data/css/default.css"72 '/css/default.css': { 73 'staticFilter.on': True, 74 'staticFilter.file': "data/css/default.css" 70 75 } 71 76 } 72 77 cherrypy.config.update(settings) 73 78 </programlisting> 74 </example> 75 <para>Each section of the configuration is a path that can be mapped to a published object 76 of the tree handled by CherryPy. Therefore when the server receives a request to 77 <code>/css/default.css</code> the static filter will be called and the server will 78 actually return the physical file name <filename>data/css/default.css</filename>. </para> 79 <para>Since the path <code>/service/xmlrpc</code> has the XML-RPC filter enabled, all the 80 exposed methods of the object <code>cherrypy.root.service.xmlrpc</code> will be treated as 81 XML-RPC methods.</para> 82 <para>The root entry, defined as <code>global</code>, is also responsible for defining the 83 server settings such as the port, the protocol version to use by default, the number of 84 threads to start with the server, etc.</para> 85 <para>The configuration file requires that all the value are Python values. Strings must be 86 quoted, boolean are set to True or False, etc.</para> 87 <para>The <code>server.environment</code> entry controls how CherryPy should run. Three values 88 are legal :</para> 89 <itemizedlist> 90 <listitem>development <itemizedlist> 91 <listitem>logDebugInfoFilter is enabled by default</listitem> 92 <listitem> the default _cpOnError displays tracebacks in the browser if errors occur 93 but still returns a "200" status code</listitem> 94 <listitem>autoreload is enabled by default</listitem> 95 </itemizedlist> 79 </example> 80 <para>Each section of the configuration refers to a URL path; each path is 81 mapped to a published object of the tree handled by CherryPy. Therefore when 82 the server receives a request for <code>/css/default.css</code>, the static 83 filter will be called and the server will actually return the physical file 84 name <filename>data/css/default.css</filename>.</para> 85 <para>Since the path <code>/service/xmlrpc</code> has the XML-RPC filter 86 enabled, all the exposed methods of the object 87 <code>cherrypy.root.service.xmlrpc</code> will be treated as XML-RPC 88 methods.</para> 89 <para>The root entry, defined as <code>global</code>, is also responsible 90 for defining the server settings such as the port, the protocol version to 91 use by default, the number of threads to start with the server, etc.</para> 92 <para>All values in the configuration file must be valid Python values. 93 Strings must be quoted, booleans must be True or False, etc.</para> 94 <para>The <code>server.environment</code> entry controls how CherryPy should 95 run. Three values are legal:</para> 96 <itemizedlist> 97 <listitem>development <itemizedlist> 98 <listitem>logDebugInfoFilter is enabled by default</listitem> 99 <listitem>the default _cpOnError displays tracebacks in the browser if 100 errors occur</listitem> 101 <listitem>autoreload is enabled by default</listitem> 102 </itemizedlist></listitem> 103 <listitem>production <itemizedlist> 104 <listitem>logDebugInfoFilter is disabled by default</listitem> 105 <listitem> 106 <para>tracebacks are logged, but are not displayed in the 107 browser</para> 96 108 </listitem> 97 <listitem>production <itemizedlist> 98 <listitem>logDebugInfoFilter is disabled by default</listitem> 99 <listitem>the default _cpOnError returns "304" or "500" status codes if errors 100 occur</listitem> 101 </itemizedlist> 102 </listitem> 103 <listitem>staging (same as production for the moment)</listitem> 104 </itemizedlist> 109 <listitem>autoreload is disabled by default</listitem> 110 </itemizedlist></listitem> 111 <listitem>staging (same as production for the moment)</listitem> 112 </itemizedlist> 105 113 </section> branches/mikerobi-experimental/docs/book/xml/fileuploadbehavior.xml
r615 r637 1 <?xml version="1.0" encoding="utf-8"?> 2 <section xmlns:db="http://docbook.org/docbook-ng" xmlns:xi="http://www.w3.org/2001/XInclude" 3 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xml:id="globaloverviewcherrypy"> 4 <title>File upload</title> 5 <para>Before version 2.1, CherryPy was handling file uploads as follows: it was reading the entire file in memory, store it in a string and pass it to the method. 6 This works well for small files but not so well for big files.</para> 7 8 <para>CherryPy 2.1 uses the python <code>cgi</code> module to parse the POST data. 9 When a file is being uploaded, this modules stores it in a temp file and returns a <code>FieldStorage</code> instance which contains information about this file. 10 CherryPy then passes this <code>FieldStorage</code> instance to the method, this instance has the following attributes:</para> 11 12 <itemizedlist> 13 <listitem><code>file</code>: the file(-like) object from which you can read the data</listitem> 14 <listitem><code>filename</code>: the client-side filename</listitem> 15 <listitem><code>type</code>: the content-type of the file </listitem> 16 </itemizedlist> 17 </section> 1 <?xml version="1.0" encoding="UTF-8"?> 2 <section xmlns:db="http://docbook.org/docbook-ng" 3 xmlns:xi="http://www.w3.org/2001/XInclude" 4 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 5 xml:id="globaloverviewcherrypy"> 6 <title>File upload</title> 7 <para>Before version 2.1, CherryPy handled file uploads by reading the 8 entire file into memory, storing it in a string, and passing it to the page 9 handler. This worked well for small files, but not so well for large 10 files.</para> 11 <para>CherryPy 2.1 uses the python <code>cgi</code> module to parse the POST 12 data. When a file is being uploaded, the <code>cgi</code> module stores it 13 in a temp file and returns a <code>FieldStorage</code> instance which 14 contains information about this file. CherryPy then passes this 15 <code>FieldStorage</code> instance to the method. The 16 <code>FieldStorage</code> instance has the following attributes:</para> 17 <itemizedlist> 18 <listitem><code>file</code>: the file(-like) object from which you can 19 read the data</listitem> 20 <listitem><code>filename</code>: the client-side filename</listitem> 21 <listitem><code>type</code>: the content-type of the file</listitem> 22 </itemizedlist> 23 </section> branches/mikerobi-experimental/docs/book/xml/globaloverviewcherrypy.xml
r615 r637 1 <?xml version="1.0" encoding="utf-8"?> 2 <section xmlns:db="http://docbook.org/docbook-ng" xmlns:xi="http://www.w3.org/2001/XInclude" 3 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xml:id="globaloverviewcherrypy"> 1 <?xml version="1.0" encoding="UTF-8"?> 2 <section xmlns:db="http://docbook.org/docbook-ng" 3 xmlns:xi="http://www.w3.org/2001/XInclude" 4 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 5 xml:id="globaloverviewcherrypy"> 4 6 <title>Filters</title> 5 <para>Filters are one of the most important features of CherryPy. A filter is a class defining a 6 set of function that will be called by the core at specific point of a request processing. The 7 very nature of filters are to let the developer write code that will be called at a low level - 8 the HTTP request/response level - and therefore should only be used in that context.</para> 9 <para>CherryPy comes with a set of filters which are turned off by default. To enable them, you 10 must use the configuration system as follow :</para> 7 <para>Filters are one of the most important features of CherryPy. The 8 CherryPy core can call user-defined functions at specific points during 9 request processing; a filter is a class which defines those functions. 10 Filters are designed to be called at a low level—the HTTP request/response 11 level—and therefore should only be used in that context.</para> 12 <para>CherryPy comes with a set of built-in filters, but they're turned off 13 by default. To enable them, you must use the configuration system as 14 follows:</para> 11 15 <itemizedlist> 12 <listitem>First you must decide at which level of the cherrypy tree of published objects you 13 need the filter to act on. The filter will then act on that level and all its sub-levels in 14 the tree. Remember that the tree is accessed as a path and then mapped internally by the core 15 to match the correct exposed object.</listitem> 16 <listitem>Second in the config file you must turn the filter on like this : <code>filterName.on 17 = True</code></listitem> 16 <listitem>First you must decide where to enable the filter. CherryPy 17 maintains a tree of published objects; you must decide which branch should 18 use the filter. The filter will then apply to that branch and all its 19 children in the tree. Remember that the tree is accessed as a path and 20 then mapped internally by the core to match the correct exposed 21 object.</listitem> 22 <listitem>Second in the config file you must turn the filter on like this 23 : <code>filterName.on = True</code></listitem> 18 24 </itemizedlist> 19 25 <example> … … 26 32 </programlisting> 27 33 </example> 28 <para> On the first line we define that when the path <code>/entries/view</code> is called, or one 29 of its sub-paths, the tidy filter will be used by the core. On the two last lines we also define 30 some parameters used by the filter. </para> 31 <para>CherryPy lets you write your own filters as we will see in the developer reference chapter. 32 Nonetheless the way to use them is different from the default filters since you do not declare 33 them within the configuration file but from the source code itself using the 34 <code>_cpFilterList</code> list as a class member of the object that will use the filter.</para> 34 <para>On the first line we define that the tidy filter will be used by the 35 core whenever the path <code>/entries/view</code> (or one of its sub-paths) 36 is called. On the two last lines we also define some parameters used by the 37 filter.</para> 38 <para>CherryPy lets you write your own filters as we will see in the 39 developer reference chapter. However, the way to use them is different from 40 the default filters. You do not declare custom filters within the 41 configuration file; instead, use the <code>_cpFilterList</code> attribute in 42 your source code:</para> 35 43 <example> 36 44 <title>Using a non default filter</title> … … 52 60 </programlisting> 53 61 </example> 54 <para>As all objects below <code>cherrypy.root.entries</code> will inherit the filter, there is no 55 need to re-specify it in each <code>_cpFilterList</code> underneath.</para> 56 <para>Keep in mind that the user defined filters are called in the order you add them to the 57 list.</para> 62 <para>As all objects below <code>cherrypy.root.entries</code> will inherit 63 the filter, there is no need to re-specify it in each 64 <code>_cpFilterList</code> underneath.</para> 65 <para>Keep in mind that the user-defined filters are called in the order you 66 add them to the list.</para> 58 67 </section> branches/mikerobi-experimental/docs/book/xml/sessions.xml
r615 r637 1 <?xml version="1.0" encoding="utf-8"?> 2 <section xmlns:db="http://docbook.org/docbook-ng" xmlns:xi="http://www.w3.org/2001/XInclude" 3 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xml:id="sessions"> 4 <title>Session Management</title> 5 <abstract> 6 <para>CherryPy 2.1 includes a powerful sessions system provided via a new <literal>sessionFilter</literal>. </para> 7 </abstract> 8 <section id="usingsessions"> 9 <title>Using Sessions</title> 10 <para>First you need to enable the session filter through the configuration system, by setting <option>sessionFilter.on</option> to <literal>True</literal>. This gives you a variable called <literal>cherrypy.session</literal>, which is a dictionary-like object where you can read/store your session data. This dictionnary always has a special key called <literal>_id</literal> which contains the session id.</para> 11 <para>Here is a sample code showing how to implement a simple counter using sessions:</para> 12 <example> 13 <programlisting> 1 <?xml version="1.0" encoding="UTF-8"?> 2 <section xmlns:db="http://docbook.org/docbook-ng" 3 xmlns:xi="http://www.w3.org/2001/XInclude" 4 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xml:id="sessions"> 5 <title>Session Management</title> 6 <abstract> 7 <para>CherryPy 2.1 includes a powerful sessions system provided via a new 8 <literal>sessionFilter</literal>.</para> 9 </abstract> 10 <section id="usingsessions"> 11 <title>Using Sessions</title> 12 <para>First you need to enable the session filter through the 13 configuration system, by setting <option>sessionFilter.on</option> to 14 <literal>True</literal>. This gives you a variable called 15 <literal>cherrypy.session</literal>, which is a dictionary-like object 16 where you can read/store your session data. This dictionary always has a 17 special key called <literal>_id</literal> which contains the session 18 id.</para> 19 <para>Here is sample code showing how to implement a simple counter using 20 sessions:</para> 21 <example> 22 <programlisting> 14 23 import cherrypy 15 24 class Root: … … 23 32 cherrypy.server.start() 24 33 </programlisting> 25 </example> 26 </section> 27 <section> 28 <title>Configuring sessions</title> 29 <para> The following configuration options are available for "sessionFilter": </para> 30 <itemizedlist> 31 <listitem> 32 <para><option>sessionFilter.on</option>: 33 <literal>True</literal> or <literal>False</literal> (default): enable/disable sessions</para> 34 </listitem> 35 <listitem> 36 <para><option>sessionFilter.storageType</option>: 37 Specify which storage type should be used for storing session data on the server. Built-in types are <literal>Ram</literal> (default), <literal>File</literal> and <literal>PostgreSQL</literal> (see <xref linkend="backends"/> for more info)</para> 38 </listitem> 39 <listitem> 40 <para><option>sessionFilter.timeout</option>: 41 The number of minutes of inactivity before an individual session can be removed. It can be a float (ex: 0.5 for 30 seconds). Defaults to 60.</para> 42 </listitem> 43 <listitem> 44 <para><option>sessionFilter.cleanUpDelay</option>: 45 Once in a while the server cleans up old/expired sessions. This config option specifies how often this clean up process should happe. The delay is in minutes. Defaults to 5.</para> 46 </listitem> 47 <listitem> 48 <para><option>sessionFilter.cookieName</option>: 49 The name of the cookie that CherryPy will use to store the session ID. Defaults to <literal>sessionID</literal>.</para> 50 </listitem> 51 <listitem> 52 <para><option>sessionFilter.getDB</option>: 53 See the <option>PostgreSQL</option> backend from <xref linkend="backends"/>.</para> 54 </listitem> 55 <listitem> 56 <para><option>sessionFilter.deadlockTimeout</option>: 57 See <xref linkend="concurrent"/>.</para> 58 </listitem> 59 <listitem> 60 <para><option>sessionFilter.onCreateSession</option>: 61 See <xref linkend="callbacks"/>.</para> 62 </listitem> 63 <listitem> 64 <para><option>sessionFilter.onDeleteSession</option>: 65 See <xref linkend="callbacks"/>.</para> 66 </listitem> 67 <listitem> 68 <para><option>sessionFilter.storageClass</option>: 69 See <xref linkend="custombackend"/>.</para> 70 </listitem> 71 </itemizedlist> 72 </section> 73 74 <section id="backends"> 75 <title>Choosing the backend</title> 76 <para>CherryPy comes with multiple build-in backends for storing session data on the server side. They are:</para> 77 78 <itemizedlist> 79 <listitem> 80 <para><option>Ram</option>: 81 All data is stored in RAM; this is the fastest storage, but it means that the data will be lost if you restart the server; and it also means that it won't scale to multiple processes/machines</para> 82 </listitem> 83 <listitem> 84 <para><option>File</option>: 85 All data is stored on disk; this is a bit slower than Ram storage, but the data will persist if you restart the server server; it also means that data can also be shared amongst multiple CherryPy processes (either on the same machine, or on multiple machines if all machines have access to the same disk ... through something like NFS for instance)</para> 86 </listitem> 87 <listitem> 88 <para><option>PostgreSQL</option>: 89 This backend is included with CherryPy to show how easy it is to implement your own custom backend for the session system. All data is stored in a PostgreSQL database; storing your data in a database is the recommend setup for production if you have a very high traffic website and you need to scale your site accross multiple machines. To use this backend you'll need to create the following table in your PostgreSQL database: 90 <screen> 34 </example> 35 </section> 36 <section> 37 <title>Configuring sessions</title> 38 <para>The following configuration options are available for 39 "sessionFilter":</para> 40 <itemizedlist> 41 <listitem> 42 <para><option>sessionFilter.on</option>: <literal>True</literal> or 43 <literal>False</literal> (default): enable/disable sessions</para> 44 </listitem> 45 <listitem> 46 <para><option>sessionFilter.storageType</option>: Specify which 47 storage type should be used for storing session data on the server. 48 Built-in types are <literal>Ram</literal> (default), 49 <literal>File</literal> and <literal>PostgreSQL</literal> (see <xref 50 linkend="backends" /> for more info)</para> 51 </listitem> 52 <listitem> 53 <para><option>sessionFilter.timeout</option>: The number of minutes of 54 inactivity before an individual session can be removed. It can be a 55 float (ex: 0.5 for 30 seconds). Defaults to 60.</para> 56 </listitem> 57 <listitem> 58 <para><option>sessionFilter.cleanUpDelay</option>: Once in a while the 59 server cleans up old/expired sessions. This config option specifies 60 how often this clean up process should happen. The delay is in 61 minutes. Defaults to 5.</para> 62 </listitem> 63 <listitem> 64 <para><option>sessionFilter.cookieName</option>: The name of the 65 cookie that CherryPy will use to store the session ID. Defaults to 66 <literal>sessionID</literal>.</para> 67 </listitem> 68 <listitem> 69 <para><option>sessionFilter.getDB</option>: See the 70 <option>PostgreSQL</option> backend from <xref 71 linkend="backends" />.</para> 72 </listitem> 73 <listitem> 74 <para><option>sessionFilter.deadlockTimeout</option>: See <xref 75 linkend="concurrent" />.</para> 76 </listitem> 77 <listitem> 78 <para><option>sessionFilter.onCreateSession</option>: See <xref 79 linkend="callbacks" />.</para> 80 </listitem> 81 <listitem> 82 <para><option>sessionFilter.onDeleteSession</option>: See <xref 83 linkend="callbacks" />.</para> 84 </listitem> 85 <listitem> 86 <para><option>sessionFilter.storageClass</option>: See <xref 87 linkend="custombackend" />.</para> 88 </listitem> 89 </itemizedlist> 90 </section> 91 <section id="backends"> 92 <title>Choosing the backend</title> 93 <para>CherryPy comes with multiple build-in backends for storing session 94 data on the server side. They are:</para> 95 <itemizedlist> 96 <listitem> 97 <para><option>Ram</option>: All data is stored in RAM; this is the 98 fastest storage, but it means that the data will be lost if you 99 restart the server; and it also means that it won't scale to multiple 100 processes/machines</para> 101 </listitem> 102 <listitem> 103 <para><option>File</option>: All data is stored on disk; this is a bit 104 slower than Ram storage, but the data will persist if you restart the 105 server. It also means that data can be shared amongst multiple 106 CherryPy processes, either on the same machine, or on multiple 107 machines if all machines have access to the same disk (for example, 108 via NFS).</para> 109 </listitem> 110 <listitem><para><option>PostgreSQL</option>: This backend is included 111 with CherryPy to show how easy it is to implement your own custom 112 backend for the session system. All data is stored in a PostgreSQL 113 database; storing your data in a database is the recommend setup for 114 production if you have a very high traffic website and you need to scale 115 your site across multiple machines. To use this backend, you'll need to 116 create the following table in your PostgreSQL database: <screen> 91 117 create table session ( 92 118 id varchar(40), … … 94 120 expiration_time timestamp 95 121 ) 96 </screen> 97 </para> 98 You also need to programmatically set the <literal>sessionFilter.getDB</literal> config option to a function that returns a DB connection. 99 </listitem> 100 </itemizedlist> 101 </section> 102 103 <section id="custombackend"> 104 <title>Writing your own custom backend</title> 105 <para>By default, CherryPy comes with 3 built-in backends, but if you have specific needs, it is very easy to implement your own custom backend (for instance, another database, or an XML-RPC server, ...). To do so, all you have to do is write a class that implements the following methods: 106 <screen> 122 </screen> </para> You also need to programmatically set the 123 <literal>sessionFilter.getDB</literal> config option to a function that 124 returns a DB connection.</listitem> 125 </itemizedlist> 126 </section> 127 <section id="custombackend"> 128 <title>Writing your own custom backend</title> 129 <para>By default, CherryPy comes with 3 built-in backends, but if you have 130 specific needs, it is very easy to implement your own custom backend (for 131 instance, another database, or an XML-RPC server, ...). To do so, all you 132 have to do is write a class that implements the following methods: 133 <screen> 107 134 class MyCustomBackend: 108 135 def save(self, id, data, expirationTime): … … 115 142 """ Delete expired session data from storage and call 116 143 'onDeleteSession' for each deleted session id """ 117 </screen> 118 Note that if you want to use <option>explicit</option> locking (see <xref linkend="concurrent"/>), you also have to implement two extra methods: <literal>acquireLock</literal> and <literal>releaseLock</literal>. 119 </para> 120 121 <para>Once you have written this class, you have to programmatically set the <literal>sessionFilter.storageClass</literal> config option to this class.</para> 122 123 <para>If you need help in writing your own custom backend it is a good idea to look at how the current ones (ram, file and postgresql) are implemented. They are implemented in the file <filename>cherrypy/lib/filter/sessionfilter.py</filename></para> 124 </section> 125 126 <section id="concurrent"> 127 <title>Handling concurrent requests for the same session data</title> 128 <para>It is normally quite rare to have to simultaneous requests with the same session ID. It means that a same browser is making 2 requests to your server at the same time (to dynamic pages ... static pages don't have sessions). However, this case can happen (if you're using frames for instance), and it will happen more and more often as more and more people start using Ajax.</para> 129 <para>In that case, we need to make sure that access to the session data is serialized. This way threads can't both modify the data at the same time and leave it in an inconsistent state.</para> 130 <para>By default, CherryPy will serialize access to the session data, so if a browser makes a second request while a first request is still being handled by the server, the second request will block while the first request is accessing the data. As soon as the first request is finished then the second request will be able to access it.</para> 131 <para>This means that the second request will block until the first request is finished. If you're using the <option>ram</option> backend, you can manually shorten the window where the second request will block. This is achieved by having the first request explicitely tell CherryPy when it starts using the session data and when it is finished with it. In order to do so, you have to call <literal>cherrypy.session.acquireLock</literal> and <literal>cherrypy.session.releaseLock</literal>. You also have to set the <literal>sessionFilter.locking</literal> config option to <option>explicit</option>.</para> 132 <para>Note that this technique only works with the <option>ram</option> backend. For other backends like <option>file</option> or <option>postgresql</option>, it is not safe to release the session before the request is finished, because the session data will only be saved at the end of the request anyway. So it would be bad if some other thread started accessing the data between the time when it is released and the time when it is saved. 133 </para> 134 </section> 135 136 <section id="callbacks"> 137 <title>Being notified when sessions are created/deleted</title> 138 <para>It is possible to configure the <literal>sessionFilter</literal> so that it calls some special callback functions from your code when sessions are being created/deleted. To do so you have to set the <literal>sessionFilter.onCreateSession</literal> and <literal>sessionFilter.onDeleteSession</literal> config options. When a session is created/deleted, CherryPy will call these functions and pass them the session data.</para> 139 </section> 144 </screen> Note that if you want to use <option>explicit</option> 145 locking (see <xref linkend="concurrent" />), you also have to implement 146 two extra methods: <literal>acquireLock</literal> and 147 <literal>releaseLock</literal>.</para> 148 <para>Once you have written this class, you have to programmatically set 149 the <literal>sessionFilter.storageClass</literal> config option to this 150 class.</para> 151 <para>If you need help in writing your own custom backend it is a good 152 idea to look at how the current ones (ram, file and postgresql) are 153 implemented. They are implemented in the file 154 <filename>cherrypy/lib/filter/sessionfilter.py</filename></para> 155 </section> 156 <section id="concurrent"> 157 <title>Handling concurrent requests for the same session data</title> 158 <para>It is normally quite rare to have two simultaneous requests with the 159 same session ID. It means that a same browser is making 2 requests to your 160 server at the same time (to dynamic pages ... static data like images 161 don't have sessions). However, this case can happen (if you're using 162 frames for instance), and it will happen more and more often as more and 163 more people start using Ajax.</para> 164 <para>In that case, we need to make sure that access to the session data 165 is serialized. This way, threads can't both modify the data at the same 166 time and leave it in an inconsistent state.</para> 167 <para>By default, CherryPy will serialize access to the session data, so 168 if a browser makes a second request while a first request is still being 169 handled by the server, the second request will block while the first 170 request is accessing the data. As soon as the first request is finished 171 then the second request will be able to access it.</para> 172 <para>This means that the second request will block until the first 173 request is finished. If you're using the <option>ram</option> backend, you 174 can manually shorten the window where the second request will block. This 175 is achieved by having the first request explicitly tell CherryPy when it 176 starts using the session data and when it is finished with it. In order to 177 do so, you have to call <literal>cherrypy.session.acquireLock</literal> 178 and <literal>cherrypy.session.releaseLock</literal>. You also have to set 179 the <literal>sessionFilter.locking</literal> config option to 180 <option>explicit</option>.</para> 181 <para>Note that this technique only works with the <option>ram</option> 182 backend. For other backends like <option>file</option> or 183 <option>postgresql</option>, it is not safe to release the session before 184 the request is finished, because the session data will only be saved at 185 the end of the request anyway. So it would be bad if some other thread 186 started accessing the data between the time when it is released and the 187 time when it is saved.</para> 188 </section> 189 <section id="callbacks"> 190 <title>Being notified when sessions are created/deleted</title> 191 <para>It is possible to configure the <literal>sessionFilter</literal> so 192 that it calls some special callback functions from your code when sessions 193 are being created/deleted. To do so you have to set the 194 <literal>sessionFilter.onCreateSession</literal> and 195 <literal>sessionFilter.onDeleteSession</literal> config options. When a 196 session is created/deleted, CherryPy will call these functions and pass 197 them the session data.</para> 198 </section> 140 199 </section> 141 branches/mikerobi-experimental/docs/book/xml/staticcontenthandling.xml
r615 r637 1 <?xml version="1.0" encoding="utf-8"?> 2 <section xmlns:db="http://docbook.org/docbook-ng" xmlns:xi="http://www.w3.org/2001/XInclude" 3 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xml:id="globaloverviewcherrypy"> 4 <title>Static content handling</title> 5 <para>Static content is now handled by a filter called "staticFilter" that can easily be enabled and configured in your config file. 6 For instance, if you wanted to serve <code>/style.css</code> from <filename>/home/site/style.css</filename> and <code>/static/*</code> 7 from <filename>/home/site/static/*</filename>, you can use the following configuration: 8 </para> 9 10 <example> 11 <title>Static filter configuration</title> 12 <programlisting> 1 <?xml version="1.0" encoding="UTF-8"?> 2 <section xmlns:db="http://docbook.org/docbook-ng" 3 xmlns:xi="http://www.w3.org/2001/XInclude" 4 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 5 xml:id="globaloverviewcherrypy"> 6 <title>Static content handling</title> 7 <para>Static content is now handled by a filter called "staticFilter" that 8 can easily be enabled and configured in your config file. For instance, if 9 you wanted to serve <code>/style.css</code> from 10 <filename>/home/site/style.css</filename> and <code>/static/*</code> from 11 <filename>/home/site/static/*</filename>, you can use the following 12 configuration:</para> 13 <example> 14 <title>Static filter configuration</title> 15 <programlisting> 13 16 [global] 14 17 staticFilter.root = "/home/site" … … 22 25 staticFilter.dir = "static" 23 26 </programlisting> 24 </example> 25 <para>The <code>staticFilter.root</code> entry is not required; if you omit it, it defaults to the directory of your <code>cherrypy.root</code> class. </para> 26 </section> 27 </example> 28 <para>The <code>staticFilter.root</code> entry can be either absolute or 29 relative. If absolute, static content is sought within that absolute path. 30 Since CherryPy cannot guess where your application root is located, relative 31 paths are assumed to be relative to the directory where your 32 <code>cherrypy.root</code> class is defined (if you do not provide a root, 33 it defaults to "", and therefore to the directory of your 34 <code>cherrypy.root</code> class).</para> 35 <para>As an application developer, the design of your application affects 36 whether you choose to use absolute or relative paths. If you are creating a 37 one-off application that will only be deployed once, you might as well use 38 absolute paths. But you can make multiple deployments easier by using 39 relative paths, letting CherryPy calculate the absolute path each time for 40 you. Absolute paths, however, give deployers the ability to place static 41 content on read-only filesystems, or on faster disks.</para> 42 </section> branches/mikerobi-experimental/docs/book/xml/templateindependant.xml
r615 r637 1 <?xml version="1.0" encoding="utf-8"?> 2 <section xmlns:db="http://docbook.org/docbook-ng" xmlns:xi="http://www.w3.org/2001/XInclude" 3 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xml:id="templateindependant"> 4 <title>Templating language independant</title> 5 <para>CherryPy is a low level framework to build web application and thus does not 6 offer high level features such as an integrated templating system. This is quite a different 7 point of view from the other web frameworks already existing.</para> 8 <para>The great point is that CherryPy does not force you to use a specific tamplating language, 9 instead it allows you to plug your favourite one the way you need. 10 </para> 11 <para>CherryPy has been reported to be working with all the main templating systems:</para> 12 <itemizedlist> 13 <listitem> 14 &
