diff options
author | Joel Rivera <rivera@joel.mx> | 2016-03-02 00:32:16 -0600 |
---|---|---|
committer | Joel Rivera <rivera@joel.mx> | 2016-03-02 00:32:16 -0600 |
commit | a466ab7f4dacd8601c1441be63abf88db1a33781 (patch) | |
tree | cfc2821c9f8cc6c83f1de52bf8b4e8171ae33ae8 | |
parent | 304e9e1f883affd097c3b6a724391d2fe3a00ed1 (diff) | |
parent | 359f6fc83fa6c763baa345d8247322132da558fa (diff) | |
download | cherrypy-a466ab7f4dacd8601c1441be63abf88db1a33781.tar.gz |
Fix bug #1382 for Python 3.5 keyword args.
-rw-r--r-- | CHANGES.txt | 8 | ||||
-rw-r--r-- | cherrypy/__init__.py | 2 | ||||
-rw-r--r-- | cherrypy/lib/cptools.py | 7 | ||||
-rw-r--r-- | cherrypy/lib/reprconf.py | 6 | ||||
-rw-r--r-- | cherrypy/test/test_conn.py | 40 | ||||
-rw-r--r-- | cherrypy/test/test_core.py | 39 | ||||
-rw-r--r-- | cherrypy/test/test_wsgi_unix_socket.py | 3 | ||||
-rw-r--r-- | cherrypy/test/webtest.py | 47 | ||||
-rw-r--r-- | cherrypy/wsgiserver/wsgiserver2.py | 2 | ||||
-rw-r--r-- | cherrypy/wsgiserver/wsgiserver3.py | 2 | ||||
-rw-r--r-- | docs/tutorials.rst | 4 | ||||
-rw-r--r-- | setup.py | 2 |
12 files changed, 73 insertions, 89 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 2bc95852..ec5d0a36 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,10 @@ ----- +5.0.1 +----- + +* Bugfix for NameError following #94. + +----- 5.0.0 ----- @@ -7,6 +13,8 @@ of SSL adapter on Python 2 WSGI servers. * Default SSL Adapter on Python 2 is the builtin SSL adapter, matching Python 3 behavior. +* Pull request #94: In proxy tool, defer to Host header for + resolving the base if no base is supplied. ----- 4.0.0 diff --git a/cherrypy/__init__.py b/cherrypy/__init__.py index ead51acf..7db50c4b 100644 --- a/cherrypy/__init__.py +++ b/cherrypy/__init__.py @@ -56,7 +56,7 @@ with customized or extended components. The core API's are: These API's are described in the `CherryPy specification <https://bitbucket.org/cherrypy/cherrypy/wiki/CherryPySpec>`_. """ -__version__ = "4.0.1" +__version__ = "5.0.2" from cherrypy._cpcompat import urljoin as _urljoin, urlencode as _urlencode from cherrypy._cpcompat import basestring, unicodestr diff --git a/cherrypy/lib/cptools.py b/cherrypy/lib/cptools.py index 38f56195..9be571ba 100644 --- a/cherrypy/lib/cptools.py +++ b/cherrypy/lib/cptools.py @@ -193,11 +193,10 @@ def proxy(base=None, local='X-Forwarded-Host', remote='X-Forwarded-For', if lbase is not None: base = lbase.split(',')[0] if not base: + base = request.headers.get('Host', '127.0.0.1') port = request.local.port - if port == 80: - base = '127.0.0.1' - else: - base = '127.0.0.1:%s' % port + if port != 80: + base += ':%s' % port if base.find("://") == -1: # add http:// or https:// if needed diff --git a/cherrypy/lib/reprconf.py b/cherrypy/lib/reprconf.py index e394a561..be1aacb4 100644 --- a/cherrypy/lib/reprconf.py +++ b/cherrypy/lib/reprconf.py @@ -378,8 +378,10 @@ class _Builder3: return self.build(o.value) def build_Call35(self, o): - """workaround for python 3.5 _ast.Call signature, docs found here - https://greentreesnakes.readthedocs.org/en/latest/nodes.html""" + """ + Workaround for python 3.5 _ast.Call signature, docs found here + https://greentreesnakes.readthedocs.org/en/latest/nodes.html + """ callee = self.build(o.func) args = () diff --git a/cherrypy/test/test_conn.py b/cherrypy/test/test_conn.py index ab830f3c..703e6dfd 100644 --- a/cherrypy/test/test_conn.py +++ b/cherrypy/test/test_conn.py @@ -3,16 +3,16 @@ import socket import sys import time -timeout = 1 +import errno import cherrypy from cherrypy._cpcompat import HTTPConnection, HTTPSConnection, NotConnected from cherrypy._cpcompat import BadStatusLine, ntob, tonative, urlopen, unicodestr from cherrypy.test import webtest -from cherrypy import _cperror +timeout = 1 pov = 'pPeErRsSiIsStTeEnNcCeE oOfF vViIsSiIoOnN' @@ -751,24 +751,31 @@ def setup_upload_server(): 'server.accepted_queue_timeout': 0.1, }) -import errno -socket_reset_errors = [] -# Not all of these names will be defined for every platform. -for _ in ("ECONNRESET", "WSAECONNRESET"): - if _ in dir(errno): - socket_reset_errors.append(getattr(errno, _)) +reset_names = 'ECONNRESET', 'WSAECONNRESET' +socket_reset_errors = [ + getattr(errno, name) + for name in reset_names + if hasattr(errno, name) +] +"reset error numbers available on this platform" + +socket_reset_errors += [ + # Python 3.5 raises an http.client.RemoteDisconnected + # with this message + "Remote end closed connection without response", +] + class LimitedRequestQueueTests(helper.CPWebCase): - setup_server = staticmethod(setup_upload_server) + setup_server = staticmethod(setup_upload_server) def test_queue_full(self): conns = [] overflow_conn = None - + try: # Make 15 initial requests and leave them open, which should use # all of wsgiserver's WorkerThreads and fill its Queue. - import time for i in range(15): conn = self.HTTP_CONN(self.HOST, self.PORT) conn.putrequest("POST", "/upload", skip_host=True) @@ -777,7 +784,7 @@ class LimitedRequestQueueTests(helper.CPWebCase): conn.putheader("Content-Length", "4") conn.endheaders() conns.append(conn) - + # Now try a 16th conn, which should be closed by the server immediately. overflow_conn = self.HTTP_CONN(self.HOST, self.PORT) # Manually connect since httplib won't let us set a timeout @@ -788,7 +795,7 @@ class LimitedRequestQueueTests(helper.CPWebCase): overflow_conn.sock.settimeout(5) overflow_conn.sock.connect(sa) break - + overflow_conn.putrequest("GET", "/", skip_host=True) overflow_conn.putheader("Host", self.HOST) overflow_conn.endheaders() @@ -799,8 +806,11 @@ class LimitedRequestQueueTests(helper.CPWebCase): if exc.args[0] in socket_reset_errors: pass # Expected. else: - raise AssertionError("Overflow conn did not get RST. " - "Got %s instead" % repr(exc.args)) + tmpl = ( + "Overflow conn did not get RST. " + "Got {exc.args!r} instead" + ) + raise AssertionError(tmpl.format(**locals())) except BadStatusLine: # This is a special case in OS X. Linux and Windows will # RST correctly. diff --git a/cherrypy/test/test_core.py b/cherrypy/test/test_core.py index ae4728de..4ebc170a 100644 --- a/cherrypy/test/test_core.py +++ b/cherrypy/test/test_core.py @@ -9,6 +9,7 @@ import cherrypy from cherrypy._cpcompat import IncompleteRead, itervalues, ntob from cherrypy import _cptools, tools from cherrypy.lib import httputil, static +from cherrypy.test._test_decorators import ExposeExamples favicon_path = os.path.join(os.getcwd(), localDir, "../favicon.ico") @@ -41,10 +42,7 @@ class CoreRequestHandlingTest(helper.CPWebCase): baseurl.exposed = True root = Root() - - if sys.version_info >= (2, 5): - from cherrypy.test._test_decorators import ExposeExamples - root.expose_dec = ExposeExamples() + root.expose_dec = ExposeExamples() class TestType(type): @@ -250,11 +248,7 @@ class CoreRequestHandlingTest(helper.CPWebCase): cherrypy.response.cookie[str(name)] = cookie.value def multiple(self, names): - for name in names: - cookie = cherrypy.request.cookie[name] - # Python2's SimpleCookie.__setitem__ won't take unicode - # keys. - cherrypy.response.cookie[str(name)] = cookie.value + list(map(self.single, names)) def append_headers(header_list, debug=False): if debug: @@ -554,21 +548,31 @@ class CoreRequestHandlingTest(helper.CPWebCase): self.getPage("/favicon.ico") self.assertBody(data) + def skip_if_bad_cookies(self): + """ + cookies module fails to reject invalid cookies + https://bitbucket.org/cherrypy/cherrypy/issues/1405 + """ + cookies = sys.modules.get('http.cookies') + _is_legal_key = getattr(cookies, '_is_legal_key', lambda x: False) + if not _is_legal_key(','): + return + issue = 'http://bugs.python.org/issue26302' + tmpl = "Broken cookies module ({issue})" + self.skip(tmpl.format(**locals())) + def testCookies(self): - if sys.version_info >= (2, 5): - header_value = lambda x: x - else: - header_value = lambda x: x + ';' + self.skip_if_bad_cookies() self.getPage("/cookies/single?name=First", [('Cookie', 'First=Dinsdale;')]) - self.assertHeader('Set-Cookie', header_value('First=Dinsdale')) + self.assertHeader('Set-Cookie', 'First=Dinsdale') self.getPage("/cookies/multiple?names=First&names=Last", [('Cookie', 'First=Dinsdale; Last=Piranha;'), ]) - self.assertHeader('Set-Cookie', header_value('First=Dinsdale')) - self.assertHeader('Set-Cookie', header_value('Last=Piranha')) + self.assertHeader('Set-Cookie', 'First=Dinsdale') + self.assertHeader('Set-Cookie', 'Last=Piranha') self.getPage("/cookies/single?name=Something-With%2CComma", [('Cookie', 'Something-With,Comma=some-value')]) @@ -660,9 +664,6 @@ class CoreRequestHandlingTest(helper.CPWebCase): self.assertBody('/page1') def test_expose_decorator(self): - if not sys.version_info >= (2, 5): - return self.skip("skipped (Python 2.5+ only) ") - # Test @expose self.getPage("/expose_dec/no_call") self.assertStatus(200) diff --git a/cherrypy/test/test_wsgi_unix_socket.py b/cherrypy/test/test_wsgi_unix_socket.py index 0e98a4c5..0a552bc5 100644 --- a/cherrypy/test/test_wsgi_unix_socket.py +++ b/cherrypy/test/test_wsgi_unix_socket.py @@ -2,6 +2,7 @@ import os import sys import socket import atexit +import tempfile import cherrypy from cherrypy.test import helper @@ -9,7 +10,7 @@ from cherrypy._cpcompat import HTTPConnection USOCKET_PATH = os.path.join( - os.path.dirname(os.path.realpath(__file__)), + tempfile.gettempdir(), 'cp_test.sock' ) diff --git a/cherrypy/test/webtest.py b/cherrypy/test/webtest.py index 1fa3f969..fc3cab49 100644 --- a/cherrypy/test/webtest.py +++ b/cherrypy/test/webtest.py @@ -510,48 +510,11 @@ def openURL(url, headers=None, method="GET", body=None, conn._http_vsn_str = protocol conn._http_vsn = int("".join([x for x in protocol if x.isdigit()])) - # skip_accept_encoding argument added in python version 2.4 - if sys.version_info < (2, 4): - def putheader(self, header, value): - if header == 'Accept-Encoding' and value == 'identity': - return - self.__class__.putheader(self, header, value) - import new - conn.putheader = new.instancemethod( - putheader, conn, conn.__class__) - conn.putrequest(method.upper(), url, skip_host=True) - elif not py3k: - conn.putrequest(method.upper(), url, skip_host=True, - skip_accept_encoding=True) - else: - import http.client - # Replace the stdlib method, which only accepts ASCII url's - - def putrequest(self, method, url): - if ( - self._HTTPConnection__response and - self._HTTPConnection__response.isclosed() - ): - self._HTTPConnection__response = None - - if self._HTTPConnection__state == http.client._CS_IDLE: - self._HTTPConnection__state = ( - http.client._CS_REQ_STARTED) - else: - raise http.client.CannotSendRequest() - - self._method = method - if not url: - url = ntob('/') - request = ntob(' ').join( - (method.encode("ASCII"), - url, - self._http_vsn_str.encode("ASCII"))) - self._output(request) - import types - conn.putrequest = types.MethodType(putrequest, conn) - - conn.putrequest(method.upper(), url) + if py3k and isinstance(url, bytes): + url = url.decode() + + conn.putrequest(method.upper(), url, skip_host=True, + skip_accept_encoding=True) for key, value in headers: conn.putheader(key, value.encode("Latin-1")) diff --git a/cherrypy/wsgiserver/wsgiserver2.py b/cherrypy/wsgiserver/wsgiserver2.py index a0c0173f..828b243f 100644 --- a/cherrypy/wsgiserver/wsgiserver2.py +++ b/cherrypy/wsgiserver/wsgiserver2.py @@ -1756,7 +1756,7 @@ class HTTPServer(object): timeout = 10 """The timeout in seconds for accepted connections (default 10).""" - version = "CherryPy/4.0.1" + version = "CherryPy/5.0.2" """A version string for the HTTPServer.""" software = None diff --git a/cherrypy/wsgiserver/wsgiserver3.py b/cherrypy/wsgiserver/wsgiserver3.py index d410eda4..b3942c90 100644 --- a/cherrypy/wsgiserver/wsgiserver3.py +++ b/cherrypy/wsgiserver/wsgiserver3.py @@ -1478,7 +1478,7 @@ class HTTPServer(object): timeout = 10 """The timeout in seconds for accepted connections (default 10).""" - version = "CherryPy/4.0.1" + version = "CherryPy/5.0.2" """A version string for the HTTPServer.""" software = None diff --git a/docs/tutorials.rst b/docs/tutorials.rst index 36994a32..e50fa1dd 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -5,7 +5,7 @@ Tutorials This tutorial will walk you through basic but complete CherryPy applications -that will show you common concepts as well as slightly more adavanced ones. +that will show you common concepts as well as slightly more advanced ones. .. contents:: :depth: 4 @@ -183,7 +183,7 @@ Tutorial 4: Submit this form ############################ CherryPy is a web framework upon which you build web applications. -The most traditionnal shape taken by applications is through +The most traditional shape taken by applications is through an HTML user-interface speaking to your CherryPy server. Let's see how to handle HTML forms via the following @@ -36,7 +36,7 @@ class cherrypy_build_py(build_py): # arguments for the setup command ############################################################################### name = "CherryPy" -version = "4.0.1" +version = "5.0.2" desc = "Object-Oriented HTTP framework" long_desc = "CherryPy is a pythonic, object-oriented HTTP framework" classifiers = [ |