summaryrefslogtreecommitdiff
path: root/cherrypy/wsgiserver/wsgiserver2.py
diff options
context:
space:
mode:
Diffstat (limited to 'cherrypy/wsgiserver/wsgiserver2.py')
-rw-r--r--cherrypy/wsgiserver/wsgiserver2.py124
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):