Commits

Robert Brewer committed 9d77e2a

Some backports (mostly whitespace, really) from the python3 branch.

  • Participants
  • Parent commits 90a2df1

Comments (0)

Files changed (13)

cherrypy/LICENSE.txt

-Copyright (c) 2004-2009, CherryPy Team (team@cherrypy.org)
+Copyright (c) 2004-2011, CherryPy Team (team@cherrypy.org)
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification, 

cherrypy/__init__.py

 
 # Timeout monitor
 class _TimeoutMonitor(process.plugins.Monitor):
-
+    
     def __init__(self, bus):
         self.servings = []
         process.plugins.Monitor.__init__(self, bus, self.run)
-
+    
     def acquire(self):
         self.servings.append((serving.request, serving.response))
-
+    
     def release(self):
         try:
             self.servings.remove((serving.request, serving.response))
         except ValueError:
             pass
-
+    
     def run(self):
         """Check timeout on all responses. (Internal)"""
         for req, resp in self.servings:
 
 def quickstart(root=None, script_name="", config=None):
     """Mount the given root, start the builtin server (and engine), then block.
-
+    
     root: an instance of a "controller class" (a collection of page handler
         methods) which represents the root of the application.
     script_name: a string containing the "mount point" of the application.
         at which to mount the given root. For example, if root.index() will
         handle requests to "http://www.example.com:8080/dept/app1/", then
         the script_name argument would be "/dept/app1".
-
+        
         It MUST NOT end in a slash. If the script_name refers to the root
         of the URI, it MUST be an empty string (not "/").
     config: a file or dict containing application config. If this contains
     """
     if config:
         _global_conf_alias.update(config)
-
+    
     tree.mount(root, script_name, config)
-
+    
     if hasattr(engine, "signal_handler"):
         engine.signal_handler.subscribe()
     if hasattr(engine, "console_control_handler"):
         engine.console_control_handler.subscribe()
-
+    
     engine.start()
     engine.block()
 
 
 class _Serving(_local):
     """An interface for registering request and response objects.
-
+    
     Rather than have a separate "thread local" object for the request and
     the response, this class works as a single threadlocal container for
     both objects (and any others which developers wish to define). In this
 
 
 class _ThreadLocalProxy(object):
-
+    
     __slots__ = ['__attrname__', '__dict__']
-
+    
     def __init__(self, attrname):
         self.__attrname__ = attrname
-
+    
     def __getattr__(self, name):
         child = getattr(serving, self.__attrname__)
         return getattr(child, name)
-
+    
     def __setattr__(self, name, value):
         if name in ("__attrname__", ):
             object.__setattr__(self, name, value)
         else:
             child = getattr(serving, self.__attrname__)
             setattr(child, name, value)
-
+    
     def __delattr__(self, name):
         child = getattr(serving, self.__attrname__)
         delattr(child, name)
-
+    
     def _get_dict(self):
         child = getattr(serving, self.__attrname__)
         d = child.__class__.__dict__.copy()
         d.update(child.__dict__)
         return d
     __dict__ = property(_get_dict)
-
+    
     def __getitem__(self, key):
         child = getattr(serving, self.__attrname__)
         return child[key]
-
+    
     def __setitem__(self, key, value):
         child = getattr(serving, self.__attrname__)
         child[key] = value
-
+    
     def __delitem__(self, key):
         child = getattr(serving, self.__attrname__)
         del child[key]
-
+    
     def __contains__(self, key):
         child = getattr(serving, self.__attrname__)
         return key in child
-
+    
     def __len__(self):
         child = getattr(serving, self.__attrname__)
         return len(child)
-
+    
     def __nonzero__(self):
         child = getattr(serving, self.__attrname__)
         return bool(child)
                 for a in alias:
                     parents[a.replace(".", "_")] = func
         return func
-
+    
     import sys, types
     if isinstance(func, (types.FunctionType, types.MethodType)):
         if alias is None:
 
 def url(path="", qs="", script_name=None, base=None, relative=None):
     """Create an absolute URL for the given path.
-
+    
     If 'path' starts with a slash ('/'), this will return
         (base + script_name + path + qs).
     If it does not start with a slash, this returns
         (base + script_name [+ request.path_info] + path + qs).
-
+    
     If script_name is None, cherrypy.request will be used
     to find a script_name, if available.
-
+    
     If base is None, cherrypy.request.base will be used (if available).
     Note that you can use cherrypy.tools.proxy to change this.
-
+    
     Finally, note that this function can be used to obtain an absolute URL
     for the current request path (minus the querystring) by passing no args.
     If you call url(qs=cherrypy.request.query_string), you should get the
     original browser URL (assuming no internal redirections).
-
+    
     If relative is None or not provided, request.app.relative_urls will
     be used (if available, else False). If False, the output will be an
     absolute URL (including the scheme, host, vhost, and script_name).
         qs = _urlencode(qs)
     if qs:
         qs = '?' + qs
-
+    
     if request.app:
         if not path.startswith("/"):
             # Append/remove trailing slash from path_info as needed
             elif request.is_index is False:
                 if pi.endswith('/') and pi != '/':
                     pi = pi[:-1]
-
+            
             if path == "":
                 path = pi
             else:
                 path = _urljoin(pi, path)
-
+        
         if script_name is None:
             script_name = request.script_name
         if base is None:
             base = request.base
-
+        
         newurl = base + script_name + path + qs
     else:
         # No request.app (we're being called outside a request).
         # if you're using vhosts or tools.proxy.
         if base is None:
             base = server.base()
-
+        
         path = (script_name or "") + path
         newurl = base + path + qs
-
+    
     if './' in newurl:
         # Normalize the URL by removing ./ and ../
         atoms = []
             else:
                 atoms.append(atom)
         newurl = '/'.join(atoms)
-
+    
     # At this point, we should have a fully-qualified absolute URL.
-
+    
     if relative is None:
         relative = getattr(request.app, "relative_urls", False)
-
+    
     # See http://www.ietf.org/rfc/rfc2396.txt
     if relative == 'server':
         # "A relative reference beginning with a single slash character is
             new.pop(0)
         new = (['..'] * len(old)) + new
         newurl = '/'.join(new)
-
+    
     return newurl
 
 

cherrypy/_cperror.py

     def __init__(self, urls, status=None, encoding=None):
         import cherrypy
         request = cherrypy.serving.request
-
+        
         if isinstance(urls, basestring):
             urls = [urls]
-
+        
         abs_urls = []
         for url in urls:
             if isinstance(url, unicode):

cherrypy/_cplogging.py

             if getattr(h, "_cpbuiltin", None) == key:
                 return h
     
+    
     # ------------------------- Screen handlers ------------------------- #
     
     def _set_screen_handler(self, log, enable, stream=None):

cherrypy/_cpreqbody.py

                 request_params[key].append(value)
             else:
                 request_params[key] = value
-

cherrypy/_cptree.py

 
 class Application(object):
     """A CherryPy Application.
-
+    
     Servers and gateways should not instantiate Request objects directly.
     Instead, they should ask an Application object for a request object.
-
+    
     An instance of this class may also be used as a WSGI callable
     (WSGI application object) for itself.
     """

cherrypy/lib/caching.py

         return
     
     def tee(body):
-        # Tee response.body into a list.
+        """Tee response.body into a list."""
         if ('no-cache' in response.headers.values('Pragma') or
             'no-store' in response.headers.values('Cache-Control')):
             for chunk in body:

cherrypy/lib/encoding.py

                             # Matches any charset. Try our default.
                             if self.debug:
                                 cherrypy.log('Attempting default encoding due '
-                                             'to %s' % element, 'TOOLS.ENCODE')
+                                             'to %r' % element, 'TOOLS.ENCODE')
                             if encoder(self.default_encoding):
                                 return self.default_encoding
                         else:
                             encoding = element.value
                             if self.debug:
-                                cherrypy.log('Attempting encoding %s (qvalue >'
+                                cherrypy.log('Attempting encoding %r (qvalue >'
                                              '0)' % element, 'TOOLS.ENCODE')
                             if encoder(encoding):
                                 return encoding

cherrypy/process/servers.py

 
 
 class ServerAdapter(object):
-    """Adapter for an HTTP server."""
+    """Adapter for an HTTP server.
+    
+    If you need to start more than one HTTP server (to serve on multiple
+    ports, or protocols, etc.), you can manually register each one and then
+    start them all with bus.start:
+    
+        s1 = ServerAdapter(bus, MyWSGIServer(host='0.0.0.0', port=80))
+        s2 = ServerAdapter(bus, another.HTTPServer(host='127.0.0.1', SSL=True))
+        s1.subscribe()
+        s2.subscribe()
+        bus.start()
+    """
     
     def __init__(self, bus, httpserver=None, bind_addr=None):
         self.bus = bus

cherrypy/test/helper.py

 import warnings
 
 import cherrypy
-from cherrypy.lib import httputil, profiler
+from cherrypy.lib import httputil
 from cherrypy.lib.reprconf import unrepr
 from cherrypy.test import webtest
 
 
 
 class CPWebCase(webtest.WebCase):
+ 
     script_name = ""
     scheme = "http"
 
 
     def prefix(self):
         return self.script_name.rstrip("/")
-
+    
     def base(self):
         if ((self.scheme == "http" and self.PORT == 80) or
             (self.scheme == "https" and self.PORT == 443)):
             port = ""
         else:
             port = ":%s" % self.PORT
-
+        
         return "%s://%s%s%s" % (self.scheme, self.HOST, port,
                                 self.script_name.rstrip("/"))
-
+    
     def exit(self):
         sys.exit()
-
+    
     def getPage(self, url, headers=None, method="GET", body=None, protocol=None):
         """Open the url. Return status, headers, body."""
         if self.script_name:
             url = httputil.urljoin(self.script_name, url)
         return webtest.WebCase.getPage(self, url, headers, method, body, protocol)
-
+    
     def skip(self, msg='skipped '):
         sys.stderr.write(msg)
-
+    
     def assertErrorPage(self, status, message=None, pattern=''):
         """Compare the response body with a built in error page.
-
+        
         The function will optionally look for the regexp pattern,
         within the exception embedded in the error page."""
-
+        
         # This will never contain a traceback
         page = cherrypy._cperror.get_error_page(status, message=message)
-
+        
         # First, test the response body without checking the traceback.
         # Stick a match-all group (.*) in to grab the traceback.
         esc = re.escape
         if not m:
             self._handlewebError('Error page does not match; expected:\n' + page)
             return
-
+        
         # Now test the pattern against the traceback
         if pattern is None:
             # Special-case None to mean that there should be *no* traceback.
                               m.group(1))):
                 msg = 'Error page does not contain %s in traceback'
                 self._handlewebError(msg % repr(pattern))
-
+    
     date_tolerance = 2
-
+    
     def assertEqualDates(self, dt1, dt2, seconds=None):
         """Assert abs(dt1 - dt2) is within Y seconds."""
         if seconds is None:
             seconds = self.date_tolerance
-
+        
         if dt1 > dt2:
             diff = dt1 - dt2
         else:
 
 
 class CPProcess(object):
-
+    
     pid_file = os.path.join(thisdir, 'test.pid')
     config_file = os.path.join(thisdir, 'test.conf')
     config_template = """[global]
 """
     error_log = os.path.join(thisdir, 'test.error.log')
     access_log = os.path.join(thisdir, 'test.access.log')
-
+    
     def __init__(self, wait=False, daemonize=False, ssl=False, socket_host=None, socket_port=None):
         self.wait = wait
         self.daemonize = daemonize
         self.ssl = ssl
         self.host = socket_host or cherrypy.server.socket_host
         self.port = socket_port or cherrypy.server.socket_port
-
+    
     def write_conf(self, extra=""):
         if self.ssl:
             serverpem = os.path.join(thisdir, 'test.pem')
 """ % (serverpem, serverpem)
         else:
             ssl = ""
-
+        
         conf = self.config_template % {
             'host': self.host,
             'port': self.port,
         f = open(self.config_file, 'wb')
         f.write(conf)
         f.close()
-
+    
     def start(self, imports=None):
         """Start cherryd in a subprocess."""
         cherrypy._cpserver.wait_for_free_port(self.host, self.port)
-
+        
         args = [sys.executable, os.path.join(thisdir, '..', 'cherryd'),
                 '-c', self.config_file, '-p', self.pid_file]
-
+        
         if not isinstance(imports, (list, tuple)):
             imports = [imports]
         for i in imports:
             if i:
                 args.append('-i')
                 args.append(i)
-
+        
         if self.daemonize:
             args.append('-d')
 
         else:
             os.spawnve(os.P_NOWAIT, sys.executable, args, env)
             cherrypy._cpserver.wait_for_occupied_port(self.host, self.port)
-
+        
         # Give the engine a wee bit more time to finish STARTING
         if self.daemonize:
             time.sleep(2)
         else:
             time.sleep(1)
-
+    
     def get_pid(self):
         return int(open(self.pid_file, 'rb').read())
-
+    
     def join(self):
         """Wait for the process to exit."""
         try:

cherrypy/tutorial/custom_error.html

     <title>403 Unauthorized</title>
 </head>
     <body>
-        <h2>You can't do that!</h2>
+        <h2>You can't do that!</h2>
         <p>%(message)s</p>
-        <p>This is a custom error page that is read from a file.<p>
+        <p>This is a custom error page that is read from a file.<p>
         <pre>%(traceback)s</pre>
     </body>
 </html>

cherrypy/tutorial/tut09_files.py

 else:
     # This branch is for the test suite; you can ignore it.
     cherrypy.tree.mount(FileDemo(), config=tutconf)
-

cherrypy/wsgiserver/__init__.py

     server = wsgiserver.CherryPyWSGIServer(
                 ('0.0.0.0', 8070), my_crazy_app,
                 server_name='www.cherrypy.example')
-
+    
 The CherryPy WSGI server can serve as many WSGI applications 
 as you want in one instance by using a WSGIPathInfoDispatcher::
     
     d = WSGIPathInfoDispatcher({'/': my_crazy_app, '/blog': my_blog_app})
     server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 80), d)
-
+    
 Want SSL support? Just set server.ssl_adapter to an SSLAdapter instance.
 
 This won't call the CherryPy engine (application side) at all, only the
         self.status = ""
         self.outheaders = []
         self.sent_headers = False
-        self.close_connection = HTTPRequest.close_connection
+        self.close_connection = self.__class__.close_connection
         self.chunked_read = False
-        self.chunked_write = HTTPRequest.chunked_write
+        self.chunked_write = self.__class__.chunked_write
     
     def parse_request(self):
         """Parse the next HTTP request start-line and message-headers."""
             if te:
                 te = [x.strip().lower() for x in te.split(",") if x.strip()]
         
+        self.chunked_read = False
+        
         if te:
             for enc in te:
                 if enc == "chunked":
     def simple_response(self, status, msg=""):
         """Write a simple response back to the client."""
         status = str(status)
-        buf = ["Content-Length: %s\r\n" % len(msg),
+        buf = [self.server.protocol + " " +
+               status + CRLF,
+               "Content-Length: %s\r\n" % len(msg),
                "Content-Type: text/plain\r\n"]
         
         if status[:3] in ("413", "414"):
                 msg = msg.encode("ISO-8859-1")
             buf.append(msg)
         
-        status_line = self.server.protocol + " " + status + CRLF
         try:
-            self.conn.wfile.sendall(status_line + "".join(buf))
+            self.conn.wfile.sendall("".join(buf))
         except socket.error, x:
             if x.args[0] not in socket_errors_to_ignore:
                 raise
                     return
         except socket.error, e:
             errnum = e.args[0]
-            if errnum == 'timed out':
+            # sadly SSL sockets return a different (longer) time out string
+            if errnum == 'timed out' or errnum == 'The read operation timed out':
                 # Don't error if we're between requests; only error
                 # if 1) no request has been started at all, or 2) we're
                 # in the middle of a request.
             af, socktype, proto, canonname, sa = res
             try:
                 self.bind(af, socktype, proto)
-            except socket.error, msg:
+            except socket.error:
                 if self.socket:
                     self.socket.close()
                 self.socket = None
                 if not s:
                     return
                 makefile = self.ssl_adapter.makefile
+                # Re-apply our timeout since we may have a new socket object
+                if hasattr(s, 'settimeout'):
+                    s.settimeout(self.timeout)
             
             conn = self.ConnectionClass(self, s, makefile)
             
         else:
             env["SERVER_PORT"] = str(req.server.bind_addr[1])
         
-        # CONTENT_TYPE/CONTENT_LENGTH
+        # Request headers
         for k, v in req.inheaders.iteritems():
             env["HTTP_" + k.upper().replace("-", "_")] = v
+        
+        # CONTENT_TYPE/CONTENT_LENGTH
         ct = env.pop("HTTP_CONTENT_TYPE", None)
         if ct is not None:
             env["CONTENT_TYPE"] = ct