summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrej Shadura <andrewsh@debian.org>2018-05-13 09:55:50 +0200
committerAndrej Shadura <andrewsh@debian.org>2018-05-13 09:55:50 +0200
commitd11da7c3ec7ffd2c8bcf0f13a663e31207dc1397 (patch)
tree5c11b8f8848182708fe960f792f8f6b88eabd652
parent1e9335a3cc8d249a51df35f61726280e6d0e6546 (diff)
parentbe227e51d4f69d7d6c065843c2a1bec1502ed3d7 (diff)
Update upstream source from tag 'upstream/1.1.0'
Update to upstream version '1.1.0' with Debian dir a90e64e170e41680072eb73899eb2038be663cd1
-rw-r--r--.travis.yml6
-rw-r--r--CHANGES.txt38
-rw-r--r--CONTRIBUTORS.txt3
-rw-r--r--appveyor.yml11
-rw-r--r--docs/conf.py10
-rw-r--r--docs/filewrapper.rst18
-rw-r--r--docs/index.rst6
-rw-r--r--setup.py3
-rw-r--r--tox.ini6
-rw-r--r--waitress/__main__.py2
-rw-r--r--waitress/parser.py21
-rw-r--r--waitress/server.py18
-rw-r--r--waitress/tests/test_parser.py20
-rw-r--r--waitress/tests/test_runner.py4
14 files changed, 134 insertions, 32 deletions
diff --git a/.travis.yml b/.travis.yml
index 7c837bd..401f191 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,12 +12,18 @@ matrix:
env: TOXENV=py34
- python: 3.5
env: TOXENV=py35
+ - python: 3.6
+ env: TOXENV=py36
- python: pypy
env: TOXENV=pypy
- python: pypy3
env: TOXENV=pypy3
- python: 3.5
env: TOXENV=py2-cover,py3-cover,coverage
+ - python: 3.5
+ env: TOXENV=docs
+ allow_failures:
+ - env: TOXENV=pypy3
install:
- travis_retry pip install tox
diff --git a/CHANGES.txt b/CHANGES.txt
index 8ccb0bf..e1726c6 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,41 @@
+1.1.0 (2017-10-10)
+------------------
+
+Features
+~~~~~~~~
+
+- Waitress now has a __main__ and thus may be called with ``python -mwaitress``
+
+Bugfixes
+~~~~~~~~
+
+- Waitress no longer allows lowercase HTTP verbs. This change was made to fall
+ in line with most HTTP servers. See https://github.com/Pylons/waitress/pull/170
+
+- When receiving non-ascii bytes in the request URL, waitress will no longer
+ abruptly close the connection, instead returning a 400 Bad Request. See
+ https://github.com/Pylons/waitress/pull/162 and
+ https://github.com/Pylons/waitress/issues/64
+
+1.0.2 (2017-02-04)
+------------------
+
+Features
+~~~~~~~~
+
+- Python 3.6 is now officially supported in Waitress
+
+Bugfixes
+~~~~~~~~
+
+- Add a work-around for libc issue on Linux not following the documented
+ standards. If getnameinfo() fails because of DNS not being available it
+ should return the IP address instead of the reverse DNS entry, however
+ instead getnameinfo() raises. We catch this, and ask getnameinfo()
+ for the same information again, explicitly asking for IP address instead of
+ reverse DNS hostname. See https://github.com/Pylons/waitress/issues/149 and
+ https://github.com/Pylons/waitress/pull/153
+
1.0.1 (2016-10-22)
------------------
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index a53e15d..3f309fc 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -137,3 +137,6 @@ Contributors
- Jason Madden, 2016-03-19
+- Atsushi Odagiri, 2017-02-12
+
+- David D Lowe, 2017-06-02
diff --git a/appveyor.yml b/appveyor.yml
index 6505c2b..bc7aa9b 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,10 +1,19 @@
environment:
matrix:
+ - PYTHON: "C:\\Python35"
+ TOXENV: "py35"
- PYTHON: "C:\\Python27"
TOXENV: "py27"
- - PYTHON: "C:\\Python35"
+ - PYTHON: "C:\\Python27-x64"
+ TOXENV: "py27"
+ - PYTHON: "C:\\Python35-x64"
TOXENV: "py35"
+cache:
+ - '%LOCALAPPDATA%\pip\Cache'
+
+version: '{branch}.{build}'
+
install:
- "%PYTHON%\\python.exe -m pip install tox"
diff --git a/docs/conf.py b/docs/conf.py
index ce3c33f..aa9b3fb 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -19,7 +19,7 @@
import sys, os
import pkg_resources
-# import pylons_sphinx_themes
+import pylons_sphinx_themes
# General configuration
# ---------------------
@@ -47,7 +47,7 @@ copyright = '2012, Agendaless Consulting <chrism@plope.com>'
# other places throughout the built documents.
#
# The short X.Y version.
-version = '1.0.1'
+version = pkg_resources.get_distribution('waitress').version
# The full version, including alpha/beta/rc tags.
release = version
@@ -89,9 +89,9 @@ pygments_style = 'sphinx'
# -----------------------
# Add and use Pylons theme
-# html_theme = 'pylons'
-# html_theme_path = # pylons_sphinx_themes.get_html_themes_path()
-# html_theme_options = dict(github_url='http://github.com/Pylons/waitress')
+html_theme = 'pylons'
+html_theme_path = pylons_sphinx_themes.get_html_themes_path()
+html_theme_options = dict(github_url='http://github.com/Pylons/waitress')
# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
diff --git a/docs/filewrapper.rst b/docs/filewrapper.rst
index fe0037f..a119594 100644
--- a/docs/filewrapper.rst
+++ b/docs/filewrapper.rst
@@ -3,7 +3,9 @@ Support for ``wsgi.file_wrapper``
Waitress supports the `WSGI file_wrapper protocol
<http://www.python.org/dev/peps/pep-0333/#optional-platform-specific-file-handling>`_
-. Here's a usage example::
+. Here's a usage example:
+
+.. code-block:: python
import os
@@ -29,19 +31,19 @@ object which supports *at least* the ``read()`` method, and the ``read()``
method must support an optional size hint argument and the ``read()`` method
*must* return **bytes** objects (never unicode). It *should* support the
``seek()`` and ``tell()`` methods. If it does not, normal iteration over the
-filelike object using the provided block_size is used (and copying is done,
-negating any benefit of the file wrapper). It *should* support a ``close()``
-method.
+``filelike_object`` using the provided ``block_size`` is used (and copying is
+done, negating any benefit of the file wrapper). It *should* support a
+``close()`` method.
The specified ``block_size`` argument to the file wrapper constructor will be
used only when the ``filelike_object`` doesn't support ``seek`` and/or
``tell`` methods. Waitress needs to use normal iteration to serve the file
in this degenerate case (as per the WSGI pec), and this block size will be
used as the iteration chunk size. The ``block_size`` argument is optional;
-if it is not passed, a default value``32768`` is used.
+if it is not passed, a default value ``32768`` is used.
-Waitress will set a ``Content-Length`` header on the behalf of an application
-when a file wrapper with a sufficiently filelike object is used if the
+Waitress will set a ``Content-Length`` header on behalf of an application
+when a file wrapper with a sufficiently file-like object is used if the
application hasn't already set one.
The machinery which handles a file wrapper currently doesn't do anything
@@ -49,4 +51,4 @@ particularly special using fancy system calls (it doesn't use ``sendfile``
for example); using it currently just prevents the system from needing to
copy data to a temporary buffer in order to send it to the client. No
copying of data is done when a WSGI app returns a file wrapper that wraps a
-sufficiently filelike object. It may do something fancier in the future.
+sufficiently file-like object. It may do something fancier in the future.
diff --git a/docs/index.rst b/docs/index.rst
index cd175e3..9e89395 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -4,7 +4,7 @@ Waitress
Waitress is meant to be a production-quality pure-Python WSGI server with
very acceptable performance. It has no dependencies except ones which live
in the Python standard library. It runs on CPython on Unix and Windows under
-Python 2.6+ and Python 3.2+. It is also known to run on PyPy 1.6.0 on UNIX.
+Python 2.7+ and Python 3.3+. It is also known to run on PyPy 1.6.0 on UNIX.
It supports HTTP/1.0 and HTTP/1.1.
Usage
@@ -23,7 +23,7 @@ and IPv6.
.. code-block:: python
- from waitress impot serve
+ from waitress import serve
serve(wsgiapp, host='0.0.0.0', port=8080)
This will run waitress on port 8080 on all available IPv4 addresses.
@@ -36,7 +36,7 @@ WSGI app as a single argument:
from waitress import serve
serve(wsgiapp)
-
+
Press Ctrl-C (or Ctrl-Break on Windows) to exit the server.
The default is to bind to any IPv4 address on port 8080:
diff --git a/setup.py b/setup.py
index c17a7b0..3bda37d 100644
--- a/setup.py
+++ b/setup.py
@@ -34,7 +34,7 @@ testing_extras = [
setup(
name='waitress',
- version='1.0.1',
+ version='1.1.0',
author='Zope Foundation and Contributors',
author_email='zope-dev@zope.org',
maintainer="Pylons Project",
@@ -55,6 +55,7 @@ setup(
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
'Natural Language :: English',
diff --git a/tox.ini b/tox.ini
index 4864c46..3dd9921 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
[tox]
envlist =
- py27,py33,py34,py35,pypy,pypy3,
+ py27,py33,py34,py35,py36,pypy,
docs,
{py2,py3}-cover,coverage
@@ -12,8 +12,8 @@ basepython =
py33: python3.3
py34: python3.4
py35: python3.5
+ py36: python3.6
pypy: pypy
- pypy3: pypy3
py2: python2.7
py3: python3.5
@@ -26,7 +26,7 @@ basepython = python3.5
whitelist_externals = make
commands =
pip install waitress[docs]
- make -C docs html epub BUILDDIR={envdir} "SPHINXOPTS=-W -E"
+ make -C docs clean html epub BUILDDIR={envdir} "SPHINXOPTS=-W -E"
[py-cover]
commands =
diff --git a/waitress/__main__.py b/waitress/__main__.py
new file mode 100644
index 0000000..e484f40
--- /dev/null
+++ b/waitress/__main__.py
@@ -0,0 +1,2 @@
+from waitress.runner import run # pragma nocover
+run() # pragma nocover
diff --git a/waitress/parser.py b/waitress/parser.py
index fc71d68..6d2f340 100644
--- a/waitress/parser.py
+++ b/waitress/parser.py
@@ -253,7 +253,10 @@ class HTTPRequestParser(object):
def split_uri(uri):
# urlsplit handles byte input by returning bytes on py3, so
# scheme, netloc, path, query, and fragment are bytes
- scheme, netloc, path, query, fragment = urlparse.urlsplit(uri)
+ try:
+ scheme, netloc, path, query, fragment = urlparse.urlsplit(uri)
+ except UnicodeError:
+ raise ParsingError('Bad URI')
return (
tostr(scheme),
tostr(netloc),
@@ -291,8 +294,20 @@ def crack_first_line(line):
version = m.group(5)
else:
version = None
- command = m.group(1).upper()
+ method = m.group(1)
+
+ # the request methods that are currently defined are all uppercase:
+ # https://www.iana.org/assignments/http-methods/http-methods.xhtml and
+ # the request method is case sensitive according to
+ # https://tools.ietf.org/html/rfc7231#section-4.1
+
+ # By disallowing anything but uppercase methods we save poor
+ # unsuspecting souls from sending lowercase HTTP methods to waitress
+ # and having the request complete, while servers like nginx drop the
+ # request onto the floor.
+ if method != method.upper():
+ raise ParsingError('Malformed HTTP method "%s"' % tostr(method))
uri = m.group(2)
- return command, uri, version
+ return method, uri, version
else:
return b'', b'', b''
diff --git a/waitress/server.py b/waitress/server.py
index d3fbd79..79aa9b7 100644
--- a/waitress/server.py
+++ b/waitress/server.py
@@ -294,9 +294,21 @@ class TcpWSGIServer(BaseWSGIServer):
self.bind(sockaddr)
def getsockname(self):
- return self.socketmod.getnameinfo(
- self.socket.getsockname(),
- self.socketmod.NI_NUMERICSERV)
+ try:
+ return self.socketmod.getnameinfo(
+ self.socket.getsockname(),
+ self.socketmod.NI_NUMERICSERV
+ )
+ except: # pragma: no cover
+ # This only happens on Linux because a DNS issue is considered a
+ # temporary failure that will raise (even when NI_NAMEREQD is not
+ # set). Instead we try again, but this time we just ask for the
+ # numerichost and the numericserv (port) and return those. It is
+ # better than nothing.
+ return self.socketmod.getnameinfo(
+ self.socket.getsockname(),
+ self.socketmod.NI_NUMERICHOST | self.socketmod.NI_NUMERICSERV
+ )
def set_socket_options(self, conn):
for (level, optname, value) in self.adj.socket_options:
diff --git a/waitress/tests/test_parser.py b/waitress/tests/test_parser.py
index 781d7c7..ecb6606 100644
--- a/waitress/tests/test_parser.py
+++ b/waitress/tests/test_parser.py
@@ -249,6 +249,16 @@ class Test_split_uri(unittest.TestCase):
self.assertEqual(self.proxy_scheme, 'https')
self.assertEqual(self.proxy_netloc, 'localhost:8080')
+ def test_split_uri_unicode_error_raises_parsing_error(self):
+ # See https://github.com/Pylons/waitress/issues/64
+ from waitress.parser import ParsingError
+ # Either pass or throw a ParsingError, just don't throw another type of
+ # exception as that will cause the connection to close badly:
+ try:
+ self._callFUT(b'/\xd0')
+ except ParsingError:
+ pass
+
class Test_get_header_lines(unittest.TestCase):
def _callFUT(self, data):
@@ -288,15 +298,19 @@ class Test_crack_first_line(unittest.TestCase):
return crack_first_line(line)
def test_crack_first_line_matchok(self):
- result = self._callFUT(b'get / HTTP/1.0')
+ result = self._callFUT(b'GET / HTTP/1.0')
self.assertEqual(result, (b'GET', b'/', b'1.0'))
+ def test_crack_first_line_lowercase_method(self):
+ from waitress.parser import ParsingError
+ self.assertRaises(ParsingError, self._callFUT, b'get / HTTP/1.0')
+
def test_crack_first_line_nomatch(self):
- result = self._callFUT(b'get / bleh')
+ result = self._callFUT(b'GET / bleh')
self.assertEqual(result, (b'', b'', b''))
def test_crack_first_line_missing_version(self):
- result = self._callFUT(b'get /')
+ result = self._callFUT(b'GET /')
self.assertEqual(result, (b'GET', b'/', None))
class TestHTTPRequestParserIntegration(unittest.TestCase):
diff --git a/waitress/tests/test_runner.py b/waitress/tests/test_runner.py
index 6fa0b40..fa927f0 100644
--- a/waitress/tests/test_runner.py
+++ b/waitress/tests/test_runner.py
@@ -104,8 +104,8 @@ class Test_run(unittest.TestCase):
['nonexistent:a'],
1,
(
- r"There was an exception \(ImportError\) importing your "
- "module.\n\nIt had these arguments: \n"
+ r"There was an exception \((ImportError|ModuleNotFoundError)\) "
+ "importing your module.\n\nIt had these arguments: \n"
"1. No module named '?nonexistent'?"
)
)