diff options
Diffstat (limited to 'cherrypy/wsgiserver/wsgiserver2.py')
-rw-r--r-- | cherrypy/wsgiserver/wsgiserver2.py | 124 |
1 files changed, 57 insertions, 67 deletions
diff --git a/cherrypy/wsgiserver/wsgiserver2.py b/cherrypy/wsgiserver/wsgiserver2.py index 8d8b04e4..f3ae1f9d 100644 --- a/cherrypy/wsgiserver/wsgiserver2.py +++ b/cherrypy/wsgiserver/wsgiserver2.py @@ -75,7 +75,8 @@ __all__ = ['HTTPRequest', 'HTTPConnection', 'HTTPServer', 'WorkerThread', 'ThreadPool', 'SSLAdapter', 'CherryPyWSGIServer', 'Gateway', 'WSGIGateway', 'WSGIGateway_10', 'WSGIGateway_u0', - 'WSGIPathInfoDispatcher', 'get_ssl_adapter_class'] + 'WSGIPathInfoDispatcher', 'get_ssl_adapter_class', + 'socket_errors_to_ignore'] import os try: @@ -83,19 +84,43 @@ try: except: import Queue as queue import re -import rfc822 +import email.utils import socket import sys +import threading +import time +import traceback as traceback_ +import operator +from urllib import unquote +import warnings +import errno +import logging +try: + # prefer slower Python-based io module + import _pyio as io +except ImportError: + # Python 2.6 + import io + +try: + import pkg_resources +except ImportError: + pass + if 'win' in sys.platform and hasattr(socket, "AF_INET6"): if not hasattr(socket, 'IPPROTO_IPV6'): socket.IPPROTO_IPV6 = 41 if not hasattr(socket, 'IPV6_V6ONLY'): socket.IPV6_V6ONLY = 27 + + +DEFAULT_BUFFER_SIZE = io.DEFAULT_BUFFER_SIZE + + try: - import cStringIO as StringIO -except ImportError: - import StringIO -DEFAULT_BUFFER_SIZE = -1 + cp_version = pkg_resources.require('cherrypy')[0].version +except Exception: + cp_version = 'unknown' class FauxSocket(object): @@ -109,23 +134,6 @@ _fileobject_uses_str_type = isinstance( socket._fileobject(FauxSocket())._rbuf, basestring) del FauxSocket # this class is not longer required for anything. -import threading -import time -import traceback - - -def format_exc(limit=None): - """Like print_exc() but return a string. Backport for Python 2.3.""" - try: - etype, value, tb = sys.exc_info() - return ''.join(traceback.format_exception(etype, value, tb, limit)) - finally: - etype = value = tb = None - -import operator - -from urllib import unquote -import warnings if sys.version_info >= (3, 0): bytestr = bytes @@ -165,8 +173,6 @@ ASTERISK = ntob('*') FORWARD_SLASH = ntob('/') quoted_slash = re.compile(ntob("(?i)%2F")) -import errno - def plat_specific_errors(*errnames): """Return error numbers for all errors in errnames on this platform. @@ -210,7 +216,6 @@ comma_separated_headers = [ ] -import logging if not hasattr(logging, 'statistics'): logging.statistics = {} @@ -302,7 +307,7 @@ class SizeCheckWrapper(object): self.bytes_read += len(data) self._check_length() res.append(data) - # See https://bitbucket.org/cherrypy/cherrypy/issue/421 + # See https://github.com/cherrypy/cherrypy/issues/421 if len(data) < 256 or data[-1:] == LF: return EMPTY.join(res) @@ -674,6 +679,10 @@ class HTTPRequest(object): # uri may be an abs_path (including "http://host.domain.tld"); scheme, authority, path = self.parse_request_uri(uri) + if path is None: + self.simple_response("400 Bad Request", + "Invalid path in Request-URI.") + return False if NUMBER_SIGN in path: self.simple_response("400 Bad Request", "Illegal #fragment in Request-URI.") @@ -798,7 +807,7 @@ class HTTPRequest(object): if self.inheaders.get("Expect", "") == "100-continue": # Don't use simple_response here, because it emits headers # we don't want. See - # https://bitbucket.org/cherrypy/cherrypy/issue/951 + # https://github.com/cherrypy/cherrypy/issues/951 msg = self.server.protocol + " 100 Continue\r\n\r\n" try: self.conn.wfile.sendall(msg) @@ -970,7 +979,7 @@ class HTTPRequest(object): self.rfile.read(remaining) if "date" not in hkeys: - self.outheaders.append(("Date", rfc822.formatdate())) + self.outheaders.append(("Date", email.utils.formatdate())) if "server" not in hkeys: self.outheaders.append(("Server", self.server.server_name)) @@ -1051,7 +1060,7 @@ class CP_fileobject(socket._fileobject): if size < 0: # Read until EOF # reset _rbuf. we consume it via buf. - self._rbuf = StringIO.StringIO() + self._rbuf = io.BytesIO() while True: data = self.recv(rbufsize) if not data: @@ -1066,12 +1075,12 @@ class CP_fileobject(socket._fileobject): # return. buf.seek(0) rv = buf.read(size) - self._rbuf = StringIO.StringIO() + self._rbuf = io.BytesIO() self._rbuf.write(buf.read()) return rv # reset _rbuf. we consume it via buf. - self._rbuf = StringIO.StringIO() + self._rbuf = io.BytesIO() while True: left = size - buf_len # recv() will malloc the amount of memory given as its @@ -1109,7 +1118,7 @@ class CP_fileobject(socket._fileobject): buf.seek(0) bline = buf.readline(size) if bline.endswith('\n') or len(bline) == size: - self._rbuf = StringIO.StringIO() + self._rbuf = io.BytesIO() self._rbuf.write(buf.read()) return bline del bline @@ -1120,7 +1129,7 @@ class CP_fileobject(socket._fileobject): buf.seek(0) buffers = [buf.read()] # reset _rbuf. we consume it via buf. - self._rbuf = StringIO.StringIO() + self._rbuf = io.BytesIO() data = None recv = self.recv while data != "\n": @@ -1132,7 +1141,7 @@ class CP_fileobject(socket._fileobject): buf.seek(0, 2) # seek end # reset _rbuf. we consume it via buf. - self._rbuf = StringIO.StringIO() + self._rbuf = io.BytesIO() while True: data = self.recv(self._rbufsize) if not data: @@ -1154,11 +1163,11 @@ class CP_fileobject(socket._fileobject): if buf_len >= size: buf.seek(0) rv = buf.read(size) - self._rbuf = StringIO.StringIO() + self._rbuf = io.BytesIO() self._rbuf.write(buf.read()) return rv # reset _rbuf. we consume it via buf. - self._rbuf = StringIO.StringIO() + self._rbuf = io.BytesIO() while True: data = self.recv(self._rbufsize) if not data: @@ -1364,7 +1373,7 @@ class HTTPConnection(object): # 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. - # See https://bitbucket.org/cherrypy/cherrypy/issue/853 + # See https://github.com/cherrypy/cherrypy/issues/853 if (not request_seen) or (req and req.started_request): # Don't bother writing the 408 if the response # has already started being written. @@ -1657,7 +1666,7 @@ class ThreadPool(object): except (AssertionError, # Ignore repeated Ctrl-C. # See - # https://bitbucket.org/cherrypy/cherrypy/issue/691. + # https://github.com/cherrypy/cherrypy/issues/691. KeyboardInterrupt): pass @@ -1757,7 +1766,7 @@ class HTTPServer(object): timeout = 10 """The timeout in seconds for accepted connections (default 10).""" - version = "CherryPy/3.6.1" + version = "CherryPy/" + cp_version """A version string for the HTTPServer.""" software = None @@ -1884,25 +1893,6 @@ class HTTPServer(object): if self.software is None: self.software = "%s Server" % self.version - # SSL backward compatibility - if (self.ssl_adapter is None and - getattr(self, 'ssl_certificate', None) and - getattr(self, 'ssl_private_key', None)): - warnings.warn( - "SSL attributes are deprecated in CherryPy 3.2, and will " - "be removed in CherryPy 3.3. Use an ssl_adapter attribute " - "instead.", - DeprecationWarning - ) - try: - from cherrypy.wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter - except ImportError: - pass - else: - self.ssl_adapter = pyOpenSSLAdapter( - self.ssl_certificate, self.ssl_private_key, - getattr(self, 'ssl_certificate_chain', None)) - # Select the appropriate socket if isinstance(self.bind_addr, basestring): # AF_UNIX socket @@ -1915,7 +1905,7 @@ class HTTPServer(object): # So everyone can access the socket... try: - os.chmod(self.bind_addr, 511) # 0777 + os.chmod(self.bind_addr, 0o777) except: pass @@ -1984,7 +1974,7 @@ class HTTPServer(object): sys.stderr.write(msg + '\n') sys.stderr.flush() if traceback: - tblines = format_exc() + tblines = traceback_.format_exc() sys.stderr.write(tblines) sys.stderr.flush() @@ -2001,7 +1991,7 @@ class HTTPServer(object): # If listening on the IPV6 any address ('::' = IN6ADDR_ANY), # activate dual-stack. See - # https://bitbucket.org/cherrypy/cherrypy/issue/871. + # https://github.com/cherrypy/cherrypy/issues/871. if (hasattr(socket, 'AF_INET6') and family == socket.AF_INET6 and self.bind_addr[0] in ('::', '::0', '::0.0.0.0')): try: @@ -2095,15 +2085,15 @@ class HTTPServer(object): # the call, and I *think* I'm reading it right that Python # will then go ahead and poll for and handle the signal # elsewhere. See - # https://bitbucket.org/cherrypy/cherrypy/issue/707. + # https://github.com/cherrypy/cherrypy/issues/707. return if x.args[0] in socket_errors_nonblocking: # Just try again. See - # https://bitbucket.org/cherrypy/cherrypy/issue/479. + # https://github.com/cherrypy/cherrypy/issues/479. return if x.args[0] in socket_errors_to_ignore: # Our socket was closed. - # See https://bitbucket.org/cherrypy/cherrypy/issue/686. + # See https://github.com/cherrypy/cherrypy/issues/686. return raise @@ -2136,7 +2126,7 @@ class HTTPServer(object): if x.args[0] not in socket_errors_to_ignore: # Changed to use error code and not message # See - # https://bitbucket.org/cherrypy/cherrypy/issue/860. + # https://github.com/cherrypy/cherrypy/issues/860. raise else: # Note that we're explicitly NOT using AI_PASSIVE, @@ -2186,7 +2176,7 @@ ssl_adapters = { } -def get_ssl_adapter_class(name='pyopenssl'): +def get_ssl_adapter_class(name='builtin'): """Return an SSL adapter class for the given name.""" adapter = ssl_adapters[name.lower()] if isinstance(adapter, basestring): |