+python-eventlet (0.18.4-1~u14.04+mos1) mos9.0; urgency=medium
+
+ * Source: http://http.debian.net/debian/pool/main/p/python-eventlet/python-eventlet_0.18.4-1.dsc
+
+ -- Ivan Udovichenko <iudovichenko@mirantis.com> Fri, 04 Mar 2016 18:29:23 +0200
+
+python-eventlet (0.18.4-1) experimental; urgency=medium
+
+ [ Ondřej Nový ]
+ * Removed greenio_send_was_running_empty_loop_on_ENOTCONN.patch
+ (Applied upstream)
+ * Rebased use-packaged-python-mock-rather-than-embedded.patch
+ * Rebased set-defaults-to-be-tlsv1-not-sslv23.patch
+ * Rebased remove-self.assert-in-tests.patcher_test.py.patch
+ * Added python(3)-dnspython build dependency.
+ * Fixed VCS URLs (https).
+ * Standards-Version is 3.9.7 now (no change).
+ * Fixed upstream changelog.
+ * Added Debian tests.
+ * Added myself as uploader.
+
+ [ Corey Bryant ]
+ * New upstream release.
+
+ -- Ondřej Nový <novy@ondrej.org> Fri, 26 Feb 2016 21:44:11 +0100
+
python-eventlet (0.17.4-2~u14.04+mos1) mos8.0; urgency=medium
* Source: http://http.debian.net/debian/pool/main/p/python-eventlet/python-eventlet_0.17.4-2.dsc
Section: python
Priority: optional
Maintainer: PKG OpenStack <openstack-devel@lists.alioth.debian.org>
-Uploaders: Laszlo Boszormenyi (GCS) <gcs@debian.hu>,
+Uploaders: Laszlo Boszormenyi (GCS) <gcs@debian.org>,
Thomas Goirand <zigo@debian.org>,
+ Ondřej Nový <novy@ondrej.org>,
Build-Depends: debhelper (>= 9),
dh-python,
openstack-pkg-tools,
python-sphinx,
python3-all,
python3-setuptools,
-Build-Depends-Indep: python-greenlet,
+Build-Depends-Indep: python-dnspython,
+ python-greenlet,
python-httplib2,
python-mock,
python-nose,
python-openssl,
python-zmq,
+ python3-dnspython,
python3-greenlet,
python3-httplib2,
python3-mock,
python3-nose,
python3-openssl,
python3-zmq,
-Standards-Version: 3.9.6
-Vcs-Browser: http://anonscm.debian.org/gitweb/?p=openstack/python-eventlet.git;a=summary
-Vcs-Git: git://anonscm.debian.org/openstack/python-eventlet.git
+Standards-Version: 3.9.7
+Vcs-Browser: https://anonscm.debian.org/cgit/openstack/python-eventlet.git/
+Vcs-Git: https://anonscm.debian.org/git/openstack/python-eventlet.git
Homepage: http://eventlet.net
Package: python-eventlet
[DEFAULT]
upstream-branch = master
-debian-branch = debian/unstable
+debian-branch = debian/experimental
upstream-tag = %(version)s
compression = xz
+++ /dev/null
-Description: greenio: send() was running empty loop on ENOTCONN
- Thanks to Seyeong Kim
- https://github.com/eventlet/eventlet/issues/192
-Author: Sergey Shepelev <temotor@gmail.com>
-Date: Fri, 15 May 2015 03:56:04 +0300
-
-diff --git a/AUTHORS b/AUTHORS
-index e0ab0e2..c57f010 100644
---- a/AUTHORS
-+++ b/AUTHORS
-@@ -119,3 +119,4 @@ Thanks To
- * Sean Dague, wsgi: Provide python logging compatibility
- * Tim Simmons, Use _socket_nodns and select in dnspython support
- * Antonio Cuni, fix fd double close on PyPy
-+* Seyeong Kim
-diff --git a/eventlet/greenio/base.py b/eventlet/greenio/base.py
-index 8da51ca..1e43176 100644
---- a/eventlet/greenio/base.py
-+++ b/eventlet/greenio/base.py
-@@ -358,7 +358,8 @@ def send(self, data, flags=0):
- try:
- total_sent += fd.send(data[total_sent:], flags)
- except socket.error as e:
-- if get_errno(e) not in SOCKET_BLOCKING:
-+ eno = get_errno(e)
-+ if eno == errno.ENOTCONN or eno not in SOCKET_BLOCKING:
- raise
-
- if total_sent == len_data:
Forwarded: no
Last-Update: 2014-09-07
-Index: python-eventlet-0.17.3/tests/patcher_test.py
-===================================================================
---- python-eventlet-0.17.3.orig/tests/patcher_test.py
-+++ python-eventlet-0.17.3/tests/patcher_test.py
-@@ -325,7 +325,7 @@ print(len(_threading._active))
+--- a/tests/patcher_test.py
++++ b/tests/patcher_test.py
+@@ -327,7 +327,7 @@
self.assertEqual(len(lines), 4, "\n".join(lines))
assert lines[0].startswith('<Thread'), lines[0]
- self.assertEqual(lines[1], "1", lines[1])
-- self.assertEqual(lines[2], "1", lines[2])
-+ #self.assertEqual(lines[2], "1", lines[2])
+ assert lines[1] == '1', lines
+- assert lines[2] == '1', lines
++ #assert lines[2] == '1', lines
def test_threading(self):
new_mod = """import eventlet
-@@ -356,7 +356,7 @@ print(len(threading._active))
+@@ -358,7 +358,7 @@
"""
self.write_to_tempfile("newmod", new_mod)
output, lines = self.launch_subprocess('newmod')
enforce-tlsv1-always.patch
set-defaults-to-be-tlsv1-not-sslv23.patch
fixed-privacy-breach-in-examples.patch
-greenio_send_was_running_empty_loop_on_ENOTCONN.patch
Forwarded: no
Last-Update: 2015-05-21
---- python-eventlet-0.17.3.orig/eventlet/green/ssl.py
-+++ python-eventlet-0.17.3/eventlet/green/ssl.py
-@@ -46,7 +46,7 @@ class GreenSSLSocket(_original_sslsocket
+--- a/eventlet/green/ssl.py
++++ b/eventlet/green/ssl.py
+@@ -48,7 +48,7 @@
def __init__(self, sock, keyfile=None, certfile=None,
server_side=False, cert_reqs=CERT_NONE,
Forwarded: no
Last-Update: 2015-02-08
---- python-eventlet-0.16.1.orig/tests/db_pool_test.py
-+++ python-eventlet-0.16.1/tests/db_pool_test.py
-@@ -7,7 +7,8 @@ import os
+--- a/tests/db_pool_test.py
++++ b/tests/db_pool_test.py
+@@ -7,7 +7,8 @@
import traceback
from unittest import TestCase, main
--from tests import mock, skipped, skip_unless, skip_with_pyevent, get_database_auth
+-from tests import mock, skip_unless, skip_with_pyevent, get_database_auth
+import mock
-+from tests import skipped, skip_unless, skip_with_pyevent, get_database_auth
++from tests import skip_unless, skip_with_pyevent, get_database_auth
from eventlet import event
from eventlet import db_pool
from eventlet.support import six
---- python-eventlet-0.16.1.orig/tests/websocket_test.py
-+++ python-eventlet-0.16.1/tests/websocket_test.py
-@@ -8,7 +8,8 @@ from eventlet.green import httplib
- from eventlet.support import six
+--- a/tests/websocket_test.py
++++ b/tests/websocket_test.py
+@@ -9,7 +9,7 @@
from eventlet.websocket import WebSocket, WebSocketWSGI
--from tests import certificate_file, LimitedTestCase, mock, private_key_file
+ import tests
+-from tests import mock
+import mock
-+from tests import certificate_file, LimitedTestCase, private_key_file
- from tests import skip_if_no_ssl
- from tests.wsgi_test import _TestBase
+ import tests.wsgi_test
+
+++ /dev/null
-python-eventlet: no-upstream-changelog
override_dh_clean:
dh_clean -O--buildsystem=python_distutils
rm -rf build
+
+override_dh_installchangelogs:
+ dh_installchangelogs NEWS
--- /dev/null
+Tests: listen listen3
+Depends: python-eventlet,
+ python3-eventlet,
--- /dev/null
+#!/usr/bin/python
+
+import eventlet
+
+eventlet.listen(('localhost', 7000))
--- /dev/null
+#!/usr/bin/python3
+
+import eventlet
+
+eventlet.listen(('localhost', 7000))
* Victor Sergeyev
* David Szotten
* Victor Stinner
+* Samuel Merritt
+* Eric Urban
Linden Lab Contributors
-----------------------
* Peter Skirko, fixing socket.settimeout(0) bug
* Derk Tegeler, Pre-cache proxied GreenSocket methods (Bitbucket #136)
* David Malcolm, optional "timeout" argument to the subprocess module (Bitbucket #89)
-* Eric Urban, fix wsgi.input 1-byte (Bitbucket #150)
* David Goetz, wsgi: Allow minimum_chunk_size to be overriden on a per request basis
* Dmitry Orlov, websocket: accept Upgrade: websocket (lowercase)
* Zhang Hua, profile: accumulate results between runs (Bitbucket #162)
* Sean Dague, wsgi: Provide python logging compatibility
* Tim Simmons, Use _socket_nodns and select in dnspython support
* Antonio Cuni, fix fd double close on PyPy
+* Seyeong Kim
+* Ihar Hrachyshka
+* Janusz Harkot
+* Fukuchi Daisuke
+* Ramakrishnan G
+* ashutosh-mishra
+* Azhar Hussain
+* Josh VanderLinden
+* Levente Polyak
+* Phus Lu
+0.18.4
+======
+* wsgi: change TCP_NODELAY to TCP_QUICKACK, ignore socket error when not available
+
+0.18.3
+======
+* wsgi: Use buffered writes - fixes partial socket.send without custom
+ writelines(); Github issue #295
+* wsgi: TCP_NODELAY enabled by default
+
+0.18.2
+======
+* wsgi: Fix data loss on partial writes (socket.send); Thanks to Jakub Stasiak
+
+0.18.1
+======
+* IMPORTANT: do not use Eventlet 0.18.0 and 0.18.1
+* patcher: Fix AttributeError in subprocess communicate()
+* greenio: Fix "TypeError: an integer is required" in sendto()
+
+0.18.0
+======
+* IMPORTANT: do not use Eventlet 0.18.0 and 0.18.1
+* greenio: Fixed a bug that could cause send() to start an endless loop on
+ ENOTCONN; Thanks to Seyeong Kim
+* wsgi: Fixed UNIX socket address being trimmed in "wsgi starting" log; Thanks
+ to Ihar Hrachyshka
+* ssl: Ported eventlet.green.OpenSSL to Python 3; Thanks to Victor Stinner
+* greenio: Made read() support buflen=-1 and added readall() (Python 3);
+ Thanks to David Szotten
+* wsgi: Made the error raised in case of chunk read failures more precise (this
+ should be backwards compatible as the new exception class,
+ wsgi.ChunkReadError, is a subclass of ValueError which was being used there
+ before); Thanks to Samuel Merritt
+* greenio: Fixed socket.recv() sometimes returning str instead of bytes on
+ Python 3; Thanks to Janusz Harkot
+* wsgi: Improved request body discarding
+* websocket: Fixed TypeError on empty websocket message (Python 3); Thanks to
+ Fukuchi Daisuke
+* subprocess: Fixed universal_newlines support
+* wsgi: Output of 0-byte chunks is now suppressed; Thanks to Samuel Merritt
+* Improved the documentation; Thanks to Ramakrishnan G, ashutosh-mishra and
+ Azhar Hussain
+* greenio: Changed GreenFileIO.write() (Python 3) to always write all data to
+ match the behavior on Python 2; Thanks to Victor Stinner
+* subprocess: Fixed missing subprocess.mswindows attribute on Python 3.5;
+ Thanks to Josh VanderLinden
+* ssl/monkey patching: Fixed a bug that would cause merely importing eventlet
+ to monkey patch the ssl module; Thanks to David Szotten
+* documentation: Added support for building plain text documentation; thanks
+ to Levente Polyak
+* greenio: Fixed handling blocking IO errors in various GreenSocket methods;
+ Thanks to Victor Stinner
+* greenio: Fixed GreenPipe ignoring the bufsize parameter on Python 2; Thanks
+ to Phus Lu
+* backdoor: Added Unix and IPv6 socket support; Thanks to Eric Urban
+
+Backwards incompatible:
+
+* monkey patching: The following select methods and selector classes are now
+ removed, instead of being left in their respective modules after patching
+ even though they are not green (this also fixes HTTPServer.serve_forever()
+ blocking whole process on Python 3):
+
+ * select.poll
+ * select.epoll
+ * select.devpoll
+ * select.kqueue
+ * select.kevent
+ * selectors.PollSelector
+ * selectors.EpollSelector
+ * selectors.DevpollSelector
+ * selectors.KqueueSelector
+
+ Additionally selectors.DefaultSelector points to a green SelectSelector
+
+* greenio: Fixed send() to no longer behave like sendall() which makes it
+ consistent with Python standard library and removes a source of very subtle
+ errors
+
0.17.4
======
* ssl: incorrect initalization of default context; Thanks to stuart-mclaren
if [ $commit -eq 1 ]; then
echo "3. Updating git branch gh-pages"
- source_name=`git rev-parse --abbrev-ref HEAD`
- source_id=`git rev-parse --short HEAD`
+ source_name=`git describe --dirty --tags`
git branch --track gh-pages origin/gh-pages || true
git checkout gh-pages
git ls-files |grep -Ev '^.gitignore$' |xargs rm -f
git status
read -p "Carefully read git status output above, press Enter to continue or Ctrl+C to abort"
- git commit --edit -m "Website built from $source_name $source_id"
+ git commit --edit -m "Website built from $source_name"
fi
if [[ ! -d venv-release ]]; then
virtualenv venv-release
echo '*' >venv-release/.gitignore
- venv-release/bin/pip install wheel sphinx
+ venv-release/bin/pip install -U pip setuptools sphinx wheel
fi
. $PWD/venv-release/bin/activate
pip install -e $PWD
+version=
+version_next=
+
main() {
branch="${1-$(git symbolic-ref --short HEAD)}"
version="$(python -c 'import eventlet; print(eventlet.__version__)')"
- printf "branch: %s version: '%s'\n" $branch $version >&2
+ printf "\nbranch: %s eventlet.__version__: '%s'\n" $branch $version >&2
if [[ "$branch" != "master" ]]; then
echo "Must be on master" >&2
exit 1
fi
if [[ -n "$(git status --short -uall)" ]]; then
- echo "Tree must be clean" >&2
+ echo "Tree must be clean. git status:" >&2
+ echo "" >&2
+ git status --short -uall
+ echo "" >&2
exit 1
fi
+ last_commit_message=$(git show --format="%s" --no-patch HEAD)
+ expect_commit_message="v$version release"
+ if [[ "$last_commit_message" != "$expect_commit_message" ]]; then
+ printf "Last commit message: '%s' expected: '%s'\n" "$last_commit_message" "$expect_commit_message" >&2
+ if confirm "Create release commit? [yN] "; then
+ create_commit
+ elif ! confirm "Continue without proper release commit? [yN] "; then
+ exit 1
+ fi
+ fi
confirm "Continue? [yN] " || exit 1
+ echo "Creating tag v$version" >&2
if ! git tag "v$version"; then
- echo "tag failed" >&2
+ echo "git tag failed " >&2
confirm "Continue still? [yN] " || exit 1
fi
+ if confirm "Build documentation (website)? [Yn] " >&2; then
+ bin/build-website.bash || exit 1
+ fi
+
if confirm "Upload to PyPi? [Yn] "; then
rm -rf build dist
- python setup.py sdist bdist_wheel register upload
+ python setup.py sdist bdist_wheel register upload || exit 1
fi
- bin/build-website.bash
-
- git push origin master
+ git push --verbose origin master gh-pages || exit 1
git push --tags
- git push origin gh-pages
+}
+
+create_commit() {
+ echo "" >&2
+ echo "Plan:" >&2
+ echo "1. bump version" >&2
+ echo "2. update NEWS, AUTHORS" >&2
+ echo "3. commit" >&2
+ echo "4. run bin/release again" >&2
+ echo "" >&2
+
+ bump_version
+ edit_news
+
+ git diff
+ confirm "Ready to commit? [Yn] " || exit 1
+ git commit -a -m "v$version_next release"
+
+ echo "Re-exec $0 to continue" >&2
+ exec $0
+}
+
+bump_version() {
+ local current=$version
+ echo "Current version: '$current'" >&2
+ echo -n "Enter next version (empty to abort): " >&2
+ read version_next
+ if [[ -z "$version_next" ]]; then
+ exit 1
+ fi
+ echo "Next version: '$version_next'" >&2
+
+ local current_tuple="${current//./, }"
+ local next_tuple="${version_next//./, }"
+ local version_path="eventlet/__init__.py"
+ echo "Updating file '$version_path'" >&2
+ if ! sed -i '' -e "s/($current_tuple)/($next_tuple)/" "$version_path"; then
+ echo "sed error $?" >&2
+ exit 1
+ fi
+ if git diff --exit-code "$version_path"; then
+ echo "File '$version_path' is not modified" >&2
+ exit 1
+ fi
+ echo "" >&2
+
+ local doc_path="doc/real_index.html"
+ echo "Updating file '$doc_path'" >&2
+ if ! sed -i '' -e "s/$current/$version_next/g" "$doc_path"; then
+ echo "sed error $?" >&2
+ exit 1
+ fi
+ if git diff --exit-code "$doc_path"; then
+ echo "File '$doc_path' is not modified" >&2
+ exit 1
+ fi
+ echo "" >&2
+
+ confirm "Confirm changes? [yN] " || exit 1
+}
+
+edit_news() {
+ echo "Changes since last release:" >&2
+ git log --format='%h %an %s' "v$version"^.. -- || exit 1
+ echo "" >&2
+
+ local editor=$(which edit 2>/dev/null)
+ [[ -z "$editor" ]] && editor="$EDITOR"
+ if [[ -n "$editor" ]]; then
+ if confirm "Open default editor for NEWS and AUTHORS? [Yn] "; then
+ $editor NEWS
+ $editor AUTHORS
+ else
+ confirm "Change files NEWS and AUTHORS manually and press any key"
+ fi
+ else
+ echo "Unable to determine default text editor." >&2
+ confirm "Change files NEWS and AUTHORS manually and press any key"
+ fi
+ echo "" >&2
+
+ if git diff --exit-code NEWS AUTHORS; then
+ echo "Files NEWS and AUTHORS are not modified" >&2
+ exit 1
+ fi
+ echo "" >&2
+
+ confirm "Confirm changes? [yN] " || exit 1
}
confirm() {
- read -n1 -p "$1" reply
- echo ""
+ local reply
+ local prompt="$1"
+ read -n1 -p "$prompt" reply >&2
+ echo "" >&2
rc=0
+ local default_y=" \[Yn\] $"
+ if [[ -z "$reply" ]] && [[ "$prompt" =~ $default_y ]]; then
+ reply="y"
+ fi
[[ "$reply" != "y" ]] && rc=1
return $rc
}
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
+.PHONY: help clean text html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
help:
@echo "Please use \`make <target>' where <target> is one of"
+ @echo " text to make text files"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " pickle to make pickle files"
clean:
-rm -rf _build/*
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) _build/text
+ @echo
+ @echo "Build finished. The text files are in _build/text."
+
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html
@echo
from eventlet.green import urllib2
urls = ["http://www.google.com/intl/en_ALL/images/logo.gif",
- "https://wiki.secondlife.com/w/images/secondlife.jpg",
+ "https://www.python.org/static/img/python-logo.png",
"http://us.i1.yimg.com/us.yimg.com/i/ww/beta/y3.gif"]
def fetch(url):
<!doctype html>
-<html>
+<html lang="en">
<head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta charset="UTF-8" />
<title>Eventlet Networking Library</title>
<link rel="stylesheet" href="doc/_static/default.css" type="text/css" />
<h3>Installation</h3>
-<p>To install eventlet, simply:
+<p>To install Eventlet, simply:
<pre>
pip install eventlet
</pre></p>
-<p>Alternately, you can download the source tarball:</p>
+<p>Alternately, you can download the source archive:</p>
<ul>
<li>latest release from <a class="reference external" target="_blank" href="https://pypi.python.org/pypi/eventlet/">PyPi</a>:
- <a class="reference external" href="https://pypi.python.org/packages/source/e/eventlet/eventlet-0.17.4.tar.gz">eventlet-0.17.4.tar.gz</a></li>
+ <a class="reference external" href="https://pypi.python.org/packages/source/e/eventlet/eventlet-0.18.4.tar.gz">eventlet-0.18.4.tar.gz</a></li>
<li>or <a class="reference external" href="https://github.com/eventlet/eventlet/archive/master.zip">latest development version</a></li>
</ul>
-version_info = (0, 17, 4)
+version_info = (0, 18, 4)
__version__ = '.'.join(map(str, version_info))
try:
import errno
import socket
import sys
+import errno
+import traceback
import eventlet
from eventlet import hubs
def finalize(self):
# restore the state of the socket
self.desc = None
- print("backdoor closed to %s:%s" % self.hostport)
+ if len(self.hostport) >= 2:
+ host = self.hostport[0]
+ port = self.hostport[1]
+ print("backdoor closed to %s:%s" % (host, port,))
+ else:
+ print('backdoor closed')
def backdoor_server(sock, locals=None):
of the interpreters. It can be convenient to stick important application
variables in here.
"""
- print("backdoor server listening on %s:%s" % sock.getsockname())
+ listening_on = sock.getsockname()
+ if sock.family == socket.AF_INET:
+ # Expand result to IP + port
+ listening_on = '%s:%s' % listening_on
+ elif sock.family == socket.AF_INET6:
+ ip, port, _, _ = listening_on
+ listening_on = '%s:%s' % (ip, port,)
+ # No action needed if sock.family == socket.AF_UNIX
+
+ print("backdoor server listening on %s" % (listening_on,))
try:
try:
while True:
(such as backdoor_server).
"""
conn, addr = conn_info
- host, port = addr
- print("backdoor to %s:%s" % (host, port))
+ if conn.family == socket.AF_INET:
+ host, port = addr
+ print("backdoor to %s:%s" % (host, port))
+ elif conn.family == socket.AF_INET6:
+ host, port, _, _ = addr
+ print("backdoor to %s:%s" % (host, port))
+ else:
+ print('backdoor opened')
fl = conn.makefile("rw")
- console = SocketConsole(fl, (host, port), locals)
+ console = SocketConsole(fl, addr, locals)
hub = hubs.get_hub()
hub.schedule_call_global(0, console.switch)
-import rand
-import crypto
-import SSL
-import tsafe
-from version import __version__
+from . import rand
+from . import crypto
+from . import SSL
+from . import tsafe
+from .version import __version__
__patched__ = ['select']
+# FIXME: must also delete `poll`, but it breaks subprocess `communicate()`
+# https://github.com/eventlet/eventlet/issues/290
+__deleted__ = ['devpoll', 'epoll', 'kqueue', 'kevent']
def get_fileno(obj):
from eventlet import patcher
from eventlet.green import select
+__patched__ = [
+ 'DefaultSelector',
+ 'SelectSelector',
+]
+
+# We only have green select so the options are:
+# * leave it be and have selectors that block
+# * try to pretend the "bad" selectors don't exist
+# * replace all with SelectSelector for the price of possibly different
+# performance characteristic and missing fileno() method (if someone
+# uses it it'll result in a crash, we may want to implement it in the future)
+#
+# This module used to follow the third approach but just removing the offending
+# selectors is less error prone and less confusing approach.
+__deleted__ = [
+ 'PollSelector',
+ 'EpollSelector',
+ 'DevpollSelector',
+ 'KqueueSelector',
+]
+
patcher.inject('selectors', globals(), ('select', select))
del patcher
if sys.platform != 'win32':
SelectSelector._select = staticmethod(select.select)
+
+DefaultSelector = SelectSelector
has_ciphers = False
timeout_exc = orig_socket.timeout
-__patched__ = ['SSLSocket', 'wrap_socket', 'sslwrap_simple']
+__patched__ = [
+ 'SSLSocket', 'SSLContext', 'wrap_socket', 'sslwrap_simple',
+ 'create_default_context', '_create_default_https_context']
_original_sslsocket = __ssl.SSLSocket
if hasattr(__ssl, 'SSLContext'):
- @functools.wraps(__ssl.SSLContext.wrap_socket)
- def _green_sslcontext_wrap_socket(self, sock, *a, **kw):
- return GreenSSLSocket(sock, *a, _context=self, **kw)
-
- # FIXME:
- # * GreenSSLContext akin to GreenSSLSocket
- # * make ssl.create_default_context() use modified SSLContext from globals as usual
- __ssl.SSLContext.wrap_socket = _green_sslcontext_wrap_socket
+ _original_sslcontext = __ssl.SSLContext
+
+ class GreenSSLContext(_original_sslcontext):
+ __slots__ = ()
+
+ def wrap_socket(self, sock, *a, **kw):
+ return GreenSSLSocket(sock, *a, _context=self, **kw)
+
+ SSLContext = GreenSSLContext
+
+ if hasattr(__ssl, 'create_default_context'):
+ _original_create_default_context = __ssl.create_default_context
+
+ def green_create_default_context(*a, **kw):
+ # We can't just monkey-patch on the green version of `wrap_socket`
+ # on to SSLContext instances, but SSLContext.create_default_context
+ # does a bunch of work. Rather than re-implementing it all, just
+ # switch out the __class__ to get our `wrap_socket` implementation
+ context = _original_create_default_context(*a, **kw)
+ context.__class__ = GreenSSLContext
+ return context
+
+ create_default_context = green_create_default_context
+ _create_default_https_context = green_create_default_context
patcher.inject('subprocess', globals(), *to_patch)
subprocess_orig = __import__("subprocess")
+mswindows = sys.platform == "win32"
if getattr(subprocess_orig, 'TimeoutExpired', None) is None:
# Windows. (see eventlet.greenio.set_nonblocking()) As the sole purpose of
# this __init__() override is to wrap the pipes for eventlet-friendly
# non-blocking I/O, don't even bother overriding it on Windows.
- if not subprocess_orig.mswindows:
+ if not mswindows:
def __init__(self, args, bufsize=0, *argss, **kwds):
self.args = args
# Forward the call to base-class constructor
# eventlet.processes.Process.run() method.
for attr in "stdin", "stdout", "stderr":
pipe = getattr(self, attr)
- if pipe is not None and not type(pipe) == greenio.GreenPipe:
- wrapped_pipe = greenio.GreenPipe(pipe, pipe.mode, bufsize)
+ if pipe is not None and type(pipe) != greenio.GreenPipe:
+ # https://github.com/eventlet/eventlet/issues/243
+ # AttributeError: '_io.TextIOWrapper' object has no attribute 'mode'
+ mode = getattr(pipe, 'mode', '')
+ if not mode:
+ if pipe.readable():
+ mode += 'r'
+ if pipe.writable():
+ mode += 'w'
+ # ValueError: can't have unbuffered text I/O
+ if bufsize == 0:
+ bufsize = -1
+ wrapped_pipe = greenio.GreenPipe(pipe, mode, bufsize)
setattr(self, attr, wrapped_pipe)
__init__.__doc__ = subprocess_orig.Popen.__init__.__doc__
raise
wait.__doc__ = subprocess_orig.Popen.wait.__doc__
- if not subprocess_orig.mswindows:
+ if not mswindows:
# don't want to rewrite the original _communicate() method, we
# just want a version that uses eventlet.green.select.select()
# instead of select.select().
import errno
import os
-from socket import socket as _original_socket
import socket
import sys
import time
import warnings
-from eventlet.support import get_errno, six
+import eventlet
from eventlet.hubs import trampoline, notify_opened, IOClosed
+from eventlet.support import get_errno, six
__all__ = [
'GreenSocket', '_GLOBAL_DEFAULT_TIMEOUT', 'set_nonblocking',
if six.PY2:
_python2_fileobject = socket._fileobject
+_original_socket = eventlet.patcher.original('socket').socket
+
def socket_connect(descriptor, address):
"""
"makefile instead", DeprecationWarning, stacklevel=2)
return self.makefile(*args, **kw)
- def recv(self, buflen, flags=0):
+ def _read_trampoline(self):
+ self._trampoline(
+ self.fd,
+ read=True,
+ timeout=self.gettimeout(),
+ timeout_exc=socket.timeout("timed out"))
+
+ def _recv_loop(self, recv_meth, *args):
fd = self.fd
if self.act_non_blocking:
- return fd.recv(buflen, flags)
+ return recv_meth(*args)
+
while True:
try:
- return fd.recv(buflen, flags)
+ # recv: bufsize=0?
+ # recv_into: buffer is empty?
+ # This is needed because behind the scenes we use sockets in
+ # nonblocking mode and builtin recv* methods. Attempting to read
+ # 0 bytes from a nonblocking socket using a builtin recv* method
+ # does not raise a timeout exception. Since we're simulating
+ # a blocking socket here we need to produce a timeout exception
+ # if needed, hence the call to trampoline.
+ if not args[0]:
+ self._read_trampoline()
+ return recv_meth(*args)
except socket.error as e:
if get_errno(e) in SOCKET_BLOCKING:
pass
elif get_errno(e) in SOCKET_CLOSED:
- return ''
+ return b''
else:
raise
+
try:
- self._trampoline(
- fd,
- read=True,
- timeout=self.gettimeout(),
- timeout_exc=socket.timeout("timed out"))
+ self._read_trampoline()
except IOClosed as e:
# Perhaps we should return '' instead?
raise EOFError()
- def recvfrom(self, *args):
- if not self.act_non_blocking:
- self._trampoline(self.fd, read=True, timeout=self.gettimeout(),
- timeout_exc=socket.timeout("timed out"))
- return self.fd.recvfrom(*args)
+ def recv(self, bufsize, flags=0):
+ return self._recv_loop(self.fd.recv, bufsize, flags)
- def recvfrom_into(self, *args):
- if not self.act_non_blocking:
- self._trampoline(self.fd, read=True, timeout=self.gettimeout(),
- timeout_exc=socket.timeout("timed out"))
- return self.fd.recvfrom_into(*args)
+ def recvfrom(self, bufsize, flags=0):
+ return self._recv_loop(self.fd.recvfrom, bufsize, flags)
- def recv_into(self, *args):
- if not self.act_non_blocking:
- self._trampoline(self.fd, read=True, timeout=self.gettimeout(),
- timeout_exc=socket.timeout("timed out"))
- return self.fd.recv_into(*args)
+ def recv_into(self, buffer, nbytes=0, flags=0):
+ return self._recv_loop(self.fd.recv_into, buffer, nbytes, flags)
- def send(self, data, flags=0):
- fd = self.fd
+ def recvfrom_into(self, buffer, nbytes=0, flags=0):
+ return self._recv_loop(self.fd.recvfrom_into, buffer, nbytes, flags)
+
+ def _send_loop(self, send_method, data, *args):
if self.act_non_blocking:
- return fd.send(data, flags)
+ return send_method(data, *args)
- # blocking socket behavior - sends all, blocks if the buffer is full
- total_sent = 0
- len_data = len(data)
while 1:
try:
- total_sent += fd.send(data[total_sent:], flags)
+ return send_method(data, *args)
except socket.error as e:
- if get_errno(e) not in SOCKET_BLOCKING:
+ eno = get_errno(e)
+ if eno == errno.ENOTCONN or eno not in SOCKET_BLOCKING:
raise
- if total_sent == len_data:
- break
-
try:
self._trampoline(self.fd, write=True, timeout=self.gettimeout(),
timeout_exc=socket.timeout("timed out"))
except IOClosed:
raise socket.error(errno.ECONNRESET, 'Connection closed by another thread')
- return total_sent
+ def send(self, data, flags=0):
+ return self._send_loop(self.fd.send, data, flags)
+
+ def sendto(self, data, *args):
+ return self._send_loop(self.fd.sendto, data, *args)
def sendall(self, data, flags=0):
tail = self.send(data, flags)
while tail < len_data:
tail += self.send(data[tail:], flags)
- def sendto(self, *args):
- self._trampoline(self.fd, write=True)
- return self.fd.sendto(*args)
-
def setblocking(self, flag):
if flag:
self.act_non_blocking = False
self._name = f.name
f.close()
- super(GreenPipe, self).__init__(_SocketDuckForFd(fileno), mode)
+ super(GreenPipe, self).__init__(_SocketDuckForFd(fileno), mode, bufsize)
set_nonblocking(self)
self.softspace = 0
def fileno(self):
return self._fileno
- def read(self, buflen):
+ def read(self, size=-1):
+ if size == -1:
+ return self.readall()
+
+ while True:
+ try:
+ return _original_os.read(self._fileno, size)
+ except OSError as e:
+ if get_errno(e) not in SOCKET_BLOCKING:
+ raise IOError(*e.args)
+ self._trampoline(self, read=True)
+
+ def readall(self):
+ buf = []
while True:
try:
- return _original_os.read(self._fileno, buflen)
+ chunk = _original_os.read(self._fileno, DEFAULT_BUFFER_SIZE)
+ if chunk == b'':
+ return b''.join(buf)
+ buf.append(chunk)
except OSError as e:
if get_errno(e) not in SOCKET_BLOCKING:
raise IOError(*e.args)
self._closed = True
def write(self, data):
- while True:
+ view = memoryview(data)
+ datalen = len(data)
+ offset = 0
+ while offset < datalen:
try:
- return _original_os.write(self._fileno, data)
+ written = _original_os.write(self._fileno, view[offset:])
except OSError as e:
if get_errno(e) not in SOCKET_BLOCKING:
raise IOError(*e.args)
- else:
- trampoline(self, write=True)
+ trampoline(self, write=True)
+ else:
+ offset += written
+ return offset
def close(self):
if not self._closed:
on.setdefault(modname, default_on)
modules_to_patch = []
- if on['os'] and not already_patched.get('os'):
- modules_to_patch += _green_os_modules()
- already_patched['os'] = True
- if on['select'] and not already_patched.get('select'):
- modules_to_patch += _green_select_modules()
- already_patched['select'] = True
- if on['socket'] and not already_patched.get('socket'):
- modules_to_patch += _green_socket_modules()
- already_patched['socket'] = True
- if on['thread'] and not already_patched.get('thread'):
- modules_to_patch += _green_thread_modules()
- already_patched['thread'] = True
- if on['time'] and not already_patched.get('time'):
- modules_to_patch += _green_time_modules()
- already_patched['time'] = True
- if on.get('MySQLdb') and not already_patched.get('MySQLdb'):
- modules_to_patch += _green_MySQLdb()
- already_patched['MySQLdb'] = True
- if on.get('builtins') and not already_patched.get('builtins'):
- modules_to_patch += _green_builtins()
- already_patched['builtins'] = True
+ for name, modules_function in [
+ ('os', _green_os_modules),
+ ('select', _green_select_modules),
+ ('socket', _green_socket_modules),
+ ('thread', _green_thread_modules),
+ ('time', _green_time_modules),
+ ('MySQLdb', _green_MySQLdb),
+ ('builtins', _green_builtins),
+ ]:
+ if on[name] and not already_patched.get(name):
+ modules_to_patch += modules_function()
+ already_patched[name] = True
+
if on['psycopg'] and not already_patched.get('psycopg'):
try:
from eventlet.support import psycopg2_patcher
patched_attr = getattr(mod, attr_name, None)
if patched_attr is not None:
setattr(orig_mod, attr_name, patched_attr)
+ deleted = getattr(mod, '__deleted__', [])
+ for attr_name in deleted:
+ if hasattr(orig_mod, attr_name):
+ delattr(orig_mod, attr_name)
finally:
imp.release_lock()
def _green_select_modules():
from eventlet.green import select
- return [('select', select)]
+ modules = [('select', select)]
+
+ if sys.version_info >= (3, 4):
+ from eventlet.green import selectors
+ modules.append(('selectors', selectors))
+
+ return modules
def _green_socket_modules():
from eventlet.greenthread import getcurrent
from eventlet.hubs import get_hub
from eventlet.support import six
+from eventlet.support.six.moves import queue as Stdlib_Queue
from eventlet.timeout import Timeout
class LightQueue(object):
"""
This is a variant of Queue that behaves mostly like the standard
- :class:`Queue`. It differs by not supporting the
- :meth:`task_done <Queue.task_done>` or :meth:`join <Queue.join>` methods,
- and is a little faster for not having that overhead.
+ :class:`Stdlib_Queue`. It differs by not supporting the
+ :meth:`task_done <Stdlib_Queue.task_done>` or
+ :meth:`join <Stdlib_Queue.join>` methods, and is a little faster for
+ not having that overhead.
"""
def __init__(self, maxsize=None):
If *maxsize* is less than zero or ``None``, the queue size is infinite.
``Queue(0)`` is a channel, that is, its :meth:`put` method always blocks
- until the item is delivered. (This is unlike the standard :class:`Queue`,
- where 0 means infinite size).
+ until the item is delivered. (This is unlike the standard
+ :class:`Stdlib_Queue`, where 0 means infinite size).
- In all other respects, this Queue class resembled the standard library,
- :class:`Queue`.
+ In all other respects, this Queue class resembles the standard library,
+ :class:`Stdlib_Queue`.
'''
def __init__(self, maxsize=None):
# See the License for the specific language governing permissions and
# limitations under the License.
+import atexit
import imp
import os
import sys
import traceback
+import eventlet
from eventlet import event, greenio, greenthread, patcher, timeout
from eventlet.support import six
Empty = Queue_module.Empty
Queue = Queue_module.Queue
-_bytetosend = ' '.encode()
+_bytetosend = b' '
_coro = None
_nthreads = int(os.environ.get('EVENTLET_THREADPOOL_SIZE', 20))
_reqq = _rspq = None
try:
_c = _rsock.recv(1)
assert _c
+ # FIXME: this is probably redundant since using sockets instead of pipe now
except ValueError:
break # will be raised when pipe is closed
while not _rspq.empty():
def setup():
- global _rsock, _wsock, _threads, _coro, _setup_already, _rspq, _reqq
+ global _rsock, _wsock, _coro, _setup_already, _rspq, _reqq
if _setup_already:
return
else:
_setup_already = True
+ assert _nthreads >= 0, "Can't specify negative number of threads"
+ if _nthreads == 0:
+ import warnings
+ warnings.warn("Zero threads in tpool. All tpool.execute calls will\
+ execute in main thread. Check the value of the environment \
+ variable EVENTLET_THREADPOOL_SIZE.", RuntimeWarning)
+ _reqq = Queue(maxsize=-1)
+ _rspq = Queue(maxsize=-1)
+
+ # connected socket pair
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.1', 0))
sock.listen(1)
csock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
csock.connect(sock.getsockname())
+ csock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
_wsock, _addr = sock.accept()
+ _wsock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
sock.close()
_rsock = greenio.GreenSocket(csock)
- _reqq = Queue(maxsize=-1)
- _rspq = Queue(maxsize=-1)
- assert _nthreads >= 0, "Can't specify negative number of threads"
- if _nthreads == 0:
- import warnings
- warnings.warn("Zero threads in tpool. All tpool.execute calls will\
- execute in main thread. Check the value of the environment \
- variable EVENTLET_THREADPOOL_SIZE.", RuntimeWarning)
for i in six.moves.range(_nthreads):
t = threading.Thread(target=tworker,
name="tpool_thread_%s" % i)
_threads.append(t)
_coro = greenthread.spawn_n(tpool_trampoline)
+ # This yield fixes subtle error with GreenSocket.__del__
+ eventlet.sleep(0)
+# Avoid ResourceWarning unclosed socket on Python3.2+
+@atexit.register
def killall():
global _setup_already, _rspq, _rsock, _wsock
if not _setup_already:
return
+
+ # This yield fixes freeze in some scenarios
+ eventlet.sleep(0)
+
for thr in _threads:
_reqq.put(None)
for thr in _threads:
del _threads[:]
# return any remaining results
- while not _rspq.empty():
+ while (_rspq is not None) and not _rspq.empty():
try:
(e, rv) = _rspq.get(block=False)
e.send(rv)
if _coro is not None:
greenthread.kill(_coro)
- _rsock.close()
- _wsock.close()
- _rsock = None
- _wsock = None
+ if _rsock is not None:
+ _rsock.close()
+ _rsock = None
+ if _wsock is not None:
+ _wsock.close()
+ _wsock = None
_rspq = None
_setup_already = False
decoder = self.UTF8Decoder() if opcode == 1 else None
message = self.Message(opcode, decoder=decoder)
if not length:
- message.push('', final=finished)
+ message.push(b'', final=finished)
else:
while received < length:
d = self.socket.recv(length - received)
import errno
+import functools
import os
import sys
import time
import types
import warnings
-from eventlet.green import BaseHTTPServer
-from eventlet.green import socket
from eventlet import greenio
from eventlet import greenpool
from eventlet import support
+from eventlet.green import BaseHTTPServer
+from eventlet.green import socket
from eventlet.support import six
-
from eventlet.support.six.moves import urllib
BROKEN_SOCK = set((errno.EPIPE, errno.ECONNRESET))
+class ChunkReadError(ValueError):
+ pass
+
+
# special flag return value for apps
class _AlreadyHandled(object):
towrite.append(b'\r\n')
self.wfile.writelines(towrite)
+ self.wfile.flush()
# Reinitialize chunk_length (expect more data)
self.chunk_length = -1
def _do_read(self, reader, length=None):
- if self.wfile is not None and \
- not self.is_hundred_continue_response_sent:
+ if self.wfile is not None and not self.is_hundred_continue_response_sent:
# 100 Continue response
self.send_hundred_continue_response()
self.is_hundred_continue_response_sent = True
- if length is None and self.content_length is not None:
- length = self.content_length - self.position
- if length and length > self.content_length - self.position:
+ if (self.content_length is not None) and (
+ length is None or length > self.content_length - self.position):
length = self.content_length - self.position
if not length:
return b''
return read
def _chunked_read(self, rfile, length=None, use_readline=False):
- if self.wfile is not None and \
- not self.is_hundred_continue_response_sent:
+ if self.wfile is not None and not self.is_hundred_continue_response_sent:
# 100 Continue response
self.send_hundred_continue_response()
self.is_hundred_continue_response_sent = True
if use_readline and data[-1] == "\n":
break
else:
- self.chunk_length = int(rfile.readline().split(b";", 1)[0], 16)
+ try:
+ self.chunk_length = int(rfile.readline().split(b";", 1)[0], 16)
+ except ValueError as err:
+ raise ChunkReadError(err)
self.position = 0
if self.chunk_length == 0:
rfile.readline()
for key, value in headers]
self.hundred_continue_headers = headers
+ def discard(self, buffer_size=16 << 10):
+ while self.read(buffer_size):
+ pass
+
class HeaderLineTooLong(Exception):
pass
self.log = log
self._debug = debug
+ def error(self, msg, *args, **kwargs):
+ self.write(msg, *args)
+
def info(self, msg, *args, **kwargs):
self.write(msg, *args)
minimum_chunk_size = MINIMUM_CHUNK_SIZE
capitalize_response_headers = True
+ # https://github.com/eventlet/eventlet/issues/295
+ # Stdlib default is 0 (unbuffered), but then `wfile.writelines()` looses data
+ # so before going back to unbuffered, remove any usage of `writelines`.
+ wbufsize = 16 << 10
+
def setup(self):
# overriding SocketServer.setup to correctly handle SSL.Connection objects
conn = self.connection = self.request
+
+ # TCP_QUICKACK is a better alternative to disabling Nagle's algorithm
+ # https://news.ycombinator.com/item?id=10607422
+ if getattr(socket, 'TCP_QUICKACK', None):
+ try:
+ conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_QUICKACK, True)
+ except socket.error:
+ pass
+
try:
self.rfile = conn.makefile('rb', self.rbufsize)
self.wfile = conn.makefile('wb', self.wbufsize)
length = [0]
status_code = [200]
- def write(data, _writelines=wfile.writelines):
+ def write(data):
towrite = []
if not headers_set:
raise AssertionError("write() before start_response()")
towrite.append(six.b("%x" % (len(data),)) + b"\r\n" + data + b"\r\n")
else:
towrite.append(data)
- _writelines(towrite)
+ wfile.writelines(towrite)
+ wfile.flush()
length[0] = length[0] + sum(map(len, towrite))
def start_response(status, response_headers, exc_info=None):
minimum_write_chunk_size = int(self.environ.get(
'eventlet.minimum_write_chunk_size', self.minimum_chunk_size))
for data in result:
+ if len(data) == 0:
+ continue
if isinstance(data, six.text_type):
data = data.encode('ascii')
finally:
if hasattr(result, 'close'):
result.close()
- if (self.environ['eventlet.input'].chunked_input or
- self.environ['eventlet.input'].position
- < (self.environ['eventlet.input'].content_length or 0)):
+ request_input = self.environ['eventlet.input']
+ if (request_input.chunked_input or
+ request_input.position < (request_input.content_length or 0)):
# Read and discard body if there was no pending 100-continue
- if not self.environ['eventlet.input'].wfile:
- # NOTE: MINIMUM_CHUNK_SIZE is used here for purpose different than chunking.
- # We use it only cause it's at hand and has reasonable value in terms of
- # emptying the buffer.
- while self.environ['eventlet.input'].read(MINIMUM_CHUNK_SIZE):
- pass
+ if not request_input.wfile and self.close_connection == 0:
+ try:
+ request_input.discard()
+ except ChunkReadError as e:
+ self.close_connection = 1
+ self.server.log.error((
+ 'chunked encoding error while discarding request body.'
+ + ' ip={0} request="{1}" error="{2}"').format(
+ self.get_client_ip(), self.requestline, e,
+ ))
finish = time.time()
for hook, args, kwargs in self.environ['eventlet.posthooks']:
ACCEPT_ERRNO = set((errno.EPIPE, errno.EBADF, errno.ECONNRESET))
+def socket_repr(sock):
+ scheme = 'http'
+ if hasattr(sock, 'do_handshake'):
+ scheme = 'https'
+
+ name = sock.getsockname()
+ if sock.family == socket.AF_INET:
+ hier_part = '//{0}:{1}'.format(*name)
+ elif sock.family == socket.AF_INET6:
+ hier_part = '//[{0}]:{1}'.format(*name[:2])
+ elif sock.family == socket.AF_UNIX:
+ hier_part = name
+ else:
+ hier_part = repr(name)
+
+ return scheme + ':' + hier_part
+
+
def server(sock, site,
log=None,
environ=None,
If not specified, sys.stderr is used.
:param environ: Additional parameters that go into the environ dictionary of every request.
:param max_size: Maximum number of client connections opened at any time by this server.
+ Default is 1024.
:param max_http_version: Set to "HTTP/1.0" to make the server pretend it only supports HTTP 1.0.
This can help with applications or clients that don't behave properly using HTTP 1.1.
:param protocol: Protocol class. Deprecated.
else:
pool = greenpool.GreenPool(max_size)
try:
- host, port = sock.getsockname()[:2]
- port = ':%s' % (port, )
- if hasattr(sock, 'do_handshake'):
- scheme = 'https'
- if port == ':443':
- port = ''
- else:
- scheme = 'http'
- if port == ':80':
- port = ''
-
- serv.log.info("(%s) wsgi starting up on %s://%s%s/" % (
- serv.pid, scheme, host, port))
+ serv.log.info("(%s) wsgi starting up on %s" % (
+ serv.pid, socket_repr(sock)))
while is_accepting:
try:
client_socket = sock.accept()
r2 = resource.getrusage(resource.RUSAGE_SELF)
utime = r2.ru_utime - r1.ru_utime
stime = r2.ru_stime - r1.ru_stime
+
+ # This check is reliably unreliable on Travis, presumably because of CPU
+ # resources being quite restricted by the build environment. The workaround
+ # is to apply an arbitrary factor that should be enough to make it work nicely.
+ if os.environ.get('TRAVIS') == 'true':
+ allowed_part *= 1.2
+
assert utime + stime < duration * allowed_part, \
"CPU usage over limit: user %.0f%% sys %.0f%% allowed %.0f%%" % (
utime / duration * 100, stime / duration * 100,
return retval
-def run_python(path):
- if not path.endswith('.py'):
- path += '.py'
- path = os.path.abspath(path)
- src_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+def run_python(path, env=None, args=None):
+ new_argv = [sys.executable]
new_env = os.environ.copy()
- new_env['PYTHONPATH'] = os.pathsep.join(sys.path + [src_dir])
+ if path:
+ if not path.endswith('.py'):
+ path += '.py'
+ path = os.path.abspath(path)
+ new_argv.append(path)
+ src_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+ new_env['PYTHONPATH'] = os.pathsep.join(sys.path + [src_dir])
+ if env:
+ new_env.update(env)
+ if args:
+ new_argv.extend(args)
p = subprocess.Popen(
- [sys.executable, path],
+ new_argv,
env=new_env,
stderr=subprocess.STDOUT,
stdin=subprocess.PIPE,
return output
-def run_isolated(path, prefix='tests/isolated/'):
- output = run_python(prefix + path).rstrip()
+def run_isolated(path, prefix='tests/isolated/', env=None, args=None):
+ output = run_python(prefix + path, env=env, args=args).rstrip()
if output.startswith(b'skip'):
parts = output.split(b':', 1)
skip_args = []
if len(parts) > 1:
skip_args.append(parts[1])
raise SkipTest(*skip_args)
- assert output == b'pass', output
+ ok = output == b'pass'
+ if not ok:
+ sys.stderr.write('Isolated test {0} output:\n---\n{1}\n---\n'.format(path, output.decode()))
+ assert ok, 'Expected single line "pass" in stdout'
certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt')
+import os
+import os.path
+
import eventlet
+
from eventlet import backdoor
from eventlet.green import socket
serv = eventlet.spawn(backdoor.backdoor_server, listener)
client = socket.socket()
client.connect(('localhost', listener.getsockname()[1]))
+ self._run_test_on_client_and_server(client, serv)
+
+ def _run_test_on_client_and_server(self, client, server_thread):
f = client.makefile('rw')
assert 'Python' in f.readline()
f.readline() # build info
self.assertEqual('>>> ', f.read(4))
f.close()
client.close()
- serv.kill()
+ server_thread.kill()
# wait for the console to discover that it's dead
eventlet.sleep(0.1)
+ def test_server_on_ipv6_socket(self):
+ listener = socket.socket(socket.AF_INET6)
+ listener.bind(('::1', 0))
+ listener.listen(5)
+ serv = eventlet.spawn(backdoor.backdoor_server, listener)
+ client = socket.socket(socket.AF_INET6)
+ client.connect(listener.getsockname())
+ self._run_test_on_client_and_server(client, serv)
+
+ def test_server_on_unix_socket(self):
+ SOCKET_PATH = '/tmp/eventlet_backdoor_test.socket'
+ if os.path.exists(SOCKET_PATH):
+ os.unlink(SOCKET_PATH)
+ listener = socket.socket(socket.AF_UNIX)
+ listener.bind(SOCKET_PATH)
+ listener.listen(5)
+ serv = eventlet.spawn(backdoor.backdoor_server, listener)
+ client = socket.socket(socket.AF_UNIX)
+ client.connect(SOCKET_PATH)
+ self._run_test_on_client_and_server(client, serv)
+
if __name__ == '__main__':
main()
import traceback
from unittest import TestCase, main
-from tests import mock, skipped, skip_unless, skip_with_pyevent, get_database_auth
+from tests import mock, skip_unless, skip_with_pyevent, get_database_auth
from eventlet import event
from eventlet import db_pool
from eventlet.support import six
assert self.pool.free() == 1
self.assertRaises(AttributeError, self.connection.cursor)
- @skipped
- def test_deletion_does_a_put(self):
- # doing a put on del causes some issues if __del__ is called in the
- # main coroutine, so, not doing that for now
- assert self.pool.free() == 0
- self.connection = None
- assert self.pool.free() == 1
-
def test_put_doesnt_double_wrap(self):
self.pool.put(self.connection)
conn = self.pool.get()
conn.commit()
self.pool.put(conn)
- @skipped
- def test_two_simultaneous_connections(self):
- # timing-sensitive test, disabled until we come up with a better
- # way to do this
- self.pool = self.create_pool(max_size=2)
- conn = self.pool.get()
- self.set_up_dummy_table(conn)
- self.fill_up_table(conn)
- curs = conn.cursor()
- conn2 = self.pool.get()
- self.set_up_dummy_table(conn2)
- self.fill_up_table(conn2)
- curs2 = conn2.cursor()
- results = []
- LONG_QUERY = "select * from test_table"
- SHORT_QUERY = "select * from test_table where row_id <= 20"
-
- evt = event.Event()
-
- def long_running_query():
- self.assert_cursor_works(curs)
- curs.execute(LONG_QUERY)
- results.append(1)
- evt.send()
- evt2 = event.Event()
-
- def short_running_query():
- self.assert_cursor_works(curs2)
- curs2.execute(SHORT_QUERY)
- results.append(2)
- evt2.send()
-
- eventlet.spawn(long_running_query)
- eventlet.spawn(short_running_query)
- evt.wait()
- evt2.wait()
- results.sort()
- self.assertEqual([1, 2], results)
-
def test_clear(self):
self.pool = self.create_pool()
self.pool.put(self.connection)
self.connection.close()
self.assertEqual(len(self.pool.free_items), 0)
- @skipped
- def test_max_idle(self):
- # This test is timing-sensitive. Rename the function without
- # the "dont" to run it, but beware that it could fail or take
- # a while.
-
- self.pool = self.create_pool(max_size=2, max_idle=0.02)
- self.connection = self.pool.get()
- self.connection.close()
- self.assertEqual(len(self.pool.free_items), 1)
- eventlet.sleep(0.01) # not long enough to trigger the idle timeout
- self.assertEqual(len(self.pool.free_items), 1)
- self.connection = self.pool.get()
- self.connection.close()
- self.assertEqual(len(self.pool.free_items), 1)
- eventlet.sleep(0.01) # idle timeout should have fired but done nothing
- self.assertEqual(len(self.pool.free_items), 1)
- self.connection = self.pool.get()
- self.connection.close()
- self.assertEqual(len(self.pool.free_items), 1)
- eventlet.sleep(0.03) # long enough to trigger idle timeout for real
- self.assertEqual(len(self.pool.free_items), 0)
-
- @skipped
- def test_max_idle_many(self):
- # This test is timing-sensitive. Rename the function without
- # the "dont" to run it, but beware that it could fail or take
- # a while.
-
- self.pool = self.create_pool(max_size=2, max_idle=0.02)
- self.connection, conn2 = self.pool.get(), self.pool.get()
- self.connection.close()
- eventlet.sleep(0.01)
- self.assertEqual(len(self.pool.free_items), 1)
- conn2.close()
- self.assertEqual(len(self.pool.free_items), 2)
- eventlet.sleep(0.02) # trigger cleanup of conn1 but not conn2
- self.assertEqual(len(self.pool.free_items), 1)
-
- @skipped
- def test_max_age(self):
- # This test is timing-sensitive. Rename the function without
- # the "dont" to run it, but beware that it could fail or take
- # a while.
-
- self.pool = self.create_pool(max_size=2, max_age=0.05)
- self.connection = self.pool.get()
- self.connection.close()
- self.assertEqual(len(self.pool.free_items), 1)
- eventlet.sleep(0.01) # not long enough to trigger the age timeout
- self.assertEqual(len(self.pool.free_items), 1)
- self.connection = self.pool.get()
- self.connection.close()
- self.assertEqual(len(self.pool.free_items), 1)
- eventlet.sleep(0.05) # long enough to trigger age timeout
- self.assertEqual(len(self.pool.free_items), 0)
-
- @skipped
- def test_max_age_many(self):
- # This test is timing-sensitive. Rename the function without
- # the "dont" to run it, but beware that it could fail or take
- # a while.
-
- self.pool = self.create_pool(max_size=2, max_age=0.15)
- self.connection, conn2 = self.pool.get(), self.pool.get()
- self.connection.close()
- self.assertEqual(len(self.pool.free_items), 1)
- eventlet.sleep(0) # not long enough to trigger the age timeout
- self.assertEqual(len(self.pool.free_items), 1)
- eventlet.sleep(0.2) # long enough to trigger age timeout
- self.assertEqual(len(self.pool.free_items), 0)
- conn2.close() # should not be added to the free items
- self.assertEqual(len(self.pool.free_items), 0)
-
def test_waiters_get_woken(self):
# verify that when there's someone waiting on an empty pool
# and someone puts an immediately-closed connection back in
self.assertEqual(self.pool.waiting(), 0)
self.pool.put(conn)
- @skipped
- def test_0_straight_benchmark(self):
- """ Benchmark; don't run unless you want to wait a while."""
- import time
- iterations = 20000
- c = self.connection.cursor()
- self.connection.commit()
-
- def bench(c):
- for i in six.moves.range(iterations):
- c.execute('select 1')
-
- bench(c) # warm-up
- results = []
- for i in range(3):
- start = time.time()
- bench(c)
- end = time.time()
- results.append(end - start)
-
- print("\n%u iterations took an average of %f seconds, (%s) in %s\n" % (
- iterations, sum(results) / len(results), results, type(self)))
-
def test_raising_create(self):
# if the create() method raises an exception the pool should
# not lose any connections
-import os
-from eventlet.support import six
-from tests.patcher_test import ProcessBase
-from tests import skip_with_pyevent
+import tests
-class Socket(ProcessBase):
- def test_patched_thread(self):
- new_mod = """from eventlet.green import socket
-socket.gethostbyname('localhost')
-socket.getaddrinfo('localhost', 80)
-"""
- os.environ['EVENTLET_TPOOL_DNS'] = 'yes'
- try:
- self.write_to_tempfile("newmod", new_mod)
- output, lines = self.launch_subprocess('newmod.py')
- self.assertEqual(len(lines), 1, lines)
- finally:
- del os.environ['EVENTLET_TPOOL_DNS']
-
+def test_hub_selects():
+ code = 'from eventlet import hubs\nprint(hubs.get_hub())'
+ output = tests.run_python(
+ path=None,
+ env={'EVENTLET_HUB': 'selects'},
+ args=['-c', code],
+ )
+ assert output.count(b'\n') == 1
+ assert b'eventlet.hubs.selects.Hub' in output
-class Tpool(ProcessBase):
- @skip_with_pyevent
- def test_tpool_size(self):
- expected = "40"
- normal = "20"
- new_mod = """from eventlet import tpool
-import eventlet
-import time
-current = [0]
-highwater = [0]
-def count():
- current[0] += 1
- time.sleep(0.1)
- if current[0] > highwater[0]:
- highwater[0] = current[0]
- current[0] -= 1
-expected = %s
-normal = %s
-p = eventlet.GreenPool()
-for i in range(expected*2):
- p.spawn(tpool.execute, count)
-p.waitall()
-assert highwater[0] > 20, "Highwater %%s <= %%s" %% (highwater[0], normal)
-"""
- os.environ['EVENTLET_THREADPOOL_SIZE'] = expected
- try:
- self.write_to_tempfile("newmod", new_mod % (expected, normal))
- output, lines = self.launch_subprocess('newmod.py')
- self.assertEqual(len(lines), 1, lines)
- finally:
- del os.environ['EVENTLET_THREADPOOL_SIZE']
- def test_tpool_negative(self):
- new_mod = """from eventlet import tpool
-import eventlet
-import time
-def do():
- print("should not get here")
-try:
- tpool.execute(do)
-except AssertionError:
- print("success")
-"""
- os.environ['EVENTLET_THREADPOOL_SIZE'] = "-1"
- try:
- self.write_to_tempfile("newmod", new_mod)
- output, lines = self.launch_subprocess('newmod.py')
- self.assertEqual(len(lines), 2, lines)
- self.assertEqual(lines[0], "success", output)
- finally:
- del os.environ['EVENTLET_THREADPOOL_SIZE']
+def test_tpool_dns():
+ code = '''\
+from eventlet.green import socket
+socket.gethostbyname('localhost')
+socket.getaddrinfo('localhost', 80)
+print('pass')
+'''
+ output = tests.run_python(
+ path=None,
+ env={'EVENTLET_TPOOL_DNS': 'yes'},
+ args=['-c', code],
+ )
+ assert output.rstrip() == b'pass'
- def test_tpool_zero(self):
- new_mod = """from eventlet import tpool
-import eventlet
-import time
-def do():
- print("ran it")
-tpool.execute(do)
-"""
- os.environ['EVENTLET_THREADPOOL_SIZE'] = "0"
- try:
- self.write_to_tempfile("newmod", new_mod)
- output, lines = self.launch_subprocess('newmod.py')
- self.assertEqual(len(lines), 4, lines)
- self.assertEqual(lines[-2], 'ran it', lines)
- assert 'Warning' in lines[1] or 'Warning' in lines[0], lines
- finally:
- del os.environ['EVENTLET_THREADPOOL_SIZE']
+@tests.skip_with_pyevent
+def test_tpool_size():
+ expected = '40'
+ normal = '20'
+ tests.run_isolated(
+ path='env_tpool_size.py',
+ env={'EVENTLET_THREADPOOL_SIZE': expected},
+ args=[expected, normal],
+ )
-class Hub(ProcessBase):
- def setUp(self):
- super(Hub, self).setUp()
- self.old_environ = os.environ.get('EVENTLET_HUB')
- os.environ['EVENTLET_HUB'] = 'selects'
+def test_tpool_negative():
+ tests.run_isolated('env_tpool_negative.py', env={'EVENTLET_THREADPOOL_SIZE': '-1'})
- def tearDown(self):
- if self.old_environ:
- os.environ['EVENTLET_HUB'] = self.old_environ
- else:
- del os.environ['EVENTLET_HUB']
- super(Hub, self).tearDown()
- def test_eventlet_hub(self):
- new_mod = """from eventlet import hubs
-print(hubs.get_hub())
-"""
- self.write_to_tempfile("newmod", new_mod)
- output, lines = self.launch_subprocess('newmod.py')
- self.assertEqual(len(lines), 2, "\n".join(lines))
- assert "selects" in lines[0]
+def test_tpool_zero():
+ tests.run_isolated('env_tpool_zero.py', env={'EVENTLET_THREADPOOL_SIZE': '0'})
import eventlet
import fcntl
import gc
+from io import DEFAULT_BUFFER_SIZE
import os
import shutil
import socket as _orig_sock
from nose.tools import eq_
+import eventlet
from eventlet import event, greenio, debug
from eventlet.hubs import get_hub
from eventlet.green import select, socket, time, ssl
import tests
-if six.PY3:
- buffer = memoryview
-
-
def bufsized(sock, size=1):
""" Resize both send and receive buffers on a socket.
Useful for testing trampoline. Returns the socket.
return sock
+def expect_socket_timeout(function, *args):
+ try:
+ function(*args)
+ raise AssertionError("socket.timeout not raised")
+ except socket.timeout as e:
+ assert hasattr(e, 'args')
+ eq_(e.args[0], 'timed out')
+
+
def min_buf_size():
"""Return the minimum buffer size that the platform supports."""
test_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(0.1)
gs = greenio.GreenSocket(s)
+
try:
- gs.connect(('192.0.2.1', 80))
- self.fail("socket.timeout not raised")
- except socket.timeout as e:
- assert hasattr(e, 'args')
- self.assertEqual(e.args[0], 'timed out')
+ expect_socket_timeout(gs.connect, ('192.0.2.1', 80))
except socket.error as e:
# unreachable is also a valid outcome
if not get_errno(e) in (errno.EHOSTUNREACH, errno.ENETUNREACH):
s.settimeout(0.1)
gs = greenio.GreenSocket(s)
- try:
- gs.accept()
- self.fail("socket.timeout not raised")
- except socket.timeout as e:
- assert hasattr(e, 'args')
- self.assertEqual(e.args[0], 'timed out')
+ expect_socket_timeout(gs.accept)
def test_connect_ex_timeout(self):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(addr)
- try:
- client.recv(8192)
- self.fail("socket.timeout not raised")
- except socket.timeout as e:
- assert hasattr(e, 'args')
- self.assertEqual(e.args[0], 'timed out')
+ expect_socket_timeout(client.recv, 0)
+ expect_socket_timeout(client.recv, 8192)
evt.send()
gt.wait()
gs.settimeout(.1)
gs.bind(('', 0))
- try:
- gs.recvfrom(8192)
- self.fail("socket.timeout not raised")
- except socket.timeout as e:
- assert hasattr(e, 'args')
- self.assertEqual(e.args[0], 'timed out')
+ expect_socket_timeout(gs.recvfrom, 0)
+ expect_socket_timeout(gs.recvfrom, 8192)
def test_recvfrom_into_timeout(self):
buf = array.array('B')
gs.settimeout(.1)
gs.bind(('', 0))
- try:
- gs.recvfrom_into(buf)
- self.fail("socket.timeout not raised")
- except socket.timeout as e:
- assert hasattr(e, 'args')
- self.assertEqual(e.args[0], 'timed out')
+ expect_socket_timeout(gs.recvfrom_into, buf)
def test_recv_into_timeout(self):
buf = array.array('B')
client.connect(addr)
- try:
- client.recv_into(buf)
- self.fail("socket.timeout not raised")
- except socket.timeout as e:
- assert hasattr(e, 'args')
- self.assertEqual(e.args[0], 'timed out')
+ expect_socket_timeout(client.recv_into, buf)
evt.send()
gt.wait()
client = bufsized(greenio.GreenSocket(socket.socket()))
client.connect(addr)
- try:
- client.settimeout(0.00001)
- msg = b"A" * 100000 # large enough number to overwhelm most buffers
- total_sent = 0
- # want to exceed the size of the OS buffer so it'll block in a
- # single send
+ client.settimeout(0.00001)
+ msg = b"A" * 100000 # large enough number to overwhelm most buffers
+
+ # want to exceed the size of the OS buffer so it'll block in a
+ # single send
+ def send():
for x in range(10):
- total_sent += client.send(msg)
- self.fail("socket.timeout not raised")
- except socket.timeout as e:
- assert hasattr(e, 'args')
- self.assertEqual(e.args[0], 'timed out')
+ client.send(msg)
+
+ expect_socket_timeout(send)
evt.send()
gt.wait()
client.settimeout(0.1)
client.connect(addr)
- try:
- msg = b"A" * (8 << 20)
-
- # want to exceed the size of the OS buffer so it'll block
- client.sendall(msg)
- self.fail("socket.timeout not raised")
- except socket.timeout as e:
- assert hasattr(e, 'args')
- self.assertEqual(e.args[0], 'timed out')
+ # want to exceed the size of the OS buffer so it'll block
+ msg = b"A" * (8 << 20)
+ expect_socket_timeout(client.sendall, msg)
evt.send()
gt.wait()
while True:
try:
sock.sendall(b'hello world')
+ # Arbitrary delay to not use all available CPU, keeps the test
+ # running quickly and reliably under a second
+ time.sleep(0.001)
except socket.error as e:
if get_errno(e) == errno.EPIPE:
return
while True:
data = client.recv(1024)
assert data
+ # Arbitrary delay to not use all available CPU, keeps the test
+ # running quickly and reliably under a second
+ time.sleep(0.001)
except socket.error as e:
# we get an EBADF because client is closed in the same process
# (but a different greenthread)
# should not raise
greenio.shutdown_safe(sock)
+ def test_datagram_socket_operations_work(self):
+ receiver = greenio.GreenSocket(socket.AF_INET, socket.SOCK_DGRAM)
+ receiver.bind(('127.0.0.1', 0))
+ address = receiver.getsockname()
+
+ sender = greenio.GreenSocket(socket.AF_INET, socket.SOCK_DGRAM)
+
+ # Two ways sendto can be called
+ sender.sendto(b'first', address)
+ sender.sendto(b'second', 0, address)
+
+ sender_address = ('127.0.0.1', sender.getsockname()[1])
+ eq_(receiver.recvfrom(1024), (b'first', sender_address))
+ eq_(receiver.recvfrom(1024), (b'second', sender_address))
+
def test_get_fileno_of_a_socket_works():
class DummySocket(object):
gt.wait()
+ def test_pip_read_until_end(self):
+ # similar to test_pip_read above but reading until eof
+ r, w = os.pipe()
+
+ r = greenio.GreenPipe(r, 'rb')
+ w = greenio.GreenPipe(w, 'wb')
+
+ w.write(b'c' * DEFAULT_BUFFER_SIZE * 2)
+ w.close()
+
+ buf = r.read() # no chunk size specified; read until end
+ self.assertEqual(len(buf), 2 * DEFAULT_BUFFER_SIZE)
+ self.assertEqual(buf[:3], b'ccc')
+
+ def test_pipe_read_unbuffered(self):
+ # Ensure that seting the buffer size works properly on GreenPipes,
+ # it used to be ignored on Python 2 and the test would hang on r.readline()
+ # below.
+ r, w = os.pipe()
+
+ r = greenio.GreenPipe(r, 'rb', 0)
+ w = greenio.GreenPipe(w, 'wb', 0)
+
+ w.write(b'line\n')
+
+ line = r.readline()
+ self.assertEqual(line, b'line\n')
+ r.close()
+ w.close()
+
def test_pipe_writes_large_messages(self):
r, w = os.pipe()
TEST_TIMEOUT = 10 # the test here might take a while depending on the OS
@tests.skip_with_pyevent
- def test_multiple_readers(self, clibufsize=False):
+ def test_multiple_readers(self):
debug.hub_prevent_multiple_readers(False)
recvsize = 2 * min_buf_size()
sendsize = 10 * recvsize
server_coro = eventlet.spawn(server)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', listener.getsockname()[1]))
- if clibufsize:
- bufsized(client, size=sendsize)
- else:
- bufsized(client)
- client.sendall(b'*' * sendsize)
+ bufsized(client, size=sendsize)
+
+ # Split into multiple chunks so that we can wait a little
+ # every iteration which allows both readers to queue and
+ # recv some data when we actually send it.
+ for i in range(20):
+ eventlet.sleep(0.001)
+ client.sendall(b'*' * (sendsize // 20))
+
client.close()
server_coro.wait()
listener.close()
assert len(results2) > 0
debug.hub_prevent_multiple_readers()
- @tests.skipped # by rdw because it fails but it's not clear how to make it pass
- @tests.skip_with_pyevent
- def test_multiple_readers2(self):
- self.test_multiple_readers(clibufsize=True)
-
-
-class TestGreenIoStarvation(tests.LimitedTestCase):
- # fixme: this doesn't succeed, because of eventlet's predetermined
- # ordering. two processes, one with server, one with client eventlets
- # might be more reliable?
-
- TEST_TIMEOUT = 300 # the test here might take a while depending on the OS
-
- @tests.skipped # by rdw, because it fails but it's not clear how to make it pass
- @tests.skip_with_pyevent
- def test_server_starvation(self, sendloops=15):
- recvsize = 2 * min_buf_size()
- sendsize = 10000 * recvsize
-
- results = [[] for i in range(5)]
-
- listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- listener.bind(('127.0.0.1', 0))
- port = listener.getsockname()[1]
- listener.listen(50)
-
- base_time = time.time()
-
- def server(my_results):
- sock, addr = listener.accept()
-
- datasize = 0
-
- t1 = None
- t2 = None
- try:
- while True:
- data = sock.recv(recvsize)
- if not t1:
- t1 = time.time() - base_time
- if not data:
- t2 = time.time() - base_time
- my_results.append(datasize)
- my_results.append((t1, t2))
- break
- datasize += len(data)
- finally:
- sock.close()
-
- def client():
- pid = os.fork()
- if pid:
- return pid
-
- client = _orig_sock.socket(socket.AF_INET, socket.SOCK_STREAM)
- client.connect(('127.0.0.1', port))
-
- bufsized(client, size=sendsize)
-
- for i in range(sendloops):
- client.sendall(b'*' * sendsize)
- client.close()
- os._exit(0)
-
- clients = []
- servers = []
- for r in results:
- servers.append(eventlet.spawn(server, r))
- for r in results:
- clients.append(client())
-
- for s in servers:
- s.wait()
- for c in clients:
- os.waitpid(c, 0)
-
- listener.close()
-
- # now test that all of the server receive intervals overlap, and
- # that there were no errors.
- for r in results:
- assert len(r) == 2, "length is %d not 2!: %s\n%s" % (len(r), r, results)
- assert r[0] == sendsize * sendloops
- assert len(r[1]) == 2
- assert r[1][0] is not None
- assert r[1][1] is not None
-
- starttimes = sorted(r[1][0] for r in results)
- endtimes = sorted(r[1][1] for r in results)
- runlengths = sorted(r[1][1] - r[1][0] for r in results)
-
- # assert that the last task started before the first task ended
- # (our no-starvation condition)
- assert starttimes[-1] < endtimes[0], \
- "Not overlapping: starts %s ends %s" % (starttimes, endtimes)
-
- maxstartdiff = starttimes[-1] - starttimes[0]
-
- assert maxstartdiff * 2 < runlengths[0], \
- "Largest difference in starting times more than twice the shortest running time!"
- assert runlengths[0] * 2 > runlengths[-1], \
- "Longest runtime more than twice as long as shortest!"
-
def test_set_nonblocking():
sock = _orig_sock.socket(socket.AF_INET, socket.SOCK_DGRAM)
def test_double_close_219():
tests.run_isolated('greenio_double_close_219.py')
+
+
+def test_partial_write_295():
+ # https://github.com/eventlet/eventlet/issues/295
+ # `socket.makefile('w').writelines()` must send all
+ # despite partial writes by underlying socket
+ listen_socket = eventlet.listen(('localhost', 0))
+ original_accept = listen_socket.accept
+
+ def talk(conn):
+ f = conn.makefile('wb')
+ line = b'*' * 2140
+ f.writelines([line] * 10000)
+ conn.close()
+
+ def accept():
+ connection, address = original_accept()
+ original_send = connection.send
+
+ def slow_send(b, *args):
+ b = b[:1031]
+ return original_send(b, *args)
+
+ connection.send = slow_send
+ eventlet.spawn(talk, connection)
+ return connection, address
+
+ listen_socket.accept = accept
+
+ eventlet.spawn(listen_socket.accept)
+ sock = eventlet.connect(listen_socket.getsockname())
+ with eventlet.Timeout(10):
+ bs = sock.makefile('rb').read()
+ assert len(bs) == 21400000
+ assert bs == (b'*' * 21400000)
+
+
+def test_socket_file_read_non_int():
+ listen_socket = eventlet.listen(('localhost', 0))
+
+ def server():
+ conn, _ = listen_socket.accept()
+ conn.recv(1)
+ conn.sendall('response')
+ conn.close()
+
+ eventlet.spawn(server)
+ sock = eventlet.connect(listen_socket.getsockname())
+
+ fd = sock.makefile('rwb')
+ fd.write(b'?')
+ fd.flush()
+ with eventlet.Timeout(1):
+ try:
+ fd.read("This shouldn't work")
+ assert False
+ except TypeError:
+ pass
+
+
+def test_pipe_context():
+ # ensure using a pipe as a context actually closes it.
+ r, w = os.pipe()
+ r = greenio.GreenPipe(r)
+ w = greenio.GreenPipe(w, 'w')
+
+ with r:
+ pass
+ assert r.closed and not w.closed
+
+ with w as f:
+ assert f == w
+ assert r.closed and w.closed
+++ /dev/null
-from __future__ import with_statement
-
-import os
-
-from eventlet import greenio
-from tests import LimitedTestCase
-
-
-class TestGreenPipeWithStatement(LimitedTestCase):
- def test_pipe_context(self):
- # ensure using a pipe as a context actually closes it.
- r, w = os.pipe()
-
- r = greenio.GreenPipe(r)
- w = greenio.GreenPipe(w, 'w')
-
- with r:
- pass
-
- assert r.closed and not w.closed
-
- with w as f:
- assert f == w
-
- assert r.closed and w.closed
--- /dev/null
+__test__ = False
+
+if __name__ == '__main__':
+ from eventlet import tpool
+
+ def do():
+ print("should not get here")
+ try:
+ tpool.execute(do)
+ except AssertionError:
+ print('pass')
--- /dev/null
+__test__ = False
+
+if __name__ == '__main__':
+ import sys
+ import time
+ from eventlet import tpool
+ import eventlet
+
+ current = [0]
+ highwater = [0]
+
+ def count():
+ current[0] += 1
+ time.sleep(0.01)
+ if current[0] > highwater[0]:
+ highwater[0] = current[0]
+ current[0] -= 1
+
+ expected = int(sys.argv[1])
+ normal = int(sys.argv[2])
+ p = eventlet.GreenPool()
+ for i in range(expected * 2):
+ p.spawn(tpool.execute, count)
+ p.waitall()
+ assert highwater[0] > normal, "Highwater %s <= %s" % (highwater[0], normal)
+ print('pass')
--- /dev/null
+__test__ = False
+
+if __name__ == '__main__':
+ import warnings
+ from eventlet import tpool
+ g = [False]
+
+ def do():
+ g[0] = True
+
+ with warnings.catch_warnings(record=True) as ws:
+ warnings.simplefilter('always')
+
+ tpool.execute(do)
+
+ assert len(ws) == 1
+ msg = str(ws[0].message)
+ assert 'Zero threads in tpool' in msg
+ assert 'EVENTLET_THREADPOOL_SIZE' in msg
+
+ assert g[0]
+ print('pass')
__test__ = False
-
-def main():
+if __name__ == '__main__':
+ import sys
import eventlet
try:
from dns import reversename
except ImportError:
print('skip:require dns (package dnspython)')
- return
+ sys.exit(1)
eventlet.monkey_patch(all=True)
reversename.from_address('127.0.0.1')
print('pass')
-
-if __name__ == '__main__':
- main()
__test__ = False
-
-def main():
+if __name__ == '__main__':
import eventlet
eventlet.monkey_patch()
import subprocess
f.close() # OSError, because the fd 3 has already been closed
print('pass')
-
-if __name__ == '__main__':
- main()
-from __future__ import print_function
-
-# no standard tests in this file, ignore
__test__ = False
if __name__ == '__main__':
--- /dev/null
+__test__ = False
+
+if __name__ == '__main__':
+ import eventlet
+ eventlet.monkey_patch()
+
+ # Leaving unpatched select methods in the select module is a recipe
+ # for trouble and this test makes sure we don't do that.
+ #
+ # Issues:
+ # * https://bitbucket.org/eventlet/eventlet/issues/167
+ # * https://github.com/eventlet/eventlet/issues/169
+ import select
+ # FIXME: must also delete `poll`, but it breaks subprocess `communicate()`
+ # https://github.com/eventlet/eventlet/issues/290
+ for name in ['devpoll', 'epoll', 'kqueue', 'kevent']:
+ assert not hasattr(select, name), name
+
+ import sys
+
+ if sys.version_info >= (3, 4):
+ import selectors
+ for name in [
+ 'PollSelector',
+ 'EpollSelector',
+ 'DevpollSelector',
+ 'KqueueSelector',
+ ]:
+ assert not hasattr(selectors, name), name
+
+ default = selectors.DefaultSelector
+ assert default is selectors.SelectSelector, default
+
+ print('pass')
-from __future__ import print_function
-
-import sys
-
-import eventlet
-
-
-# no standard tests in this file, ignore
__test__ = False
if __name__ == '__main__':
+ import sys
+ import eventlet
+
eventlet.monkey_patch()
threading = eventlet.patcher.original('threading')
--- /dev/null
+__test__ = False
+
+if __name__ == '__main__':
+ import eventlet
+ eventlet.monkey_patch()
+
+ from eventlet.support.six.moves.BaseHTTPServer import (
+ HTTPServer,
+ BaseHTTPRequestHandler,
+ )
+ import threading
+
+ server = HTTPServer(('localhost', 0), BaseHTTPRequestHandler)
+ thread = threading.Thread(target=server.serve_forever)
+
+ # Before fixing it the code would never go pass this line because:
+ # * socketserver.BaseServer that's used behind the scenes here uses
+ # selectors.PollSelector if it's available and we don't have green poll
+ # implementation so this just couldn't work
+ # * making socketserver use selectors.SelectSelector wasn't enough as
+ # until now we just failed to monkey patch selectors module
+ #
+ # Due to the issues above this thread.start() call effectively behaved
+ # like calling server.serve_forever() directly in the current thread
+ #
+ # Original report: https://github.com/eventlet/eventlet/issues/249
+ thread.start()
+
+ server.shutdown()
+ print('pass')
# Issue #185: test threading.Condition with monkey-patching
-import eventlet
-
-# no standard tests in this file, ignore
__test__ = False
-
if __name__ == '__main__':
+ import eventlet
eventlet.monkey_patch()
import threading
# Issue #223: test threading.Thread.join with monkey-patching
-import eventlet
-
-# no standard tests in this file, ignore
__test__ = False
-
if __name__ == '__main__':
+ import eventlet
eventlet.monkey_patch()
import threading
--- /dev/null
+__test__ = False
+
+if __name__ == '__main__':
+ import sys
+ import eventlet
+ import subprocess
+ eventlet.monkey_patch(all=True)
+ p = subprocess.Popen([sys.executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ p.communicate()
+
+ print('pass')
@staticmethod
def write(s):
output_buffer.append(s.rstrip())
+ return len(s)
# This test might make you wince
--- /dev/null
+import tests
+
+
+def test_import():
+ # https://github.com/eventlet/eventlet/issues/238
+ # Ensure that it's possible to import eventlet.green.OpenSSL.
+ # Most basic test to check Python 3 compatibility.
+ try:
+ import OpenSSL
+ except ImportError:
+ raise tests.SkipTest('need pyopenssl')
+
+ import eventlet.green.OpenSSL.SSL
+ import eventlet.green.OpenSSL.crypto
+ import eventlet.green.OpenSSL.rand
+ import eventlet.green.OpenSSL.tsafe
+ import eventlet.green.OpenSSL.version
self.assertEqual(len(lines), 2, "\n".join(lines))
-class Subprocess(ProcessBase):
- def test_monkeypatched_subprocess(self):
- new_mod = """import eventlet
+def test_subprocess_after_monkey_patch():
+ code = '''\
+import sys
+import eventlet
eventlet.monkey_patch()
from eventlet.green import subprocess
-
-subprocess.Popen(['true'], stdin=subprocess.PIPE)
-print("done")
-"""
- self.write_to_tempfile("newmod", new_mod)
- output, lines = self.launch_subprocess('newmod')
- self.assertEqual(output, "done\n", output)
+subprocess.Popen([sys.executable, '-c', ''], stdin=subprocess.PIPE).wait()
+print('pass')
+'''
+ output = tests.run_python(
+ path=None,
+ args=['-c', code],
+ )
+ assert output.rstrip() == b'pass'
class Threading(ProcessBase):
output, lines = self.launch_subprocess('newmod')
self.assertEqual(len(lines), 4, "\n".join(lines))
assert lines[0].startswith('<Thread'), lines[0]
- self.assertEqual(lines[1], "1", lines[1])
- self.assertEqual(lines[2], "1", lines[2])
+ assert lines[1] == '1', lines
+ assert lines[2] == '1', lines
def test_threading(self):
new_mod = """import eventlet
def test_threading_join():
tests.run_isolated('patcher_threading_join.py')
+
+
+def test_socketserver_selectors():
+ tests.run_isolated('patcher_socketserver_selectors.py')
+
+
+def test_blocking_select_methods_are_deleted():
+ tests.run_isolated('patcher_blocking_select_methods_are_deleted.py')
if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
+ unittest.main()
+import eventlet
from eventlet.green import socket
socket.create_connection(('192.0.2.1', 80), timeout=0.1)
except (IOError, OSError):
pass
+
+
+def test_recv_type():
+ # https://github.com/eventlet/eventlet/issues/245
+ # socket recv returning multiple data types
+ # For this test to work, client and server have to be in separate
+ # processes or OS threads. Just running two greenthreads gives
+ # false test pass.
+ threading = eventlet.patcher.original('threading')
+ addr = []
+
+ def server():
+ sock = eventlet.listen(('127.0.0.1', 0))
+ addr[:] = sock.getsockname()
+ eventlet.sleep(0.2)
+
+ server_thread = threading.Thread(target=server)
+ server_thread.start()
+ eventlet.sleep(0.1)
+ sock = eventlet.connect(tuple(addr))
+ s = sock.recv(1)
+ assert isinstance(s, bytes)
+import sys
+import time
+
import eventlet
from eventlet.green import subprocess
import eventlet.patcher
-import sys
-import time
+import tests
original_subprocess = eventlet.patcher.original('subprocess')
p.stdin.close()
except Exception as e:
assert False, "Exception should not be raised, got %r instead" % e
+
+
+def test_universal_lines():
+ p = subprocess.Popen(
+ [sys.executable, '--version'],
+ shell=False,
+ stdout=subprocess.PIPE,
+ universal_newlines=True)
+ p.communicate(None)
+
+
+def test_patched_communicate_290():
+ # https://github.com/eventlet/eventlet/issues/290
+ # Certain order of import and monkey_patch breaks subprocess communicate()
+ # with AttributeError module `select` has no `poll` on Linux
+ # unpatched methods are removed for safety reasons in commit f63165c0e3
+ tests.run_isolated('subprocess_patched_communicate.py')
from eventlet.green import thread
from eventlet.support import six
-from tests import LimitedTestCase, skipped
+from tests import LimitedTestCase
class Locals(LimitedTestCase):
self.results = []
super(Locals, self).tearDown()
- @skipped # cause it relies on internal details of corolocal that are no longer true
- def test_simple(self):
- tls = thread._local()
- g_ids = []
- evt = event.Event()
-
- def setter(tls, v):
- g_id = id(greenthread.getcurrent())
- g_ids.append(g_id)
- tls.value = v
- evt.wait()
-
- thread.start_new_thread(setter, args=(tls, 1))
- thread.start_new_thread(setter, args=(tls, 2))
- eventlet.sleep()
- objs = object.__getattribute__(tls, "__objs")
- assert sorted(g_ids) == sorted(objs.keys())
- assert objs[g_ids[0]]['value'] == 1
- assert objs[g_ids[1]]['value'] == 2
- assert getattr(tls, 'value', None) is None
- evt.send("done")
- eventlet.sleep()
-
def test_assignment(self):
my_local = corolocal.local()
my_local.a = 1
import eventlet
from eventlet import tpool, debug, event
from eventlet.support import six
-from tests import LimitedTestCase, skipped, skip_with_pyevent, main
+from tests import LimitedTestCase, skip_with_pyevent, main
one = 1
self.assertEqual(len(results), cnt)
tpool.killall()
- @skipped
- def test_benchmark(self):
- """ Benchmark computing the amount of overhead tpool adds to function calls."""
- iterations = 10000
- import timeit
- imports = """
-from tests.tpool_test import noop
-from eventlet.tpool import execute
- """
- t = timeit.Timer("noop()", imports)
- results = t.repeat(repeat=3, number=iterations)
- best_normal = min(results)
-
- t = timeit.Timer("execute(noop)", imports)
- results = t.repeat(repeat=3, number=iterations)
- best_tpool = min(results)
-
- tpool_overhead = (best_tpool - best_normal) / iterations
- print("%s iterations\nTpool overhead is %s seconds per call. Normal: %s; Tpool: %s" % (
- iterations, tpool_overhead, best_normal, best_tpool))
- tpool.killall()
-
@skip_with_pyevent
def test_leakage_from_tracebacks(self):
tpool.execute(noop) # get it started
from eventlet.green import socket
from eventlet.support import six
-from tests.wsgi_test import _TestBase
+import tests.wsgi_test
# demo app
wsapp = websocket.WebSocketWSGI(handle)
-class TestWebSocket(_TestBase):
+class TestWebSocket(tests.wsgi_test._TestBase):
TEST_TIMEOUT = 5
def set_site(self):
headers = dict(kv.split(': ') for kv in [
"Upgrade: websocket",
# NOTE: intentionally no connection header
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Version: 13",
])
- http = httplib.HTTPConnection('localhost', self.port)
+ http = httplib.HTTPConnection(*self.server_addr)
http.request("GET", "/echo", headers=headers)
resp = http.getresponse()
headers = dict(kv.split(': ') for kv in [
"Upgrade: websocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Version: 13",
])
- http = httplib.HTTPConnection('localhost', self.port)
+ http = httplib.HTTPConnection(*self.server_addr)
http.request("GET", "/echo", headers=headers)
resp = http.getresponse()
# No Upgrade now
headers = dict(kv.split(': ') for kv in [
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Version: 13",
])
- http = httplib.HTTPConnection('localhost', self.port)
+ http = httplib.HTTPConnection(*self.server_addr)
http.request("GET", "/echo", headers=headers)
resp = http.getresponse()
"GET /echo HTTP/1.1",
"Upgrade: websocket",
"Connection: %s" % http_connection,
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Version: 13",
"Sec-WebSocket-Key: d9MXuOzlVQ0h+qRllvSCIg==",
]
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n'))
result = sock.recv(1024)
"GET /echo HTTP/1.1",
"Upgrade: websocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Version: 13",
"Sec-WebSocket-Key: d9MXuOzlVQ0h+qRllvSCIg==",
]
- sock = eventlet.connect(
- ('localhost', self.port))
-
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n'))
sock.recv(1024)
ws = websocket.RFC6455WebSocket(sock, {}, client=True)
"GET /echo HTTP/1.1",
"Upgrade: websocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Version: 13",
"Sec-WebSocket-Key: d9MXuOzlVQ0h+qRllvSCIg==",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n'))
sock.recv(1024) # get the headers
sock.close() # close while the app is running
"GET /echo HTTP/1.1",
"Upgrade: websocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Version: 13",
"Sec-WebSocket-Key: d9MXuOzlVQ0h+qRllvSCIg==",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n'))
sock.recv(1024) # get the headers
closeframe = struct.pack('!BBIH', 1 << 7 | 8, 1 << 7 | 2, 0, 1000)
"GET /echo HTTP/1.1",
"Upgrade: websocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Version: 13",
"Sec-WebSocket-Key: d9MXuOzlVQ0h+qRllvSCIg==",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n'))
sock.recv(1024) # get the headers
sock.sendall(b'\x07\xff') # Weird packet.
from eventlet.support import six
from eventlet.websocket import WebSocket, WebSocketWSGI
-from tests import certificate_file, LimitedTestCase, mock, private_key_file
-from tests import skip_if_no_ssl
-from tests.wsgi_test import _TestBase
+import tests
+from tests import mock
+import tests.wsgi_test
# demo app
wsapp = WebSocketWSGI(handle)
-class TestWebSocket(_TestBase):
+class TestWebSocket(tests.wsgi_test._TestBase):
TEST_TIMEOUT = 5
def set_site(self):
self.site = wsapp
def test_incorrect_headers(self):
- http = httplib.HTTPConnection('localhost', self.port)
+ http = httplib.HTTPConnection(*self.server_addr)
http.request("GET", "/echo")
response = http.getresponse()
assert response.status == 400
headers = dict(kv.split(': ') for kv in [
"Upgrade: WebSocket",
# NOTE: intentionally no connection header
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"WebSocket-Protocol: ws",
])
- http = httplib.HTTPConnection('localhost', self.port)
+ http = httplib.HTTPConnection(*self.server_addr)
http.request("GET", "/echo", headers=headers)
resp = http.getresponse()
headers = dict(kv.split(': ') for kv in [
"Upgrade: WebSocket",
# NOTE: intentionally no connection header
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Protocol: ws",
])
- http = httplib.HTTPConnection('localhost', self.port)
+ http = httplib.HTTPConnection(*self.server_addr)
http.request("GET", "/echo", headers=headers)
resp = http.getresponse()
headers = dict(kv.split(': ') for kv in [
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Protocol: ws",
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5",
# NOTE: Intentionally no Key2 header
])
- http = httplib.HTTPConnection('localhost', self.port)
+ http = httplib.HTTPConnection(*self.server_addr)
http.request("GET", "/echo", headers=headers)
resp = http.getresponse()
"GET /echo HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"WebSocket-Protocol: ws",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n'))
result = sock.recv(1024)
'HTTP/1.1 101 Web Socket Protocol Handshake',
'Upgrade: WebSocket',
'Connection: Upgrade',
- 'WebSocket-Origin: http://localhost:%s' % self.port,
- 'WebSocket-Location: ws://localhost:%s/echo\r\n\r\n' % self.port,
+ 'WebSocket-Origin: http://%s:%s' % self.server_addr,
+ 'WebSocket-Location: ws://%s:%s/echo\r\n\r\n' % self.server_addr,
])))
def test_correct_upgrade_request_76(self):
"GET /echo HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Protocol: ws",
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5",
"Sec-WebSocket-Key2: 12998 5 Y3 1 .P00",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n^n:ds[4U'))
result = sock.recv(1024)
'HTTP/1.1 101 WebSocket Protocol Handshake',
'Upgrade: WebSocket',
'Connection: Upgrade',
- 'Sec-WebSocket-Origin: http://localhost:%s' % self.port,
+ 'Sec-WebSocket-Origin: http://%s:%s' % self.server_addr,
'Sec-WebSocket-Protocol: ws',
- 'Sec-WebSocket-Location: ws://localhost:%s/echo\r\n\r\n8jKS\'y:G*Co,Wxa-' % self.port,
+ 'Sec-WebSocket-Location: ws://%s:%s/echo\r\n\r\n8jKS\'y:G*Co,Wxa-' % self.server_addr,
])))
def test_query_string(self):
"GET /echo?query_string HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Protocol: ws",
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5",
"Sec-WebSocket-Key2: 12998 5 Y3 1 .P00",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n^n:ds[4U'))
result = sock.recv(1024)
'HTTP/1.1 101 WebSocket Protocol Handshake',
'Upgrade: WebSocket',
'Connection: Upgrade',
- 'Sec-WebSocket-Origin: http://localhost:%s' % self.port,
+ 'Sec-WebSocket-Origin: http://%s:%s' % self.server_addr,
'Sec-WebSocket-Protocol: ws',
'Sec-WebSocket-Location: '
- 'ws://localhost:%s/echo?query_string\r\n\r\n8jKS\'y:G*Co,Wxa-' % self.port,
+ 'ws://%s:%s/echo?query_string\r\n\r\n8jKS\'y:G*Co,Wxa-' % self.server_addr,
])))
def test_empty_query_string(self):
"GET /echo? HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Protocol: ws",
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5",
"Sec-WebSocket-Key2: 12998 5 Y3 1 .P00",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n^n:ds[4U'))
result = sock.recv(1024)
'HTTP/1.1 101 WebSocket Protocol Handshake',
'Upgrade: WebSocket',
'Connection: Upgrade',
- 'Sec-WebSocket-Origin: http://localhost:%s' % self.port,
+ 'Sec-WebSocket-Origin: http://%s:%s' % self.server_addr,
'Sec-WebSocket-Protocol: ws',
- 'Sec-WebSocket-Location: ws://localhost:%s/echo?\r\n\r\n8jKS\'y:G*Co,Wxa-' % self.port,
+ 'Sec-WebSocket-Location: ws://%s:%s/echo?\r\n\r\n8jKS\'y:G*Co,Wxa-' % self.server_addr,
])))
def test_sending_messages_to_websocket_75(self):
"GET /echo HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"WebSocket-Protocol: ws",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n'))
sock.recv(1024)
"GET /echo HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Protocol: ws",
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5",
"Sec-WebSocket-Key2: 12998 5 Y3 1 .P00",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n^n:ds[4U'))
sock.recv(1024)
"GET /range HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"WebSocket-Protocol: ws",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n'))
resp = sock.recv(1024)
"GET /range HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Protocol: ws",
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5",
"Sec-WebSocket-Key2: 12998 5 Y3 1 .P00",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n^n:ds[4U'))
resp = sock.recv(1024)
"GET /range HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"WebSocket-Protocol: ws",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n'))
sock.recv(1024) # get the headers
sock.close() # close while the app is running
"GET /range HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Protocol: ws",
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5",
"Sec-WebSocket-Key2: 12998 5 Y3 1 .P00",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n^n:ds[4U'))
sock.recv(1024) # get the headers
sock.close() # close while the app is running
"GET /echo HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Protocol: ws",
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5",
"Sec-WebSocket-Key2: 12998 5 Y3 1 .P00",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n^n:ds[4U'))
sock.recv(1024) # get the headers
sock.sendall(b'\xff\x00') # "Close the connection" packet.
"GET /echo HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Protocol: ws",
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5",
"Sec-WebSocket-Key2: 12998 5 Y3 1 .P00",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n^n:ds[4U'))
sock.recv(1024) # get the headers
sock.sendall(b'\xef\x00') # Weird packet.
"GET / HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Protocol: ws",
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5",
"Sec-WebSocket-Key2: 12998 5 Y3 1 .P00",
]
- sock = eventlet.connect(
- ('localhost', self.port))
-
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n^n:ds[4U'))
resp = sock.recv(1024)
headers, result = resp.split(b'\r\n\r\n')
"GET /error HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"WebSocket-Protocol: ws",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n'))
sock.recv(1024)
done_with_request.wait()
"GET /error HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Protocol: ws",
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5",
"Sec-WebSocket-Key2: 12998 5 Y3 1 .P00",
]
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n^n:ds[4U'))
sock.recv(1024)
done_with_request.wait()
assert error_detected[0]
-class TestWebSocketSSL(_TestBase):
+class TestWebSocketSSL(tests.wsgi_test._TestBase):
def set_site(self):
self.site = wsapp
- @skip_if_no_ssl
+ @tests.skip_if_no_ssl
def test_ssl_sending_messages(self):
s = eventlet.wrap_ssl(eventlet.listen(('localhost', 0)),
- certfile=certificate_file,
- keyfile=private_key_file,
+ certfile=tests.certificate_file,
+ keyfile=tests.private_key_file,
server_side=True)
self.spawn_server(sock=s)
connect = [
"GET /echo HTTP/1.1",
"Upgrade: WebSocket",
"Connection: Upgrade",
- "Host: localhost:%s" % self.port,
- "Origin: http://localhost:%s" % self.port,
+ "Host: %s:%s" % self.server_addr,
+ "Origin: http://%s:%s" % self.server_addr,
"Sec-WebSocket-Protocol: ws",
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5",
"Sec-WebSocket-Key2: 12998 5 Y3 1 .P00",
]
- sock = eventlet.wrap_ssl(eventlet.connect(
- ('localhost', self.port)))
+ sock = eventlet.wrap_ssl(eventlet.connect(self.server_addr))
sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n^n:ds[4U'))
first_resp = b''
# make sure it sets the wss: protocol on the location header
loc_line = [x for x in first_resp.split(b"\r\n")
if x.lower().startswith(b'sec-websocket-location')][0]
- self.assert_(b"wss://localhost" in loc_line,
- "Expecting wss protocol in location: %s" % loc_line)
+ expect_wss = ('wss://%s:%s' % self.server_addr).encode()
+ assert expect_wss in loc_line, "Expecting wss protocol in location: %s" % loc_line
+
sock.sendall(b'\x00hello\xFF')
result = sock.recv(1024)
self.assertEqual(result, b'\x00hello\xff')
eventlet.sleep(0.01)
-class TestWebSocketObject(LimitedTestCase):
+class TestWebSocketObject(tests.LimitedTestCase):
def setUp(self):
self.mock_socket = s = mock.Mock()
import collections
import errno
import os
+import shutil
import signal
import socket
import sys
+import tempfile
import traceback
import unittest
import eventlet
from eventlet import debug
from eventlet import event
-from eventlet.green import socket as greensocket
-from eventlet.green import ssl
-from eventlet.green import subprocess
from eventlet import greenio
from eventlet import greenthread
from eventlet import support
-from eventlet.support import bytes_to_str, capture_stderr, six
from eventlet import tpool
from eventlet import wsgi
-
+from eventlet.green import socket as greensocket
+from eventlet.green import ssl
+from eventlet.support import bytes_to_str, capture_stderr, six
import tests
CONTENT_LENGTH = 'content-length'
-"""
-HTTP/1.1 200 OK
-Date: foo
-Content-length: 11
-
-hello world
-"""
-
-
-def recvall(socket_):
+def recvall(sock):
result = b''
while True:
- chunk = socket_.recv()
- result += chunk
+ chunk = sock.recv(16 << 10)
if chunk == b'':
- break
-
- return result
+ return result
+ result += chunk
class ConnectionClosed(Exception):
"""Spawns a new wsgi server with the given arguments using
:meth:`spawn_thread`.
- Sets self.port to the port of the server
+ Sets `self.server_addr` to (host, port) tuple suitable for `socket.connect`.
"""
new_kwargs = dict(max_size=128,
log=self.logfile,
if 'sock' not in new_kwargs:
new_kwargs['sock'] = eventlet.listen(('localhost', 0))
- self.port = new_kwargs['sock'].getsockname()[1]
+ self.server_addr = new_kwargs['sock'].getsockname()
self.spawn_thread(wsgi.server, **new_kwargs)
def spawn_thread(self, target, **kwargs):
self.site = Site()
def test_001_server(self):
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
- fd.flush()
- result = fd.read()
- fd.close()
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
+ result = recvall(sock)
# The server responds with the maximum version it supports
assert result.startswith(b'HTTP'), result
assert result.endswith(b'hello world'), result
def test_002_keepalive(self):
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('wb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
read_http(sock)
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
read_http(sock)
- fd.close()
- sock.close()
-
- def test_003_passing_non_int_to_read(self):
- # This should go in greenio_test
- sock = eventlet.connect(
- ('localhost', self.port))
-
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
- cancel = eventlet.Timeout(1, RuntimeError)
- self.assertRaises(TypeError, fd.read, "This shouldn't work")
- cancel.cancel()
- fd.close()
def test_004_close_keepalive(self):
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('wb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
- read_http(sock)
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
- read_http(sock)
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
+ result1 = read_http(sock)
+ assert result1.status == 'HTTP/1.1 200 OK'
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
+ result2 = read_http(sock)
+ assert result2.status == 'HTTP/1.1 200 OK'
+ assert result2.headers_lower['connection'] == 'close'
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
self.assertRaises(ConnectionClosed, read_http, sock)
- fd.close()
-
- @tests.skipped
- def test_005_run_apachebench(self):
- url = 'http://localhost:12346/'
- # ab is apachebench
- subprocess.call(
- [tests.find_command('ab'), '-c', '64', '-n', '1024', '-k', url],
- stdout=subprocess.PIPE)
def test_006_reject_long_urls(self):
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
path_parts = []
for ii in range(3000):
path_parts.append('path')
return [six.b('a is %s, body is %s' % (a, body))]
self.site.application = new_app
- sock = eventlet.connect(
- ('localhost', self.port))
- request = '\r\n'.join((
- 'POST / HTTP/1.0',
- 'Host: localhost',
- 'Content-Length: 3',
- '',
- 'a=a'))
- fd = sock.makefile('wb')
- fd.write(request.encode())
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ request = b'\r\n'.join((
+ b'POST / HTTP/1.0',
+ b'Host: localhost',
+ b'Content-Length: 3',
+ b'',
+ b'a=a'))
+ sock.sendall(request)
# send some junk after the actual request
- fd.write(b'01234567890123456789')
+ sock.sendall(b'01234567890123456789')
result = read_http(sock)
self.assertEqual(result.body, b'a is a, body is a=a')
- fd.close()
def test_008_correctresponse(self):
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('wb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
result_200 = read_http(sock)
- fd.write(b'GET /notexist HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock.sendall(b'GET /notexist HTTP/1.1\r\nHost: localhost\r\n\r\n')
read_http(sock)
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
result_test = read_http(sock)
self.assertEqual(result_200.status, result_test.status)
- fd.close()
- sock.close()
def test_009_chunked_response(self):
self.site.application = chunked_app
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
- assert b'Transfer-Encoding: chunked' in fd.read()
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
+ assert b'Transfer-Encoding: chunked' in recvall(sock)
def test_010_no_chunked_http_1_0(self):
self.site.application = chunked_app
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
- assert b'Transfer-Encoding: chunked' not in fd.read()
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n')
+ assert b'Transfer-Encoding: chunked' not in recvall(sock)
def test_011_multiple_chunks(self):
self.site.application = big_chunks
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
# Require a CRLF to close the message body
self.assertEqual(response, b'\r\n')
+ def test_partial_writes_are_handled(self):
+ # https://github.com/eventlet/eventlet/issues/295
+ # Eventlet issue: "Python 3: wsgi doesn't handle correctly partial
+ # write of socket send() when using writelines()".
+ #
+ # The bug was caused by the default writelines() implementaiton
+ # (used by the wsgi module) which doesn't check if write()
+ # successfully completed sending *all* data therefore data could be
+ # lost and the client could be left hanging forever.
+ #
+ # Switching wsgi wfile to buffered mode fixes the issue.
+ #
+ # Related CPython issue: "Raw I/O writelines() broken",
+ # http://bugs.python.org/issue26292
+ #
+ # Custom accept() and send() in order to simulate a connection that
+ # only sends one byte at a time so that any code that doesn't handle
+ # partial writes correctly has to fail.
+ listen_socket = eventlet.listen(('localhost', 0))
+ original_accept = listen_socket.accept
+
+ def accept():
+ connection, address = original_accept()
+ original_send = connection.send
+
+ def send(b, *args):
+ b = b[:1]
+ return original_send(b, *args)
+
+ connection.send = send
+ return connection, address
+
+ listen_socket.accept = accept
+
+ def application(env, start_response):
+ # Sending content-length is important here so that the client knows
+ # exactly how many bytes does it need to wait for.
+ start_response('200 OK', [('Content-length', 3)])
+ yield 'asd'
+
+ self.spawn_server(sock=listen_socket)
+ self.site.application = application
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
+ # This would previously hang forever
+ result = read_http(sock)
+ assert result.body == b'asd'
+
@tests.skip_if_no_ssl
def test_012_ssl_server(self):
def wsgi_app(environ, start_response):
server_side=True)
self.spawn_server(sock=server_sock, site=wsgi_app)
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock = eventlet.wrap_ssl(sock)
sock.write(
b'POST /foo HTTP/1.1\r\nHost: localhost\r\n'
def test_014_chunked_post(self):
self.site.application = chunked_post
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write('PUT /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n'
'Transfer-Encoding: chunked\r\n\r\n'
response = fd.read()
assert response == b'oh hai', 'invalid response %s' % response
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write('PUT /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n'
'Transfer-Encoding: chunked\r\n\r\n'
response = fd.read()
assert response == b'oh hai', 'invalid response %s' % response
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write('PUT /c HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n'
'Transfer-Encoding: chunked\r\n\r\n'
def test_015_write(self):
self.site.application = use_write
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('wb')
- fd.write(b'GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
result1 = read_http(sock)
assert 'content-length' in result1.headers_lower
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('wb')
- fd.write(b'GET /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
result2 = read_http(sock)
assert 'transfer-encoding' in result2.headers_lower
assert result2.headers_lower['transfer-encoding'] == 'chunked'
start_response('200 OK', [('Content-Length', '7')])
return [b'testing']
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write(b'GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
fd.flush()
def test_018_http_10_keepalive(self):
# verify that if an http/1.0 client sends connection: keep-alive
# that we don't close the connection
- sock = eventlet.connect(
- ('localhost', self.port))
-
- fd = sock.makefile('wb')
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
result1 = read_http(sock)
assert 'connection' in result1.headers_lower
self.assertEqual('keep-alive', result1.headers_lower['connection'])
+
# repeat request to verify connection is actually still open
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
- fd.flush()
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
result2 = read_http(sock)
assert 'connection' in result2.headers_lower
self.assertEqual('keep-alive', result2.headers_lower['connection'])
return [b'hello!']
self.site.application = use_fieldstorage
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('rwb')
- fd.write('POST / HTTP/1.1\r\n'
- 'Host: localhost\r\n'
- 'Connection: close\r\n'
- 'Transfer-Encoding: chunked\r\n\r\n'
- '2\r\noh\r\n'
- '4\r\n hai\r\n0\r\n\r\n'.encode())
- fd.flush()
- assert b'hello!' in fd.read()
+ sock.sendall(b'POST / HTTP/1.1\r\n'
+ b'Host: localhost\r\n'
+ b'Connection: close\r\n'
+ b'Transfer-Encoding: chunked\r\n\r\n'
+ b'2\r\noh\r\n'
+ b'4\r\n hai\r\n0\r\n\r\n')
+ assert b'hello!' in recvall(sock)
def test_020_x_forwarded_for(self):
request_bytes = (
+ b'X-Forwarded-For: 1.2.3.4, 5.6.7.8\r\n\r\n'
)
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(request_bytes)
sock.recv(1024)
sock.close()
self.logfile = six.StringIO()
self.spawn_server(log_x_forwarded_for=False)
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(request_bytes)
sock.recv(1024)
sock.close()
server_sock_2 = server_sock.dup()
self.spawn_server(sock=server_sock_2)
# do a single req/response to verify it's up
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
- fd.flush()
- result = fd.read(1024)
- fd.close()
+ sock = eventlet.connect(server_sock.getsockname())
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
+ result = sock.recv(1024)
assert result.startswith(b'HTTP'), result
assert result.endswith(b'hello world'), result
except socket.error as exc:
self.assertEqual(support.get_errno(exc), errno.EBADF)
self.spawn_server(sock=server_sock)
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
- fd.flush()
- result = fd.read(1024)
- fd.close()
+ sock = eventlet.connect(server_sock.getsockname())
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
+ result = sock.recv(1024)
assert result.startswith(b'HTTP'), result
assert result.endswith(b'hello world'), result
start_response('200 OK', [('Content-type', 'text/plain')])
return []
self.site.application = clobberin_time
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write('GET / HTTP/1.1\r\n'
- 'Host: localhost\r\n'
- 'Connection: close\r\n'
- '\r\n\r\n'.encode())
- fd.flush()
- assert b'200 OK' in fd.read()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.1\r\n'
+ b'Host: localhost\r\n'
+ b'Connection: close\r\n'
+ b'\r\n\r\n')
+ assert b'200 OK' in recvall(sock)
def test_022_custom_pool(self):
# just test that it accepts the parameter for now
self.spawn_server(custom_pool=p)
# this stuff is copied from test_001_server, could be better factored
- sock = eventlet.connect(
- ('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
- fd.flush()
- result = fd.read()
- fd.close()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
+ result = recvall(sock)
assert result.startswith(b'HTTP'), result
assert result.endswith(b'hello world'), result
def test_023_bad_content_length(self):
- sock = eventlet.connect(
- ('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nContent-length: argh\r\n\r\n')
- fd.flush()
- result = fd.read()
- fd.close()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nContent-length: argh\r\n\r\n')
+ result = recvall(sock)
assert result.startswith(b'HTTP'), result
assert b'400 Bad Request' in result, result
assert b'500' not in result, result
start_response('200 OK', [('Content-Length', str(len(text)))])
return [text]
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write(b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 1025\r\n'
b'Expect: 100-continue\r\n\r\n')
start_response('200 OK', [('Content-Length', str(len(text)))])
return [text]
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write(b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 1025\r\n'
b'Expect: 100-continue\r\n\r\n')
start_response('200 OK', [('Content-Length', str(len(text)))])
return [text]
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write(b'PUT /a HTTP/1.1\r\n'
b'Host: localhost\r\nConnection: close\r\n'
return [text]
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write(b'PUT /a HTTP/1.1\r\n'
b'Host: localhost\r\nConnection: close\r\n'
self.spawn_server(sock=listener)
eventlet.sleep(0) # need to enter server loop
try:
- eventlet.connect(('localhost', self.port))
+ eventlet.connect(self.server_addr)
self.fail("Didn't expect to connect")
except socket.error as exc:
self.assertEqual(support.get_errno(exc), errno.ECONNREFUSED)
def test_026_log_format(self):
self.spawn_server(log_format="HI %(request_line)s HI")
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(b'GET /yo! HTTP/1.1\r\nHost: localhost\r\n\r\n')
sock.recv(1024)
sock.close()
# and we're not speaking with a 1.1 client, that we
# close the connection
self.site.application = chunked_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
self.assertNotEqual(result.headers_lower.get('transfer-encoding'), 'chunked')
self.assertEqual(result.body, b"thisischunked")
+ def test_chunked_response_when_app_yields_empty_string(self):
+ def empty_string_chunked_app(env, start_response):
+ env['eventlet.minimum_write_chunk_size'] = 0 # no buffering
+ start_response('200 OK', [('Content-type', 'text/plain')])
+ return iter([b"stuff", b"", b"more stuff"])
+
+ self.site.application = empty_string_chunked_app
+ sock = eventlet.connect(self.server_addr)
+
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
+
+ result = read_http(sock)
+ self.assertEqual(result.headers_lower.get('transfer-encoding'), 'chunked')
+ self.assertEqual(result.body, b"5\r\nstuff\r\na\r\nmore stuff\r\n0\r\n\r\n")
+
def test_minimum_chunk_size_parameter_leaves_httpprotocol_class_member_intact(self):
start_size = wsgi.HttpProtocol.minimum_chunk_size
self.spawn_server(minimum_chunk_size=start_size * 2)
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
read_http(sock)
self.spawn_server(minimum_chunk_size=1)
self.site.application = chunked_fail_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
# verify that if an http/1.0 client sends connection: keep-alive
# and the server doesn't accept keep-alives, we close the connection
self.spawn_server(keepalive=False)
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
result = read_http(sock)
def test_027_keepalive_chunked(self):
self.site.application = chunked_post
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('wb')
+ sock = eventlet.connect(self.server_addr)
common_suffix = (
b'Host: localhost\r\nTransfer-Encoding: chunked\r\n\r\n' +
b'10\r\n0123456789abcdef\r\n0\r\n\r\n')
- fd.write(b'PUT /a HTTP/1.1\r\n' + common_suffix)
- fd.flush()
+ sock.sendall(b'PUT /a HTTP/1.1\r\n' + common_suffix)
read_http(sock)
- fd.write(b'PUT /b HTTP/1.1\r\n' + common_suffix)
- fd.flush()
+ sock.sendall(b'PUT /b HTTP/1.1\r\n' + common_suffix)
read_http(sock)
- fd.write(b'PUT /c HTTP/1.1\r\n' + common_suffix)
- fd.flush()
+ sock.sendall(b'PUT /c HTTP/1.1\r\n' + common_suffix)
read_http(sock)
- fd.write(b'PUT /a HTTP/1.1\r\n' + common_suffix)
- fd.flush()
+ sock.sendall(b'PUT /a HTTP/1.1\r\n' + common_suffix)
read_http(sock)
sock.close()
eventlet.listen(('localhost', 0)),
certfile=certificate_file, keyfile=private_key_file,
server_side=True)
- port = srv_sock.getsockname()[1]
+ addr = srv_sock.getsockname()
g = eventlet.spawn_n(server, srv_sock)
- client = eventlet.connect(('localhost', port))
+ client = eventlet.connect(addr)
if data: # send non-ssl request
client.sendall(data.encode())
else: # close sock prematurely
assert not errored[0], errored[0]
# make another request to ensure the server's still alive
try:
- client = ssl.wrap_socket(eventlet.connect(('localhost', port)))
+ client = ssl.wrap_socket(eventlet.connect(addr))
client.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
result = recvall(client)
assert result.startswith(b'HTTP'), result
start_response('200 OK', [('Content-Type', 'text/plain')])
yield b''
self.site.application = one_posthook_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fp = sock.makefile('rwb')
fp.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fp.flush()
start_response('200 OK', [('Content-Type', 'text/plain')])
yield b''
self.site.application = two_posthook_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fp = sock.makefile('rwb')
fp.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fp.flush()
self.assertEqual(posthook2_count[0], 25)
def test_030_reject_long_header_lines(self):
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
request = 'GET / HTTP/1.0\r\nHost: localhost\r\nLong: %s\r\n\r\n' % \
('a' * 10000)
send_expect_close(sock, request.encode())
self.assertEqual(result.status, 'HTTP/1.0 400 Header Line Too Long')
def test_031_reject_large_headers(self):
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
headers = ('Name: %s\r\n' % ('a' * 7000,)) * 20
request = 'GET / HTTP/1.0\r\nHost: localhost\r\n%s\r\n\r\n' % headers
send_expect_close(sock, request.encode())
'Host: localhost\r\n'
'Content-Length: %i\r\n\r\n%s'
) % (len(upload_data), bytes_to_str(upload_data))
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(request.encode())
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(request.encode())
result = read_http(sock)
self.assertEqual(result.body, upload_data)
- fd.close()
self.assertEqual(g[0], 1)
def test_zero_length_chunked_response(self):
yield b""
self.site.application = zero_chunked_app
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
- response = fd.read().split(b'\r\n')
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
+ response = recvall(sock).split(b'\r\n')
headers = []
while True:
h = response.pop(0)
def test_configurable_url_length_limit(self):
self.spawn_server(url_length_limit=20000)
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
path = 'x' * 15000
request = 'GET /%s HTTP/1.0\r\nHost: localhost\r\n\r\n' % path
fd = sock.makefile('rwb')
read_content.send(content)
start_response('200 OK', [('Content-Type', 'text/plain')])
return [content]
+
self.site.application = chunk_reader
expected_body = 'a bunch of stuff'
data = "\r\n".join(['PUT /somefile HTTP/1.0',
'def',
expected_body])
# start PUT-ing some chunked data but close prematurely
- sock = eventlet.connect(('127.0.0.1', self.port))
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(data.encode())
+ sock.close()
+ # the test passes if we successfully get here, and read all the data
+ # in spite of the early close
+ self.assertEqual(read_content.wait(), b'ok')
+ assert blew_up[0]
+
+ def test_aborted_chunked_post_between_chunks(self):
+ read_content = event.Event()
+ blew_up = [False]
+
+ def chunk_reader(env, start_response):
+ try:
+ content = env['wsgi.input'].read(1024)
+ except wsgi.ChunkReadError:
+ blew_up[0] = True
+ content = b'ok'
+ except Exception as err:
+ blew_up[0] = True
+ content = b'wrong exception: ' + str(err).encode()
+ read_content.send(content)
+ start_response('200 OK', [('Content-Type', 'text/plain')])
+ return [content]
+ self.site.application = chunk_reader
+ expected_body = 'A' * 0xdb
+ data = "\r\n".join(['PUT /somefile HTTP/1.0',
+ 'Transfer-Encoding: chunked',
+ '',
+ 'db',
+ expected_body])
+ # start PUT-ing some chunked data but close prematurely
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(data.encode())
+ sock.close()
+ # the test passes if we successfully get here, and read all the data
+ # in spite of the early close
+ self.assertEqual(read_content.wait(), b'ok')
+ assert blew_up[0]
+
+ def test_aborted_chunked_post_bad_chunks(self):
+ read_content = event.Event()
+ blew_up = [False]
+
+ def chunk_reader(env, start_response):
+ try:
+ content = env['wsgi.input'].read(1024)
+ except wsgi.ChunkReadError:
+ blew_up[0] = True
+ content = b'ok'
+ except Exception as err:
+ blew_up[0] = True
+ content = b'wrong exception: ' + str(err).encode()
+ read_content.send(content)
+ start_response('200 OK', [('Content-Type', 'text/plain')])
+ return [content]
+ self.site.application = chunk_reader
+ expected_body = 'look here is some data for you'
+ data = "\r\n".join(['PUT /somefile HTTP/1.0',
+ 'Transfer-Encoding: chunked',
+ '',
+ 'cats',
+ expected_body])
+ # start PUT-ing some garbage
+ sock = eventlet.connect(self.server_addr)
sock.sendall(data.encode())
sock.close()
# the test passes if we successfully get here, and read all the data
def wsgi_app(environ, start_response):
raise RuntimeError("intentional error")
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
result = read_http(sock)
self.assertEqual(result.status, 'HTTP/1.1 500 Internal Server Error')
self.assertEqual(result.headers_lower['connection'], 'close')
yield b"oh hai, "
yield u"xxx"
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
result = read_http(sock)
assert b'xxx' in result.body
yield b"oh hai, "
yield u"xxx \u0230"
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
result = read_http(sock)
self.assertEqual(result.status, 'HTTP/1.1 500 Internal Server Error')
self.assertEqual(result.headers_lower['connection'], 'close')
yield six.b("decoded: %s" % environ['PATH_INFO'])
yield six.b("raw: %s" % environ['RAW_PATH_INFO'])
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET /a*b@%40%233 HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET /a*b@%40%233 HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
result = read_http(sock)
self.assertEqual(result.status, 'HTTP/1.1 200 OK')
assert b'decoded: /a*b@@#3' in result.body
raise RuntimeError("intentional crash")
self.site.application = crasher
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('wb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
result1 = read_http(sock)
self.assertEqual(result1.status, 'HTTP/1.1 500 Internal Server Error')
self.assertEqual(result1.body, b'')
# verify traceback when debugging enabled
self.spawn_server(debug=True)
self.site.application = crasher
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('wb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
result2 = read_http(sock)
self.assertEqual(result2.status, 'HTTP/1.1 500 Internal Server Error')
assert b'intentional crash' in result2.body, result2.body
yield b'a' * 9876
server_sock = eventlet.listen(('localhost', 0))
- self.port = server_sock.getsockname()[1]
+ self.server_addr = server_sock.getsockname()
server = wsgi.Server(server_sock, server_sock.getsockname(), long_response,
log=self.logfile)
def test_server_socket_timeout(self):
self.spawn_server(socket_timeout=0.1)
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.send(b'GET / HTTP/1.1\r\n')
eventlet.sleep(0.1)
try:
self.spawn_server(site=wsgi_app, capitalize_response_headers=False)
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
result = read_http(sock)
sock.close()
self.assertEqual(result.headers_lower[random_case_header[0].lower()], random_case_header[1])
self.assertEqual(result.headers_original[random_case_header[0]], random_case_header[1])
+ def test_log_unix_address(self):
+ tempdir = tempfile.mkdtemp('eventlet_test_log_unix_address')
+ path = ''
+ try:
+ sock = eventlet.listen(tempdir + '/socket', socket.AF_UNIX)
+ path = sock.getsockname()
+
+ log = six.StringIO()
+ self.spawn_server(sock=sock, log=log)
+ eventlet.sleep(0) # need to enter server loop
+ assert 'http:' + path in log.getvalue()
+ finally:
+ shutil.rmtree(tempdir)
+
def read_headers(sock):
fd = sock.makefile('rb')
def test_iterable_app_keeps_socket_open_unless_connection_close_sent(self):
self.site.application = self.get_app()
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
-
- fd.flush()
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
response_line, headers = read_headers(sock)
self.assertEqual(response_line, 'HTTP/1.1 200 OK\r\n')
assert 'connection' not in headers
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
+
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
result = read_http(sock)
self.assertEqual(result.status, 'HTTP/1.1 200 OK')
self.assertEqual(result.headers_lower.get('transfer-encoding'), 'chunked')
class TestChunkedInput(_TestBase):
- dirt = ""
validator = None
def application(self, env, start_response):
return response
def connect(self):
- return eventlet.connect(('localhost', self.port))
+ return eventlet.connect(self.server_addr)
def set_site(self):
self.site = Site()
self.site.application = self.application
- def chunk_encode(self, chunks, dirt=None):
- if dirt is None:
- dirt = self.dirt
-
+ def chunk_encode(self, chunks, dirt=""):
b = ""
for c in chunks:
b += "%x%s\r\n%s\r\n" % (len(c), dirt, c)
return b
- def body(self, dirt=None):
+ def body(self, dirt=""):
return self.chunk_encode(["this", " is ", "chunked", "\nline",
" 2", "\n", "line3", ""], dirt=dirt)
pep8 benchmarks/ eventlet/ tests/
[testenv]
-downloadcache = {toxworkdir}/pip_download_cache
+passenv = TRAVIS*
setenv =
PYTHONDONTWRITEBYTECODE = 1
selects: EVENTLET_HUB = selects