diff -Nru python-eventlet-0.20.0/AUTHORS python-eventlet-0.24.1/AUTHORS --- python-eventlet-0.20.0/AUTHORS 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/AUTHORS 2018-08-06 16:17:47.000000000 +0000 @@ -140,3 +140,29 @@ * Ondřej Nový * Jarrod Johnson * Whitney Young +* Matthew D. Pagel +* Matt Yule-Bennett +* Artur Stawiarski +* Tal Wrii +* Roman Podoliaka +* Gevorg Davoian +* Ondřej Kobližek +* Yuichi Bando +* Feng +* Aayush Kasurde +* Linbing +* Geoffrey Thomas +* Costas Christofi, adding permessage-deflate weboscket extension support +* Peter Kovary, adding permessage-deflate weboscket extension support +* Konstantin Enchant +* James Page +* Stefan Nica +* Haikel Guemar +* Miguel Grinberg +* Chris Kerr +* Anthony Sottile +* Quan Tian +* orishoshan +* Matt Bennett +* Ralf Haferkamp +* Jake Tesler diff -Nru python-eventlet-0.20.0/benchmarks/context.py python-eventlet-0.24.1/benchmarks/context.py --- python-eventlet-0.20.0/benchmarks/context.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/benchmarks/context.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -"""Test context switching performance of threading and eventlet""" -from __future__ import print_function - -import threading -import time - -import eventlet -from eventlet import hubs -from eventlet.hubs import pyevent, epolls, poll, selects - - -CONTEXT_SWITCHES = 100000 - - -def run(event, wait_event): - counter = 0 - while counter <= CONTEXT_SWITCHES: - wait_event.wait() - wait_event.reset() - counter += 1 - event.send() - - -def test_eventlet(): - event1 = eventlet.event.Event() - event2 = eventlet.event.Event() - event1.send() - thread1 = eventlet.spawn(run, event1, event2) - thread2 = eventlet.spawn(run, event2, event1) - - thread1.wait() - thread2.wait() - - -class BenchThread(threading.Thread): - def __init__(self, event, wait_event): - threading.Thread.__init__(self) - self.counter = 0 - self.event = event - self.wait_event = wait_event - - def run(self): - while self.counter <= CONTEXT_SWITCHES: - self.wait_event.wait() - self.wait_event.clear() - self.counter += 1 - self.event.set() - - -def test_thread(): - event1 = threading.Event() - event2 = threading.Event() - event1.set() - thread1 = BenchThread(event1, event2) - thread2 = BenchThread(event2, event1) - thread1.start() - thread2.start() - thread1.join() - thread2.join() - - -print("Testing with %d context switches" % CONTEXT_SWITCHES) -start = time.time() -test_thread() -print("threading: %.02f seconds" % (time.time() - start)) - -try: - hubs.use_hub(pyevent) - start = time.time() - test_eventlet() - print("pyevent: %.02f seconds" % (time.time() - start)) -except: - print("pyevent hub unavailable") - -try: - hubs.use_hub(epolls) - start = time.time() - test_eventlet() - print("epoll: %.02f seconds" % (time.time() - start)) -except: - print("epoll hub unavailable") - -try: - hubs.use_hub(poll) - start = time.time() - test_eventlet() - print("poll: %.02f seconds" % (time.time() - start)) -except: - print("poll hub unavailable") - -try: - hubs.use_hub(selects) - start = time.time() - test_eventlet() - print("select: %.02f seconds" % (time.time() - start)) -except: - print("select hub unavailable") diff -Nru python-eventlet-0.20.0/benchmarks/hub_timers.py python-eventlet-0.24.1/benchmarks/hub_timers.py --- python-eventlet-0.20.0/benchmarks/hub_timers.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/benchmarks/hub_timers.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -#! /usr/bin/env python -from __future__ import print_function - -# test timer adds & expires on hubs.hub.BaseHub - -import sys -import eventlet -import random -import time - -from eventlet.hubs import timer, get_hub -from eventlet.support import six - - -timer_count = 100000 - -if len(sys.argv) >= 2: - timer_count = int(sys.argv[1]) - -l = [] - - -def work(n): - l.append(n) - -timeouts = [random.uniform(0, 10) for x in six.moves.range(timer_count)] - -hub = get_hub() - -start = time.time() - -scheduled = [] - -for timeout in timeouts: - t = timer.Timer(timeout, work, timeout) - t.schedule() - - scheduled.append(t) - -hub.prepare_timers() -hub.fire_timers(time.time() + 11) -hub.prepare_timers() - -end = time.time() - -print("Duration: %f" % (end - start,)) diff -Nru python-eventlet-0.20.0/benchmarks/__init__.py python-eventlet-0.24.1/benchmarks/__init__.py --- python-eventlet-0.20.0/benchmarks/__init__.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/benchmarks/__init__.py 2018-08-06 16:17:47.000000000 +0000 @@ -2,7 +2,7 @@ import timeit import random -from eventlet.support import six +import six def measure_best(repeat, iters, diff -Nru python-eventlet-0.20.0/benchmarks/localhost_socket.py python-eventlet-0.24.1/benchmarks/localhost_socket.py --- python-eventlet-0.20.0/benchmarks/localhost_socket.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/benchmarks/localhost_socket.py 2018-08-06 16:17:47.000000000 +0000 @@ -4,7 +4,7 @@ import time import benchmarks -from eventlet.support import six +import six BYTES = 1000 diff -Nru python-eventlet-0.20.0/benchmarks/spawn_plot.py python-eventlet-0.24.1/benchmarks/spawn_plot.py --- python-eventlet-0.20.0/benchmarks/spawn_plot.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/benchmarks/spawn_plot.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,101 +0,0 @@ -#!/usr/bin/env python -''' - Compare spawn to spawn_n, among other things. - - This script will generate a number of "properties" files for the - Hudson plot plugin -''' - -import os -import eventlet -import benchmarks - -DATA_DIR = 'plot_data' - -if not os.path.exists(DATA_DIR): - os.makedirs(DATA_DIR) - - -def write_result(filename, best): - fd = open(os.path.join(DATA_DIR, filename), 'w') - fd.write('YVALUE=%s' % best) - fd.close() - - -def cleanup(): - eventlet.sleep(0.2) - -iters = 10000 -best = benchmarks.measure_best( - 5, iters, - 'pass', - cleanup, - eventlet.sleep) - -write_result('eventlet.sleep_main', best[eventlet.sleep]) - -gt = eventlet.spawn( - benchmarks.measure_best, 5, iters, - 'pass', - cleanup, - eventlet.sleep) -best = gt.wait() -write_result('eventlet.sleep_gt', best[eventlet.sleep]) - - -def dummy(i=None): - return i - - -def run_spawn(): - eventlet.spawn(dummy, 1) - - -def run_spawn_n(): - eventlet.spawn_n(dummy, 1) - - -def run_spawn_n_kw(): - eventlet.spawn_n(dummy, i=1) - - -best = benchmarks.measure_best( - 5, iters, - 'pass', - cleanup, - run_spawn_n, - run_spawn, - run_spawn_n_kw) -write_result('eventlet.spawn', best[run_spawn]) -write_result('eventlet.spawn_n', best[run_spawn_n]) -write_result('eventlet.spawn_n_kw', best[run_spawn_n_kw]) - -pool = None - - -def setup(): - global pool - pool = eventlet.GreenPool(iters) - - -def run_pool_spawn(): - pool.spawn(dummy, 1) - - -def run_pool_spawn_n(): - pool.spawn_n(dummy, 1) - - -def cleanup_pool(): - pool.waitall() - - -best = benchmarks.measure_best( - 3, iters, - setup, - cleanup_pool, - run_pool_spawn, - run_pool_spawn_n, -) -write_result('eventlet.GreenPool.spawn', best[run_pool_spawn]) -write_result('eventlet.GreenPool.spawn_n', best[run_pool_spawn_n]) diff -Nru python-eventlet-0.20.0/bin/build-website.bash python-eventlet-0.24.1/bin/build-website.bash --- python-eventlet-0.20.0/bin/build-website.bash 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/bin/build-website.bash 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -#!/bin/bash -set -e - -build="$PWD/website-build" -usage="Builds eventlet.net website static pages into ${build}. -Requires sphinx-build, git and Github account. - - --no-commit Just build HTML, skip any git operations." - -commit=1 -while [ -n "$1" ]; do - case $1 in - --no-commit) - commit=0 - ;; - *) - echo "$usage" >&2 - exit 1 - ;; - esac - shift -done - -if ! which sphinx-build >/dev/null; then - echo "sphinx-build not found. Possible solution: pip install sphinx" >&2 - echo "Links: http://sphinx-doc.org/" >&2 - exit 1 -fi - -if [ $commit -eq 1 ] && ! git status >/dev/null; then - echo "git not found. git and Github account are required to update online documentation." >&2 - echo "Links: http://git-scm.com/ https://github.com/" >&2 - exit 1 -fi - -echo "1. clean" -rm -rf "$build" -mkdir -p "$build/doc" - -echo "2. build static pages" -cp doc/real_index.html "$build/index.html" -cp NEWS doc/changelog.rst - -# -b html -- builder, output mode -# -d dir -- path to doctrees cache -# -n -- nit-picky mode (kind of -Wall for gcc) -# -W -- turns warnings into errors -# -q -- quiet, emit only warnings and errors -sphinx-build -b html -d "$build/tmp" -n -q "doc" "$build/doc" -rm -rf "$build/tmp" -rm -f "$build/doc/.buildinfo" -rm -f "doc/changelog.rst" - -if [ $commit -eq 1 ]; then - echo "3. Updating git branch gh-pages" - 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 - rm -rf "doc" - - mv "$build"/* ./ - touch ".nojekyll" - echo "eventlet.net" >"CNAME" - rmdir "$build" - - echo "4. Commit" - git add -A - 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" -fi diff -Nru python-eventlet-0.20.0/bin/pull-dnspython python-eventlet-0.24.1/bin/pull-dnspython --- python-eventlet-0.20.0/bin/pull-dnspython 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/bin/pull-dnspython 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -#!/bin/bash -eux -cd "$( dirname "${BASH_SOURCE[0]}" )/.." -version=${1-bb0c9f21f4a6f56f2fe8d7c1fc991080ef89d223} -upstream_path=./dnspython-${version} -if [[ ! -d "${upstream_path}" ]]; then - curl -L -odnspython.zip "https://github.com/rthalley/dnspython/archive/${version}.zip" - unzip dnspython.zip - rm dnspython.zip -fi -rm -rf eventlet/support/dns -# patch --directory=eventlet/support -p1 --normal --forward -r/dev/null <./dns.patch -mv ${upstream_path}/dns eventlet/support/ -rm -rf ${upstream_path} diff -Nru python-eventlet-0.20.0/bin/release python-eventlet-0.24.1/bin/release --- python-eventlet-0.20.0/bin/release 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/bin/release 1970-01-01 00:00:00.000000000 +0000 @@ -1,163 +0,0 @@ -#!/bin/bash -e -cd "$( dirname "${BASH_SOURCE[0]}" )/.." -if [[ ! -d venv-release ]]; then - virtualenv venv-release - echo '*' >venv-release/.gitignore - 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 "\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. 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 "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 - git checkout "$branch" - fi - - if confirm "Upload to PyPi? [Yn] "; then - rm -rf build dist - python setup.py sdist bdist_wheel register upload || exit 1 - fi - - git push --verbose origin master gh-pages || exit 1 - git push --tags -} - -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() { - 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 -} - -main "$@" diff -Nru python-eventlet-0.20.0/debian/changelog python-eventlet-0.24.1/debian/changelog --- python-eventlet-0.20.0/debian/changelog 2018-09-30 12:39:27.000000000 +0000 +++ python-eventlet-0.24.1/debian/changelog 2018-12-21 14:16:24.000000000 +0000 @@ -1,3 +1,38 @@ +python-eventlet (0.24.1-0ubuntu3) disco; urgency=medium + + * d/p/0016-*.patch: Replace patch with proper fix cherry-picked from + upstream master branch (LP: #1809033). + + -- Corey Bryant Fri, 21 Dec 2018 09:16:24 -0500 + +python-eventlet (0.24.1-0ubuntu2) disco; urgency=medium + + * d/p/0016-endheaders-py27-work-around.patch: Patch the endheaders + method definition to drop the "*" parameter for now as it is not + valid for Python 2.7 (LP: #1809033). + + -- Corey Bryant Tue, 18 Dec 2018 14:58:36 -0500 + +python-eventlet (0.24.1-0ubuntu1) disco; urgency=medium + + * d/gbp.conf: Update gbp configuration file. + * d/control: Update Vcs-* links and maintainers. + * New upstream release. + * d/control: Align (Build-)Depends with upstream. + * d/p/0003-Allow-more-busy-CPU.patch, + d/p/0009-Removed-test_urllib-that-is-failing-in-py36.patch, + d/p/0014-Fix-for-Python-3.7.patch: Rebased. + * d/p/0007-Patched-test_getaddrinfo-due-netbase-update.patch, + d/p/0008-Disable-test_server_connection_timeout_exception.patch, + d/p/0012-ssl-RecursionError-on-Python3.6.patch: Dropped. Fixed in new + upstream release. + * d/p/0005-Removed-failing-test.patch, + d/p/0011-Avoid-dependency-on-enum-compat.patch: Dropped. No longer needed. + * d/p/0015-IMPORTANT-late-import-in-use_hub-thread-race-caused-.patch: + Cherry-picked from upstream master branch. + + -- Corey Bryant Mon, 17 Dec 2018 08:38:17 -0500 + python-eventlet (0.20.0-5) unstable; urgency=medium * Don't reset http{,s}_proxy, pybuild sets it correctly diff -Nru python-eventlet-0.20.0/debian/control python-eventlet-0.24.1/debian/control --- python-eventlet-0.20.0/debian/control 2018-09-30 12:29:54.000000000 +0000 +++ python-eventlet-0.24.1/debian/control 2018-12-21 14:16:24.000000000 +0000 @@ -1,7 +1,8 @@ Source: python-eventlet Section: python Priority: optional -Maintainer: Debian Python Modules Team +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Debian Python Modules Team Uploaders: Thomas Goirand , Ondřej Nový , @@ -19,27 +20,34 @@ python-enum34, python-greenlet, python-httplib2, + python-monotonic, python-nose, python-openssl, + python-six, python-subprocess32, python-zmq, python3-dnspython, python3-greenlet, python3-httplib2, + python3-monotonic, python3-nose, python3-openssl, + python3-six, python3-zmq, Standards-Version: 4.2.1 -Vcs-Browser: https://salsa.debian.org/python-team/modules/python-eventlet -Vcs-Git: https://salsa.debian.org/python-team/modules/python-eventlet.git +Vcs-Browser: https://git.launchpad.net/~ubuntu-server-dev/ubuntu/+source/python-eventlet +Vcs-Git: https://git.launchpad.net/~ubuntu-server-dev/ubuntu/+source/python-eventlet Homepage: http://eventlet.net Package: python-eventlet Architecture: all Depends: netbase, + python-dnspython, python-enum34, python-greenlet, + python-monotonic, + python-six, ${misc:Depends}, ${python:Depends}, Suggests: @@ -84,7 +92,10 @@ Architecture: all Depends: netbase, + python3-dnspython, python3-greenlet, + python3-monotonic, + python3-six, ${misc:Depends}, ${python3:Depends}, ${sphinxdoc:Depends}, diff -Nru python-eventlet-0.20.0/debian/gbp.conf python-eventlet-0.24.1/debian/gbp.conf --- python-eventlet-0.20.0/debian/gbp.conf 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/debian/gbp.conf 2018-12-21 14:16:24.000000000 +0000 @@ -0,0 +1,7 @@ +[DEFAULT] +debian-branch = master +upstream-tag = %(version)s +pristine-tar = True + +[buildpackage] +export-dir = ../build-area diff -Nru python-eventlet-0.20.0/debian/patches/0003-Allow-more-busy-CPU.patch python-eventlet-0.24.1/debian/patches/0003-Allow-more-busy-CPU.patch --- python-eventlet-0.20.0/debian/patches/0003-Allow-more-busy-CPU.patch 2018-05-10 18:27:24.000000000 +0000 +++ python-eventlet-0.24.1/debian/patches/0003-Allow-more-busy-CPU.patch 2018-12-21 14:16:24.000000000 +0000 @@ -11,28 +11,26 @@ tests/zmq_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) -diff --git a/tests/zmq_test.py b/tests/zmq_test.py -index 2910c11..e925038 100644 --- a/tests/zmq_test.py +++ b/tests/zmq_test.py -@@ -448,7 +448,7 @@ class TestUpstreamDownStream(tests.LimitedTestCase): +@@ -449,7 +449,7 @@ self.sockets.append(sock) sock.bind_to_random_port("tcp://127.0.0.1") - sleep() + eventlet.sleep() - tests.check_idle_cpu_usage(0.2, 0.1) + tests.check_idle_cpu_usage(0.2, 0.2) @tests.skip_unless(zmq_supported) def test_cpu_usage_after_pub_send_or_dealer_recv(self): -@@ -460,14 +460,14 @@ class TestUpstreamDownStream(tests.LimitedTestCase): +@@ -461,14 +461,14 @@ sub.setsockopt(zmq.SUBSCRIBE, b"") - sleep() + eventlet.sleep() pub.send(b'test_send') - tests.check_idle_cpu_usage(0.2, 0.1) + tests.check_idle_cpu_usage(0.2, 0.2) sender, receiver, _port = self.create_bound_pair(zmq.DEALER, zmq.DEALER) - sleep() + eventlet.sleep() sender.send(b'test_recv') msg = receiver.recv() self.assertEqual(msg, b'test_recv') diff -Nru python-eventlet-0.20.0/debian/patches/0005-Removed-failing-test.patch python-eventlet-0.24.1/debian/patches/0005-Removed-failing-test.patch --- python-eventlet-0.20.0/debian/patches/0005-Removed-failing-test.patch 2018-05-10 18:27:24.000000000 +0000 +++ python-eventlet-0.24.1/debian/patches/0005-Removed-failing-test.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -From b51e359bd18a8f625c50becd55fa455c183c6f94 Mon Sep 17 00:00:00 2001 -From: Thomas Goirand -Date: Fri, 4 Aug 2017 21:47:20 +0200 -Subject: Removed failing test - - This test fails in Sid. -Forwarded: no -Last-Update: 2016-10-07 ---- - tests/patcher_test.py | 22 ---------------------- - 1 file changed, 22 deletions(-) - -diff --git a/tests/patcher_test.py b/tests/patcher_test.py -index fb9c19b..f1c8c34 100644 ---- a/tests/patcher_test.py -+++ b/tests/patcher_test.py -@@ -82,28 +82,6 @@ class ImportPatched(ProcessBase): - assert 'eventlet.green.urllib' in lines[2], repr(output) - assert 'eventlet.green.httplib' not in lines[2], repr(output) - -- def test_import_patched_defaults(self): -- self.write_to_tempfile("base", """ --import socket --try: -- import urllib.request as urllib --except ImportError: -- import urllib --print("base {0} {1}".format(socket, urllib))""") -- -- new_mod = """ --from eventlet import patcher --base = patcher.import_patched('base') --print("newmod {0} {1} {2}".format(base, base.socket, base.urllib.socket.socket)) --""" -- self.write_to_tempfile("newmod", new_mod) -- output, lines = self.launch_subprocess('newmod.py') -- assert lines[0].startswith('base'), repr(output) -- assert lines[1].startswith('newmod'), repr(output) -- assert 'eventlet.green.socket' in lines[1], repr(output) -- assert 'GreenSocket' in lines[1], repr(output) -- -- - class MonkeyPatch(ProcessBase): - def test_patched_modules(self): - new_mod = """ diff -Nru python-eventlet-0.20.0/debian/patches/0007-Patched-test_getaddrinfo-due-netbase-update.patch python-eventlet-0.24.1/debian/patches/0007-Patched-test_getaddrinfo-due-netbase-update.patch --- python-eventlet-0.20.0/debian/patches/0007-Patched-test_getaddrinfo-due-netbase-update.patch 2018-05-10 18:27:24.000000000 +0000 +++ python-eventlet-0.24.1/debian/patches/0007-Patched-test_getaddrinfo-due-netbase-update.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -From d344d2b3587c669e087dc9169822c6c34e488886 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Ond=C5=99ej=20Kobli=C5=BEek?= -Date: Fri, 4 Aug 2017 21:47:22 +0200 -Subject: Patched test_getaddrinfo due netbase update - - Asserting udp for ssh introduce test failures with netbase 5.4 - because removed ssh (22/udp). - This fix changes ssh -> domain, which better suit for test name and - allows tcp and udp simultaneously. -Forwarded: https://github.com/eventlet/eventlet/pull/375 ---- - tests/greendns_test.py | 18 +++++++++--------- - 1 file changed, 9 insertions(+), 9 deletions(-) - -diff --git a/tests/greendns_test.py b/tests/greendns_test.py -index cf17999..6ffc28f 100644 ---- a/tests/greendns_test.py -+++ b/tests/greendns_test.py -@@ -458,11 +458,11 @@ class TestGetaddrinfo(tests.LimitedTestCase): - greendns.resolve = _make_mock_resolve() - greendns.resolve.add('example.com', '127.0.0.2') - greendns.resolve.add('example.com', '::1') -- res = greendns.getaddrinfo('example.com', 'ssh') -- addr = ('127.0.0.2', 22) -+ res = greendns.getaddrinfo('example.com', 'domain') -+ addr = ('127.0.0.2', 53) - tcp = (socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, addr) - udp = (socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP, addr) -- addr = ('::1', 22, 0, 0) -+ addr = ('::1', 53, 0, 0) - tcp6 = (socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_TCP, addr) - udp6 = (socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP, addr) - filt_res = [ai[:3] + (ai[4],) for ai in res] -@@ -475,8 +475,8 @@ class TestGetaddrinfo(tests.LimitedTestCase): - greendns.resolve = _make_mock_resolve() - idn_name = u'евентлет.com' - greendns.resolve.add(idn_name.encode('idna').decode('ascii'), '127.0.0.2') -- res = greendns.getaddrinfo(idn_name, 'ssh') -- addr = ('127.0.0.2', 22) -+ res = greendns.getaddrinfo(idn_name, 'domain') -+ addr = ('127.0.0.2', 53) - tcp = (socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, addr) - udp = (socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP, addr) - filt_res = [ai[:3] + (ai[4],) for ai in res] -@@ -486,8 +486,8 @@ class TestGetaddrinfo(tests.LimitedTestCase): - def test_getaddrinfo_inet(self): - greendns.resolve = _make_mock_resolve() - greendns.resolve.add('example.com', '127.0.0.2') -- res = greendns.getaddrinfo('example.com', 'ssh', socket.AF_INET) -- addr = ('127.0.0.2', 22) -+ res = greendns.getaddrinfo('example.com', 'domain', socket.AF_INET) -+ addr = ('127.0.0.2', 53) - tcp = (socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, addr) - udp = (socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP, addr) - assert tcp in [ai[:3] + (ai[4],) for ai in res] -@@ -496,8 +496,8 @@ class TestGetaddrinfo(tests.LimitedTestCase): - def test_getaddrinfo_inet6(self): - greendns.resolve = _make_mock_resolve() - greendns.resolve.add('example.com', '::1') -- res = greendns.getaddrinfo('example.com', 'ssh', socket.AF_INET6) -- addr = ('::1', 22, 0, 0) -+ res = greendns.getaddrinfo('example.com', 'domain', socket.AF_INET6) -+ addr = ('::1', 53, 0, 0) - tcp = (socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_TCP, addr) - udp = (socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP, addr) - assert tcp in [ai[:3] + (ai[4],) for ai in res] diff -Nru python-eventlet-0.20.0/debian/patches/0008-Disable-test_server_connection_timeout_exception.patch python-eventlet-0.24.1/debian/patches/0008-Disable-test_server_connection_timeout_exception.patch --- python-eventlet-0.20.0/debian/patches/0008-Disable-test_server_connection_timeout_exception.patch 2018-05-10 18:27:24.000000000 +0000 +++ python-eventlet-0.24.1/debian/patches/0008-Disable-test_server_connection_timeout_exception.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -From 9b3a864614dd2f88157b6e10ed6dc48436c3559d Mon Sep 17 00:00:00 2001 -From: Thomas Goirand -Date: Fri, 4 Aug 2017 21:47:23 +0200 -Subject: Disable test_server_connection_timeout_exception() - - As per the bug report, the test is non-deterministic. Therefore, - remove it it. -Bug-Debian: https://bugs.debian.org/857893 -Forwarded: no -Last-Update: 2017-03-16 ---- - tests/wsgi_test.py | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/tests/wsgi_test.py b/tests/wsgi_test.py -index bc581a8..a22e688 100644 ---- a/tests/wsgi_test.py -+++ b/tests/wsgi_test.py -@@ -1477,11 +1477,11 @@ class TestHttpd(_TestBase): - request_thread.wait() - server_sock.close() - -- def test_server_connection_timeout_exception(self): -- # Handle connection socket timeouts -- # https://bitbucket.org/eventlet/eventlet/issue/143/ -- # Runs tests.wsgi_test_conntimeout in a separate process. -- tests.run_isolated('wsgi_connection_timeout.py') -+# def test_server_connection_timeout_exception(self): -+# # Handle connection socket timeouts -+# # https://bitbucket.org/eventlet/eventlet/issue/143/ -+# # Runs tests.wsgi_test_conntimeout in a separate process. -+# tests.run_isolated('wsgi_connection_timeout.py') - - def test_server_socket_timeout(self): - self.spawn_server(socket_timeout=0.1) diff -Nru python-eventlet-0.20.0/debian/patches/0009-Removed-test_urllib-that-is-failing-in-py36.patch python-eventlet-0.24.1/debian/patches/0009-Removed-test_urllib-that-is-failing-in-py36.patch --- python-eventlet-0.20.0/debian/patches/0009-Removed-test_urllib-that-is-failing-in-py36.patch 2018-05-10 18:27:25.000000000 +0000 +++ python-eventlet-0.24.1/debian/patches/0009-Removed-test_urllib-that-is-failing-in-py36.patch 2018-12-21 14:16:24.000000000 +0000 @@ -8,9 +8,6 @@ 1 file changed, 51 deletions(-) delete mode 100644 tests/test__greenness.py -diff --git a/tests/test__greenness.py b/tests/test__greenness.py -deleted file mode 100644 -index 37a77d7..0000000 --- a/tests/test__greenness.py +++ /dev/null @@ -1,51 +0,0 @@ @@ -20,7 +17,7 @@ -""" -import eventlet -from eventlet.green import BaseHTTPServer --from eventlet.support import six +-import six - -if six.PY2: - from eventlet.green.urllib2 import HTTPError, urlopen diff -Nru python-eventlet-0.20.0/debian/patches/0011-Avoid-dependency-on-enum-compat.patch python-eventlet-0.24.1/debian/patches/0011-Avoid-dependency-on-enum-compat.patch --- python-eventlet-0.20.0/debian/patches/0011-Avoid-dependency-on-enum-compat.patch 2018-05-10 18:27:24.000000000 +0000 +++ python-eventlet-0.24.1/debian/patches/0011-Avoid-dependency-on-enum-compat.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -From 5bc467c897fea2010d4c105147435f530e508493 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= -Date: Fri, 1 Dec 2017 13:02:13 +0100 -Subject: Avoid dependency on enum-compat - ---- - setup.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/setup.py b/setup.py -index 6e16e16..f741c55 100644 ---- a/setup.py -+++ b/setup.py -@@ -13,7 +13,7 @@ setup( - url='http://eventlet.net', - packages=find_packages(exclude=['benchmarks', 'tests', 'tests.*']), - install_requires=( -- 'enum-compat', -+ 'enum34;python_version<"3.4"', - 'greenlet >= 0.3', - ), - zip_safe=False, diff -Nru python-eventlet-0.20.0/debian/patches/0012-ssl-RecursionError-on-Python3.6.patch python-eventlet-0.24.1/debian/patches/0012-ssl-RecursionError-on-Python3.6.patch --- python-eventlet-0.20.0/debian/patches/0012-ssl-RecursionError-on-Python3.6.patch 2018-05-10 18:27:25.000000000 +0000 +++ python-eventlet-0.24.1/debian/patches/0012-ssl-RecursionError-on-Python3.6.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -From 0609b79275ad55e05c2a7dd6d167b1b97b605f52 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= -Date: Thu, 10 May 2018 20:26:59 +0200 -Subject: ssl: RecursionError on Python3.6+ - -Origin: https://github.com/eventlet/eventlet/commit/de06878e5a295bfbbddca0048c3453d16168a676 ---- - eventlet/green/ssl.py | 20 ++++++++++++++++++++ - tests/isolated/green_ssl_py36_properties.py | 16 ++++++++++++++++ - 2 files changed, 36 insertions(+) - create mode 100644 tests/isolated/green_ssl_py36_properties.py - -diff --git a/eventlet/green/ssl.py b/eventlet/green/ssl.py -index d7fbef7..a5a2062 100644 ---- a/eventlet/green/ssl.py -+++ b/eventlet/green/ssl.py -@@ -401,6 +401,26 @@ if hasattr(__ssl, 'SSLContext'): - def wrap_socket(self, sock, *a, **kw): - return GreenSSLSocket(sock, *a, _context=self, **kw) - -+ # https://github.com/eventlet/eventlet/issues/371 -+ # Thanks to Gevent developers for sharing patch to this problem. -+ if hasattr(_original_sslcontext.options, 'setter'): -+ # In 3.6, these became properties. They want to access the -+ # property __set__ method in the superclass, and they do so by using -+ # super(SSLContext, SSLContext). But we rebind SSLContext when we monkey -+ # patch, which causes infinite recursion. -+ # https://github.com/python/cpython/commit/328067c468f82e4ec1b5c510a4e84509e010f296 -+ @_original_sslcontext.options.setter -+ def options(self, value): -+ super(_original_sslcontext, _original_sslcontext).options.__set__(self, value) -+ -+ @_original_sslcontext.verify_flags.setter -+ def verify_flags(self, value): -+ super(_original_sslcontext, _original_sslcontext).verify_flags.__set__(self, value) -+ -+ @_original_sslcontext.verify_mode.setter -+ def verify_mode(self, value): -+ super(_original_sslcontext, _original_sslcontext).verify_mode.__set__(self, value) -+ - SSLContext = GreenSSLContext - - if hasattr(__ssl, 'create_default_context'): -diff --git a/tests/isolated/green_ssl_py36_properties.py b/tests/isolated/green_ssl_py36_properties.py -new file mode 100644 -index 0000000..aa6b5b5 ---- /dev/null -+++ b/tests/isolated/green_ssl_py36_properties.py -@@ -0,0 +1,16 @@ -+__test__ = False -+ -+ -+if __name__ == '__main__': -+ import eventlet -+ eventlet.monkey_patch() -+ -+ try: -+ eventlet.wrap_ssl( -+ eventlet.listen(('localhost', 0)), -+ certfile='does-not-exist', -+ keyfile='does-not-exist', -+ server_side=True) -+ except IOError as ex: -+ assert ex.errno == 2 -+ print('pass') diff -Nru python-eventlet-0.20.0/debian/patches/0014-Fix-for-Python-3.7.patch python-eventlet-0.24.1/debian/patches/0014-Fix-for-Python-3.7.patch --- python-eventlet-0.20.0/debian/patches/0014-Fix-for-Python-3.7.patch 2018-09-30 12:31:32.000000000 +0000 +++ python-eventlet-0.24.1/debian/patches/0014-Fix-for-Python-3.7.patch 2018-12-21 14:16:24.000000000 +0000 @@ -27,7 +27,7 @@ --- a/eventlet/green/ssl.py +++ b/eventlet/green/ssl.py -@@ -28,6 +28,7 @@ +@@ -24,6 +24,7 @@ 'create_default_context', '_create_default_https_context'] _original_sslsocket = __ssl.SSLSocket @@ -35,7 +35,7 @@ class GreenSSLSocket(_original_sslsocket): -@@ -61,11 +62,41 @@ +@@ -57,11 +58,41 @@ # this assignment self._timeout = sock.gettimeout() @@ -82,7 +82,7 @@ # the superclass initializer trashes the methods so we remove # the local-object versions of them and let the actual class -@@ -333,7 +364,10 @@ +@@ -323,7 +354,10 @@ except NameError: self._sslobj = sslobj else: @@ -96,19 +96,17 @@ self.do_handshake() --- a/setup.py +++ b/setup.py -@@ -34,6 +34,9 @@ - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3.3", +@@ -42,6 +42,7 @@ "Programming Language :: Python :: 3.4", -+ "Programming Language :: Python :: 3.5", -+ "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python", "Topic :: Internet", "Topic :: Software Development :: Libraries :: Python Modules", - "Intended Audience :: Developers", --- a/tests/debug_test.py +++ b/tests/debug_test.py -@@ -30,6 +30,11 @@ +@@ -29,6 +29,11 @@ assert self.tracer is None def test_line(self): @@ -120,7 +118,7 @@ sys.stdout = six.StringIO() s = debug.Spew() f = sys._getframe() -@@ -37,7 +42,7 @@ +@@ -36,7 +41,7 @@ lineno = f.f_lineno - 1 # -1 here since we called with frame f in the line above output = sys.stdout.getvalue() assert "%s:%i" % (__name__, lineno) in output, "Didn't find line %i in %s" % (lineno, output) @@ -129,7 +127,7 @@ def test_line_nofile(self): sys.stdout = six.StringIO() -@@ -52,6 +57,11 @@ +@@ -51,6 +56,11 @@ assert "VM instruction #" in output, output def test_line_global(self): @@ -141,7 +139,7 @@ global GLOBAL_VAR sys.stdout = six.StringIO() GLOBAL_VAR = debug.Spew() -@@ -60,7 +70,7 @@ +@@ -59,7 +69,7 @@ lineno = f.f_lineno - 1 # -1 here since we called with frame f in the line above output = sys.stdout.getvalue() assert "%s:%i" % (__name__, lineno) in output, "Didn't find line %i in %s" % (lineno, output) diff -Nru python-eventlet-0.20.0/debian/patches/0015-IMPORTANT-late-import-in-use_hub-thread-race-caused-.patch python-eventlet-0.24.1/debian/patches/0015-IMPORTANT-late-import-in-use_hub-thread-race-caused-.patch --- python-eventlet-0.20.0/debian/patches/0015-IMPORTANT-late-import-in-use_hub-thread-race-caused-.patch 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/debian/patches/0015-IMPORTANT-late-import-in-use_hub-thread-race-caused-.patch 2018-12-21 14:16:24.000000000 +0000 @@ -0,0 +1,717 @@ +From 77bccbe48d4d9a46982b2e0503e76784e76b066a Mon Sep 17 00:00:00 2001 +From: Sergey Shepelev +Date: Sun, 2 Sep 2018 01:38:23 +0500 +Subject: [PATCH] IMPORTANT: late import in `use_hub()` + thread race caused + using epolls even when it is unsupported on current platform + +Solution: eager import all built-in hubs, explicitly check support later + +https://github.com/eventlet/eventlet/issues/466 +--- + eventlet/hubs/__init__.py | 103 +++++++++++------------ + eventlet/hubs/epolls.py | 39 +++------ + eventlet/hubs/hub.py | 5 +- + eventlet/hubs/kqueue.py | 34 ++++---- + eventlet/hubs/poll.py | 38 +++++---- + eventlet/hubs/pyevent.py | 10 ++- + eventlet/hubs/selects.py | 38 +++++---- + eventlet/hubs/timer.py | 6 +- + tests/hub_test.py | 56 ++---------- + tests/isolated/hub_kqueue_unsupported.py | 28 ++++++ + tests/isolated/hub_use_hub_class.py | 13 +++ + 11 files changed, 182 insertions(+), 188 deletions(-) + create mode 100644 tests/isolated/hub_kqueue_unsupported.py + create mode 100644 tests/isolated/hub_use_hub_class.py + +diff --git a/eventlet/hubs/__init__.py b/eventlet/hubs/__init__.py +index fc5d3f3..867628c 100644 +--- a/eventlet/hubs/__init__.py ++++ b/eventlet/hubs/__init__.py +@@ -1,4 +1,7 @@ ++import importlib ++import inspect + import os ++import warnings + + from eventlet import patcher + from eventlet.support import greenlets as greenlet +@@ -11,6 +14,15 @@ threading = patcher.original('threading') + _threadlocal = threading.local() + + ++# order is important, get_default_hub returns first available from here ++builtin_hub_names = ('epolls', 'kqueue', 'poll', 'selects') ++builtin_hub_modules = tuple(importlib.import_module('eventlet.hubs.' + name) for name in builtin_hub_names) ++ ++ ++class HubError(Exception): ++ pass ++ ++ + def get_default_hub(): + """Select the default hub implementation based on what multiplexing + libraries are installed. The order that the hubs are tried is: +@@ -26,44 +38,33 @@ def get_default_hub(): + .. include:: ../doc/common.txt + .. note :: |internal| + """ ++ for mod in builtin_hub_modules: ++ if mod.is_available(): ++ return mod + +- # pyevent hub disabled for now because it is not thread-safe +- # try: +- # import eventlet.hubs.pyevent +- # return eventlet.hubs.pyevent +- # except: +- # pass +- +- select = patcher.original('select') +- try: +- import eventlet.hubs.epolls +- return eventlet.hubs.epolls +- except ImportError: +- try: +- import eventlet.hubs.kqueue +- return eventlet.hubs.kqueue +- except ImportError: +- if hasattr(select, 'poll'): +- import eventlet.hubs.poll +- return eventlet.hubs.poll +- else: +- import eventlet.hubs.selects +- return eventlet.hubs.selects ++ raise HubError('no built-in hubs are available: {}'.format(builtin_hub_modules)) + + + def use_hub(mod=None): + """Use the module *mod*, containing a class called Hub, as the + event hub. Usually not required; the default hub is usually fine. + +- Mod can be an actual module, a string, or None. If *mod* is a module, +- it uses it directly. If *mod* is a string and contains either '.' or ':' +- use_hub tries to import the hub using the 'package.subpackage.module:Class' +- convention, otherwise use_hub looks for a matching setuptools entry point +- in the 'eventlet.hubs' group to load or finally tries to import +- `eventlet.hubs.mod` and use that as the hub module. If *mod* is None, +- use_hub uses the default hub. Only call use_hub during application +- initialization, because it resets the hub's state and any existing ++ `mod` can be an actual hub class, a module, a string, or None. ++ ++ If `mod` is a class, use it directly. ++ If `mod` is a module, use `module.Hub` class ++ If `mod` is a string and contains either '.' or ':' ++ then `use_hub` uses 'package.subpackage.module:Class' convention, ++ otherwise imports `eventlet.hubs.mod`. ++ If `mod` is None, `use_hub` uses the default hub. ++ ++ Only call use_hub during application initialization, ++ because it resets the hub's state and any existing + timers or listeners will never be resumed. ++ ++ These two threadlocal attributes are not part of Eventlet public API: ++ - `threadlocal.Hub` (capital H) is hub constructor, used when no hub is currently active ++ - `threadlocal.hub` (lowercase h) is active hub instance + """ + if mod is None: + mod = os.environ.get('EVENTLET_HUB', None) +@@ -71,36 +72,30 @@ def use_hub(mod=None): + mod = get_default_hub() + if hasattr(_threadlocal, 'hub'): + del _threadlocal.hub ++ ++ classname = '' + if isinstance(mod, six.string_types): + assert mod.strip(), "Need to specify a hub" + if '.' in mod or ':' in mod: + modulename, _, classname = mod.strip().partition(':') +- mod = __import__(modulename, globals(), locals(), [classname]) +- if classname: +- mod = getattr(mod, classname) + else: +- found = False +- +- # setuptools 5.4.1 test_import_patched_defaults fail +- # https://github.com/eventlet/eventlet/issues/177 +- try: +- # try and import pkg_resources ... +- import pkg_resources +- except ImportError: +- # ... but do not depend on it +- pkg_resources = None +- if pkg_resources is not None: +- for entry in pkg_resources.iter_entry_points( +- group='eventlet.hubs', name=mod): +- mod, found = entry.load(), True +- break +- if not found: +- mod = __import__( +- 'eventlet.hubs.' + mod, globals(), locals(), ['Hub']) +- if hasattr(mod, 'Hub'): +- _threadlocal.Hub = mod.Hub ++ modulename = 'eventlet.hubs.' + mod ++ mod = importlib.import_module(modulename) ++ ++ if hasattr(mod, 'is_available'): ++ if not mod.is_available(): ++ raise Exception('selected hub is not available on this system mod={}'.format(mod)) + else: +- _threadlocal.Hub = mod ++ msg = '''Please provide `is_available()` function in your custom Eventlet hub {mod}. ++It must return bool: whether hub supports current platform. See eventlet/hubs/{{epoll,kqueue}} for example. ++'''.format(mod=mod) ++ warnings.warn(msg, DeprecationWarning, stacklevel=3) ++ ++ hubclass = mod ++ if not inspect.isclass(mod): ++ hubclass = getattr(mod, classname or 'Hub') ++ ++ _threadlocal.Hub = hubclass + + + def get_hub(): +diff --git a/eventlet/hubs/epolls.py b/eventlet/hubs/epolls.py +index c338756..07fec14 100644 +--- a/eventlet/hubs/epolls.py ++++ b/eventlet/hubs/epolls.py +@@ -1,40 +1,29 @@ + import errno +-from eventlet.support import get_errno +-from eventlet import patcher ++from eventlet import patcher, support ++from eventlet.hubs import hub, poll + select = patcher.original('select') +-if not hasattr(select, 'epoll'): +- # TODO: remove mention of python-epoll on 2019-01 +- raise ImportError('No epoll implementation found in select module.' +- ' python-epoll (or similar) package support was removed,' +- ' please open issue on https://github.com/eventlet/eventlet/' +- ' if you must use epoll outside stdlib.') +-epoll = select.epoll + +-from eventlet.hubs.hub import BaseHub +-from eventlet.hubs import poll +-from eventlet.hubs.poll import READ, WRITE + +-# NOTE: we rely on the fact that the epoll flag constants +-# are identical in value to the poll constants ++def is_available(): ++ return hasattr(select, 'epoll') + + ++# NOTE: we rely on the fact that the epoll flag constants ++# are identical in value to the poll constants + class Hub(poll.Hub): + def __init__(self, clock=None): +- BaseHub.__init__(self, clock) +- self.poll = epoll() ++ super(Hub, self).__init__(clock=clock) ++ self.poll = select.epoll() + + def add(self, evtype, fileno, cb, tb, mac): +- oldlisteners = bool(self.listeners[READ].get(fileno) or +- self.listeners[WRITE].get(fileno)) +- listener = BaseHub.add(self, evtype, fileno, cb, tb, mac) ++ oldlisteners = bool(self.listeners[self.READ].get(fileno) or ++ self.listeners[self.WRITE].get(fileno)) ++ # not super() to avoid double register() ++ listener = hub.BaseHub.add(self, evtype, fileno, cb, tb, mac) + try: +- if not oldlisteners: +- # Means we've added a new listener +- self.register(fileno, new=True) +- else: +- self.register(fileno, new=False) ++ self.register(fileno, new=not oldlisteners) + except IOError as ex: # ignore EEXIST, #80 +- if get_errno(ex) != errno.EEXIST: ++ if support.get_errno(ex) != errno.EEXIST: + raise + return listener + +diff --git a/eventlet/hubs/hub.py b/eventlet/hubs/hub.py +index 112f467..8871082 100644 +--- a/eventlet/hubs/hub.py ++++ b/eventlet/hubs/hub.py +@@ -19,7 +19,8 @@ else: + signal.alarm(math.ceil(seconds)) + arm_alarm = alarm_signal + +-from eventlet.hubs import timer, IOClosed ++import eventlet.hubs ++from eventlet.hubs import timer + from eventlet.support import greenlets as greenlet, clear_sys_exc_info + import monotonic + import six +@@ -265,7 +266,7 @@ class BaseHub(object): + listener = self.closed.pop() + if not listener.greenlet.dead: + # There's no point signalling a greenlet that's already dead. +- listener.tb(IOClosed(errno.ENOTCONN, "Operation on closed file")) ++ listener.tb(eventlet.hubs.IOClosed(errno.ENOTCONN, "Operation on closed file")) + + def ensure_greenlet(self): + if self.greenlet.dead: +diff --git a/eventlet/hubs/kqueue.py b/eventlet/hubs/kqueue.py +index 0e60d33..bad4a87 100644 +--- a/eventlet/hubs/kqueue.py ++++ b/eventlet/hubs/kqueue.py +@@ -1,25 +1,24 @@ + import os + import sys + from eventlet import patcher, support ++from eventlet.hubs import hub + import six + select = patcher.original('select') + time = patcher.original('time') + +-from eventlet.hubs.hub import BaseHub, READ, WRITE, noop + ++def is_available(): ++ return hasattr(select, 'kqueue') + +-if getattr(select, 'kqueue', None) is None: +- raise ImportError('No kqueue implementation found in select module') + +- +-FILTERS = {READ: select.KQ_FILTER_READ, +- WRITE: select.KQ_FILTER_WRITE} +- +- +-class Hub(BaseHub): ++class Hub(hub.BaseHub): + MAX_EVENTS = 100 + + def __init__(self, clock=None): ++ self.FILTERS = { ++ hub.READ: select.KQ_FILTER_READ, ++ hub.WRITE: select.KQ_FILTER_WRITE, ++ } + super(Hub, self).__init__(clock) + self._events = {} + self._init_kqueue() +@@ -31,10 +30,9 @@ class Hub(BaseHub): + def _reinit_kqueue(self): + self.kqueue.close() + self._init_kqueue() +- kqueue = self.kqueue + events = [e for i in six.itervalues(self._events) + for e in six.itervalues(i)] +- kqueue.control(events, 0, 0) ++ self.kqueue.control(events, 0, 0) + + def _control(self, events, max_events, timeout): + try: +@@ -51,7 +49,7 @@ class Hub(BaseHub): + events = self._events.setdefault(fileno, {}) + if evtype not in events: + try: +- event = select.kevent(fileno, FILTERS.get(evtype), select.KQ_EV_ADD) ++ event = select.kevent(fileno, self.FILTERS.get(evtype), select.KQ_EV_ADD) + self._control([event], 0, 0) + events[evtype] = event + except ValueError: +@@ -90,8 +88,8 @@ class Hub(BaseHub): + pass + + def wait(self, seconds=None): +- readers = self.listeners[READ] +- writers = self.listeners[WRITE] ++ readers = self.listeners[self.READ] ++ writers = self.listeners[self.WRITE] + + if not readers and not writers: + if seconds: +@@ -103,10 +101,10 @@ class Hub(BaseHub): + fileno = event.ident + evfilt = event.filter + try: +- if evfilt == FILTERS[READ]: +- readers.get(fileno, noop).cb(fileno) +- if evfilt == FILTERS[WRITE]: +- writers.get(fileno, noop).cb(fileno) ++ if evfilt == select.KQ_FILTER_READ: ++ readers.get(fileno, hub.noop).cb(fileno) ++ if evfilt == select.KQ_FILTER_WRITE: ++ writers.get(fileno, hub.noop).cb(fileno) + except SYSTEM_EXCEPTIONS: + raise + except: +diff --git a/eventlet/hubs/poll.py b/eventlet/hubs/poll.py +index 17bc9e7..1bbd401 100644 +--- a/eventlet/hubs/poll.py ++++ b/eventlet/hubs/poll.py +@@ -1,21 +1,22 @@ + import errno + import sys + +-from eventlet import patcher ++from eventlet import patcher, support ++from eventlet.hubs import hub + select = patcher.original('select') + time = patcher.original('time') + +-from eventlet.hubs.hub import BaseHub, READ, WRITE, noop +-from eventlet.support import get_errno, clear_sys_exc_info + +-EXC_MASK = select.POLLERR | select.POLLHUP +-READ_MASK = select.POLLIN | select.POLLPRI +-WRITE_MASK = select.POLLOUT ++def is_available(): ++ return hasattr(select, 'poll') + + +-class Hub(BaseHub): ++class Hub(hub.BaseHub): + def __init__(self, clock=None): + super(Hub, self).__init__(clock) ++ self.EXC_MASK = select.POLLERR | select.POLLHUP ++ self.READ_MASK = select.POLLIN | select.POLLPRI ++ self.WRITE_MASK = select.POLLOUT + self.poll = select.poll() + + def add(self, evtype, fileno, cb, tb, mac): +@@ -29,10 +30,10 @@ class Hub(BaseHub): + + def register(self, fileno, new=False): + mask = 0 +- if self.listeners[READ].get(fileno): +- mask |= READ_MASK | EXC_MASK +- if self.listeners[WRITE].get(fileno): +- mask |= WRITE_MASK | EXC_MASK ++ if self.listeners[self.READ].get(fileno): ++ mask |= self.READ_MASK | self.EXC_MASK ++ if self.listeners[self.WRITE].get(fileno): ++ mask |= self.WRITE_MASK | self.EXC_MASK + try: + if mask: + if new: +@@ -68,8 +69,8 @@ class Hub(BaseHub): + return self.poll.poll(int(seconds * 1000.0)) + + def wait(self, seconds=None): +- readers = self.listeners[READ] +- writers = self.listeners[WRITE] ++ readers = self.listeners[self.READ] ++ writers = self.listeners[self.WRITE] + + if not readers and not writers: + if seconds: +@@ -78,7 +79,7 @@ class Hub(BaseHub): + try: + presult = self.do_poll(seconds) + except (IOError, select.error) as e: +- if get_errno(e) == errno.EINTR: ++ if support.get_errno(e) == errno.EINTR: + return + raise + SYSTEM_EXCEPTIONS = self.SYSTEM_EXCEPTIONS +@@ -92,15 +93,16 @@ class Hub(BaseHub): + # polled for. It prevents one handler from invalidating + # another. + callbacks = set() ++ noop = hub.noop # shave getattr + for fileno, event in presult: +- if event & READ_MASK: ++ if event & self.READ_MASK: + callbacks.add((readers.get(fileno, noop), fileno)) +- if event & WRITE_MASK: ++ if event & self.WRITE_MASK: + callbacks.add((writers.get(fileno, noop), fileno)) + if event & select.POLLNVAL: + self.remove_descriptor(fileno) + continue +- if event & EXC_MASK: ++ if event & self.EXC_MASK: + callbacks.add((readers.get(fileno, noop), fileno)) + callbacks.add((writers.get(fileno, noop), fileno)) + +@@ -111,7 +113,7 @@ class Hub(BaseHub): + raise + except: + self.squelch_exception(fileno, sys.exc_info()) +- clear_sys_exc_info() ++ support.clear_sys_exc_info() + + if self.debug_blocking: + self.block_detect_post() +diff --git a/eventlet/hubs/pyevent.py b/eventlet/hubs/pyevent.py +index 73c0a18..8367a65 100644 +--- a/eventlet/hubs/pyevent.py ++++ b/eventlet/hubs/pyevent.py +@@ -1,12 +1,20 @@ + import sys + import traceback +-import event + import types + + from eventlet.support import greenlets as greenlet + import six + from eventlet.hubs.hub import BaseHub, READ, WRITE + ++try: ++ import event ++except ImportError: ++ event = None ++ ++ ++def is_available(): ++ return event is not None ++ + + class event_wrapper(object): + +diff --git a/eventlet/hubs/selects.py b/eventlet/hubs/selects.py +index 3f04e1a..0ead5b8 100644 +--- a/eventlet/hubs/selects.py ++++ b/eventlet/hubs/selects.py +@@ -1,60 +1,64 @@ + import errno + import sys +-from eventlet import patcher +-from eventlet.support import get_errno, clear_sys_exc_info ++from eventlet import patcher, support ++from eventlet.hubs import hub + select = patcher.original('select') + time = patcher.original('time') + +-from eventlet.hubs.hub import BaseHub, READ, WRITE, noop +- + try: + BAD_SOCK = set((errno.EBADF, errno.WSAENOTSOCK)) + except AttributeError: + BAD_SOCK = set((errno.EBADF,)) + + +-class Hub(BaseHub): ++def is_available(): ++ return hasattr(select, 'select') ++ ++ ++class Hub(hub.BaseHub): + def _remove_bad_fds(self): + """ Iterate through fds, removing the ones that are bad per the + operating system. + """ +- all_fds = list(self.listeners[READ]) + list(self.listeners[WRITE]) ++ all_fds = list(self.listeners[self.READ]) + list(self.listeners[self.WRITE]) + for fd in all_fds: + try: + select.select([fd], [], [], 0) + except select.error as e: +- if get_errno(e) in BAD_SOCK: ++ if support.get_errno(e) in BAD_SOCK: + self.remove_descriptor(fd) + + def wait(self, seconds=None): +- readers = self.listeners[READ] +- writers = self.listeners[WRITE] ++ readers = self.listeners[self.READ] ++ writers = self.listeners[self.WRITE] + if not readers and not writers: + if seconds: + time.sleep(seconds) + return +- all_fds = list(readers) + list(writers) ++ reader_fds = list(readers) ++ writer_fds = list(writers) ++ all_fds = reader_fds + writer_fds + try: +- r, w, er = select.select(readers.keys(), writers.keys(), all_fds, seconds) ++ r, w, er = select.select(reader_fds, writer_fds, all_fds, seconds) + except select.error as e: +- if get_errno(e) == errno.EINTR: ++ if support.get_errno(e) == errno.EINTR: + return +- elif get_errno(e) in BAD_SOCK: ++ elif support.get_errno(e) in BAD_SOCK: + self._remove_bad_fds() + return + else: + raise + + for fileno in er: +- readers.get(fileno, noop).cb(fileno) +- writers.get(fileno, noop).cb(fileno) ++ readers.get(fileno, hub.noop).cb(fileno) ++ writers.get(fileno, hub.noop).cb(fileno) + + for listeners, events in ((readers, r), (writers, w)): + for fileno in events: + try: +- listeners.get(fileno, noop).cb(fileno) ++ listeners.get(fileno, hub.noop).cb(fileno) + except self.SYSTEM_EXCEPTIONS: + raise + except: + self.squelch_exception(fileno, sys.exc_info()) +- clear_sys_exc_info() ++ support.clear_sys_exc_info() +diff --git a/eventlet/hubs/timer.py b/eventlet/hubs/timer.py +index 9b10b00..1dfd561 100644 +--- a/eventlet/hubs/timer.py ++++ b/eventlet/hubs/timer.py +@@ -1,8 +1,8 @@ + import traceback + ++import eventlet.hubs + from eventlet.support import greenlets as greenlet + import six +-from eventlet.hubs import get_hub + + """ If true, captures a stack trace for each timer when constructed. This is + useful for debugging leaking timers, to find out where the timer was set up. """ +@@ -48,7 +48,7 @@ class Timer(object): + """Schedule this timer to run in the current runloop. + """ + self.called = False +- self.scheduled_time = get_hub().add_timer(self) ++ self.scheduled_time = eventlet.hubs.get_hub().add_timer(self) + return self + + def __call__(self, *args): +@@ -69,7 +69,7 @@ class Timer(object): + """ + if not self.called: + self.called = True +- get_hub().timer_canceled(self) ++ eventlet.hubs.get_hub().timer_canceled(self) + try: + del self.tpl + except AttributeError: +diff --git a/tests/hub_test.py b/tests/hub_test.py +index 61b5b0b..d62b805 100644 +--- a/tests/hub_test.py ++++ b/tests/hub_test.py +@@ -4,7 +4,6 @@ import time + + import tests + from tests import skip_with_pyevent, skip_if_no_itimer, skip_unless +-from tests.patcher_test import ProcessBase + import eventlet + from eventlet import hubs + from eventlet.support import greenlets +@@ -205,17 +204,6 @@ class TestExceptionInGreenthread(tests.LimitedTestCase): + g.kill() + + +-class TestHubSelection(tests.LimitedTestCase): +- +- def test_explicit_hub(self): +- oldhub = hubs.get_hub() +- try: +- hubs.use_hub(Foo) +- assert isinstance(hubs.get_hub(), Foo), hubs.get_hub() +- finally: +- hubs._threadlocal.hub = oldhub +- +- + class TestHubBlockingDetector(tests.LimitedTestCase): + TEST_TIMEOUT = 10 + +@@ -361,43 +349,11 @@ class TestDeadRunLoop(tests.LimitedTestCase): + assert g.dead # sanity check that dummyproc has completed + + +-class Foo(object): +- pass +- +- +-class TestDefaultHub(ProcessBase): +- +- def test_kqueue_unsupported(self): +- # https://github.com/eventlet/eventlet/issues/38 +- # get_hub on windows broken by kqueue +- module_source = r''' +-from __future__ import print_function +- +-# Simulate absence of kqueue even on platforms that support it. +-import select +-try: +- del select.kqueue +-except AttributeError: +- pass +- +-from six.moves import builtins +- +-original_import = builtins.__import__ +- +-def fail_import(name, *args, **kwargs): +- if 'epoll' in name: +- raise ImportError('disabled for test') +- if 'kqueue' in name: +- print('kqueue tried') +- return original_import(name, *args, **kwargs) +- +-builtins.__import__ = fail_import ++def test_use_hub_class(): ++ tests.run_isolated('hub_use_hub_class.py') + + +-import eventlet.hubs +-eventlet.hubs.get_default_hub() +-print('ok') +-''' +- self.write_to_tempfile('newmod', module_source) +- output, _ = self.launch_subprocess('newmod.py') +- self.assertEqual(output, 'kqueue tried\nok\n') ++def test_kqueue_unsupported(): ++ # https://github.com/eventlet/eventlet/issues/38 ++ # get_hub on windows broken by kqueue ++ tests.run_isolated('hub_kqueue_unsupported.py') +diff --git a/tests/isolated/hub_kqueue_unsupported.py b/tests/isolated/hub_kqueue_unsupported.py +new file mode 100644 +index 0000000..373df98 +--- /dev/null ++++ b/tests/isolated/hub_kqueue_unsupported.py +@@ -0,0 +1,28 @@ ++from __future__ import print_function ++__test__ = False ++ ++ ++def delattr_silent(x, name): ++ try: ++ delattr(x, name) ++ except AttributeError: ++ pass ++ ++ ++if __name__ == '__main__': ++ # Simulate absence of kqueue even on platforms that support it. ++ import select ++ delattr_silent(select, 'kqueue') ++ delattr_silent(select, 'KQ_FILTER_READ') ++ # patcher.original used in hub may reimport and return deleted kqueue attribute ++ import eventlet.patcher ++ select_original = eventlet.patcher.original('select') ++ delattr_silent(select_original, 'kqueue') ++ delattr_silent(select_original, 'KQ_FILTER_READ') ++ ++ import eventlet.hubs ++ default = eventlet.hubs.get_default_hub() ++ assert not default.__name__.endswith('kqueue') ++ import eventlet.hubs.kqueue ++ assert not eventlet.hubs.kqueue.is_available() ++ print('pass') +diff --git a/tests/isolated/hub_use_hub_class.py b/tests/isolated/hub_use_hub_class.py +new file mode 100644 +index 0000000..9f7f308 +--- /dev/null ++++ b/tests/isolated/hub_use_hub_class.py +@@ -0,0 +1,13 @@ ++from __future__ import print_function ++__test__ = False ++ ++ ++class Foo(object): ++ pass ++ ++if __name__ == '__main__': ++ import eventlet.hubs ++ eventlet.hubs.use_hub(Foo) ++ hub = eventlet.hubs.get_hub() ++ assert isinstance(hub, Foo), repr(hub) ++ print('pass') +-- +2.19.1 + diff -Nru python-eventlet-0.20.0/debian/patches/0016-Issue-535-use-Python-2-compatible-syntax-for-keyword.patch python-eventlet-0.24.1/debian/patches/0016-Issue-535-use-Python-2-compatible-syntax-for-keyword.patch --- python-eventlet-0.20.0/debian/patches/0016-Issue-535-use-Python-2-compatible-syntax-for-keyword.patch 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/debian/patches/0016-Issue-535-use-Python-2-compatible-syntax-for-keyword.patch 2018-12-21 14:16:24.000000000 +0000 @@ -0,0 +1,56 @@ +From 551580928797e00a94d56e0280cbdf4a33bdeea5 Mon Sep 17 00:00:00 2001 +From: nat-goodspeed +Date: Thu, 20 Dec 2018 09:39:08 -0500 +Subject: [PATCH] Issue 535: use Python 2 compatible syntax for keyword-only + args. (#536) + +* Issue #535: use Python 2 compatible syntax for keyword-only args. + +* Validate that encode_chunked is the *only* keyword argument passed. +--- + eventlet/green/http/client.py | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/eventlet/green/http/client.py b/eventlet/green/http/client.py +index 07ebccf..e4bd2ad 100644 +--- a/eventlet/green/http/client.py ++++ b/eventlet/green/http/client.py +@@ -1281,22 +1281,32 @@ class HTTPConnection: + header = header + b': ' + value + self._output(header) + +- def endheaders(self, message_body=None, *, encode_chunked=False): ++ def endheaders(self, message_body=None, **kwds): + """Indicate that the last header line has been sent to the server. + + This method sends the request to the server. The optional message_body + argument can be used to pass a message body associated with the + request. + """ ++ encode_chunked = kwds.pop('encode_chunked', False) ++ if kwds: ++ # mimic interpreter error for unrecognized keyword ++ raise TypeError("endheaders() got an unexpected keyword argument '{0}'" ++ .format(kwds.popitem()[0])) ++ + if self.__state == _CS_REQ_STARTED: + self.__state = _CS_REQ_SENT + else: + raise CannotSendHeader() + self._send_output(message_body, encode_chunked=encode_chunked) + +- def request(self, method, url, body=None, headers={}, *, +- encode_chunked=False): ++ def request(self, method, url, body=None, headers={}, **kwds): + """Send a complete request to the server.""" ++ encode_chunked = kwds.pop('encode_chunked', False) ++ if kwds: ++ # mimic interpreter error for unrecognized keyword ++ raise TypeError("request() got an unexpected keyword argument '{0}'" ++ .format(kwds.popitem()[0])) + self._send_request(method, url, body, headers, encode_chunked) + + def _set_content_length(self, body, method): +-- +2.19.1 + diff -Nru python-eventlet-0.20.0/debian/patches/series python-eventlet-0.24.1/debian/patches/series --- python-eventlet-0.20.0/debian/patches/series 2018-09-30 12:23:14.000000000 +0000 +++ python-eventlet-0.24.1/debian/patches/series 2018-12-21 14:16:24.000000000 +0000 @@ -2,13 +2,10 @@ 0002-Fixed-privacy-breach-in-examples.patch 0003-Allow-more-busy-CPU.patch 0004-Remove-networking-tests.patch -0005-Removed-failing-test.patch 0006-Patch-out-intersphinx.patch -0007-Patched-test_getaddrinfo-due-netbase-update.patch -0008-Disable-test_server_connection_timeout_exception.patch 0009-Removed-test_urllib-that-is-failing-in-py36.patch 0010-Fix-compilation-errors-when-installing-package-in-Py.patch -0011-Avoid-dependency-on-enum-compat.patch -0012-ssl-RecursionError-on-Python3.6.patch 0013-New_test_crt.patch 0014-Fix-for-Python-3.7.patch +0015-IMPORTANT-late-import-in-use_hub-thread-race-caused-.patch +0016-Issue-535-use-Python-2-compatible-syntax-for-keyword.patch diff -Nru python-eventlet-0.20.0/doc/hubs.rst python-eventlet-0.24.1/doc/hubs.rst --- python-eventlet-0.20.0/doc/hubs.rst 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/doc/hubs.rst 2018-08-06 16:17:47.000000000 +0000 @@ -8,7 +8,7 @@ Eventlet has multiple hub implementations, and when you start using it, it tries to select the best hub implementation for your system. The hubs that it supports are (in order of preference): **epolls** - Requires Python 2.6 or the `python-epoll `_ package, and Linux. This is the fastest pure-Python hub. + Linux. **poll** On platforms that support it **selects** @@ -21,19 +21,19 @@ .. function:: eventlet.hubs.use_hub(hub=None) Use this to control which hub Eventlet selects. Call it with the name of the desired hub module. Make sure to do this before the application starts doing any I/O! Calling use_hub completely eliminates the old hub, and any file descriptors or timers that it had been managing will be forgotten. Put the call as one of the first lines in the main module.:: - + """ This is the main module """ from eventlet import hubs hubs.use_hub("pyevent") - + Hubs are implemented as thread-local class instances. :func:`eventlet.hubs.use_hub` only operates on the current thread. When using multiple threads that each need their own hub, call :func:`eventlet.hubs.use_hub` at the beginning of each thread function that needs a specific hub. In practice, it may not be necessary to specify a hub in each thread; it works to use one special hub for the main thread, and let other threads use the default hub; this hybrid hub configuration will work fine. - + It is also possible to use a third-party hub module in place of one of the built-in ones. Simply pass the module itself to :func:`eventlet.hubs.use_hub`. The task of writing such a hub is a little beyond the scope of this document, it's probably a good idea to simply inspect the code of the existing hubs to see how they work.:: - from eventlet import hubs + from eventlet import hubs from mypackage import myhub hubs.use_hub(myhub) - + Supplying None as the argument to :func:`eventlet.hubs.use_hub` causes it to select the default hub. diff -Nru python-eventlet-0.20.0/doc/make.bat python-eventlet-0.24.1/doc/make.bat --- python-eventlet-0.20.0/doc/make.bat 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/doc/make.bat 1970-01-01 00:00:00.000000000 +0000 @@ -1,112 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -set SPHINXBUILD=sphinx-build -set ALLSPHINXOPTS=-d _build/doctrees %SPHINXOPTS% . -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. changes to make an overview over all changed/added/deprecated items - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (_build\*) do rmdir /q /s %%i - del /q /s _build\* - goto end -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% _build/html - echo. - echo.Build finished. The HTML pages are in _build/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% _build/dirhtml - echo. - echo.Build finished. The HTML pages are in _build/dirhtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% _build/pickle - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% _build/json - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% _build/htmlhelp - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in _build/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% _build/qthelp - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in _build/qthelp, like this: - echo.^> qcollectiongenerator _build\qthelp\Eventlet.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile _build\qthelp\Eventlet.ghc - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% _build/latex - echo. - echo.Build finished; the LaTeX files are in _build/latex. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% _build/changes - echo. - echo.The overview file is in _build/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% _build/linkcheck - echo. - echo.Link check complete; look for any errors in the above output ^ -or in _build/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% _build/doctest - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in _build/doctest/output.txt. - goto end -) - -:end diff -Nru python-eventlet-0.20.0/doc/modules/backdoor.rst python-eventlet-0.24.1/doc/modules/backdoor.rst --- python-eventlet-0.20.0/doc/modules/backdoor.rst 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/doc/modules/backdoor.rst 2018-08-06 16:17:47.000000000 +0000 @@ -4,24 +4,22 @@ The backdoor module is convenient for inspecting the state of a long-running process. It supplies the normal Python interactive interpreter in a way that does not block the normal operation of the application. This can be useful for debugging, performance tuning, or simply learning about how things behave in situ. In the application, spawn a greenthread running backdoor_server on a listening socket:: - + eventlet.spawn(backdoor.backdoor_server, eventlet.listen(('localhost', 3000))) - + When this is running, the backdoor is accessible via telnet to the specified port. .. code-block:: sh $ telnet localhost 3000 - Python 2.6.2 (r262:71600, Apr 16 2009, 09:17:39) - [GCC 4.0.1 (Apple Computer, Inc. build 5250)] on darwin + (python version, build info) Type "help", "copyright", "credits" or "license" for more information. >>> import myapp >>> dir(myapp) ['__all__', '__doc__', '__name__', 'myfunc'] >>> - + The backdoor cooperatively yields to the rest of the application between commands, so on a running server continuously serving requests, you can observe the internal state changing between interpreter commands. .. automodule:: eventlet.backdoor :members: - diff -Nru python-eventlet-0.20.0/doc/modules/zmq.rst python-eventlet-0.24.1/doc/modules/zmq.rst --- python-eventlet-0.20.0/doc/modules/zmq.rst 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/doc/modules/zmq.rst 2018-08-06 16:17:47.000000000 +0000 @@ -1,14 +1,15 @@ :mod:`eventlet.green.zmq` -- ØMQ support ======================================== +:mod:`pyzmq ` [1]_ is a python binding to the C++ ØMQ [2]_ library written in Cython [3]_. +:mod:`eventlet.green.zmq` is greenthread aware version of `pyzmq`. + .. automodule:: eventlet.green.zmq :show-inheritance: .. currentmodule:: eventlet.green.zmq -.. autofunction:: Context - -.. autoclass:: _Context +.. autoclass:: Context :show-inheritance: .. automethod:: socket @@ -23,20 +24,6 @@ .. module:: zmq -:mod:`zmq` -- The pyzmq ØMQ python bindings -=========================================== - -:mod:`pyzmq ` [1]_ Is a python binding to the C++ ØMQ [2]_ library written in Cython [3]_. The following is -auto generated :mod:`pyzmq's ` from documentation. - -.. autoclass:: zmq.core.context.Context - :members: - -.. autoclass:: zmq.core.socket.Socket - -.. autoclass:: zmq.core.poll.Poller - :members: - .. [1] http://github.com/zeromq/pyzmq .. [2] http://www.zeromq.com diff -Nru python-eventlet-0.20.0/doc/real_index.html python-eventlet-0.24.1/doc/real_index.html --- python-eventlet-0.20.0/doc/real_index.html 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/doc/real_index.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,181 +0,0 @@ - - - - - - - Eventlet Networking Library - - - - - - - - -
-
-
-
- -
-

Eventlet

- -

Eventlet is a concurrent networking library for Python that allows you to change how you run your code, not how you write it.

- -
    -
  • It uses epoll or kqueue or libevent for highly scalable non-blocking I/O.
  • -
  • Coroutines ensure that the developer uses a blocking style of programming that is similar to threading, but provide the benefits of non-blocking I/O.
  • -
  • The event dispatch is implicit, which means you can easily use Eventlet from the Python interpreter, or as a small part of a larger application.
  • -
- -

It's easy to get started using Eventlet, and easy to convert existing applications to use it. Start off by looking at examples, common design patterns, and the list of the basic API primitives.

- -

License: MIT.

- -

API Documentation

- - -

Installation

- -

To install Eventlet, simply: -

-pip install eventlet
-

- -

Alternately, you can download the source archive:

- - - -

Discussion

- - - - -

Development

- - -

Both repositories are equal and kept in sync. - You can use whichever you fancy for downloading, forking, reporting issues and submitting pull requests.

-

Mercurial repository used to be the main one, but most of the contribution and discussions happen on Github nowadays.

- -

Pull request policy

-
    -
  • Test is required
  • -
  • One commit is strongly preferred, except for very big changes
  • -
  • Commit message should follow the following formula: -
    -subsystem: description of why the change is useful
    -
    -optional details or links to related issues or websites
    -
    - The why part is very important. Diff already says what you have done. But nobody knows why. -
  • -
  • Feel free to append yourself into AUTHORS file, sections Thanks To or Contributors. -
-

If you don't like these rules, raw patches are more than welcome!

- - -

Bugs

- -

Please be sure to report bugs as effectively as possible, to ensure that we understand and act on them quickly.

- -

You may report bugs via: -

    -
  1. Github
  2. -
  3. Bitbucket (no registration is required)
  4. -
  5. Email eventletdev@lists.secondlife.com
  6. -
- - -
-

Web Crawler Example

-

This is a simple web “crawler” that fetches a bunch of urls using a coroutine pool. It has as much concurrency (i.e. pages being fetched simultaneously) as coroutines in the pool.

- -
import eventlet
-from eventlet.green import urllib2
-
-
-urls = [
-    "http://www.google.com/intl/en_ALL/images/logo.gif",
-    "https://wiki.secondlife.com/w/images/secondlife.jpg",
-    "http://us.i1.yimg.com/us.yimg.com/i/ww/beta/y3.gif",
-]
-
-
-def fetch(url):
-    return urllib2.urlopen(url).read()
-
-
-pool = eventlet.GreenPool()
-
-for body in pool.imap(fetch, urls):
-    print("got body", len(body))
-
- - -

Stats

-

Travis build

- - - -
-
-
- - -
-
-
-
-
- - - - - - diff -Nru python-eventlet-0.20.0/doc/ssl.rst python-eventlet-0.24.1/doc/ssl.rst --- python-eventlet-0.20.0/doc/ssl.rst 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/doc/ssl.rst 2018-08-06 16:17:47.000000000 +0000 @@ -1,7 +1,7 @@ Using SSL With Eventlet ======================== -Eventlet makes it easy to use non-blocking SSL sockets. If you're using Python 2.6 or later, you're all set, eventlet wraps the built-in ssl module. If on Python 2.5 or 2.4, you have to install pyOpenSSL_ to use eventlet. +Eventlet makes it easy to use non-blocking SSL sockets. If you're using Python 2.7 or later, you're all set, eventlet wraps the built-in ssl module. In either case, the ``green`` modules handle SSL sockets transparently, just like their standard counterparts. As an example, :mod:`eventlet.green.urllib2` can be used to fetch https urls in as non-blocking a fashion as you please:: @@ -13,31 +13,29 @@ print(b.wait().read()) -With Python 2.6 ----------------- - -To use ssl sockets directly in Python 2.6, use :mod:`eventlet.green.ssl`, which is a non-blocking wrapper around the standard Python :mod:`ssl` module, and which has the same interface. See the standard documentation for instructions on use. - -With Python 2.5 or Earlier ---------------------------- - -Prior to Python 2.6, there is no :mod:`ssl`, so SSL support is much weaker. Eventlet relies on pyOpenSSL to implement its SSL support on these older versions, so be sure to install pyOpenSSL, or you'll get an ImportError whenever your system tries to make an SSL connection. - -Once pyOpenSSL is installed, you can then use the ``eventlet.green`` modules, like :mod:`eventlet.green.httplib` to fetch https urls. You can also use :func:`eventlet.green.socket.ssl`, which is a nonblocking wrapper for :func:`socket.ssl`. - PyOpenSSL ---------- :mod:`eventlet.green.OpenSSL` has exactly the same interface as pyOpenSSL_ `(docs) `_, and works in all versions of Python. This module is much more powerful than :func:`socket.ssl`, and may have some advantages over :mod:`ssl`, depending on your needs. -Here's an example of a server:: +For testing purpose first create self-signed certificate using following commands :: + + $ openssl genrsa 1024 > server.key + $ openssl req -new -x509 -nodes -sha1 -days 365 -key server.key > server.cert + +Keep these Private key and Self-signed certificate in same directory as `server.py` and `client.py` for simplicity sake. + +Here's an example of a server (`server.py`) :: from eventlet.green import socket from eventlet.green.OpenSSL import SSL # insecure context, only for example purposes context = SSL.Context(SSL.SSLv23_METHOD) - context.set_verify(SSL.VERIFY_NONE, lambda *x: True)) + # Pass server's private key created + context.use_privatekey_file('server.key') + # Pass self-signed certificate created + context.use_certificate_file('server.cert') # create underlying green socket and wrap it in ssl sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -45,7 +43,7 @@ # configure as server connection.set_accept_state() - connection.bind(('127.0.0.1', 80443)) + connection.bind(('127.0.0.1', 8443)) connection.listen(50) # accept one client connection then close up shop @@ -55,4 +53,28 @@ client_conn.close() connection.close() +Here's an example of a client (`client.py`) :: + + import socket + # Create socket + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + # Connect to server + s.connect(('127.0.0.1', 8443)) + sslSocket = socket.ssl(s) + print repr(sslSocket.server()) + print repr(sslSocket.issuer()) + sslSocket.write('Hello secure socket\n') + # Close client + s.close() + +Running example:: + +In first terminal + + $ python server.py + +In another terminal + + $ python client.py + .. _pyOpenSSL: https://launchpad.net/pyopenssl diff -Nru python-eventlet-0.20.0/doc/_templates/layout.html python-eventlet-0.24.1/doc/_templates/layout.html --- python-eventlet-0.20.0/doc/_templates/layout.html 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/doc/_templates/layout.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -{% extends "!layout.html" %} - -{% block footer %} -{{ super() }} - -{% endblock %} diff -Nru python-eventlet-0.20.0/doc/zeromq.rst python-eventlet-0.24.1/doc/zeromq.rst --- python-eventlet-0.20.0/doc/zeromq.rst 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/doc/zeromq.rst 2018-08-06 16:17:47.000000000 +0000 @@ -26,4 +26,4 @@ API documentation ================= -ØMQ support is provided in the :mod:`eventlet.green.zmq` module \ No newline at end of file +ØMQ support is provided in the :mod:`eventlet.green.zmq` module. diff -Nru python-eventlet-0.20.0/eventlet/convenience.py python-eventlet-0.24.1/eventlet/convenience.py --- python-eventlet-0.20.0/eventlet/convenience.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/convenience.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,8 +1,9 @@ import sys +import warnings -from eventlet import greenio from eventlet import greenpool from eventlet import greenthread +from eventlet import support from eventlet.green import socket from eventlet.support import greenlets as greenlet @@ -22,7 +23,15 @@ return sock -def listen(addr, family=socket.AF_INET, backlog=50): +class ReuseRandomPortWarning(Warning): + pass + + +class ReusePortUnavailableWarning(Warning): + pass + + +def listen(addr, family=socket.AF_INET, backlog=50, reuse_addr=True, reuse_port=None): """Convenience function for opening server sockets. This socket can be used in :func:`~eventlet.serve` or a custom ``accept()`` loop. @@ -38,11 +47,34 @@ :return: The listening green socket object. """ sock = socket.socket(family, socket.SOCK_STREAM) - if sys.platform[:3] != "win": + if reuse_addr and sys.platform[:3] != 'win': sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - if hasattr(socket, 'SO_REUSEPORT'): + if family in (socket.AF_INET, socket.AF_INET6) and addr[1] == 0: + if reuse_port: + warnings.warn( + '''listen on random port (0) with SO_REUSEPORT is dangerous. + Double check your intent. + Example problem: https://github.com/eventlet/eventlet/issues/411''', + ReuseRandomPortWarning, stacklevel=3) + elif reuse_port is None: + reuse_port = True + if reuse_port and hasattr(socket, 'SO_REUSEPORT'): # NOTE(zhengwei): linux kernel >= 3.9 - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + try: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + # OSError is enough on Python 3+ + except (OSError, socket.error) as ex: + if support.get_errno(ex) in (22, 92): + # A famous platform defines unsupported socket option. + # https://github.com/eventlet/eventlet/issues/380 + # https://github.com/eventlet/eventlet/issues/418 + warnings.warn( + '''socket.SO_REUSEPORT is defined but not supported. + On Windows: known bug, wontfix. + On other systems: please comment in the issue linked below. + More information: https://github.com/eventlet/eventlet/issues/380''', + ReusePortUnavailableWarning, stacklevel=3) + sock.bind(addr) sock.listen(backlog) return sock @@ -135,7 +167,7 @@ except ImportError: def wrap_ssl_impl(*a, **kw): raise ImportError( - "To use SSL with Eventlet, you must install PyOpenSSL or use Python 2.6 or later.") + "To use SSL with Eventlet, you must install PyOpenSSL or use Python 2.7 or later.") else: def wrap_ssl_impl(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=None, ssl_version=None, ca_certs=None, diff -Nru python-eventlet-0.20.0/eventlet/dagpool.py python-eventlet-0.24.1/eventlet/dagpool.py --- python-eventlet-0.20.0/eventlet/dagpool.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/dagpool.py 2018-08-06 16:17:47.000000000 +0000 @@ -5,7 +5,7 @@ from eventlet.event import Event from eventlet import greenthread -from eventlet.support import six +import six import collections diff -Nru python-eventlet-0.20.0/eventlet/db_pool.py python-eventlet-0.24.1/eventlet/db_pool.py --- python-eventlet-0.20.0/eventlet/db_pool.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/db_pool.py 2018-08-06 16:17:47.000000000 +0000 @@ -327,98 +327,53 @@ def __repr__(self): return self._base.__repr__() - def affected_rows(self): - return self._base.affected_rows() - - def autocommit(self, *args, **kwargs): - return self._base.autocommit(*args, **kwargs) - - def begin(self): - return self._base.begin() - - def change_user(self, *args, **kwargs): - return self._base.change_user(*args, **kwargs) - - def character_set_name(self, *args, **kwargs): - return self._base.character_set_name(*args, **kwargs) - - def close(self, *args, **kwargs): - return self._base.close(*args, **kwargs) - - def commit(self, *args, **kwargs): - return self._base.commit(*args, **kwargs) - - def cursor(self, *args, **kwargs): - return self._base.cursor(*args, **kwargs) - - def dump_debug_info(self, *args, **kwargs): - return self._base.dump_debug_info(*args, **kwargs) - - def errno(self, *args, **kwargs): - return self._base.errno(*args, **kwargs) - - def error(self, *args, **kwargs): - return self._base.error(*args, **kwargs) - - def errorhandler(self, *args, **kwargs): - return self._base.errorhandler(*args, **kwargs) - - def insert_id(self, *args, **kwargs): - return self._base.insert_id(*args, **kwargs) - - def literal(self, *args, **kwargs): - return self._base.literal(*args, **kwargs) - - def set_character_set(self, *args, **kwargs): - return self._base.set_character_set(*args, **kwargs) - - def set_sql_mode(self, *args, **kwargs): - return self._base.set_sql_mode(*args, **kwargs) - - def show_warnings(self): - return self._base.show_warnings() - - def warning_count(self): - return self._base.warning_count() - - def ping(self, *args, **kwargs): - return self._base.ping(*args, **kwargs) - - def query(self, *args, **kwargs): - return self._base.query(*args, **kwargs) - - def rollback(self, *args, **kwargs): - return self._base.rollback(*args, **kwargs) - - def select_db(self, *args, **kwargs): - return self._base.select_db(*args, **kwargs) - - def set_server_option(self, *args, **kwargs): - return self._base.set_server_option(*args, **kwargs) - - def server_capabilities(self, *args, **kwargs): - return self._base.server_capabilities(*args, **kwargs) - - def shutdown(self, *args, **kwargs): - return self._base.shutdown(*args, **kwargs) - - def sqlstate(self, *args, **kwargs): - return self._base.sqlstate(*args, **kwargs) - - def stat(self, *args, **kwargs): - return self._base.stat(*args, **kwargs) - - def store_result(self, *args, **kwargs): - return self._base.store_result(*args, **kwargs) - - def string_literal(self, *args, **kwargs): - return self._base.string_literal(*args, **kwargs) - - def thread_id(self, *args, **kwargs): - return self._base.thread_id(*args, **kwargs) - - def use_result(self, *args, **kwargs): - return self._base.use_result(*args, **kwargs) + _proxy_funcs = ( + 'affected_rows', + 'autocommit', + 'begin', + 'change_user', + 'character_set_name', + 'close', + 'commit', + 'cursor', + 'dump_debug_info', + 'errno', + 'error', + 'errorhandler', + 'insert_id', + 'literal', + 'ping', + 'query', + 'rollback', + 'select_db', + 'server_capabilities', + 'set_character_set', + 'set_isolation_level', + 'set_server_option', + 'set_sql_mode', + 'show_warnings', + 'shutdown', + 'sqlstate', + 'stat', + 'store_result', + 'string_literal', + 'thread_id', + 'use_result', + 'warning_count', + ) +for _proxy_fun in GenericConnectionWrapper._proxy_funcs: + # excess wrapper for early binding (closure by value) + def _wrapper(_proxy_fun=_proxy_fun): + def _proxy_method(self, *args, **kwargs): + return getattr(self._base, _proxy_fun)(*args, **kwargs) + _proxy_method.func_name = _proxy_fun + _proxy_method.__name__ = _proxy_fun + _proxy_method.__qualname__ = 'GenericConnectionWrapper.' + _proxy_fun + return _proxy_method + setattr(GenericConnectionWrapper, _proxy_fun, _wrapper(_proxy_fun)) +del GenericConnectionWrapper._proxy_funcs +del _proxy_fun +del _wrapper class PooledConnectionWrapper(GenericConnectionWrapper): diff -Nru python-eventlet-0.20.0/eventlet/event.py python-eventlet-0.24.1/eventlet/event.py --- python-eventlet-0.20.0/eventlet/event.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/event.py 2018-08-06 16:17:47.000000000 +0000 @@ -92,14 +92,12 @@ return self.wait() return notready - def wait(self): + def wait(self, timeout=None): """Wait until another coroutine calls :meth:`send`. - Returns the value the other coroutine passed to - :meth:`send`. + Returns the value the other coroutine passed to :meth:`send`. - >>> from eventlet import event >>> import eventlet - >>> evt = event.Event() + >>> evt = eventlet.Event() >>> def wait_on(): ... retval = evt.wait() ... print("waited for {0}".format(retval)) @@ -108,17 +106,26 @@ >>> eventlet.sleep(0) waited for result - Returns immediately if the event has already - occurred. + Returns immediately if the event has already occurred. >>> evt.wait() 'result' + + When the timeout argument is present and not None, it should be a floating point number + specifying a timeout for the operation in seconds (or fractions thereof). """ current = greenlet.getcurrent() if self._result is NOT_USED: + hub = hubs.get_hub() self._waiters.add(current) + timer = None + if timeout is not None: + timer = hub.schedule_call_local(timeout, self._do_send, None, None, current) try: - return hubs.get_hub().switch() + result = hub.switch() + if timer is not None: + timer.cancel() + return result finally: self._waiters.discard(current) if self._exc is not None: diff -Nru python-eventlet-0.20.0/eventlet/green/BaseHTTPServer.py python-eventlet-0.24.1/eventlet/green/BaseHTTPServer.py --- python-eventlet-0.20.0/eventlet/green/BaseHTTPServer.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/BaseHTTPServer.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,7 +1,7 @@ from eventlet import patcher from eventlet.green import socket from eventlet.green import SocketServer -from eventlet.support import six +import six patcher.inject( 'BaseHTTPServer' if six.PY2 else 'http.server', diff -Nru python-eventlet-0.20.0/eventlet/green/http/client.py python-eventlet-0.24.1/eventlet/green/http/client.py --- python-eventlet-0.20.0/eventlet/green/http/client.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/http/client.py 2018-08-06 16:17:47.000000000 +0000 @@ -849,6 +849,44 @@ auto_open = 1 debuglevel = 0 + @staticmethod + def _is_textIO(stream): + """Test whether a file-like object is a text or a binary stream. + """ + return isinstance(stream, io.TextIOBase) + + @staticmethod + def _get_content_length(body, method): + """Get the content-length based on the body. + + If the body is None, we set Content-Length: 0 for methods that expect + a body (RFC 7230, Section 3.3.2). We also set the Content-Length for + any method if the body is a str or bytes-like object and not a file. + """ + if body is None: + # do an explicit check for not None here to distinguish + # between unset and set but empty + if method.upper() in _METHODS_EXPECTING_BODY: + return 0 + else: + return None + + if hasattr(body, 'read'): + # file-like object. + return None + + try: + # does it implement the buffer protocol (bytes, bytearray, array)? + mv = memoryview(body) + return mv.nbytes + except TypeError: + pass + + if isinstance(body, str): + return len(body) + + return None + def __init__(self, host, port=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None): self.timeout = timeout @@ -1024,7 +1062,22 @@ """ self._buffer.append(s) - def _send_output(self, message_body=None): + def _read_readable(self, readable): + blocksize = 8192 + if self.debuglevel > 0: + print("sendIng a read()able") + encode = self._is_textIO(readable) + if encode and self.debuglevel > 0: + print("encoding file using iso-8859-1") + while True: + datablock = readable.read(blocksize) + if not datablock: + break + if encode: + datablock = datablock.encode("iso-8859-1") + yield datablock + + def _send_output(self, message_body=None, encode_chunked=False): """Send the currently buffered request and clear the buffer. Appends an extra \\r\\n to the buffer. @@ -1033,10 +1086,49 @@ self._buffer.extend((b"", b"")) msg = b"\r\n".join(self._buffer) del self._buffer[:] - self.send(msg) + if message_body is not None: - self.send(message_body) + + # create a consistent interface to message_body + if hasattr(message_body, 'read'): + # Let file-like take precedence over byte-like. This + # is needed to allow the current position of mmap'ed + # files to be taken into account. + chunks = self._read_readable(message_body) + else: + try: + # this is solely to check to see if message_body + # implements the buffer API. it /would/ be easier + # to capture if PyObject_CheckBuffer was exposed + # to Python. + memoryview(message_body) + except TypeError: + try: + chunks = iter(message_body) + except TypeError: + raise TypeError("message_body should be a bytes-like " + "object or an iterable, got %r" + % type(message_body)) + else: + # the object implements the buffer interface and + # can be passed directly into socket methods + chunks = (message_body,) + + for chunk in chunks: + if not chunk: + if self.debuglevel > 0: + print('Zero length chunk ignored') + continue + + if encode_chunked and self._http_vsn == 11: + # chunked encoding + chunk = '{0:X}\r\n'.format(len(chunk)).encode('ascii') + chunk + b'\r\n' + self.send(chunk) + + if encode_chunked and self._http_vsn == 11: + # end chunked transfer + self.send(b'0\r\n\r\n') def putrequest(self, method, url, skip_host=0, skip_accept_encoding=0): """Send a request to the server. @@ -1189,24 +1281,23 @@ header = header + b': ' + value self._output(header) - def endheaders(self, message_body=None): + def endheaders(self, message_body=None, *, encode_chunked=False): """Indicate that the last header line has been sent to the server. This method sends the request to the server. The optional message_body argument can be used to pass a message body associated with the - request. The message body will be sent in the same packet as the - message headers if it is a string, otherwise it is sent as a separate - packet. + request. """ if self.__state == _CS_REQ_STARTED: self.__state = _CS_REQ_SENT else: raise CannotSendHeader() - self._send_output(message_body) + self._send_output(message_body, encode_chunked=encode_chunked) - def request(self, method, url, body=None, headers={}): + def request(self, method, url, body=None, headers={}, *, + encode_chunked=False): """Send a complete request to the server.""" - self._send_request(method, url, body, headers) + self._send_request(method, url, body, headers, encode_chunked) def _set_content_length(self, body, method): # Set the content-length based on the body. If the body is "empty", we @@ -1232,9 +1323,9 @@ if thelen is not None: self.putheader('Content-Length', thelen) - def _send_request(self, method, url, body, headers): + def _send_request(self, method, url, body, headers, encode_chunked): # Honor explicitly requested Host: and Accept-Encoding: headers. - header_names = dict.fromkeys([k.lower() for k in headers]) + header_names = frozenset(k.lower() for k in headers) skips = {} if 'host' in header_names: skips['skip_host'] = 1 @@ -1243,15 +1334,40 @@ self.putrequest(method, url, **skips) + # chunked encoding will happen if HTTP/1.1 is used and either + # the caller passes encode_chunked=True or the following + # conditions hold: + # 1. content-length has not been explicitly set + # 2. the body is a file or iterable, but not a str or bytes-like + # 3. Transfer-Encoding has NOT been explicitly set by the caller + if 'content-length' not in header_names: - self._set_content_length(body, method) + # only chunk body if not explicitly set for backwards + # compatibility, assuming the client code is already handling the + # chunking + if 'transfer-encoding' not in header_names: + # if content-length cannot be automatically determined, fall + # back to chunked encoding + encode_chunked = False + content_length = self._get_content_length(body, method) + if content_length is None: + if body is not None: + if self.debuglevel > 0: + print('Unable to determine size of %r' % body) + encode_chunked = True + self.putheader('Transfer-Encoding', 'chunked') + else: + self.putheader('Content-Length', str(content_length)) + else: + encode_chunked = False + for hdr, value in headers.items(): self.putheader(hdr, value) if isinstance(body, str): # RFC 2616 Section 3.7.1 says that text default has a # default charset of iso-8859-1. body = _encode(body, 'body') - self.endheaders(body) + self.endheaders(body, encode_chunked=encode_chunked) def getresponse(self): """Get the response from the server. diff -Nru python-eventlet-0.20.0/eventlet/green/http/__init__.py python-eventlet-0.24.1/eventlet/green/http/__init__.py --- python-eventlet-0.20.0/eventlet/green/http/__init__.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/http/__init__.py 2018-08-06 16:17:47.000000000 +0000 @@ -52,7 +52,7 @@ # 8. By copying, installing or otherwise using Python, Licensee # agrees to be bound by the terms and conditions of this License # Agreement. -from eventlet.support import six +import six assert six.PY3, 'This is a Python 3 module' from enum import IntEnum diff -Nru python-eventlet-0.20.0/eventlet/green/httplib.py python-eventlet-0.24.1/eventlet/green/httplib.py --- python-eventlet-0.20.0/eventlet/green/httplib.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/httplib.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,6 +1,6 @@ from eventlet import patcher from eventlet.green import socket -from eventlet.support import six +import six to_patch = [('socket', socket)] diff -Nru python-eventlet-0.20.0/eventlet/green/OpenSSL/__init__.py python-eventlet-0.24.1/eventlet/green/OpenSSL/__init__.py --- python-eventlet-0.20.0/eventlet/green/OpenSSL/__init__.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/OpenSSL/__init__.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,4 +1,3 @@ -from . import rand from . import crypto from . import SSL from . import tsafe diff -Nru python-eventlet-0.20.0/eventlet/green/OpenSSL/rand.py python-eventlet-0.24.1/eventlet/green/OpenSSL/rand.py --- python-eventlet-0.20.0/eventlet/green/OpenSSL/rand.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/OpenSSL/rand.py 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -from OpenSSL.rand import * diff -Nru python-eventlet-0.20.0/eventlet/green/profile.py python-eventlet-0.24.1/eventlet/green/profile.py --- python-eventlet-0.20.0/eventlet/green/profile.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/profile.py 2018-08-06 16:17:47.000000000 +0000 @@ -40,9 +40,9 @@ from eventlet import greenthread from eventlet import patcher -from eventlet.support import six +import six -thread = patcher.original('thread') # non-monkeypatched module needed +thread = patcher.original(six.moves._thread.__name__) # non-monkeypatched module needed # This class provides the start() and stop() functions @@ -117,13 +117,6 @@ self.trace_dispatch_c_call(frame, 0) return self.trace_dispatch_return(frame, t) - # Add "return safety" to the dispatchers - dispatch = dict(profile_orig.Profile.dispatch) - dispatch.update({ - "return": trace_dispatch_return_extend_back, - "c_return": trace_dispatch_c_return_extend_back, - }) - def SwitchTasklet(self, t0, t1, t): # tally the time spent in the old tasklet pt, it, et, fn, frame, rcur = self.cur @@ -141,19 +134,6 @@ self.simulate_call("profiler") self.simulate_call("new_tasklet") - def ContextWrap(f): - @functools.wraps(f) - def ContextWrapper(self, arg, t): - current = greenthread.getcurrent() - if current != self.current_tasklet: - self.SwitchTasklet(self.current_tasklet, current, t) - t = 0.0 # the time was billed to the previous tasklet - return f(self, arg, t) - return ContextWrapper - - # Add automatic tasklet detection to the callbacks. - dispatch = dict([(key, ContextWrap(val)) for key, val in six.iteritems(dispatch)]) - def TallyTimings(self): oldtimings = self.sleeping self.sleeping = {} @@ -216,6 +196,26 @@ return cur +def ContextWrap(f): + @functools.wraps(f) + def ContextWrapper(self, arg, t): + current = greenthread.getcurrent() + if current != self.current_tasklet: + self.SwitchTasklet(self.current_tasklet, current, t) + t = 0.0 # the time was billed to the previous tasklet + return f(self, arg, t) + return ContextWrapper + + +# Add "return safety" to the dispatchers +Profile.dispatch = dict(profile_orig.Profile.dispatch, **{ + 'return': Profile.trace_dispatch_return_extend_back, + 'c_return': Profile.trace_dispatch_c_return_extend_back, +}) +# Add automatic tasklet detection to the callbacks. +Profile.dispatch = dict((k, ContextWrap(v)) for k, v in six.viewitems(Profile.dispatch)) + + # run statements shamelessly stolen from profile.py def run(statement, filename=None, sort=-1): """Run statement under profiler optionally saving results in filename diff -Nru python-eventlet-0.20.0/eventlet/green/select.py python-eventlet-0.24.1/eventlet/green/select.py --- python-eventlet-0.20.0/eventlet/green/select.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/select.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,8 +1,8 @@ -__select = __import__('select') -error = __select.error -from eventlet.greenthread import getcurrent +import eventlet from eventlet.hubs import get_hub -from eventlet.support import six +import six +__select = eventlet.patcher.original('select') +error = __select.error __patched__ = ['select'] @@ -36,7 +36,7 @@ raise TypeError("Expected number for timeout") hub = get_hub() timers = [] - current = getcurrent() + current = eventlet.getcurrent() assert hub.greenlet is not current, 'do not call blocking functions from the mainloop' ds = {} for r in read_list: @@ -56,10 +56,6 @@ original = ds[get_fileno(d)]['write'] current.switch(([], [original], [])) - def on_error(d, _err=None): - original = ds[get_fileno(d)]['error'] - current.switch(([], [], [original])) - def on_timeout2(): current.switch(([], [], [])) @@ -77,9 +73,9 @@ try: for k, v in six.iteritems(ds): if v.get('read'): - listeners.append(hub.add(hub.READ, k, on_read, on_error, lambda x: None)) + listeners.append(hub.add(hub.READ, k, on_read, current.throw, lambda: None)) if v.get('write'): - listeners.append(hub.add(hub.WRITE, k, on_write, on_error, lambda x: None)) + listeners.append(hub.add(hub.WRITE, k, on_write, current.throw, lambda: None)) try: return hub.switch() finally: diff -Nru python-eventlet-0.20.0/eventlet/green/_socket_nodns.py python-eventlet-0.24.1/eventlet/green/_socket_nodns.py --- python-eventlet-0.20.0/eventlet/green/_socket_nodns.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/_socket_nodns.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,17 +1,19 @@ __socket = __import__('socket') __all__ = __socket.__all__ -__patched__ = ['fromfd', 'socketpair', 'ssl', 'socket'] +__patched__ = ['fromfd', 'socketpair', 'ssl', 'socket', 'timeout'] -from eventlet.patcher import slurp_properties -slurp_properties(__socket, globals(), - ignore=__patched__, srckeys=dir(__socket)) +import eventlet.patcher +eventlet.patcher.slurp_properties(__socket, globals(), ignore=__patched__, srckeys=dir(__socket)) os = __import__('os') import sys -from eventlet.hubs import get_hub -from eventlet.greenio import GreenSocket as socket -from eventlet.greenio import _GLOBAL_DEFAULT_TIMEOUT +from eventlet import greenio + + +socket = greenio.GreenSocket +_GLOBAL_DEFAULT_TIMEOUT = greenio._GLOBAL_DEFAULT_TIMEOUT +timeout = greenio.socket_timeout try: __original_fromfd__ = __socket.fromfd diff -Nru python-eventlet-0.20.0/eventlet/green/socket.py python-eventlet-0.24.1/eventlet/green/socket.py --- python-eventlet-0.20.0/eventlet/green/socket.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/socket.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,6 +1,5 @@ import os import sys -import warnings __import__('eventlet.green._socket_nodns') __socket = sys.modules['eventlet.green._socket_nodns'] @@ -18,18 +17,13 @@ slurp_properties(__socket, globals(), srckeys=dir(__socket)) -if os.environ.get("EVENTLET_NO_GREENDNS", '').lower() == "yes": - warnings.warn( - 'EVENTLET_NO_GREENDNS is noop, dnspython is bundled and DNS resolution is always green', - DeprecationWarning, - stacklevel=2, - ) - -from eventlet.support import greendns -gethostbyname = greendns.gethostbyname -getaddrinfo = greendns.getaddrinfo -gethostbyname_ex = greendns.gethostbyname_ex -getnameinfo = greendns.getnameinfo +if os.environ.get("EVENTLET_NO_GREENDNS", '').lower() != 'yes': + from eventlet.support import greendns + gethostbyname = greendns.gethostbyname + getaddrinfo = greendns.getaddrinfo + gethostbyname_ex = greendns.gethostbyname_ex + getnameinfo = greendns.getnameinfo + del greendns def create_connection(address, diff -Nru python-eventlet-0.20.0/eventlet/green/SocketServer.py python-eventlet-0.24.1/eventlet/green/SocketServer.py --- python-eventlet-0.20.0/eventlet/green/SocketServer.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/SocketServer.py 2018-08-06 16:17:47.000000000 +0000 @@ -3,7 +3,7 @@ from eventlet.green import socket from eventlet.green import select from eventlet.green import threading -from eventlet.support import six +import six patcher.inject( 'SocketServer' if six.PY2 else 'socketserver', diff -Nru python-eventlet-0.20.0/eventlet/green/ssl.py python-eventlet-0.24.1/eventlet/green/ssl.py --- python-eventlet-0.20.0/eventlet/green/ssl.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/ssl.py 2018-08-06 16:17:47.000000000 +0000 @@ -13,15 +13,11 @@ set_nonblocking, GreenSocket, CONNECT_ERR, CONNECT_SUCCESS, ) from eventlet.hubs import trampoline, IOClosed -from eventlet.support import get_errno, PY33, six +from eventlet.support import get_errno, PY33 +import six orig_socket = __import__('socket') socket = orig_socket.socket -if sys.version_info >= (2, 7): - has_ciphers = True - timeout_exc = SSLError -else: - has_ciphers = False - timeout_exc = orig_socket.timeout +timeout_exc = SSLError __patched__ = [ 'SSLSocket', 'SSLContext', 'wrap_socket', 'sslwrap_simple', @@ -215,13 +211,7 @@ raise ValueError( "non-zero flags not allowed in calls to %s() on %s" % plain_socket_function.__name__, self.__class__) - if sys.version_info < (2, 7) and into: - # Python 2.6 SSLSocket.read() doesn't support reading into - # a given buffer so we need to emulate - data = self.read(nbytes) - buffer_[:len(data)] = data - read = len(data) - elif into: + if into: read = self.read(nbytes, buffer_) else: read = self.read(nbytes) @@ -325,7 +315,7 @@ else: sslobj = sslwrap(self._sock, server_side, self.keyfile, self.certfile, self.cert_reqs, self.ssl_version, - self.ca_certs, *([self.ciphers] if has_ciphers else [])) + self.ca_certs, *self.ciphers) try: # This is added in Python 3.5, http://bugs.python.org/issue21965 @@ -401,6 +391,26 @@ def wrap_socket(self, sock, *a, **kw): return GreenSSLSocket(sock, *a, _context=self, **kw) + # https://github.com/eventlet/eventlet/issues/371 + # Thanks to Gevent developers for sharing patch to this problem. + if hasattr(_original_sslcontext.options, 'setter'): + # In 3.6, these became properties. They want to access the + # property __set__ method in the superclass, and they do so by using + # super(SSLContext, SSLContext). But we rebind SSLContext when we monkey + # patch, which causes infinite recursion. + # https://github.com/python/cpython/commit/328067c468f82e4ec1b5c510a4e84509e010f296 + @_original_sslcontext.options.setter + def options(self, value): + super(_original_sslcontext, _original_sslcontext).options.__set__(self, value) + + @_original_sslcontext.verify_flags.setter + def verify_flags(self, value): + super(_original_sslcontext, _original_sslcontext).verify_flags.__set__(self, value) + + @_original_sslcontext.verify_mode.setter + def verify_mode(self, value): + super(_original_sslcontext, _original_sslcontext).verify_mode.__set__(self, value) + SSLContext = GreenSSLContext if hasattr(__ssl, 'create_default_context'): diff -Nru python-eventlet-0.20.0/eventlet/green/subprocess.py python-eventlet-0.24.1/eventlet/green/subprocess.py --- python-eventlet-0.20.0/eventlet/green/subprocess.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/subprocess.py 2018-08-06 16:17:47.000000000 +0000 @@ -6,7 +6,7 @@ from eventlet import greenio from eventlet import patcher from eventlet.green import select, threading, time -from eventlet.support import six +import six __patched__ = ['call', 'check_call', 'Popen'] @@ -18,6 +18,7 @@ patcher.inject('subprocess', globals(), *to_patch) subprocess_orig = patcher.original("subprocess") +subprocess_imported = sys.modules.get('subprocess', subprocess_orig) mswindows = sys.platform == "win32" @@ -37,6 +38,8 @@ def __str__(self): return ("Command '%s' timed out after %s seconds" % (self.cmd, self.timeout)) +else: + TimeoutExpired = subprocess_imported.TimeoutExpired # This is the meat of this module, the green version of Popen. @@ -133,3 +136,8 @@ __patched__.append('check_output') check_output = patched_function(subprocess_orig.check_output) del patched_function + +# Keep exceptions identity. +# https://github.com/eventlet/eventlet/issues/413 +CalledProcessError = subprocess_imported.CalledProcessError +del subprocess_imported diff -Nru python-eventlet-0.20.0/eventlet/green/threading.py python-eventlet-0.24.1/eventlet/green/threading.py --- python-eventlet-0.20.0/eventlet/green/threading.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/threading.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,8 +1,9 @@ """Implements the standard threading module, using greenthreads.""" -from eventlet import patcher +import eventlet from eventlet.green import thread from eventlet.green import time -from eventlet.support import greenlets as greenlet, six +from eventlet.support import greenlets as greenlet +import six __patched__ = ['_start_new_thread', '_allocate_lock', '_sleep', 'local', 'stack_size', 'Lock', 'currentThread', @@ -13,18 +14,17 @@ else: __patched__ += ['get_ident', '_set_sentinel'] -__orig_threading = patcher.original('threading') +__orig_threading = eventlet.patcher.original('threading') __threadlocal = __orig_threading.local() +__patched_enumerate = None -patcher.inject( +eventlet.patcher.inject( 'threading', globals(), ('thread' if six.PY2 else '_thread', thread), ('time', time)) -del patcher - _count = 1 @@ -89,6 +89,7 @@ def current_thread(): + global __patched_enumerate g = greenlet.getcurrent() if not g: # Not currently in a greenthread, fall back to standard function @@ -99,21 +100,34 @@ except AttributeError: active = __threadlocal.active = {} + g_id = id(g) + t = active.get(g_id) + if t is not None: + return t + + # FIXME: move import from function body to top + # (jaketesler@github) Furthermore, I was unable to have the current_thread() return correct results from + # threading.enumerate() unless the enumerate() function was a) imported at runtime using the gross __import__() call + # and b) was hot-patched using patch_function(). + # https://github.com/eventlet/eventlet/issues/172#issuecomment-379421165 + if __patched_enumerate is None: + __patched_enumerate = eventlet.patcher.patch_function(__import__('threading').enumerate) + found = [th for th in __patched_enumerate() if th.ident == g_id] + if found: + return found[0] + + # Add green thread to active if we can clean it up on exit + def cleanup(g): + del active[g_id] try: - t = active[id(g)] - except KeyError: - # Add green thread to active if we can clean it up on exit - def cleanup(g): - del active[id(g)] - try: - g.link(cleanup) - except AttributeError: - # Not a GreenThread type, so there's no way to hook into - # the green thread exiting. Fall back to the standard - # function then. - t = _fixup_thread(__orig_threading.currentThread()) - else: - t = active[id(g)] = _GreenThread(g) + g.link(cleanup) + except AttributeError: + # Not a GreenThread type, so there's no way to hook into + # the green thread exiting. Fall back to the standard + # function then. + t = _fixup_thread(__orig_threading.current_thread()) + else: + t = active[g_id] = _GreenThread(g) return t diff -Nru python-eventlet-0.20.0/eventlet/green/thread.py python-eventlet-0.24.1/eventlet/green/thread.py --- python-eventlet-0.20.0/eventlet/green/thread.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/thread.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,6 +1,7 @@ """Implements the standard thread module, using greenthreads.""" -from eventlet.support.six.moves import _thread as __thread -from eventlet.support import greenlets as greenlet, six +from six.moves import _thread as __thread +import six +from eventlet.support import greenlets as greenlet from eventlet import greenthread from eventlet.semaphore import Semaphore as LockType import sys diff -Nru python-eventlet-0.20.0/eventlet/green/urllib/__init__.py python-eventlet-0.24.1/eventlet/green/urllib/__init__.py --- python-eventlet-0.20.0/eventlet/green/urllib/__init__.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/urllib/__init__.py 2018-08-06 16:17:47.000000000 +0000 @@ -3,7 +3,7 @@ from eventlet.green import time from eventlet.green import httplib from eventlet.green import ftplib -from eventlet.support import six +import six if six.PY2: to_patch = [('socket', socket), ('httplib', httplib), diff -Nru python-eventlet-0.20.0/eventlet/green/zmq.py python-eventlet-0.24.1/eventlet/green/zmq.py --- python-eventlet-0.20.0/eventlet/green/zmq.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/green/zmq.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,12 +1,9 @@ -# -*- coding: utf-8 -*- +# coding: utf-8 """The :mod:`zmq` module wraps the :class:`Socket` and :class:`Context` -found in :mod:`pyzmq ` to be non blocking +found in :mod:`pyzmq ` to be non blocking. """ - -from __future__ import with_statement - __zmq__ = __import__('zmq') -from eventlet import hubs +import eventlet.hubs from eventlet.patcher import slurp_properties from eventlet.support import greenlets as greenlet @@ -40,7 +37,7 @@ self._waiters = deque() self._count = 0 self._holder = None - self._hub = hubs.get_hub() + self._hub = eventlet.hubs.get_hub() def __nonzero__(self): return bool(self._count) @@ -88,18 +85,21 @@ def __init__(self): self._blocked_thread = None self._wakeupper = None - self._hub = hubs.get_hub() + self._hub = eventlet.hubs.get_hub() def __nonzero__(self): return self._blocked_thread is not None __bool__ = __nonzero__ - def block(self): + def block(self, deadline=None): if self._blocked_thread is not None: raise Exception("Cannot block more than one thread on one BlockedThread") self._blocked_thread = greenlet.getcurrent() + if deadline is not None: + self._hub.schedule_call_local(deadline - self._hub.clock(), self.wake) + try: self._hub.switch() finally: @@ -123,13 +123,13 @@ class Context(__zmq__.Context): - """Subclass of :class:`zmq.core.context.Context` + """Subclass of :class:`zmq.Context` """ def socket(self, socket_type): """Overridden method to ensure that the green version of socket is used - Behaves the same as :meth:`zmq.core.context.Context.socket`, but ensures + Behaves the same as :meth:`zmq.Context.socket`, but ensures that a :class:`Socket` with all of its send and recv methods set to be non-blocking is returned """ @@ -239,18 +239,19 @@ # avoid repeated wakeups _Socket_getsockopt(self, EVENTS) - hub = hubs.get_hub() + hub = eventlet.hubs.get_hub() self.__dict__['_eventlet_listener'] = hub.add(hub.READ, self.getsockopt(FD), event, lambda _: None, lambda: None) + self.__dict__['_eventlet_clock'] = hub.clock @_wraps(_Socket.close) def close(self, linger=None): super(Socket, self).close(linger) if self._eventlet_listener is not None: - hubs.get_hub().remove(self._eventlet_listener) + eventlet.hubs.get_hub().remove(self._eventlet_listener) self.__dict__['_eventlet_listener'] = None # wake any blocked threads self._eventlet_send_event.wake() @@ -320,46 +321,46 @@ return _Socket_send_multipart(self, msg_parts, flags, copy, track) @_wraps(_Socket.send_string) - def send_string(self, msg_parts, flags=0, copy=True, track=False): + def send_string(self, u, flags=0, copy=True, encoding='utf-8'): """A send_string method that's safe to use when multiple greenthreads are calling send, send_string, recv and recv_string on the same socket. """ if flags & NOBLOCK: - return _Socket_send_string(self, msg_parts, flags, copy, track) + return _Socket_send_string(self, u, flags, copy, encoding) # acquire lock here so the subsequent calls to send for the # message parts after the first don't block with self._eventlet_send_lock: - return _Socket_send_string(self, msg_parts, flags, copy, track) + return _Socket_send_string(self, u, flags, copy, encoding) @_wraps(_Socket.send_pyobj) - def send_pyobj(self, msg_parts, flags=0, copy=True, track=False): + def send_pyobj(self, obj, flags=0, protocol=2): """A send_pyobj method that's safe to use when multiple greenthreads are calling send, send_pyobj, recv and recv_pyobj on the same socket. """ if flags & NOBLOCK: - return _Socket_send_pyobj(self, msg_parts, flags, copy, track) + return _Socket_send_pyobj(self, obj, flags, protocol) # acquire lock here so the subsequent calls to send for the # message parts after the first don't block with self._eventlet_send_lock: - return _Socket_send_pyobj(self, msg_parts, flags, copy, track) + return _Socket_send_pyobj(self, obj, flags, protocol) @_wraps(_Socket.send_json) - def send_json(self, msg_parts, flags=0, copy=True, track=False): + def send_json(self, obj, flags=0, **kwargs): """A send_json method that's safe to use when multiple greenthreads are calling send, send_json, recv and recv_json on the same socket. """ if flags & NOBLOCK: - return _Socket_send_json(self, msg_parts, flags, copy, track) + return _Socket_send_json(self, obj, flags, **kwargs) # acquire lock here so the subsequent calls to send for the # message parts after the first don't block with self._eventlet_send_lock: - return _Socket_send_json(self, msg_parts, flags, copy, track) + return _Socket_send_json(self, obj, flags, **kwargs) @_wraps(_Socket.recv) def recv(self, flags=0, copy=True, track=False): @@ -376,6 +377,16 @@ self._eventlet_recv_event.wake() return msg + deadline = None + if hasattr(__zmq__, 'RCVTIMEO'): + sock_timeout = self.getsockopt(__zmq__.RCVTIMEO) + if sock_timeout == -1: + pass + elif sock_timeout > 0: + deadline = self._eventlet_clock() + sock_timeout / 1000.0 + else: + raise ValueError(sock_timeout) + flags |= NOBLOCK with self._eventlet_recv_lock: while True: @@ -383,7 +394,12 @@ return _Socket_recv(self, flags, copy, track) except ZMQError as e: if e.errno == EAGAIN: - self._eventlet_recv_event.block() + # zmq in its wisdom decided to reuse EAGAIN for timeouts + if deadline is not None and self._eventlet_clock() > deadline: + e.is_timeout = True + raise + + self._eventlet_recv_event.block(deadline=deadline) else: raise finally: @@ -407,43 +423,43 @@ return _Socket_recv_multipart(self, flags, copy, track) @_wraps(_Socket.recv_string) - def recv_string(self, flags=0, copy=True, track=False): + def recv_string(self, flags=0, encoding='utf-8'): """A recv_string method that's safe to use when multiple greenthreads are calling send, send_string, recv and recv_string on the same socket. """ if flags & NOBLOCK: - return _Socket_recv_string(self, flags, copy, track) + return _Socket_recv_string(self, flags, encoding) # acquire lock here so the subsequent calls to recv for the # message parts after the first don't block with self._eventlet_recv_lock: - return _Socket_recv_string(self, flags, copy, track) + return _Socket_recv_string(self, flags, encoding) - @_wraps(_Socket.recv_pyobj) - def recv_pyobj(self, flags=0, copy=True, track=False): - """A recv_pyobj method that's safe to use when multiple - greenthreads are calling send, send_pyobj, recv and - recv_pyobj on the same socket. + @_wraps(_Socket.recv_json) + def recv_json(self, flags=0, **kwargs): + """A recv_json method that's safe to use when multiple + greenthreads are calling send, send_json, recv and + recv_json on the same socket. """ if flags & NOBLOCK: - return _Socket_recv_pyobj(self, flags, copy, track) + return _Socket_recv_json(self, flags, **kwargs) # acquire lock here so the subsequent calls to recv for the # message parts after the first don't block with self._eventlet_recv_lock: - return _Socket_recv_pyobj(self, flags, copy, track) + return _Socket_recv_json(self, flags, **kwargs) - @_wraps(_Socket.recv_json) - def recv_json(self, flags=0, copy=True, track=False): - """A recv_json method that's safe to use when multiple - greenthreads are calling send, send_json, recv and - recv_json on the same socket. + @_wraps(_Socket.recv_pyobj) + def recv_pyobj(self, flags=0): + """A recv_pyobj method that's safe to use when multiple + greenthreads are calling send, send_pyobj, recv and + recv_pyobj on the same socket. """ if flags & NOBLOCK: - return _Socket_recv_json(self, flags, copy, track) + return _Socket_recv_pyobj(self, flags) # acquire lock here so the subsequent calls to recv for the # message parts after the first don't block with self._eventlet_recv_lock: - return _Socket_recv_json(self, flags, copy, track) \ No newline at end of file + return _Socket_recv_pyobj(self, flags) diff -Nru python-eventlet-0.20.0/eventlet/greenio/base.py python-eventlet-0.24.1/eventlet/greenio/base.py --- python-eventlet-0.20.0/eventlet/greenio/base.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/greenio/base.py 2018-08-06 16:17:47.000000000 +0000 @@ -7,12 +7,14 @@ import eventlet from eventlet.hubs import trampoline, notify_opened, IOClosed -from eventlet.support import get_errno, six +from eventlet.support import get_errno +import six __all__ = [ 'GreenSocket', '_GLOBAL_DEFAULT_TIMEOUT', 'set_nonblocking', 'SOCKET_BLOCKING', 'SOCKET_CLOSED', 'CONNECT_ERR', 'CONNECT_SUCCESS', 'shutdown_safe', 'SSL', + 'socket_timeout', ] BUFFER_SIZE = 4096 @@ -27,6 +29,9 @@ _original_socket = eventlet.patcher.original('socket').socket +socket_timeout = eventlet.timeout.wrap_is_timeout(socket.timeout) + + def socket_connect(descriptor, address): """ Attempts to connect to the address, returns the descriptor if it succeeds, @@ -208,16 +213,19 @@ def accept(self): if self.act_non_blocking: - return self.fd.accept() + res = self.fd.accept() + notify_opened(res[0].fileno()) + return res fd = self.fd + _timeout_exc = socket_timeout('timed out') while True: res = socket_accept(fd) if res is not None: client, addr = res + notify_opened(client.fileno()) set_nonblocking(client) return type(self)(client), addr - self._trampoline(fd, read=True, timeout=self.gettimeout(), - timeout_exc=socket.timeout("timed out")) + self._trampoline(fd, read=True, timeout=self.gettimeout(), timeout_exc=_timeout_exc) def _mark_as_closed(self): """ Mark this socket as being closed """ @@ -233,6 +241,7 @@ if self.act_non_blocking: return self.fd.connect(address) fd = self.fd + _timeout_exc = socket_timeout('timed out') if self.gettimeout() is None: while not socket_connect(fd, address): try: @@ -246,10 +255,10 @@ if socket_connect(fd, address): return if time.time() >= end: - raise socket.timeout("timed out") + raise _timeout_exc + timeout = end - time.time() try: - self._trampoline(fd, write=True, timeout=end - time.time(), - timeout_exc=socket.timeout("timed out")) + self._trampoline(fd, write=True, timeout=timeout, timeout_exc=_timeout_exc) except IOClosed: # ... we need some workable errno here. raise socket.error(errno.EBADFD) @@ -270,14 +279,15 @@ return errno.EBADFD else: end = time.time() + self.gettimeout() + timeout_exc = socket.timeout(errno.EAGAIN) while True: try: if socket_connect(fd, address): return 0 if time.time() >= end: - raise socket.timeout(errno.EAGAIN) + raise timeout_exc self._trampoline(fd, write=True, timeout=end - time.time(), - timeout_exc=socket.timeout(errno.EAGAIN)) + timeout_exc=timeout_exc) socket_checkerr(fd) except socket.error as ex: return get_errno(ex) @@ -316,7 +326,7 @@ self.fd, read=True, timeout=self.gettimeout(), - timeout_exc=socket.timeout("timed out")) + timeout_exc=socket_timeout('timed out')) def _recv_loop(self, recv_meth, empty_val, *args): fd = self.fd @@ -366,7 +376,8 @@ if self.act_non_blocking: return send_method(data, *args) - while 1: + _timeout_exc = socket_timeout('timed out') + while True: try: return send_method(data, *args) except socket.error as e: @@ -376,7 +387,7 @@ try: self._trampoline(self.fd, write=True, timeout=self.gettimeout(), - timeout_exc=socket.timeout("timed out")) + timeout_exc=_timeout_exc) except IOClosed: raise socket.error(errno.ECONNRESET, 'Connection closed by another thread') @@ -421,6 +432,12 @@ def gettimeout(self): return self._timeout + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + if "__pypy__" in sys.builtin_module_names: def _reuse(self): getattr(self.fd, '_sock', self.fd)._reuse() @@ -465,11 +482,11 @@ def shutdown_safe(sock): - """ Shuts down the socket. This is a convenience method for + """Shuts down the socket. This is a convenience method for code that wants to gracefully handle regular sockets, SSL.Connection - sockets from PyOpenSSL and ssl.SSLSocket objects from Python 2.6 - interchangeably. Both types of ssl socket require a shutdown() before - close, but they have different arity on their shutdown method. + sockets from PyOpenSSL and ssl.SSLSocket objects from Python 2.7 interchangeably. + Both types of ssl socket require a shutdown() before close, + but they have different arity on their shutdown method. Regular sockets don't need a shutdown before close, but it doesn't hurt. """ @@ -483,5 +500,5 @@ except socket.error as e: # we don't care if the socket is already closed; # this will often be the case in an http server context - if get_errno(e) not in (errno.ENOTCONN, errno.EBADF): + if get_errno(e) not in (errno.ENOTCONN, errno.EBADF, errno.ENOTSOCK): raise diff -Nru python-eventlet-0.20.0/eventlet/greenio/__init__.py python-eventlet-0.24.1/eventlet/greenio/__init__.py --- python-eventlet-0.20.0/eventlet/greenio/__init__.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/greenio/__init__.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,4 +1,4 @@ -from eventlet.support import six +import six from eventlet.greenio.base import * # noqa diff -Nru python-eventlet-0.20.0/eventlet/greenio/py2.py python-eventlet-0.24.1/eventlet/greenio/py2.py --- python-eventlet-0.20.0/eventlet/greenio/py2.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/greenio/py2.py 2018-08-06 16:17:47.000000000 +0000 @@ -9,7 +9,8 @@ SOCKET_BLOCKING, ) from eventlet.hubs import trampoline, notify_close, notify_opened, IOClosed -from eventlet.support import get_errno, six +from eventlet.support import get_errno +import six __all__ = ['_fileobject', 'GreenPipe'] diff -Nru python-eventlet-0.20.0/eventlet/greenio/py3.py python-eventlet-0.24.1/eventlet/greenio/py3.py --- python-eventlet-0.20.0/eventlet/greenio/py3.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/greenio/py3.py 2018-08-06 16:17:47.000000000 +0000 @@ -19,7 +19,8 @@ SOCKET_BLOCKING, ) from eventlet.hubs import notify_close, notify_opened, IOClosed, trampoline -from eventlet.support import get_errno, six +from eventlet.support import get_errno +import six __all__ = ['_fileobject', 'GreenPipe'] diff -Nru python-eventlet-0.20.0/eventlet/greenpool.py python-eventlet-0.24.1/eventlet/greenpool.py --- python-eventlet-0.20.0/eventlet/greenpool.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/greenpool.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,11 +1,9 @@ import traceback -from eventlet import event -from eventlet import greenthread +import eventlet from eventlet import queue -from eventlet import semaphore from eventlet.support import greenlets as greenlet -from eventlet.support import six +import six __all__ = ['GreenPool', 'GreenPile'] @@ -17,10 +15,18 @@ """ def __init__(self, size=1000): + try: + size = int(size) + except ValueError as e: + msg = 'GreenPool() expect size :: int, actual: {0} {1}'.format(type(size), str(e)) + raise TypeError(msg) + if size < 0: + msg = 'GreenPool() expect size >= 0, actual: {0}'.format(repr(size)) + raise ValueError(msg) self.size = size self.coroutines_running = set() - self.sem = semaphore.Semaphore(size) - self.no_coros_running = event.Event() + self.sem = eventlet.Semaphore(size) + self.no_coros_running = eventlet.Event() def resize(self, new_size): """ Change the max number of greenthreads doing work at any given time. @@ -49,7 +55,7 @@ def spawn(self, function, *args, **kwargs): """Run the *function* with its arguments in its own green thread. - Returns the :class:`GreenThread ` + Returns the :class:`GreenThread ` object that is running the function, which can be used to retrieve the results. @@ -61,17 +67,17 @@ """ # if reentering an empty pool, don't try to wait on a coroutine freeing # itself -- instead, just execute in the current coroutine - current = greenthread.getcurrent() + current = eventlet.getcurrent() if self.sem.locked() and current in self.coroutines_running: # a bit hacky to use the GT without switching to it - gt = greenthread.GreenThread(current) + gt = eventlet.greenthread.GreenThread(current) gt.main(function, args, kwargs) return gt else: self.sem.acquire() - gt = greenthread.spawn(function, *args, **kwargs) + gt = eventlet.spawn(function, *args, **kwargs) if not self.coroutines_running: - self.no_coros_running = event.Event() + self.no_coros_running = eventlet.Event() self.coroutines_running.add(gt) gt.link(self._spawn_done) return gt @@ -89,7 +95,7 @@ if coro is None: return else: - coro = greenthread.getcurrent() + coro = eventlet.getcurrent() self._spawn_done(coro) def spawn_n(self, function, *args, **kwargs): @@ -99,21 +105,21 @@ """ # if reentering an empty pool, don't try to wait on a coroutine freeing # itself -- instead, just execute in the current coroutine - current = greenthread.getcurrent() + current = eventlet.getcurrent() if self.sem.locked() and current in self.coroutines_running: self._spawn_n_impl(function, args, kwargs, None) else: self.sem.acquire() - g = greenthread.spawn_n( + g = eventlet.spawn_n( self._spawn_n_impl, function, args, kwargs, True) if not self.coroutines_running: - self.no_coros_running = event.Event() + self.no_coros_running = eventlet.Event() self.coroutines_running.add(g) def waitall(self): """Waits until all greenthreads in the pool are finished working.""" - assert greenthread.getcurrent() not in self.coroutines_running, \ + assert eventlet.getcurrent() not in self.coroutines_running, \ "Calling waitall() from within one of the " \ "GreenPool's greenthreads will never terminate." if self.running(): @@ -151,7 +157,7 @@ if function is None: function = lambda *a: a gi = GreenMap(self.size) - greenthread.spawn_n(self._do_map, function, iterable, gi) + eventlet.spawn_n(self._do_map, function, iterable, gi) return gi def imap(self, function, *iterables): diff -Nru python-eventlet-0.20.0/eventlet/greenthread.py python-eventlet-0.24.1/eventlet/greenthread.py --- python-eventlet-0.20.0/eventlet/greenthread.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/greenthread.py 2018-08-06 16:17:47.000000000 +0000 @@ -3,9 +3,11 @@ from eventlet import event from eventlet import hubs +from eventlet import support from eventlet import timeout from eventlet.hubs import timer -from eventlet.support import greenlets as greenlet, six +from eventlet.support import greenlets as greenlet +import six import warnings __all__ = ['getcurrent', 'sleep', 'spawn', 'spawn_n', @@ -144,8 +146,11 @@ return hub.schedule_call_local(seconds, getcurrent().throw, *throw_args) # deprecate, remove -TimeoutError = timeout.Timeout -with_timeout = timeout.with_timeout +TimeoutError, with_timeout = ( + support.wrap_deprecated(old, new)(fun) for old, new, fun in ( + ('greenthread.TimeoutError', 'Timeout', timeout.Timeout), + ('greenthread.with_timeout', 'with_timeout', timeout.with_timeout), + )) def _spawn_n(seconds, func, args, kwargs): diff -Nru python-eventlet-0.20.0/eventlet/hubs/epolls.py python-eventlet-0.24.1/eventlet/hubs/epolls.py --- python-eventlet-0.20.0/eventlet/hubs/epolls.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/hubs/epolls.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,29 +1,14 @@ import errno from eventlet.support import get_errno from eventlet import patcher -time = patcher.original('time') -select = patcher.original("select") -if hasattr(select, 'epoll'): - epoll = select.epoll -else: - try: - # http://pypi.python.org/pypi/select26/ - from select26 import epoll - except ImportError: - try: - import epoll as _epoll_mod - except ImportError: - raise ImportError( - "No epoll implementation found in select module or PYTHONPATH") - else: - if hasattr(_epoll_mod, 'poll'): - epoll = _epoll_mod.poll - else: - raise ImportError( - "You have an old, buggy epoll module in PYTHONPATH." - " Install http://pypi.python.org/pypi/python-epoll/" - " NOT http://pypi.python.org/pypi/pyepoll/. " - " easy_install pyepoll installs the wrong version.") +select = patcher.original('select') +if not hasattr(select, 'epoll'): + # TODO: remove mention of python-epoll on 2019-01 + raise ImportError('No epoll implementation found in select module.' + ' python-epoll (or similar) package support was removed,' + ' please open issue on https://github.com/eventlet/eventlet/' + ' if you must use epoll outside stdlib.') +epoll = select.epoll from eventlet.hubs.hub import BaseHub from eventlet.hubs import poll @@ -34,14 +19,9 @@ class Hub(poll.Hub): - def __init__(self, clock=time.time): + def __init__(self, clock=None): BaseHub.__init__(self, clock) self.poll = epoll() - try: - # modify is required by select.epoll - self.modify = self.poll.modify - except AttributeError: - self.modify = self.poll.register def add(self, evtype, fileno, cb, tb, mac): oldlisteners = bool(self.listeners[READ].get(fileno) or diff -Nru python-eventlet-0.20.0/eventlet/hubs/hub.py python-eventlet-0.24.1/eventlet/hubs/hub.py --- python-eventlet-0.20.0/eventlet/hubs/hub.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/hubs/hub.py 2018-08-06 16:17:47.000000000 +0000 @@ -19,10 +19,10 @@ signal.alarm(math.ceil(seconds)) arm_alarm = alarm_signal -from eventlet import patcher from eventlet.hubs import timer, IOClosed -from eventlet.support import greenlets as greenlet, clear_sys_exc_info, six -time = patcher.original('time') +from eventlet.support import greenlets as greenlet, clear_sys_exc_info +import monotonic +import six g_prevent_multiple_readers = True @@ -113,12 +113,15 @@ READ = READ WRITE = WRITE - def __init__(self, clock=time.time): + def __init__(self, clock=None): self.listeners = {READ: {}, WRITE: {}} self.secondaries = {READ: {}, WRITE: {}} self.closed = [] + if clock is None: + clock = monotonic.monotonic self.clock = clock + self.greenlet = greenlet.greenlet(self.run) self.stopping = False self.running = False diff -Nru python-eventlet-0.20.0/eventlet/hubs/__init__.py python-eventlet-0.24.1/eventlet/hubs/__init__.py --- python-eventlet-0.20.0/eventlet/hubs/__init__.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/hubs/__init__.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,7 +1,8 @@ import os from eventlet import patcher -from eventlet.support import greenlets as greenlet, six +from eventlet.support import greenlets as greenlet +import six __all__ = ["use_hub", "get_hub", "get_default_hub", "trampoline"] @@ -118,6 +119,7 @@ return hub +# Lame middle file import because complex dependencies in import graph from eventlet import timeout diff -Nru python-eventlet-0.20.0/eventlet/hubs/kqueue.py python-eventlet-0.24.1/eventlet/hubs/kqueue.py --- python-eventlet-0.20.0/eventlet/hubs/kqueue.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/hubs/kqueue.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,12 +1,10 @@ import os import sys -from eventlet import patcher -from eventlet.support import six +from eventlet import patcher, support +import six select = patcher.original('select') time = patcher.original('time') -sleep = time.sleep -from eventlet.support import clear_sys_exc_info from eventlet.hubs.hub import BaseHub, READ, WRITE, noop @@ -21,7 +19,7 @@ class Hub(BaseHub): MAX_EVENTS = 100 - def __init__(self, clock=time.time): + def __init__(self, clock=None): super(Hub, self).__init__(clock) self._events = {} self._init_kqueue() @@ -73,9 +71,11 @@ evtype = listener.evtype fileno = listener.fileno if not self.listeners[evtype].get(fileno): - event = self._events[fileno].pop(evtype) + event = self._events[fileno].pop(evtype, None) + if event is None: + return try: - self._delete_events([event]) + self._delete_events((event,)) except OSError: pass @@ -95,7 +95,7 @@ if not readers and not writers: if seconds: - sleep(seconds) + time.sleep(seconds) return result = self._control([], self.MAX_EVENTS, seconds) SYSTEM_EXCEPTIONS = self.SYSTEM_EXCEPTIONS @@ -111,4 +111,4 @@ raise except: self.squelch_exception(fileno, sys.exc_info()) - clear_sys_exc_info() + support.clear_sys_exc_info() diff -Nru python-eventlet-0.20.0/eventlet/hubs/poll.py python-eventlet-0.24.1/eventlet/hubs/poll.py --- python-eventlet-0.20.0/eventlet/hubs/poll.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/hubs/poll.py 2018-08-06 16:17:47.000000000 +0000 @@ -4,7 +4,6 @@ from eventlet import patcher select = patcher.original('select') time = patcher.original('time') -sleep = time.sleep from eventlet.hubs.hub import BaseHub, READ, WRITE, noop from eventlet.support import get_errno, clear_sys_exc_info @@ -15,14 +14,9 @@ class Hub(BaseHub): - def __init__(self, clock=time.time): + def __init__(self, clock=None): super(Hub, self).__init__(clock) self.poll = select.poll() - # poll.modify is new to 2.6 - try: - self.modify = self.poll.modify - except AttributeError: - self.modify = self.poll.register def add(self, evtype, fileno, cb, tb, mac): listener = super(Hub, self).add(evtype, fileno, cb, tb, mac) @@ -45,7 +39,7 @@ self.poll.register(fileno, mask) else: try: - self.modify(fileno, mask) + self.poll.modify(fileno, mask) except (IOError, OSError): self.poll.register(fileno, mask) else: @@ -79,7 +73,7 @@ if not readers and not writers: if seconds: - sleep(seconds) + time.sleep(seconds) return try: presult = self.do_poll(seconds) diff -Nru python-eventlet-0.20.0/eventlet/hubs/pyevent.py python-eventlet-0.24.1/eventlet/hubs/pyevent.py --- python-eventlet-0.20.0/eventlet/hubs/pyevent.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/hubs/pyevent.py 2018-08-06 16:17:47.000000000 +0000 @@ -3,7 +3,8 @@ import event import types -from eventlet.support import greenlets as greenlet, six +from eventlet.support import greenlets as greenlet +import six from eventlet.hubs.hub import BaseHub, READ, WRITE diff -Nru python-eventlet-0.20.0/eventlet/hubs/timer.py python-eventlet-0.24.1/eventlet/hubs/timer.py --- python-eventlet-0.20.0/eventlet/hubs/timer.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/hubs/timer.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,6 +1,7 @@ import traceback -from eventlet.support import greenlets as greenlet, six +from eventlet.support import greenlets as greenlet +import six from eventlet.hubs import get_hub """ If true, captures a stack trace for each timer when constructed. This is diff -Nru python-eventlet-0.20.0/eventlet/__init__.py python-eventlet-0.24.1/eventlet/__init__.py --- python-eventlet-0.20.0/eventlet/__init__.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/__init__.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,14 +1,39 @@ -version_info = (0, 20, 0) -__version__ = '.'.join(map(str, version_info)) +import os -try: - from eventlet import greenthread + +version_info = (0, 24, 1) +__version__ = '.'.join(map(str, version_info)) +# This is to make Debian packaging easier, it ignores import +# errors of greenlet so that the packager can still at least +# access the version. Also this makes easy_install a little quieter +if os.environ.get('EVENTLET_IMPORT_VERSION_ONLY') != '1': + from eventlet import convenience + from eventlet import event from eventlet import greenpool + from eventlet import greenthread + from eventlet import patcher from eventlet import queue + from eventlet import semaphore + from eventlet import support from eventlet import timeout - from eventlet import patcher - from eventlet import convenience import greenlet + # Force monotonic library search as early as possible. + # Helpful when CPython < 3.5 on Linux blocked in `os.waitpid(-1)` before first use of hub. + # Example: gunicorn + # https://github.com/eventlet/eventlet/issues/401#issuecomment-327500352 + import monotonic + del monotonic + + connect = convenience.connect + listen = convenience.listen + serve = convenience.serve + StopServe = convenience.StopServe + wrap_ssl = convenience.wrap_ssl + + Event = event.Event + + GreenPool = greenpool.GreenPool + GreenPile = greenpool.GreenPile sleep = greenthread.sleep spawn = greenthread.spawn @@ -16,34 +41,28 @@ spawn_after = greenthread.spawn_after kill = greenthread.kill - Timeout = timeout.Timeout - with_timeout = timeout.with_timeout - - GreenPool = greenpool.GreenPool - GreenPile = greenpool.GreenPile + import_patched = patcher.import_patched + monkey_patch = patcher.monkey_patch Queue = queue.Queue - import_patched = patcher.import_patched - monkey_patch = patcher.monkey_patch + Semaphore = semaphore.Semaphore + CappedSemaphore = semaphore.CappedSemaphore + BoundedSemaphore = semaphore.BoundedSemaphore - connect = convenience.connect - listen = convenience.listen - serve = convenience.serve - StopServe = convenience.StopServe - wrap_ssl = convenience.wrap_ssl + Timeout = timeout.Timeout + with_timeout = timeout.with_timeout + wrap_is_timeout = timeout.wrap_is_timeout + is_timeout = timeout.is_timeout getcurrent = greenlet.greenlet.getcurrent # deprecated - TimeoutError = timeout.Timeout - exc_after = greenthread.exc_after - call_after_global = greenthread.call_after_global -except ImportError as e: - # This is to make Debian packaging easier, it ignores import - # errors of greenlet so that the packager can still at least - # access the version. Also this makes easy_install a little quieter - if 'greenlet' not in str(e): - # any other exception should be printed - import traceback - traceback.print_exc() + TimeoutError, exc_after, call_after_global = ( + support.wrap_deprecated(old, new)(fun) for old, new, fun in ( + ('TimeoutError', 'Timeout', Timeout), + ('exc_after', 'greenthread.exc_after', greenthread.exc_after), + ('call_after_global', 'greenthread.call_after_global', greenthread.call_after_global), + )) + +del os diff -Nru python-eventlet-0.20.0/eventlet/patcher.py python-eventlet-0.24.1/eventlet/patcher.py --- python-eventlet-0.20.0/eventlet/patcher.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/patcher.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,7 +1,8 @@ import imp import sys -from eventlet.support import six +import eventlet +import six __all__ = ['inject', 'import_patched', 'monkey_patch', 'is_monkey_patched'] @@ -222,6 +223,16 @@ It's safe to call monkey_patch multiple times. """ + + # Workaround for import cycle observed as following in monotonic + # RuntimeError: no suitable implementation for this system + # see https://github.com/eventlet/eventlet/issues/401#issuecomment-325015989 + # + # Make sure the hub is completely imported before any + # monkey-patching, or we risk recursion if the process of importing + # the hub calls into monkey-patched modules. + eventlet.hubs.get_hub() + accepted_args = set(('os', 'select', 'socket', 'thread', 'time', 'psycopg', 'MySQLdb', 'builtins', 'subprocess')) @@ -358,7 +369,7 @@ rlock._RLock__block = new if old.locked(): new.acquire() - rlock._RLock__owner = tid + rlock._RLock__owner = tid def _fix_py3_rlock(old): diff -Nru python-eventlet-0.20.0/eventlet/pools.py python-eventlet-0.24.1/eventlet/pools.py --- python-eventlet-0.20.0/eventlet/pools.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/pools.py 2018-08-06 16:17:47.000000000 +0000 @@ -121,12 +121,16 @@ return if self.waiting(): - self.channel.put(item) + try: + self.channel.put(item, block=False) + return + except queue.Full: + pass + + if self.order_as_stack: + self.free_items.appendleft(item) else: - if self.order_as_stack: - self.free_items.appendleft(item) - else: - self.free_items.append(item) + self.free_items.append(item) def resize(self, new_size): """Resize the pool to *new_size*. diff -Nru python-eventlet-0.20.0/eventlet/queue.py python-eventlet-0.24.1/eventlet/queue.py --- python-eventlet-0.20.0/eventlet/queue.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/queue.py 2018-08-06 16:17:47.000000000 +0000 @@ -49,8 +49,8 @@ from eventlet.event import Event 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 +import six +from six.moves import queue as Stdlib_Queue from eventlet.timeout import Timeout @@ -116,7 +116,7 @@ if self.greenlet is not None: try: self.greenlet.switch(value) - except: + except Exception: traceback.print_exc() def throw(self, *throw_args): @@ -128,7 +128,7 @@ if self.greenlet is not None: try: self.greenlet.throw(*throw_args) - except: + except Exception: traceback.print_exc() # XXX should be renamed to get() ? and the whole class is called Receiver? @@ -255,7 +255,7 @@ return raise Full elif block: - waiter = ItemWaiter(item) + waiter = ItemWaiter(item, block) self.putters.add(waiter) timeout = Timeout(timeout, Full) try: @@ -268,6 +268,14 @@ finally: timeout.cancel() self.putters.discard(waiter) + elif self.getters: + waiter = ItemWaiter(item, block) + self.putters.add(waiter) + self._schedule_unlock() + result = waiter.wait() + assert result is waiter, "Invalid switch into Queue.put: %r" % (result, ) + if waiter.item is not _NONE: + raise Full else: raise Full @@ -310,7 +318,11 @@ self.getters.add(waiter) if self.putters: self._schedule_unlock() - return waiter.wait() + try: + return waiter.wait() + except: + self._schedule_unlock() + raise finally: self.getters.discard(waiter) timeout.cancel() @@ -356,6 +368,14 @@ self.qsize() < self.maxsize): putter = self.putters.pop() putter.switch(putter) + elif self.putters and not self.getters: + full = [p for p in self.putters if not p.block] + if not full: + break + for putter in full: + self.putters.discard(putter) + get_hub().schedule_call_global( + 0, putter.greenlet.throw, Full) else: break finally: @@ -370,11 +390,12 @@ class ItemWaiter(Waiter): - __slots__ = ['item'] + __slots__ = ['item', 'block'] - def __init__(self, item): + def __init__(self, item, block): Waiter.__init__(self) self.item = item + self.block = block class Queue(LightQueue): diff -Nru python-eventlet-0.20.0/eventlet/semaphore.py python-eventlet-0.24.1/eventlet/semaphore.py --- python-eventlet-0.20.0/eventlet/semaphore.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/semaphore.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,10 +1,7 @@ -from __future__ import with_statement - import collections -from eventlet import greenthread +import eventlet from eventlet import hubs -from eventlet.timeout import Timeout class Semaphore(object): @@ -34,10 +31,15 @@ """ def __init__(self, value=1): - self.counter = value + try: + value = int(value) + except ValueError as e: + msg = 'Semaphore() expect value :: int, actual: {0} {1}'.format(type(value), str(e)) + raise TypeError(msg) if value < 0: - raise ValueError("Semaphore must be initialized with a positive " - "number, got %s" % value) + msg = 'Semaphore() expect value >= 0, actual: {0}'.format(repr(value)) + raise ValueError(msg) + self.counter = value self._waiters = collections.deque() def __repr__(self): @@ -92,7 +94,7 @@ if not blocking and self.locked(): return False - current_thread = greenthread.getcurrent() + current_thread = eventlet.getcurrent() if self.counter <= 0 or self._waiters: if current_thread not in self._waiters: @@ -100,7 +102,7 @@ try: if timeout is not None: ok = False - with Timeout(timeout, False): + with eventlet.Timeout(timeout, False): while self.counter <= 0: hubs.get_hub().switch() ok = True diff -Nru python-eventlet-0.20.0/eventlet/support/dns/_compat.py python-eventlet-0.24.1/eventlet/support/dns/_compat.py --- python-eventlet-0.20.0/eventlet/support/dns/_compat.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/_compat.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -import sys -import decimal -from decimal import Context - -if sys.version_info > (3,): - long = int - xrange = range -else: - long = long # pylint: disable=long-builtin - xrange = xrange # pylint: disable=xrange-builtin - -# unicode / binary types -if sys.version_info > (3,): - text_type = str - binary_type = bytes - string_types = (str,) - unichr = chr - def maybe_decode(x): - return x.decode() - def maybe_encode(x): - return x.encode() -else: - text_type = unicode # pylint: disable=unicode-builtin, undefined-variable - binary_type = str - string_types = ( - basestring, # pylint: disable=basestring-builtin, undefined-variable - ) - unichr = unichr # pylint: disable=unichr-builtin - def maybe_decode(x): - return x - def maybe_encode(x): - return x - - -def round_py2_compat(what): - """ - Python 2 and Python 3 use different rounding strategies in round(). This - function ensures that results are python2/3 compatible and backward - compatible with previous py2 releases - :param what: float - :return: rounded long - """ - d = Context( - prec=len(str(long(what))), # round to integer with max precision - rounding=decimal.ROUND_HALF_UP - ).create_decimal(str(what)) # str(): python 2.6 compat - return long(d) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/dnssec.py python-eventlet-0.24.1/eventlet/support/dns/dnssec.py --- python-eventlet-0.20.0/eventlet/support/dns/dnssec.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/dnssec.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,457 +0,0 @@ -# Copyright (C) 2003-2007, 2009, 2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Common DNSSEC-related functions and constants.""" - -from io import BytesIO -import struct -import time - -import dns.exception -import dns.hash -import dns.name -import dns.node -import dns.rdataset -import dns.rdata -import dns.rdatatype -import dns.rdataclass -from ._compat import string_types - - -class UnsupportedAlgorithm(dns.exception.DNSException): - - """The DNSSEC algorithm is not supported.""" - - -class ValidationFailure(dns.exception.DNSException): - - """The DNSSEC signature is invalid.""" - -RSAMD5 = 1 -DH = 2 -DSA = 3 -ECC = 4 -RSASHA1 = 5 -DSANSEC3SHA1 = 6 -RSASHA1NSEC3SHA1 = 7 -RSASHA256 = 8 -RSASHA512 = 10 -ECDSAP256SHA256 = 13 -ECDSAP384SHA384 = 14 -INDIRECT = 252 -PRIVATEDNS = 253 -PRIVATEOID = 254 - -_algorithm_by_text = { - 'RSAMD5': RSAMD5, - 'DH': DH, - 'DSA': DSA, - 'ECC': ECC, - 'RSASHA1': RSASHA1, - 'DSANSEC3SHA1': DSANSEC3SHA1, - 'RSASHA1NSEC3SHA1': RSASHA1NSEC3SHA1, - 'RSASHA256': RSASHA256, - 'RSASHA512': RSASHA512, - 'INDIRECT': INDIRECT, - 'ECDSAP256SHA256': ECDSAP256SHA256, - 'ECDSAP384SHA384': ECDSAP384SHA384, - 'PRIVATEDNS': PRIVATEDNS, - 'PRIVATEOID': PRIVATEOID, -} - -# We construct the inverse mapping programmatically to ensure that we -# cannot make any mistakes (e.g. omissions, cut-and-paste errors) that -# would cause the mapping not to be true inverse. - -_algorithm_by_value = dict((y, x) for x, y in _algorithm_by_text.items()) - - -def algorithm_from_text(text): - """Convert text into a DNSSEC algorithm value - @rtype: int""" - - value = _algorithm_by_text.get(text.upper()) - if value is None: - value = int(text) - return value - - -def algorithm_to_text(value): - """Convert a DNSSEC algorithm value to text - @rtype: string""" - - text = _algorithm_by_value.get(value) - if text is None: - text = str(value) - return text - - -def _to_rdata(record, origin): - s = BytesIO() - record.to_wire(s, origin=origin) - return s.getvalue() - - -def key_id(key, origin=None): - rdata = _to_rdata(key, origin) - rdata = bytearray(rdata) - if key.algorithm == RSAMD5: - return (rdata[-3] << 8) + rdata[-2] - else: - total = 0 - for i in range(len(rdata) // 2): - total += (rdata[2 * i] << 8) + \ - rdata[2 * i + 1] - if len(rdata) % 2 != 0: - total += rdata[len(rdata) - 1] << 8 - total += ((total >> 16) & 0xffff) - return total & 0xffff - - -def make_ds(name, key, algorithm, origin=None): - if algorithm.upper() == 'SHA1': - dsalg = 1 - hash = dns.hash.hashes['SHA1']() - elif algorithm.upper() == 'SHA256': - dsalg = 2 - hash = dns.hash.hashes['SHA256']() - else: - raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm) - - if isinstance(name, string_types): - name = dns.name.from_text(name, origin) - hash.update(name.canonicalize().to_wire()) - hash.update(_to_rdata(key, origin)) - digest = hash.digest() - - dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, dsalg) + digest - return dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.DS, dsrdata, 0, - len(dsrdata)) - - -def _find_candidate_keys(keys, rrsig): - candidate_keys = [] - value = keys.get(rrsig.signer) - if value is None: - return None - if isinstance(value, dns.node.Node): - try: - rdataset = value.find_rdataset(dns.rdataclass.IN, - dns.rdatatype.DNSKEY) - except KeyError: - return None - else: - rdataset = value - for rdata in rdataset: - if rdata.algorithm == rrsig.algorithm and \ - key_id(rdata) == rrsig.key_tag: - candidate_keys.append(rdata) - return candidate_keys - - -def _is_rsa(algorithm): - return algorithm in (RSAMD5, RSASHA1, - RSASHA1NSEC3SHA1, RSASHA256, - RSASHA512) - - -def _is_dsa(algorithm): - return algorithm in (DSA, DSANSEC3SHA1) - - -def _is_ecdsa(algorithm): - return _have_ecdsa and (algorithm in (ECDSAP256SHA256, ECDSAP384SHA384)) - - -def _is_md5(algorithm): - return algorithm == RSAMD5 - - -def _is_sha1(algorithm): - return algorithm in (DSA, RSASHA1, - DSANSEC3SHA1, RSASHA1NSEC3SHA1) - - -def _is_sha256(algorithm): - return algorithm in (RSASHA256, ECDSAP256SHA256) - - -def _is_sha384(algorithm): - return algorithm == ECDSAP384SHA384 - - -def _is_sha512(algorithm): - return algorithm == RSASHA512 - - -def _make_hash(algorithm): - if _is_md5(algorithm): - return dns.hash.hashes['MD5']() - if _is_sha1(algorithm): - return dns.hash.hashes['SHA1']() - if _is_sha256(algorithm): - return dns.hash.hashes['SHA256']() - if _is_sha384(algorithm): - return dns.hash.hashes['SHA384']() - if _is_sha512(algorithm): - return dns.hash.hashes['SHA512']() - raise ValidationFailure('unknown hash for algorithm %u' % algorithm) - - -def _make_algorithm_id(algorithm): - if _is_md5(algorithm): - oid = [0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05] - elif _is_sha1(algorithm): - oid = [0x2b, 0x0e, 0x03, 0x02, 0x1a] - elif _is_sha256(algorithm): - oid = [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01] - elif _is_sha512(algorithm): - oid = [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03] - else: - raise ValidationFailure('unknown algorithm %u' % algorithm) - olen = len(oid) - dlen = _make_hash(algorithm).digest_size - idbytes = [0x30] + [8 + olen + dlen] + \ - [0x30, olen + 4] + [0x06, olen] + oid + \ - [0x05, 0x00] + [0x04, dlen] - return struct.pack('!%dB' % len(idbytes), *idbytes) - - -def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None): - """Validate an RRset against a single signature rdata - - The owner name of the rrsig is assumed to be the same as the owner name - of the rrset. - - @param rrset: The RRset to validate - @type rrset: dns.rrset.RRset or (dns.name.Name, dns.rdataset.Rdataset) - tuple - @param rrsig: The signature rdata - @type rrsig: dns.rrset.Rdata - @param keys: The key dictionary. - @type keys: a dictionary keyed by dns.name.Name with node or rdataset - values - @param origin: The origin to use for relative names - @type origin: dns.name.Name or None - @param now: The time to use when validating the signatures. The default - is the current time. - @type now: int - """ - - if isinstance(origin, string_types): - origin = dns.name.from_text(origin, dns.name.root) - - for candidate_key in _find_candidate_keys(keys, rrsig): - if not candidate_key: - raise ValidationFailure('unknown key') - - # For convenience, allow the rrset to be specified as a (name, - # rdataset) tuple as well as a proper rrset - if isinstance(rrset, tuple): - rrname = rrset[0] - rdataset = rrset[1] - else: - rrname = rrset.name - rdataset = rrset - - if now is None: - now = time.time() - if rrsig.expiration < now: - raise ValidationFailure('expired') - if rrsig.inception > now: - raise ValidationFailure('not yet valid') - - hash = _make_hash(rrsig.algorithm) - - if _is_rsa(rrsig.algorithm): - keyptr = candidate_key.key - (bytes_,) = struct.unpack('!B', keyptr[0:1]) - keyptr = keyptr[1:] - if bytes_ == 0: - (bytes_,) = struct.unpack('!H', keyptr[0:2]) - keyptr = keyptr[2:] - rsa_e = keyptr[0:bytes_] - rsa_n = keyptr[bytes_:] - keylen = len(rsa_n) * 8 - pubkey = Crypto.PublicKey.RSA.construct( - (Crypto.Util.number.bytes_to_long(rsa_n), - Crypto.Util.number.bytes_to_long(rsa_e))) - sig = (Crypto.Util.number.bytes_to_long(rrsig.signature),) - elif _is_dsa(rrsig.algorithm): - keyptr = candidate_key.key - (t,) = struct.unpack('!B', keyptr[0:1]) - keyptr = keyptr[1:] - octets = 64 + t * 8 - dsa_q = keyptr[0:20] - keyptr = keyptr[20:] - dsa_p = keyptr[0:octets] - keyptr = keyptr[octets:] - dsa_g = keyptr[0:octets] - keyptr = keyptr[octets:] - dsa_y = keyptr[0:octets] - pubkey = Crypto.PublicKey.DSA.construct( - (Crypto.Util.number.bytes_to_long(dsa_y), - Crypto.Util.number.bytes_to_long(dsa_g), - Crypto.Util.number.bytes_to_long(dsa_p), - Crypto.Util.number.bytes_to_long(dsa_q))) - (dsa_r, dsa_s) = struct.unpack('!20s20s', rrsig.signature[1:]) - sig = (Crypto.Util.number.bytes_to_long(dsa_r), - Crypto.Util.number.bytes_to_long(dsa_s)) - elif _is_ecdsa(rrsig.algorithm): - if rrsig.algorithm == ECDSAP256SHA256: - curve = ecdsa.curves.NIST256p - key_len = 32 - elif rrsig.algorithm == ECDSAP384SHA384: - curve = ecdsa.curves.NIST384p - key_len = 48 - else: - # shouldn't happen - raise ValidationFailure('unknown ECDSA curve') - keyptr = candidate_key.key - x = Crypto.Util.number.bytes_to_long(keyptr[0:key_len]) - y = Crypto.Util.number.bytes_to_long(keyptr[key_len:key_len * 2]) - assert ecdsa.ecdsa.point_is_valid(curve.generator, x, y) - point = ecdsa.ellipticcurve.Point(curve.curve, x, y, curve.order) - verifying_key = ecdsa.keys.VerifyingKey.from_public_point(point, - curve) - pubkey = ECKeyWrapper(verifying_key, key_len) - r = rrsig.signature[:key_len] - s = rrsig.signature[key_len:] - sig = ecdsa.ecdsa.Signature(Crypto.Util.number.bytes_to_long(r), - Crypto.Util.number.bytes_to_long(s)) - else: - raise ValidationFailure('unknown algorithm %u' % rrsig.algorithm) - - hash.update(_to_rdata(rrsig, origin)[:18]) - hash.update(rrsig.signer.to_digestable(origin)) - - if rrsig.labels < len(rrname) - 1: - suffix = rrname.split(rrsig.labels + 1)[1] - rrname = dns.name.from_text('*', suffix) - rrnamebuf = rrname.to_digestable(origin) - rrfixed = struct.pack('!HHI', rdataset.rdtype, rdataset.rdclass, - rrsig.original_ttl) - rrlist = sorted(rdataset) - for rr in rrlist: - hash.update(rrnamebuf) - hash.update(rrfixed) - rrdata = rr.to_digestable(origin) - rrlen = struct.pack('!H', len(rrdata)) - hash.update(rrlen) - hash.update(rrdata) - - digest = hash.digest() - - if _is_rsa(rrsig.algorithm): - # PKCS1 algorithm identifier goop - digest = _make_algorithm_id(rrsig.algorithm) + digest - padlen = keylen // 8 - len(digest) - 3 - digest = struct.pack('!%dB' % (2 + padlen + 1), - *([0, 1] + [0xFF] * padlen + [0])) + digest - elif _is_dsa(rrsig.algorithm) or _is_ecdsa(rrsig.algorithm): - pass - else: - # Raise here for code clarity; this won't actually ever happen - # since if the algorithm is really unknown we'd already have - # raised an exception above - raise ValidationFailure('unknown algorithm %u' % rrsig.algorithm) - - if pubkey.verify(digest, sig): - return - raise ValidationFailure('verify failure') - - -def _validate(rrset, rrsigset, keys, origin=None, now=None): - """Validate an RRset - - @param rrset: The RRset to validate - @type rrset: dns.rrset.RRset or (dns.name.Name, dns.rdataset.Rdataset) - tuple - @param rrsigset: The signature RRset - @type rrsigset: dns.rrset.RRset or (dns.name.Name, dns.rdataset.Rdataset) - tuple - @param keys: The key dictionary. - @type keys: a dictionary keyed by dns.name.Name with node or rdataset - values - @param origin: The origin to use for relative names - @type origin: dns.name.Name or None - @param now: The time to use when validating the signatures. The default - is the current time. - @type now: int - """ - - if isinstance(origin, string_types): - origin = dns.name.from_text(origin, dns.name.root) - - if isinstance(rrset, tuple): - rrname = rrset[0] - else: - rrname = rrset.name - - if isinstance(rrsigset, tuple): - rrsigname = rrsigset[0] - rrsigrdataset = rrsigset[1] - else: - rrsigname = rrsigset.name - rrsigrdataset = rrsigset - - rrname = rrname.choose_relativity(origin) - rrsigname = rrname.choose_relativity(origin) - if rrname != rrsigname: - raise ValidationFailure("owner names do not match") - - for rrsig in rrsigrdataset: - try: - _validate_rrsig(rrset, rrsig, keys, origin, now) - return - except ValidationFailure: - pass - raise ValidationFailure("no RRSIGs validated") - - -def _need_pycrypto(*args, **kwargs): - raise NotImplementedError("DNSSEC validation requires pycrypto") - -try: - import Crypto.PublicKey.RSA - import Crypto.PublicKey.DSA - import Crypto.Util.number - validate = _validate - validate_rrsig = _validate_rrsig - _have_pycrypto = True -except ImportError: - validate = _need_pycrypto - validate_rrsig = _need_pycrypto - _have_pycrypto = False - -try: - import ecdsa - import ecdsa.ecdsa - import ecdsa.ellipticcurve - import ecdsa.keys - _have_ecdsa = True - - class ECKeyWrapper(object): - - def __init__(self, key, key_len): - self.key = key - self.key_len = key_len - - def verify(self, digest, sig): - diglong = Crypto.Util.number.bytes_to_long(digest) - return self.key.pubkey.verifies(diglong, sig) - -except ImportError: - _have_ecdsa = False diff -Nru python-eventlet-0.20.0/eventlet/support/dns/e164.py python-eventlet-0.24.1/eventlet/support/dns/e164.py --- python-eventlet-0.20.0/eventlet/support/dns/e164.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/e164.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -# Copyright (C) 2006, 2007, 2009, 2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS E.164 helpers - -@var public_enum_domain: The DNS public ENUM domain, e164.arpa. -@type public_enum_domain: dns.name.Name object -""" - - -import dns.exception -import dns.name -import dns.resolver -from ._compat import string_types - -public_enum_domain = dns.name.from_text('e164.arpa.') - - -def from_e164(text, origin=public_enum_domain): - """Convert an E.164 number in textual form into a Name object whose - value is the ENUM domain name for that number. - @param text: an E.164 number in textual form. - @type text: str - @param origin: The domain in which the number should be constructed. - The default is e164.arpa. - @type origin: dns.name.Name object or None - @rtype: dns.name.Name object - """ - parts = [d for d in text if d.isdigit()] - parts.reverse() - return dns.name.from_text('.'.join(parts), origin=origin) - - -def to_e164(name, origin=public_enum_domain, want_plus_prefix=True): - """Convert an ENUM domain name into an E.164 number. - @param name: the ENUM domain name. - @type name: dns.name.Name object. - @param origin: A domain containing the ENUM domain name. The - name is relativized to this domain before being converted to text. - @type origin: dns.name.Name object or None - @param want_plus_prefix: if True, add a '+' to the beginning of the - returned number. - @rtype: str - """ - if origin is not None: - name = name.relativize(origin) - dlabels = [d for d in name.labels if d.isdigit() and len(d) == 1] - if len(dlabels) != len(name.labels): - raise dns.exception.SyntaxError('non-digit labels in ENUM domain name') - dlabels.reverse() - text = b''.join(dlabels) - if want_plus_prefix: - text = b'+' + text - return text - - -def query(number, domains, resolver=None): - """Look for NAPTR RRs for the specified number in the specified domains. - - e.g. lookup('16505551212', ['e164.dnspython.org.', 'e164.arpa.']) - """ - if resolver is None: - resolver = dns.resolver.get_default_resolver() - e_nx = dns.resolver.NXDOMAIN() - for domain in domains: - if isinstance(domain, string_types): - domain = dns.name.from_text(domain) - qname = dns.e164.from_e164(number, domain) - try: - return resolver.query(qname, 'NAPTR') - except dns.resolver.NXDOMAIN as e: - e_nx += e - raise e_nx diff -Nru python-eventlet-0.20.0/eventlet/support/dns/edns.py python-eventlet-0.24.1/eventlet/support/dns/edns.py --- python-eventlet-0.20.0/eventlet/support/dns/edns.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/edns.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,150 +0,0 @@ -# Copyright (C) 2009, 2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""EDNS Options""" - -NSID = 3 - - -class Option(object): - - """Base class for all EDNS option types. - """ - - def __init__(self, otype): - """Initialize an option. - @param otype: The rdata type - @type otype: int - """ - self.otype = otype - - def to_wire(self, file): - """Convert an option to wire format. - """ - raise NotImplementedError - - @classmethod - def from_wire(cls, otype, wire, current, olen): - """Build an EDNS option object from wire format - - @param otype: The option type - @type otype: int - @param wire: The wire-format message - @type wire: string - @param current: The offset in wire of the beginning of the rdata. - @type current: int - @param olen: The length of the wire-format option data - @type olen: int - @rtype: dns.edns.Option instance""" - raise NotImplementedError - - def _cmp(self, other): - """Compare an EDNS option with another option of the same type. - Return < 0 if self < other, 0 if self == other, - and > 0 if self > other. - """ - raise NotImplementedError - - def __eq__(self, other): - if not isinstance(other, Option): - return False - if self.otype != other.otype: - return False - return self._cmp(other) == 0 - - def __ne__(self, other): - if not isinstance(other, Option): - return False - if self.otype != other.otype: - return False - return self._cmp(other) != 0 - - def __lt__(self, other): - if not isinstance(other, Option) or \ - self.otype != other.otype: - return NotImplemented - return self._cmp(other) < 0 - - def __le__(self, other): - if not isinstance(other, Option) or \ - self.otype != other.otype: - return NotImplemented - return self._cmp(other) <= 0 - - def __ge__(self, other): - if not isinstance(other, Option) or \ - self.otype != other.otype: - return NotImplemented - return self._cmp(other) >= 0 - - def __gt__(self, other): - if not isinstance(other, Option) or \ - self.otype != other.otype: - return NotImplemented - return self._cmp(other) > 0 - - -class GenericOption(Option): - - """Generate Rdata Class - - This class is used for EDNS option types for which we have no better - implementation. - """ - - def __init__(self, otype, data): - super(GenericOption, self).__init__(otype) - self.data = data - - def to_wire(self, file): - file.write(self.data) - - @classmethod - def from_wire(cls, otype, wire, current, olen): - return cls(otype, wire[current: current + olen]) - - def _cmp(self, other): - if self.data == other.data: - return 0 - if self.data > other.data: - return 1 - return -1 - -_type_to_class = { -} - - -def get_option_class(otype): - cls = _type_to_class.get(otype) - if cls is None: - cls = GenericOption - return cls - - -def option_from_wire(otype, wire, current, olen): - """Build an EDNS option object from wire format - - @param otype: The option type - @type otype: int - @param wire: The wire-format message - @type wire: string - @param current: The offset in wire of the beginning of the rdata. - @type current: int - @param olen: The length of the wire-format option data - @type olen: int - @rtype: dns.edns.Option instance""" - - cls = get_option_class(otype) - return cls.from_wire(otype, wire, current, olen) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/entropy.py python-eventlet-0.24.1/eventlet/support/dns/entropy.py --- python-eventlet-0.20.0/eventlet/support/dns/entropy.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/entropy.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -# Copyright (C) 2009, 2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import os -import random -import time -from ._compat import long, binary_type -try: - import threading as _threading -except ImportError: - import dummy_threading as _threading - - -class EntropyPool(object): - - def __init__(self, seed=None): - self.pool_index = 0 - self.digest = None - self.next_byte = 0 - self.lock = _threading.Lock() - try: - import hashlib - self.hash = hashlib.sha1() - self.hash_len = 20 - except ImportError: - try: - import sha - self.hash = sha.new() - self.hash_len = 20 - except ImportError: - import md5 # pylint: disable=import-error - self.hash = md5.new() - self.hash_len = 16 - self.pool = bytearray(b'\0' * self.hash_len) - if seed is not None: - self.stir(bytearray(seed)) - self.seeded = True - self.seed_pid = os.getpid() - else: - self.seeded = False - self.seed_pid = 0 - - def stir(self, entropy, already_locked=False): - if not already_locked: - self.lock.acquire() - try: - for c in entropy: - if self.pool_index == self.hash_len: - self.pool_index = 0 - b = c & 0xff - self.pool[self.pool_index] ^= b - self.pool_index += 1 - finally: - if not already_locked: - self.lock.release() - - def _maybe_seed(self): - if not self.seeded or self.seed_pid != os.getpid(): - try: - seed = os.urandom(16) - except Exception: - try: - r = open('/dev/urandom', 'rb', 0) - try: - seed = r.read(16) - finally: - r.close() - except Exception: - seed = str(time.time()) - self.seeded = True - self.seed_pid = os.getpid() - self.digest = None - seed = bytearray(seed) - self.stir(seed, True) - - def random_8(self): - self.lock.acquire() - try: - self._maybe_seed() - if self.digest is None or self.next_byte == self.hash_len: - self.hash.update(binary_type(self.pool)) - self.digest = bytearray(self.hash.digest()) - self.stir(self.digest, True) - self.next_byte = 0 - value = self.digest[self.next_byte] - self.next_byte += 1 - finally: - self.lock.release() - return value - - def random_16(self): - return self.random_8() * 256 + self.random_8() - - def random_32(self): - return self.random_16() * 65536 + self.random_16() - - def random_between(self, first, last): - size = last - first + 1 - if size > long(4294967296): - raise ValueError('too big') - if size > 65536: - rand = self.random_32 - max = long(4294967295) - elif size > 256: - rand = self.random_16 - max = 65535 - else: - rand = self.random_8 - max = 255 - return first + size * rand() // (max + 1) - -pool = EntropyPool() - -try: - system_random = random.SystemRandom() -except Exception: - system_random = None - -def random_16(): - if system_random is not None: - return system_random.randrange(0, 65536) - else: - return pool.random_16() - -def between(first, last): - if system_random is not None: - return system_random.randrange(first, last + 1) - else: - return pool.random_between(first, last) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/exception.py python-eventlet-0.24.1/eventlet/support/dns/exception.py --- python-eventlet-0.20.0/eventlet/support/dns/exception.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/exception.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,128 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Common DNS Exceptions.""" - - -class DNSException(Exception): - - """Abstract base class shared by all dnspython exceptions. - - It supports two basic modes of operation: - - a) Old/compatible mode is used if __init__ was called with - empty **kwargs. - In compatible mode all *args are passed to standard Python Exception class - as before and all *args are printed by standard __str__ implementation. - Class variable msg (or doc string if msg is None) is returned from str() - if *args is empty. - - b) New/parametrized mode is used if __init__ was called with - non-empty **kwargs. - In the new mode *args has to be empty and all kwargs has to exactly match - set in class variable self.supp_kwargs. All kwargs are stored inside - self.kwargs and used in new __str__ implementation to construct - formatted message based on self.fmt string. - - In the simplest case it is enough to override supp_kwargs and fmt - class variables to get nice parametrized messages. - """ - msg = None # non-parametrized message - supp_kwargs = set() # accepted parameters for _fmt_kwargs (sanity check) - fmt = None # message parametrized with results from _fmt_kwargs - - def __init__(self, *args, **kwargs): - self._check_params(*args, **kwargs) - if kwargs: - self.kwargs = self._check_kwargs(**kwargs) - self.msg = str(self) - else: - self.kwargs = dict() # defined but empty for old mode exceptions - if self.msg is None: - # doc string is better implicit message than empty string - self.msg = self.__doc__ - if args: - super(DNSException, self).__init__(*args) - else: - super(DNSException, self).__init__(self.msg) - - def _check_params(self, *args, **kwargs): - """Old exceptions supported only args and not kwargs. - - For sanity we do not allow to mix old and new behavior.""" - if args or kwargs: - assert bool(args) != bool(kwargs), \ - 'keyword arguments are mutually exclusive with positional args' - - def _check_kwargs(self, **kwargs): - if kwargs: - assert set(kwargs.keys()) == self.supp_kwargs, \ - 'following set of keyword args is required: %s' % ( - self.supp_kwargs) - return kwargs - - def _fmt_kwargs(self, **kwargs): - """Format kwargs before printing them. - - Resulting dictionary has to have keys necessary for str.format call - on fmt class variable. - """ - fmtargs = {} - for kw, data in kwargs.items(): - if isinstance(data, (list, set)): - # convert list of to list of str() - fmtargs[kw] = list(map(str, data)) - if len(fmtargs[kw]) == 1: - # remove list brackets [] from single-item lists - fmtargs[kw] = fmtargs[kw].pop() - else: - fmtargs[kw] = data - return fmtargs - - def __str__(self): - if self.kwargs and self.fmt: - # provide custom message constructed from keyword arguments - fmtargs = self._fmt_kwargs(**self.kwargs) - return self.fmt.format(**fmtargs) - else: - # print *args directly in the same way as old DNSException - return super(DNSException, self).__str__() - - -class FormError(DNSException): - - """DNS message is malformed.""" - - -class SyntaxError(DNSException): - - """Text input is malformed.""" - - -class UnexpectedEnd(SyntaxError): - - """Text input ended unexpectedly.""" - - -class TooBig(DNSException): - - """The DNS message is too big.""" - - -class Timeout(DNSException): - - """The DNS operation timed out.""" - supp_kwargs = set(['timeout']) - fmt = "The DNS operation timed out after {timeout} seconds" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/flags.py python-eventlet-0.24.1/eventlet/support/dns/flags.py --- python-eventlet-0.20.0/eventlet/support/dns/flags.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/flags.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,112 +0,0 @@ -# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Message Flags.""" - -# Standard DNS flags - -QR = 0x8000 -AA = 0x0400 -TC = 0x0200 -RD = 0x0100 -RA = 0x0080 -AD = 0x0020 -CD = 0x0010 - -# EDNS flags - -DO = 0x8000 - -_by_text = { - 'QR': QR, - 'AA': AA, - 'TC': TC, - 'RD': RD, - 'RA': RA, - 'AD': AD, - 'CD': CD -} - -_edns_by_text = { - 'DO': DO -} - - -# We construct the inverse mappings programmatically to ensure that we -# cannot make any mistakes (e.g. omissions, cut-and-paste errors) that -# would cause the mappings not to be true inverses. - -_by_value = dict((y, x) for x, y in _by_text.items()) - -_edns_by_value = dict((y, x) for x, y in _edns_by_text.items()) - - -def _order_flags(table): - order = list(table.items()) - order.sort() - order.reverse() - return order - -_flags_order = _order_flags(_by_value) - -_edns_flags_order = _order_flags(_edns_by_value) - - -def _from_text(text, table): - flags = 0 - tokens = text.split() - for t in tokens: - flags = flags | table[t.upper()] - return flags - - -def _to_text(flags, table, order): - text_flags = [] - for k, v in order: - if flags & k != 0: - text_flags.append(v) - return ' '.join(text_flags) - - -def from_text(text): - """Convert a space-separated list of flag text values into a flags - value. - @rtype: int""" - - return _from_text(text, _by_text) - - -def to_text(flags): - """Convert a flags value into a space-separated list of flag text - values. - @rtype: string""" - - return _to_text(flags, _by_value, _flags_order) - - -def edns_from_text(text): - """Convert a space-separated list of EDNS flag text values into a EDNS - flags value. - @rtype: int""" - - return _from_text(text, _edns_by_text) - - -def edns_to_text(flags): - """Convert an EDNS flags value into a space-separated list of EDNS flag - text values. - @rtype: string""" - - return _to_text(flags, _edns_by_value, _edns_flags_order) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/grange.py python-eventlet-0.24.1/eventlet/support/dns/grange.py --- python-eventlet-0.20.0/eventlet/support/dns/grange.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/grange.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS GENERATE range conversion.""" - -import dns - - -def from_text(text): - """Convert the text form of a range in a GENERATE statement to an - integer. - - @param text: the textual range - @type text: string - @return: The start, stop and step values. - @rtype: tuple - """ - # TODO, figure out the bounds on start, stop and step. - - step = 1 - cur = '' - state = 0 - # state 0 1 2 3 4 - # x - y / z - - if text and text[0] == '-': - raise dns.exception.SyntaxError("Start cannot be a negative number") - - for c in text: - if c == '-' and state == 0: - start = int(cur) - cur = '' - state = 2 - elif c == '/': - stop = int(cur) - cur = '' - state = 4 - elif c.isdigit(): - cur += c - else: - raise dns.exception.SyntaxError("Could not parse %s" % (c)) - - if state in (1, 3): - raise dns.exception.SyntaxError() - - if state == 2: - stop = int(cur) - - if state == 4: - step = int(cur) - - assert step >= 1 - assert start >= 0 - assert start <= stop - # TODO, can start == stop? - - return (start, stop, step) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/hash.py python-eventlet-0.24.1/eventlet/support/dns/hash.py --- python-eventlet-0.20.0/eventlet/support/dns/hash.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/hash.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -# Copyright (C) 2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Hashing backwards compatibility wrapper""" - -import hashlib - - -hashes = {} -hashes['MD5'] = hashlib.md5 -hashes['SHA1'] = hashlib.sha1 -hashes['SHA224'] = hashlib.sha224 -hashes['SHA256'] = hashlib.sha256 -hashes['SHA384'] = hashlib.sha384 -hashes['SHA512'] = hashlib.sha512 - - -def get(algorithm): - return hashes[algorithm.upper()] diff -Nru python-eventlet-0.20.0/eventlet/support/dns/inet.py python-eventlet-0.24.1/eventlet/support/dns/inet.py --- python-eventlet-0.20.0/eventlet/support/dns/inet.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/inet.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Generic Internet address helper functions.""" - -import socket - -import dns.ipv4 -import dns.ipv6 - - -# We assume that AF_INET is always defined. - -AF_INET = socket.AF_INET - -# AF_INET6 might not be defined in the socket module, but we need it. -# We'll try to use the socket module's value, and if it doesn't work, -# we'll use our own value. - -try: - AF_INET6 = socket.AF_INET6 -except AttributeError: - AF_INET6 = 9999 - - -def inet_pton(family, text): - """Convert the textual form of a network address into its binary form. - - @param family: the address family - @type family: int - @param text: the textual address - @type text: string - @raises NotImplementedError: the address family specified is not - implemented. - @rtype: string - """ - - if family == AF_INET: - return dns.ipv4.inet_aton(text) - elif family == AF_INET6: - return dns.ipv6.inet_aton(text) - else: - raise NotImplementedError - - -def inet_ntop(family, address): - """Convert the binary form of a network address into its textual form. - - @param family: the address family - @type family: int - @param address: the binary address - @type address: string - @raises NotImplementedError: the address family specified is not - implemented. - @rtype: string - """ - if family == AF_INET: - return dns.ipv4.inet_ntoa(address) - elif family == AF_INET6: - return dns.ipv6.inet_ntoa(address) - else: - raise NotImplementedError - - -def af_for_address(text): - """Determine the address family of a textual-form network address. - - @param text: the textual address - @type text: string - @raises ValueError: the address family cannot be determined from the input. - @rtype: int - """ - try: - dns.ipv4.inet_aton(text) - return AF_INET - except Exception: - try: - dns.ipv6.inet_aton(text) - return AF_INET6 - except: - raise ValueError - - -def is_multicast(text): - """Is the textual-form network address a multicast address? - - @param text: the textual address - @raises ValueError: the address family cannot be determined from the input. - @rtype: bool - """ - try: - first = ord(dns.ipv4.inet_aton(text)[0]) - return first >= 224 and first <= 239 - except Exception: - try: - first = ord(dns.ipv6.inet_aton(text)[0]) - return first == 255 - except Exception: - raise ValueError diff -Nru python-eventlet-0.20.0/eventlet/support/dns/__init__.py python-eventlet-0.24.1/eventlet/support/dns/__init__.py --- python-eventlet-0.20.0/eventlet/support/dns/__init__.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -# Copyright (C) 2003-2007, 2009, 2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""dnspython DNS toolkit""" - -__all__ = [ - 'dnssec', - 'e164', - 'edns', - 'entropy', - 'exception', - 'flags', - 'hash', - 'inet', - 'ipv4', - 'ipv6', - 'message', - 'name', - 'namedict', - 'node', - 'opcode', - 'query', - 'rcode', - 'rdata', - 'rdataclass', - 'rdataset', - 'rdatatype', - 'renderer', - 'resolver', - 'reversename', - 'rrset', - 'set', - 'tokenizer', - 'tsig', - 'tsigkeyring', - 'ttl', - 'rdtypes', - 'update', - 'version', - 'wiredata', - 'zone', -] diff -Nru python-eventlet-0.20.0/eventlet/support/dns/ipv4.py python-eventlet-0.24.1/eventlet/support/dns/ipv4.py --- python-eventlet-0.20.0/eventlet/support/dns/ipv4.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/ipv4.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""IPv4 helper functions.""" - -import struct - -import dns.exception -from ._compat import binary_type - -def inet_ntoa(address): - """Convert an IPv4 address in network form to text form. - - @param address: The IPv4 address - @type address: string - @returns: string - """ - if len(address) != 4: - raise dns.exception.SyntaxError - if not isinstance(address, bytearray): - address = bytearray(address) - return (u'%u.%u.%u.%u' % (address[0], address[1], - address[2], address[3])).encode() - -def inet_aton(text): - """Convert an IPv4 address in text form to network form. - - @param text: The IPv4 address - @type text: string - @returns: string - """ - if not isinstance(text, binary_type): - text = text.encode() - parts = text.split(b'.') - if len(parts) != 4: - raise dns.exception.SyntaxError - for part in parts: - if not part.isdigit(): - raise dns.exception.SyntaxError - if len(part) > 1 and part[0] == '0': - # No leading zeros - raise dns.exception.SyntaxError - try: - bytes = [int(part) for part in parts] - return struct.pack('BBBB', *bytes) - except: - raise dns.exception.SyntaxError diff -Nru python-eventlet-0.20.0/eventlet/support/dns/ipv6.py python-eventlet-0.24.1/eventlet/support/dns/ipv6.py --- python-eventlet-0.20.0/eventlet/support/dns/ipv6.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/ipv6.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,172 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""IPv6 helper functions.""" - -import re -import binascii - -import dns.exception -import dns.ipv4 -from ._compat import xrange, binary_type, maybe_decode - -_leading_zero = re.compile(b'0+([0-9a-f]+)') - -def inet_ntoa(address): - """Convert a network format IPv6 address into text. - - @param address: the binary address - @type address: string - @rtype: string - @raises ValueError: the address isn't 16 bytes long - """ - - if len(address) != 16: - raise ValueError("IPv6 addresses are 16 bytes long") - hex = binascii.hexlify(address) - chunks = [] - i = 0 - l = len(hex) - while i < l: - chunk = hex[i : i + 4] - # strip leading zeros. we do this with an re instead of - # with lstrip() because lstrip() didn't support chars until - # python 2.2.2 - m = _leading_zero.match(chunk) - if not m is None: - chunk = m.group(1) - chunks.append(chunk) - i += 4 - # - # Compress the longest subsequence of 0-value chunks to :: - # - best_start = 0 - best_len = 0 - start = -1 - last_was_zero = False - for i in xrange(8): - if chunks[i] != b'0': - if last_was_zero: - end = i - current_len = end - start - if current_len > best_len: - best_start = start - best_len = current_len - last_was_zero = False - elif not last_was_zero: - start = i - last_was_zero = True - if last_was_zero: - end = 8 - current_len = end - start - if current_len > best_len: - best_start = start - best_len = current_len - if best_len > 1: - if best_start == 0 and \ - (best_len == 6 or - best_len == 5 and chunks[5] == b'ffff'): - # We have an embedded IPv4 address - if best_len == 6: - prefix = b'::' - else: - prefix = b'::ffff:' - hex = prefix + dns.ipv4.inet_ntoa(address[12:]) - else: - hex = b':'.join(chunks[:best_start]) + b'::' + \ - b':'.join(chunks[best_start + best_len:]) - else: - hex = b':'.join(chunks) - return maybe_decode(hex) - -_v4_ending = re.compile(b'(.*):(\d+\.\d+\.\d+\.\d+)$') -_colon_colon_start = re.compile(b'::.*') -_colon_colon_end = re.compile(b'.*::$') - -def inet_aton(text): - """Convert a text format IPv6 address into network format. - - @param text: the textual address - @type text: string - @rtype: string - @raises dns.exception.SyntaxError: the text was not properly formatted - """ - - # - # Our aim here is not something fast; we just want something that works. - # - if not isinstance(text, binary_type): - text = text.encode() - - if text == b'::': - text = b'0::' - # - # Get rid of the icky dot-quad syntax if we have it. - # - m = _v4_ending.match(text) - if not m is None: - b = bytearray(dns.ipv4.inet_aton(m.group(2))) - text = (u"%s:%02x%02x:%02x%02x" % (m.group(1).decode(), b[0], b[1], - b[2], b[3])).encode() - # - # Try to turn '::' into ':'; if no match try to - # turn '::' into ':' - # - m = _colon_colon_start.match(text) - if not m is None: - text = text[1:] - else: - m = _colon_colon_end.match(text) - if not m is None: - text = text[:-1] - # - # Now canonicalize into 8 chunks of 4 hex digits each - # - chunks = text.split(b':') - l = len(chunks) - if l > 8: - raise dns.exception.SyntaxError - seen_empty = False - canonical = [] - for c in chunks: - if c == b'': - if seen_empty: - raise dns.exception.SyntaxError - seen_empty = True - for i in xrange(0, 8 - l + 1): - canonical.append(b'0000') - else: - lc = len(c) - if lc > 4: - raise dns.exception.SyntaxError - if lc != 4: - c = (b'0' * (4 - lc)) + c - canonical.append(c) - if l < 8 and not seen_empty: - raise dns.exception.SyntaxError - text = b''.join(canonical) - - # - # Finally we can go to binary. - # - try: - return binascii.unhexlify(text) - except (binascii.Error, TypeError): - raise dns.exception.SyntaxError - -_mapped_prefix = b'\x00' * 10 + b'\xff\xff' - -def is_mapped(address): - return address.startswith(_mapped_prefix) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/message.py python-eventlet-0.24.1/eventlet/support/dns/message.py --- python-eventlet-0.20.0/eventlet/support/dns/message.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/message.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,1152 +0,0 @@ -# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Messages""" - -from __future__ import absolute_import - -from io import StringIO -import struct -import time - -import dns.edns -import dns.exception -import dns.flags -import dns.name -import dns.opcode -import dns.entropy -import dns.rcode -import dns.rdata -import dns.rdataclass -import dns.rdatatype -import dns.rrset -import dns.renderer -import dns.tsig -import dns.wiredata - -from ._compat import long, xrange, string_types - - -class ShortHeader(dns.exception.FormError): - - """The DNS packet passed to from_wire() is too short.""" - - -class TrailingJunk(dns.exception.FormError): - - """The DNS packet passed to from_wire() has extra junk at the end of it.""" - - -class UnknownHeaderField(dns.exception.DNSException): - - """The header field name was not recognized when converting from text - into a message.""" - - -class BadEDNS(dns.exception.FormError): - - """OPT record occurred somewhere other than the start of - the additional data section.""" - - -class BadTSIG(dns.exception.FormError): - - """A TSIG record occurred somewhere other than the end of - the additional data section.""" - - -class UnknownTSIGKey(dns.exception.DNSException): - - """A TSIG with an unknown key was received.""" - - -class Message(object): - - """A DNS message. - - @ivar id: The query id; the default is a randomly chosen id. - @type id: int - @ivar flags: The DNS flags of the message. @see: RFC 1035 for an - explanation of these flags. - @type flags: int - @ivar question: The question section. - @type question: list of dns.rrset.RRset objects - @ivar answer: The answer section. - @type answer: list of dns.rrset.RRset objects - @ivar authority: The authority section. - @type authority: list of dns.rrset.RRset objects - @ivar additional: The additional data section. - @type additional: list of dns.rrset.RRset objects - @ivar edns: The EDNS level to use. The default is -1, no Edns. - @type edns: int - @ivar ednsflags: The EDNS flags - @type ednsflags: long - @ivar payload: The EDNS payload size. The default is 0. - @type payload: int - @ivar options: The EDNS options - @type options: list of dns.edns.Option objects - @ivar request_payload: The associated request's EDNS payload size. - @type request_payload: int - @ivar keyring: The TSIG keyring to use. The default is None. - @type keyring: dict - @ivar keyname: The TSIG keyname to use. The default is None. - @type keyname: dns.name.Name object - @ivar keyalgorithm: The TSIG algorithm to use; defaults to - dns.tsig.default_algorithm. Constants for TSIG algorithms are defined - in dns.tsig, and the currently implemented algorithms are - HMAC_MD5, HMAC_SHA1, HMAC_SHA224, HMAC_SHA256, HMAC_SHA384, and - HMAC_SHA512. - @type keyalgorithm: string - @ivar request_mac: The TSIG MAC of the request message associated with - this message; used when validating TSIG signatures. @see: RFC 2845 for - more information on TSIG fields. - @type request_mac: string - @ivar fudge: TSIG time fudge; default is 300 seconds. - @type fudge: int - @ivar original_id: TSIG original id; defaults to the message's id - @type original_id: int - @ivar tsig_error: TSIG error code; default is 0. - @type tsig_error: int - @ivar other_data: TSIG other data. - @type other_data: string - @ivar mac: The TSIG MAC for this message. - @type mac: string - @ivar xfr: Is the message being used to contain the results of a DNS - zone transfer? The default is False. - @type xfr: bool - @ivar origin: The origin of the zone in messages which are used for - zone transfers or for DNS dynamic updates. The default is None. - @type origin: dns.name.Name object - @ivar tsig_ctx: The TSIG signature context associated with this - message. The default is None. - @type tsig_ctx: hmac.HMAC object - @ivar had_tsig: Did the message decoded from wire format have a TSIG - signature? - @type had_tsig: bool - @ivar multi: Is this message part of a multi-message sequence? The - default is false. This variable is used when validating TSIG signatures - on messages which are part of a zone transfer. - @type multi: bool - @ivar first: Is this message standalone, or the first of a multi - message sequence? This variable is used when validating TSIG signatures - on messages which are part of a zone transfer. - @type first: bool - @ivar index: An index of rrsets in the message. The index key is - (section, name, rdclass, rdtype, covers, deleting). Indexing can be - disabled by setting the index to None. - @type index: dict - """ - - def __init__(self, id=None): - if id is None: - self.id = dns.entropy.random_16() - else: - self.id = id - self.flags = 0 - self.question = [] - self.answer = [] - self.authority = [] - self.additional = [] - self.edns = -1 - self.ednsflags = 0 - self.payload = 0 - self.options = [] - self.request_payload = 0 - self.keyring = None - self.keyname = None - self.keyalgorithm = dns.tsig.default_algorithm - self.request_mac = '' - self.other_data = '' - self.tsig_error = 0 - self.fudge = 300 - self.original_id = self.id - self.mac = '' - self.xfr = False - self.origin = None - self.tsig_ctx = None - self.had_tsig = False - self.multi = False - self.first = True - self.index = {} - - def __repr__(self): - return '' - - def __str__(self): - return self.to_text() - - def to_text(self, origin=None, relativize=True, **kw): - """Convert the message to text. - - The I{origin}, I{relativize}, and any other keyword - arguments are passed to the rrset to_wire() method. - - @rtype: string - """ - - s = StringIO() - s.write(u'id %d\n' % self.id) - s.write(u'opcode %s\n' % - dns.opcode.to_text(dns.opcode.from_flags(self.flags))) - rc = dns.rcode.from_flags(self.flags, self.ednsflags) - s.write(u'rcode %s\n' % dns.rcode.to_text(rc)) - s.write(u'flags %s\n' % dns.flags.to_text(self.flags)) - if self.edns >= 0: - s.write(u'edns %s\n' % self.edns) - if self.ednsflags != 0: - s.write(u'eflags %s\n' % - dns.flags.edns_to_text(self.ednsflags)) - s.write(u'payload %d\n' % self.payload) - is_update = dns.opcode.is_update(self.flags) - if is_update: - s.write(u';ZONE\n') - else: - s.write(u';QUESTION\n') - for rrset in self.question: - s.write(rrset.to_text(origin, relativize, **kw)) - s.write(u'\n') - if is_update: - s.write(u';PREREQ\n') - else: - s.write(u';ANSWER\n') - for rrset in self.answer: - s.write(rrset.to_text(origin, relativize, **kw)) - s.write(u'\n') - if is_update: - s.write(u';UPDATE\n') - else: - s.write(u';AUTHORITY\n') - for rrset in self.authority: - s.write(rrset.to_text(origin, relativize, **kw)) - s.write(u'\n') - s.write(u';ADDITIONAL\n') - for rrset in self.additional: - s.write(rrset.to_text(origin, relativize, **kw)) - s.write(u'\n') - # - # We strip off the final \n so the caller can print the result without - # doing weird things to get around eccentricities in Python print - # formatting - # - return s.getvalue()[:-1] - - def __eq__(self, other): - """Two messages are equal if they have the same content in the - header, question, answer, and authority sections. - @rtype: bool""" - if not isinstance(other, Message): - return False - if self.id != other.id: - return False - if self.flags != other.flags: - return False - for n in self.question: - if n not in other.question: - return False - for n in other.question: - if n not in self.question: - return False - for n in self.answer: - if n not in other.answer: - return False - for n in other.answer: - if n not in self.answer: - return False - for n in self.authority: - if n not in other.authority: - return False - for n in other.authority: - if n not in self.authority: - return False - return True - - def __ne__(self, other): - """Are two messages not equal? - @rtype: bool""" - return not self.__eq__(other) - - def is_response(self, other): - """Is other a response to self? - @rtype: bool""" - if other.flags & dns.flags.QR == 0 or \ - self.id != other.id or \ - dns.opcode.from_flags(self.flags) != \ - dns.opcode.from_flags(other.flags): - return False - if dns.rcode.from_flags(other.flags, other.ednsflags) != \ - dns.rcode.NOERROR: - return True - if dns.opcode.is_update(self.flags): - return True - for n in self.question: - if n not in other.question: - return False - for n in other.question: - if n not in self.question: - return False - return True - - def section_number(self, section): - if section is self.question: - return 0 - elif section is self.answer: - return 1 - elif section is self.authority: - return 2 - elif section is self.additional: - return 3 - else: - raise ValueError('unknown section') - - def find_rrset(self, section, name, rdclass, rdtype, - covers=dns.rdatatype.NONE, deleting=None, create=False, - force_unique=False): - """Find the RRset with the given attributes in the specified section. - - @param section: the section of the message to look in, e.g. - self.answer. - @type section: list of dns.rrset.RRset objects - @param name: the name of the RRset - @type name: dns.name.Name object - @param rdclass: the class of the RRset - @type rdclass: int - @param rdtype: the type of the RRset - @type rdtype: int - @param covers: the covers value of the RRset - @type covers: int - @param deleting: the deleting value of the RRset - @type deleting: int - @param create: If True, create the RRset if it is not found. - The created RRset is appended to I{section}. - @type create: bool - @param force_unique: If True and create is also True, create a - new RRset regardless of whether a matching RRset exists already. - @type force_unique: bool - @raises KeyError: the RRset was not found and create was False - @rtype: dns.rrset.RRset object""" - - key = (self.section_number(section), - name, rdclass, rdtype, covers, deleting) - if not force_unique: - if self.index is not None: - rrset = self.index.get(key) - if rrset is not None: - return rrset - else: - for rrset in section: - if rrset.match(name, rdclass, rdtype, covers, deleting): - return rrset - if not create: - raise KeyError - rrset = dns.rrset.RRset(name, rdclass, rdtype, covers, deleting) - section.append(rrset) - if self.index is not None: - self.index[key] = rrset - return rrset - - def get_rrset(self, section, name, rdclass, rdtype, - covers=dns.rdatatype.NONE, deleting=None, create=False, - force_unique=False): - """Get the RRset with the given attributes in the specified section. - - If the RRset is not found, None is returned. - - @param section: the section of the message to look in, e.g. - self.answer. - @type section: list of dns.rrset.RRset objects - @param name: the name of the RRset - @type name: dns.name.Name object - @param rdclass: the class of the RRset - @type rdclass: int - @param rdtype: the type of the RRset - @type rdtype: int - @param covers: the covers value of the RRset - @type covers: int - @param deleting: the deleting value of the RRset - @type deleting: int - @param create: If True, create the RRset if it is not found. - The created RRset is appended to I{section}. - @type create: bool - @param force_unique: If True and create is also True, create a - new RRset regardless of whether a matching RRset exists already. - @type force_unique: bool - @rtype: dns.rrset.RRset object or None""" - - try: - rrset = self.find_rrset(section, name, rdclass, rdtype, covers, - deleting, create, force_unique) - except KeyError: - rrset = None - return rrset - - def to_wire(self, origin=None, max_size=0, **kw): - """Return a string containing the message in DNS compressed wire - format. - - Additional keyword arguments are passed to the rrset to_wire() - method. - - @param origin: The origin to be appended to any relative names. - @type origin: dns.name.Name object - @param max_size: The maximum size of the wire format output; default - is 0, which means 'the message's request payload, if nonzero, or - 65536'. - @type max_size: int - @raises dns.exception.TooBig: max_size was exceeded - @rtype: string - """ - - if max_size == 0: - if self.request_payload != 0: - max_size = self.request_payload - else: - max_size = 65535 - if max_size < 512: - max_size = 512 - elif max_size > 65535: - max_size = 65535 - r = dns.renderer.Renderer(self.id, self.flags, max_size, origin) - for rrset in self.question: - r.add_question(rrset.name, rrset.rdtype, rrset.rdclass) - for rrset in self.answer: - r.add_rrset(dns.renderer.ANSWER, rrset, **kw) - for rrset in self.authority: - r.add_rrset(dns.renderer.AUTHORITY, rrset, **kw) - if self.edns >= 0: - r.add_edns(self.edns, self.ednsflags, self.payload, self.options) - for rrset in self.additional: - r.add_rrset(dns.renderer.ADDITIONAL, rrset, **kw) - r.write_header() - if self.keyname is not None: - r.add_tsig(self.keyname, self.keyring[self.keyname], - self.fudge, self.original_id, self.tsig_error, - self.other_data, self.request_mac, - self.keyalgorithm) - self.mac = r.mac - return r.get_wire() - - def use_tsig(self, keyring, keyname=None, fudge=300, - original_id=None, tsig_error=0, other_data='', - algorithm=dns.tsig.default_algorithm): - """When sending, a TSIG signature using the specified keyring - and keyname should be added. - - @param keyring: The TSIG keyring to use; defaults to None. - @type keyring: dict - @param keyname: The name of the TSIG key to use; defaults to None. - The key must be defined in the keyring. If a keyring is specified - but a keyname is not, then the key used will be the first key in the - keyring. Note that the order of keys in a dictionary is not defined, - so applications should supply a keyname when a keyring is used, unless - they know the keyring contains only one key. - @type keyname: dns.name.Name or string - @param fudge: TSIG time fudge; default is 300 seconds. - @type fudge: int - @param original_id: TSIG original id; defaults to the message's id - @type original_id: int - @param tsig_error: TSIG error code; default is 0. - @type tsig_error: int - @param other_data: TSIG other data. - @type other_data: string - @param algorithm: The TSIG algorithm to use; defaults to - dns.tsig.default_algorithm - """ - - self.keyring = keyring - if keyname is None: - self.keyname = list(self.keyring.keys())[0] - else: - if isinstance(keyname, string_types): - keyname = dns.name.from_text(keyname) - self.keyname = keyname - self.keyalgorithm = algorithm - self.fudge = fudge - if original_id is None: - self.original_id = self.id - else: - self.original_id = original_id - self.tsig_error = tsig_error - self.other_data = other_data - - def use_edns(self, edns=0, ednsflags=0, payload=1280, request_payload=None, - options=None): - """Configure EDNS behavior. - @param edns: The EDNS level to use. Specifying None, False, or -1 - means 'do not use EDNS', and in this case the other parameters are - ignored. Specifying True is equivalent to specifying 0, i.e. 'use - EDNS0'. - @type edns: int or bool or None - @param ednsflags: EDNS flag values. - @type ednsflags: int - @param payload: The EDNS sender's payload field, which is the maximum - size of UDP datagram the sender can handle. - @type payload: int - @param request_payload: The EDNS payload size to use when sending - this message. If not specified, defaults to the value of payload. - @type request_payload: int or None - @param options: The EDNS options - @type options: None or list of dns.edns.Option objects - @see: RFC 2671 - """ - if edns is None or edns is False: - edns = -1 - if edns is True: - edns = 0 - if request_payload is None: - request_payload = payload - if edns < 0: - ednsflags = 0 - payload = 0 - request_payload = 0 - options = [] - else: - # make sure the EDNS version in ednsflags agrees with edns - ednsflags &= long(0xFF00FFFF) - ednsflags |= (edns << 16) - if options is None: - options = [] - self.edns = edns - self.ednsflags = ednsflags - self.payload = payload - self.options = options - self.request_payload = request_payload - - def want_dnssec(self, wanted=True): - """Enable or disable 'DNSSEC desired' flag in requests. - @param wanted: Is DNSSEC desired? If True, EDNS is enabled if - required, and then the DO bit is set. If False, the DO bit is - cleared if EDNS is enabled. - @type wanted: bool - """ - if wanted: - if self.edns < 0: - self.use_edns() - self.ednsflags |= dns.flags.DO - elif self.edns >= 0: - self.ednsflags &= ~dns.flags.DO - - def rcode(self): - """Return the rcode. - @rtype: int - """ - return dns.rcode.from_flags(self.flags, self.ednsflags) - - def set_rcode(self, rcode): - """Set the rcode. - @param rcode: the rcode - @type rcode: int - """ - (value, evalue) = dns.rcode.to_flags(rcode) - self.flags &= 0xFFF0 - self.flags |= value - self.ednsflags &= long(0x00FFFFFF) - self.ednsflags |= evalue - if self.ednsflags != 0 and self.edns < 0: - self.edns = 0 - - def opcode(self): - """Return the opcode. - @rtype: int - """ - return dns.opcode.from_flags(self.flags) - - def set_opcode(self, opcode): - """Set the opcode. - @param opcode: the opcode - @type opcode: int - """ - self.flags &= 0x87FF - self.flags |= dns.opcode.to_flags(opcode) - - -class _WireReader(object): - - """Wire format reader. - - @ivar wire: the wire-format message. - @type wire: string - @ivar message: The message object being built - @type message: dns.message.Message object - @ivar current: When building a message object from wire format, this - variable contains the offset from the beginning of wire of the next octet - to be read. - @type current: int - @ivar updating: Is the message a dynamic update? - @type updating: bool - @ivar one_rr_per_rrset: Put each RR into its own RRset? - @type one_rr_per_rrset: bool - @ivar ignore_trailing: Ignore trailing junk at end of request? - @type ignore_trailing: bool - @ivar zone_rdclass: The class of the zone in messages which are - DNS dynamic updates. - @type zone_rdclass: int - """ - - def __init__(self, wire, message, question_only=False, - one_rr_per_rrset=False, ignore_trailing=False): - self.wire = dns.wiredata.maybe_wrap(wire) - self.message = message - self.current = 0 - self.updating = False - self.zone_rdclass = dns.rdataclass.IN - self.question_only = question_only - self.one_rr_per_rrset = one_rr_per_rrset - self.ignore_trailing = ignore_trailing - - def _get_question(self, qcount): - """Read the next I{qcount} records from the wire data and add them to - the question section. - @param qcount: the number of questions in the message - @type qcount: int""" - - if self.updating and qcount > 1: - raise dns.exception.FormError - - for i in xrange(0, qcount): - (qname, used) = dns.name.from_wire(self.wire, self.current) - if self.message.origin is not None: - qname = qname.relativize(self.message.origin) - self.current = self.current + used - (rdtype, rdclass) = \ - struct.unpack('!HH', - self.wire[self.current:self.current + 4]) - self.current = self.current + 4 - self.message.find_rrset(self.message.question, qname, - rdclass, rdtype, create=True, - force_unique=True) - if self.updating: - self.zone_rdclass = rdclass - - def _get_section(self, section, count): - """Read the next I{count} records from the wire data and add them to - the specified section. - @param section: the section of the message to which to add records - @type section: list of dns.rrset.RRset objects - @param count: the number of records to read - @type count: int""" - - if self.updating or self.one_rr_per_rrset: - force_unique = True - else: - force_unique = False - seen_opt = False - for i in xrange(0, count): - rr_start = self.current - (name, used) = dns.name.from_wire(self.wire, self.current) - absolute_name = name - if self.message.origin is not None: - name = name.relativize(self.message.origin) - self.current = self.current + used - (rdtype, rdclass, ttl, rdlen) = \ - struct.unpack('!HHIH', - self.wire[self.current:self.current + 10]) - self.current = self.current + 10 - if rdtype == dns.rdatatype.OPT: - if section is not self.message.additional or seen_opt: - raise BadEDNS - self.message.payload = rdclass - self.message.ednsflags = ttl - self.message.edns = (ttl & 0xff0000) >> 16 - self.message.options = [] - current = self.current - optslen = rdlen - while optslen > 0: - (otype, olen) = \ - struct.unpack('!HH', - self.wire[current:current + 4]) - current = current + 4 - opt = dns.edns.option_from_wire( - otype, self.wire, current, olen) - self.message.options.append(opt) - current = current + olen - optslen = optslen - 4 - olen - seen_opt = True - elif rdtype == dns.rdatatype.TSIG: - if not (section is self.message.additional and - i == (count - 1)): - raise BadTSIG - if self.message.keyring is None: - raise UnknownTSIGKey('got signed message without keyring') - secret = self.message.keyring.get(absolute_name) - if secret is None: - raise UnknownTSIGKey("key '%s' unknown" % name) - self.message.keyname = absolute_name - (self.message.keyalgorithm, self.message.mac) = \ - dns.tsig.get_algorithm_and_mac(self.wire, self.current, - rdlen) - self.message.tsig_ctx = \ - dns.tsig.validate(self.wire, - absolute_name, - secret, - int(time.time()), - self.message.request_mac, - rr_start, - self.current, - rdlen, - self.message.tsig_ctx, - self.message.multi, - self.message.first) - self.message.had_tsig = True - else: - if ttl < 0: - ttl = 0 - if self.updating and \ - (rdclass == dns.rdataclass.ANY or - rdclass == dns.rdataclass.NONE): - deleting = rdclass - rdclass = self.zone_rdclass - else: - deleting = None - if deleting == dns.rdataclass.ANY or \ - (deleting == dns.rdataclass.NONE and - section is self.message.answer): - covers = dns.rdatatype.NONE - rd = None - else: - rd = dns.rdata.from_wire(rdclass, rdtype, self.wire, - self.current, rdlen, - self.message.origin) - covers = rd.covers() - if self.message.xfr and rdtype == dns.rdatatype.SOA: - force_unique = True - rrset = self.message.find_rrset(section, name, - rdclass, rdtype, covers, - deleting, True, force_unique) - if rd is not None: - rrset.add(rd, ttl) - self.current = self.current + rdlen - - def read(self): - """Read a wire format DNS message and build a dns.message.Message - object.""" - - l = len(self.wire) - if l < 12: - raise ShortHeader - (self.message.id, self.message.flags, qcount, ancount, - aucount, adcount) = struct.unpack('!HHHHHH', self.wire[:12]) - self.current = 12 - if dns.opcode.is_update(self.message.flags): - self.updating = True - self._get_question(qcount) - if self.question_only: - return - self._get_section(self.message.answer, ancount) - self._get_section(self.message.authority, aucount) - self._get_section(self.message.additional, adcount) - if not self.ignore_trailing and self.current != l: - raise TrailingJunk - if self.message.multi and self.message.tsig_ctx and \ - not self.message.had_tsig: - self.message.tsig_ctx.update(self.wire) - - -def from_wire(wire, keyring=None, request_mac='', xfr=False, origin=None, - tsig_ctx=None, multi=False, first=True, - question_only=False, one_rr_per_rrset=False, - ignore_trailing=False): - """Convert a DNS wire format message into a message - object. - - @param keyring: The keyring to use if the message is signed. - @type keyring: dict - @param request_mac: If the message is a response to a TSIG-signed request, - I{request_mac} should be set to the MAC of that request. - @type request_mac: string - @param xfr: Is this message part of a zone transfer? - @type xfr: bool - @param origin: If the message is part of a zone transfer, I{origin} - should be the origin name of the zone. - @type origin: dns.name.Name object - @param tsig_ctx: The ongoing TSIG context, used when validating zone - transfers. - @type tsig_ctx: hmac.HMAC object - @param multi: Is this message part of a multiple message sequence? - @type multi: bool - @param first: Is this message standalone, or the first of a multi - message sequence? - @type first: bool - @param question_only: Read only up to the end of the question section? - @type question_only: bool - @param one_rr_per_rrset: Put each RR into its own RRset - @type one_rr_per_rrset: bool - @param ignore_trailing: Ignore trailing junk at end of request? - @type ignore_trailing: bool - @raises ShortHeader: The message is less than 12 octets long. - @raises TrailingJunk: There were octets in the message past the end - of the proper DNS message. - @raises BadEDNS: An OPT record was in the wrong section, or occurred more - than once. - @raises BadTSIG: A TSIG record was not the last record of the additional - data section. - @rtype: dns.message.Message object""" - - m = Message(id=0) - m.keyring = keyring - m.request_mac = request_mac - m.xfr = xfr - m.origin = origin - m.tsig_ctx = tsig_ctx - m.multi = multi - m.first = first - - reader = _WireReader(wire, m, question_only, one_rr_per_rrset, - ignore_trailing) - reader.read() - - return m - - -class _TextReader(object): - - """Text format reader. - - @ivar tok: the tokenizer - @type tok: dns.tokenizer.Tokenizer object - @ivar message: The message object being built - @type message: dns.message.Message object - @ivar updating: Is the message a dynamic update? - @type updating: bool - @ivar zone_rdclass: The class of the zone in messages which are - DNS dynamic updates. - @type zone_rdclass: int - @ivar last_name: The most recently read name when building a message object - from text format. - @type last_name: dns.name.Name object - """ - - def __init__(self, text, message): - self.message = message - self.tok = dns.tokenizer.Tokenizer(text) - self.last_name = None - self.zone_rdclass = dns.rdataclass.IN - self.updating = False - - def _header_line(self, section): - """Process one line from the text format header section.""" - - token = self.tok.get() - what = token.value - if what == 'id': - self.message.id = self.tok.get_int() - elif what == 'flags': - while True: - token = self.tok.get() - if not token.is_identifier(): - self.tok.unget(token) - break - self.message.flags = self.message.flags | \ - dns.flags.from_text(token.value) - if dns.opcode.is_update(self.message.flags): - self.updating = True - elif what == 'edns': - self.message.edns = self.tok.get_int() - self.message.ednsflags = self.message.ednsflags | \ - (self.message.edns << 16) - elif what == 'eflags': - if self.message.edns < 0: - self.message.edns = 0 - while True: - token = self.tok.get() - if not token.is_identifier(): - self.tok.unget(token) - break - self.message.ednsflags = self.message.ednsflags | \ - dns.flags.edns_from_text(token.value) - elif what == 'payload': - self.message.payload = self.tok.get_int() - if self.message.edns < 0: - self.message.edns = 0 - elif what == 'opcode': - text = self.tok.get_string() - self.message.flags = self.message.flags | \ - dns.opcode.to_flags(dns.opcode.from_text(text)) - elif what == 'rcode': - text = self.tok.get_string() - self.message.set_rcode(dns.rcode.from_text(text)) - else: - raise UnknownHeaderField - self.tok.get_eol() - - def _question_line(self, section): - """Process one line from the text format question section.""" - - token = self.tok.get(want_leading=True) - if not token.is_whitespace(): - self.last_name = dns.name.from_text(token.value, None) - name = self.last_name - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - # Class - try: - rdclass = dns.rdataclass.from_text(token.value) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except dns.exception.SyntaxError: - raise dns.exception.SyntaxError - except Exception: - rdclass = dns.rdataclass.IN - # Type - rdtype = dns.rdatatype.from_text(token.value) - self.message.find_rrset(self.message.question, name, - rdclass, rdtype, create=True, - force_unique=True) - if self.updating: - self.zone_rdclass = rdclass - self.tok.get_eol() - - def _rr_line(self, section): - """Process one line from the text format answer, authority, or - additional data sections. - """ - - deleting = None - # Name - token = self.tok.get(want_leading=True) - if not token.is_whitespace(): - self.last_name = dns.name.from_text(token.value, None) - name = self.last_name - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - # TTL - try: - ttl = int(token.value, 0) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except dns.exception.SyntaxError: - raise dns.exception.SyntaxError - except Exception: - ttl = 0 - # Class - try: - rdclass = dns.rdataclass.from_text(token.value) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - if rdclass == dns.rdataclass.ANY or rdclass == dns.rdataclass.NONE: - deleting = rdclass - rdclass = self.zone_rdclass - except dns.exception.SyntaxError: - raise dns.exception.SyntaxError - except Exception: - rdclass = dns.rdataclass.IN - # Type - rdtype = dns.rdatatype.from_text(token.value) - token = self.tok.get() - if not token.is_eol_or_eof(): - self.tok.unget(token) - rd = dns.rdata.from_text(rdclass, rdtype, self.tok, None) - covers = rd.covers() - else: - rd = None - covers = dns.rdatatype.NONE - rrset = self.message.find_rrset(section, name, - rdclass, rdtype, covers, - deleting, True, self.updating) - if rd is not None: - rrset.add(rd, ttl) - - def read(self): - """Read a text format DNS message and build a dns.message.Message - object.""" - - line_method = self._header_line - section = None - while 1: - token = self.tok.get(True, True) - if token.is_eol_or_eof(): - break - if token.is_comment(): - u = token.value.upper() - if u == 'HEADER': - line_method = self._header_line - elif u == 'QUESTION' or u == 'ZONE': - line_method = self._question_line - section = self.message.question - elif u == 'ANSWER' or u == 'PREREQ': - line_method = self._rr_line - section = self.message.answer - elif u == 'AUTHORITY' or u == 'UPDATE': - line_method = self._rr_line - section = self.message.authority - elif u == 'ADDITIONAL': - line_method = self._rr_line - section = self.message.additional - self.tok.get_eol() - continue - self.tok.unget(token) - line_method(section) - - -def from_text(text): - """Convert the text format message into a message object. - - @param text: The text format message. - @type text: string - @raises UnknownHeaderField: - @raises dns.exception.SyntaxError: - @rtype: dns.message.Message object""" - - # 'text' can also be a file, but we don't publish that fact - # since it's an implementation detail. The official file - # interface is from_file(). - - m = Message() - - reader = _TextReader(text, m) - reader.read() - - return m - - -def from_file(f): - """Read the next text format message from the specified file. - - @param f: file or string. If I{f} is a string, it is treated - as the name of a file to open. - @raises UnknownHeaderField: - @raises dns.exception.SyntaxError: - @rtype: dns.message.Message object""" - - str_type = string_types - opts = 'rU' - - if isinstance(f, str_type): - f = open(f, opts) - want_close = True - else: - want_close = False - - try: - m = from_text(f) - finally: - if want_close: - f.close() - return m - - -def make_query(qname, rdtype, rdclass=dns.rdataclass.IN, use_edns=None, - want_dnssec=False, ednsflags=None, payload=None, - request_payload=None, options=None): - """Make a query message. - - The query name, type, and class may all be specified either - as objects of the appropriate type, or as strings. - - The query will have a randomly chosen query id, and its DNS flags - will be set to dns.flags.RD. - - @param qname: The query name. - @type qname: dns.name.Name object or string - @param rdtype: The desired rdata type. - @type rdtype: int - @param rdclass: The desired rdata class; the default is class IN. - @type rdclass: int - @param use_edns: The EDNS level to use; the default is None (no EDNS). - See the description of dns.message.Message.use_edns() for the possible - values for use_edns and their meanings. - @type use_edns: int or bool or None - @param want_dnssec: Should the query indicate that DNSSEC is desired? - @type want_dnssec: bool - @param ednsflags: EDNS flag values. - @type ednsflags: int - @param payload: The EDNS sender's payload field, which is the maximum - size of UDP datagram the sender can handle. - @type payload: int - @param request_payload: The EDNS payload size to use when sending - this message. If not specified, defaults to the value of payload. - @type request_payload: int or None - @param options: The EDNS options - @type options: None or list of dns.edns.Option objects - @see: RFC 2671 - @rtype: dns.message.Message object""" - - if isinstance(qname, string_types): - qname = dns.name.from_text(qname) - if isinstance(rdtype, string_types): - rdtype = dns.rdatatype.from_text(rdtype) - if isinstance(rdclass, string_types): - rdclass = dns.rdataclass.from_text(rdclass) - m = Message() - m.flags |= dns.flags.RD - m.find_rrset(m.question, qname, rdclass, rdtype, create=True, - force_unique=True) - # only pass keywords on to use_edns if they have been set to a - # non-None value. Setting a field will turn EDNS on if it hasn't - # been configured. - kwargs = {} - if ednsflags is not None: - kwargs['ednsflags'] = ednsflags - if use_edns is None: - use_edns = 0 - if payload is not None: - kwargs['payload'] = payload - if use_edns is None: - use_edns = 0 - if request_payload is not None: - kwargs['request_payload'] = request_payload - if use_edns is None: - use_edns = 0 - if options is not None: - kwargs['options'] = options - if use_edns is None: - use_edns = 0 - kwargs['edns'] = use_edns - m.use_edns(**kwargs) - m.want_dnssec(want_dnssec) - return m - - -def make_response(query, recursion_available=False, our_payload=8192, - fudge=300): - """Make a message which is a response for the specified query. - The message returned is really a response skeleton; it has all - of the infrastructure required of a response, but none of the - content. - - The response's question section is a shallow copy of the query's - question section, so the query's question RRsets should not be - changed. - - @param query: the query to respond to - @type query: dns.message.Message object - @param recursion_available: should RA be set in the response? - @type recursion_available: bool - @param our_payload: payload size to advertise in EDNS responses; default - is 8192. - @type our_payload: int - @param fudge: TSIG time fudge; default is 300 seconds. - @type fudge: int - @rtype: dns.message.Message object""" - - if query.flags & dns.flags.QR: - raise dns.exception.FormError('specified query message is not a query') - response = dns.message.Message(query.id) - response.flags = dns.flags.QR | (query.flags & dns.flags.RD) - if recursion_available: - response.flags |= dns.flags.RA - response.set_opcode(query.opcode()) - response.question = list(query.question) - if query.edns >= 0: - response.use_edns(0, 0, our_payload, query.payload) - if query.had_tsig: - response.use_tsig(query.keyring, query.keyname, fudge, None, 0, '', - query.keyalgorithm) - response.request_mac = query.mac - return response diff -Nru python-eventlet-0.20.0/eventlet/support/dns/namedict.py python-eventlet-0.24.1/eventlet/support/dns/namedict.py --- python-eventlet-0.20.0/eventlet/support/dns/namedict.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/namedict.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,104 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# Copyright (C) 2016 Coresec Systems AB -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND CORESEC SYSTEMS AB DISCLAIMS ALL -# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CORESEC -# SYSTEMS AB BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR -# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION -# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS name dictionary""" - -import collections -import dns.name -from ._compat import xrange - - -class NameDict(collections.MutableMapping): - - """A dictionary whose keys are dns.name.Name objects. - @ivar max_depth: the maximum depth of the keys that have ever been - added to the dictionary. - @type max_depth: int - @ivar max_depth_items: the number of items of maximum depth - @type max_depth_items: int - """ - - __slots__ = ["max_depth", "max_depth_items", "__store"] - - def __init__(self, *args, **kwargs): - self.__store = dict() - self.max_depth = 0 - self.max_depth_items = 0 - self.update(dict(*args, **kwargs)) - - def __update_max_depth(self, key): - if len(key) == self.max_depth: - self.max_depth_items = self.max_depth_items + 1 - elif len(key) > self.max_depth: - self.max_depth = len(key) - self.max_depth_items = 1 - - def __getitem__(self, key): - return self.__store[key] - - def __setitem__(self, key, value): - if not isinstance(key, dns.name.Name): - raise ValueError('NameDict key must be a name') - self.__store[key] = value - self.__update_max_depth(key) - - def __delitem__(self, key): - value = self.__store.pop(key) - if len(value) == self.max_depth: - self.max_depth_items = self.max_depth_items - 1 - if self.max_depth_items == 0: - self.max_depth = 0 - for k in self.__store: - self.__update_max_depth(k) - - def __iter__(self): - return iter(self.__store) - - def __len__(self): - return len(self.__store) - - def has_key(self, key): - return key in self.__store - - def get_deepest_match(self, name): - """Find the deepest match to I{name} in the dictionary. - - The deepest match is the longest name in the dictionary which is - a superdomain of I{name}. - - @param name: the name - @type name: dns.name.Name object - @rtype: (key, value) tuple - """ - - depth = len(name) - if depth > self.max_depth: - depth = self.max_depth - for i in xrange(-depth, 0): - n = dns.name.Name(name[i:]) - if n in self: - return (n, self[n]) - v = self[dns.name.empty] - return (dns.name.empty, v) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/name.py python-eventlet-0.24.1/eventlet/support/dns/name.py --- python-eventlet-0.20.0/eventlet/support/dns/name.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/name.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,886 +0,0 @@ -# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Names. - -@var root: The DNS root name. -@type root: dns.name.Name object -@var empty: The empty DNS name. -@type empty: dns.name.Name object -""" - -from io import BytesIO -import struct -import sys -import copy -import encodings.idna -try: - import idna - have_idna_2008 = True -except ImportError: - have_idna_2008 = False - -import dns.exception -import dns.wiredata - -from ._compat import long, binary_type, text_type, unichr - -try: - maxint = sys.maxint -except AttributeError: - maxint = (1 << (8 * struct.calcsize("P"))) // 2 - 1 - -NAMERELN_NONE = 0 -NAMERELN_SUPERDOMAIN = 1 -NAMERELN_SUBDOMAIN = 2 -NAMERELN_EQUAL = 3 -NAMERELN_COMMONANCESTOR = 4 - - -class EmptyLabel(dns.exception.SyntaxError): - - """A DNS label is empty.""" - - -class BadEscape(dns.exception.SyntaxError): - - """An escaped code in a text format of DNS name is invalid.""" - - -class BadPointer(dns.exception.FormError): - - """A DNS compression pointer points forward instead of backward.""" - - -class BadLabelType(dns.exception.FormError): - - """The label type in DNS name wire format is unknown.""" - - -class NeedAbsoluteNameOrOrigin(dns.exception.DNSException): - - """An attempt was made to convert a non-absolute name to - wire when there was also a non-absolute (or missing) origin.""" - - -class NameTooLong(dns.exception.FormError): - - """A DNS name is > 255 octets long.""" - - -class LabelTooLong(dns.exception.SyntaxError): - - """A DNS label is > 63 octets long.""" - - -class AbsoluteConcatenation(dns.exception.DNSException): - - """An attempt was made to append anything other than the - empty name to an absolute DNS name.""" - - -class NoParent(dns.exception.DNSException): - - """An attempt was made to get the parent of the root name - or the empty name.""" - -class NoIDNA2008(dns.exception.DNSException): - - """IDNA 2008 processing was requested but the idna module is not - available.""" - - -class IDNAException(dns.exception.DNSException): - - """IDNA 2008 processing raised an exception.""" - - supp_kwargs = set(['idna_exception']) - fmt = "IDNA processing exception: {idna_exception}" - -class IDNACodec(object): - - """Abstract base class for IDNA encoder/decoders.""" - - def encode(self, label): - raise NotImplementedError - - def decode(self, label): - raise NotImplementedError - -class IDNA2003Codec(IDNACodec): - - """IDNA 2003 encoder/decoder.""" - - def encode(self, label): - if label == '': - return b'' - try: - return encodings.idna.ToASCII(label) - except UnicodeError: - raise LabelTooLong - - def decode(self, label): - if label == b'': - return u'' - return _escapify(encodings.idna.ToUnicode(label), True) - -class IDNA2008Codec(IDNACodec): - - """IDNA 2008 encoder/decoder.""" - - def __init__(self, uts_46=False, transitional=False, - allow_pure_ascii=False): - """Initialize the IDNA 2008 encoder/decoder. - @param uts_46: If True, apply Unicode IDNA compatibility processing - as described in Unicode Technical Standard #46 - (U{http://unicode.org/reports/tr46/}). This parameter is only - meaningful if IDNA 2008 is in use. If False, do not apply - the mapping. The default is False - @type uts_46: bool - @param transitional: If True, use the "transitional" mode described - in Unicode Technical Standard #46. This parameter is only - meaningful if IDNA 2008 is in use. The default is False. - @type transitional: bool - @param allow_pure_ascii: If True, then a label which - consists of only ASCII characters is allowed. This is less strict - than regular IDNA 2008, but is also necessary for mixed names, - e.g. a name with starting with "_sip._tcp." and ending in an IDN - suffixm which would otherwise be disallowed. The default is False - @type allow_pure_ascii: bool - """ - self.uts_46 = uts_46 - self.transitional = transitional - self.allow_pure_ascii = allow_pure_ascii - - def is_all_ascii(self, label): - for c in label: - if ord(c) > 0x7f: - return False - return True - - def encode(self, label): - if label == '': - return b'' - if self.allow_pure_ascii and self.is_all_ascii(label): - return label.encode('ascii') - if not have_idna_2008: - raise NoIDNA2008 - try: - if self.uts_46: - label = idna.uts46_remap(label, False, self.transitional) - return idna.alabel(label) - except idna.IDNAError as e: - raise IDNAException(idna_exception=e) - - def decode(self, label): - if label == b'': - return u'' - if not have_idna_2008: - raise NoIDNA2008 - try: - if self.uts_46: - label = idna.uts46_remap(label, False, False) - return _escapify(idna.ulabel(label), True) - except idna.IDNAError as e: - raise IDNAException(idna_exception=e) - - -_escaped = bytearray(b'"().;\\@$') - -IDNA_2003 = IDNA2003Codec() -IDNA_2008_Practical = IDNA2008Codec(True, False, True) -IDNA_2008_UTS_46 = IDNA2008Codec(True, False, False) -IDNA_2008_Strict = IDNA2008Codec(False, False, False) -IDNA_2008_Transitional = IDNA2008Codec(True, True, False) -IDNA_2008 = IDNA_2008_Practical - -def _escapify(label, unicode_mode=False): - """Escape the characters in label which need it. - @param unicode_mode: escapify only special and whitespace (<= 0x20) - characters - @returns: the escaped string - @rtype: string""" - if not unicode_mode: - text = '' - if isinstance(label, text_type): - label = label.encode() - for c in bytearray(label): - if c in _escaped: - text += '\\' + chr(c) - elif c > 0x20 and c < 0x7F: - text += chr(c) - else: - text += '\\%03d' % c - return text.encode() - - text = u'' - if isinstance(label, binary_type): - label = label.decode() - for c in label: - if c > u'\x20' and c < u'\x7f': - text += c - else: - if c >= u'\x7f': - text += c - else: - text += u'\\%03d' % ord(c) - return text - -def _validate_labels(labels): - """Check for empty labels in the middle of a label sequence, - labels that are too long, and for too many labels. - @raises NameTooLong: the name as a whole is too long - @raises EmptyLabel: a label is empty (i.e. the root label) and appears - in a position other than the end of the label sequence""" - - l = len(labels) - total = 0 - i = -1 - j = 0 - for label in labels: - ll = len(label) - total += ll + 1 - if ll > 63: - raise LabelTooLong - if i < 0 and label == b'': - i = j - j += 1 - if total > 255: - raise NameTooLong - if i >= 0 and i != l - 1: - raise EmptyLabel - - -def _ensure_bytes(label): - if isinstance(label, binary_type): - return label - if isinstance(label, text_type): - return label.encode() - raise ValueError - - -class Name(object): - - """A DNS name. - - The dns.name.Name class represents a DNS name as a tuple of labels. - Instances of the class are immutable. - - @ivar labels: The tuple of labels in the name. Each label is a string of - up to 63 octets.""" - - __slots__ = ['labels'] - - def __init__(self, labels): - """Initialize a domain name from a list of labels. - @param labels: the labels - @type labels: any iterable whose values are strings - """ - labels = [_ensure_bytes(x) for x in labels] - super(Name, self).__setattr__('labels', tuple(labels)) - _validate_labels(self.labels) - - def __setattr__(self, name, value): - raise TypeError("object doesn't support attribute assignment") - - def __copy__(self): - return Name(self.labels) - - def __deepcopy__(self, memo): - return Name(copy.deepcopy(self.labels, memo)) - - def __getstate__(self): - return {'labels': self.labels} - - def __setstate__(self, state): - super(Name, self).__setattr__('labels', state['labels']) - _validate_labels(self.labels) - - def is_absolute(self): - """Is the most significant label of this name the root label? - @rtype: bool - """ - - return len(self.labels) > 0 and self.labels[-1] == b'' - - def is_wild(self): - """Is this name wild? (I.e. Is the least significant label '*'?) - @rtype: bool - """ - - return len(self.labels) > 0 and self.labels[0] == b'*' - - def __hash__(self): - """Return a case-insensitive hash of the name. - @rtype: int - """ - - h = long(0) - for label in self.labels: - for c in bytearray(label.lower()): - h += (h << 3) + c - return int(h % maxint) - - def fullcompare(self, other): - """Compare two names, returning a 3-tuple (relation, order, nlabels). - - I{relation} describes the relation ship between the names, - and is one of: dns.name.NAMERELN_NONE, - dns.name.NAMERELN_SUPERDOMAIN, dns.name.NAMERELN_SUBDOMAIN, - dns.name.NAMERELN_EQUAL, or dns.name.NAMERELN_COMMONANCESTOR - - I{order} is < 0 if self < other, > 0 if self > other, and == - 0 if self == other. A relative name is always less than an - absolute name. If both names have the same relativity, then - the DNSSEC order relation is used to order them. - - I{nlabels} is the number of significant labels that the two names - have in common. - """ - - sabs = self.is_absolute() - oabs = other.is_absolute() - if sabs != oabs: - if sabs: - return (NAMERELN_NONE, 1, 0) - else: - return (NAMERELN_NONE, -1, 0) - l1 = len(self.labels) - l2 = len(other.labels) - ldiff = l1 - l2 - if ldiff < 0: - l = l1 - else: - l = l2 - - order = 0 - nlabels = 0 - namereln = NAMERELN_NONE - while l > 0: - l -= 1 - l1 -= 1 - l2 -= 1 - label1 = self.labels[l1].lower() - label2 = other.labels[l2].lower() - if label1 < label2: - order = -1 - if nlabels > 0: - namereln = NAMERELN_COMMONANCESTOR - return (namereln, order, nlabels) - elif label1 > label2: - order = 1 - if nlabels > 0: - namereln = NAMERELN_COMMONANCESTOR - return (namereln, order, nlabels) - nlabels += 1 - order = ldiff - if ldiff < 0: - namereln = NAMERELN_SUPERDOMAIN - elif ldiff > 0: - namereln = NAMERELN_SUBDOMAIN - else: - namereln = NAMERELN_EQUAL - return (namereln, order, nlabels) - - def is_subdomain(self, other): - """Is self a subdomain of other? - - The notion of subdomain includes equality. - @rtype: bool - """ - - (nr, o, nl) = self.fullcompare(other) - if nr == NAMERELN_SUBDOMAIN or nr == NAMERELN_EQUAL: - return True - return False - - def is_superdomain(self, other): - """Is self a superdomain of other? - - The notion of subdomain includes equality. - @rtype: bool - """ - - (nr, o, nl) = self.fullcompare(other) - if nr == NAMERELN_SUPERDOMAIN or nr == NAMERELN_EQUAL: - return True - return False - - def canonicalize(self): - """Return a name which is equal to the current name, but is in - DNSSEC canonical form. - @rtype: dns.name.Name object - """ - - return Name([x.lower() for x in self.labels]) - - def __eq__(self, other): - if isinstance(other, Name): - return self.fullcompare(other)[1] == 0 - else: - return False - - def __ne__(self, other): - if isinstance(other, Name): - return self.fullcompare(other)[1] != 0 - else: - return True - - def __lt__(self, other): - if isinstance(other, Name): - return self.fullcompare(other)[1] < 0 - else: - return NotImplemented - - def __le__(self, other): - if isinstance(other, Name): - return self.fullcompare(other)[1] <= 0 - else: - return NotImplemented - - def __ge__(self, other): - if isinstance(other, Name): - return self.fullcompare(other)[1] >= 0 - else: - return NotImplemented - - def __gt__(self, other): - if isinstance(other, Name): - return self.fullcompare(other)[1] > 0 - else: - return NotImplemented - - def __repr__(self): - return '' - - def __str__(self): - return self.to_text(False).decode() - - def to_text(self, omit_final_dot=False): - """Convert name to text format. - @param omit_final_dot: If True, don't emit the final dot (denoting the - root label) for absolute names. The default is False. - @rtype: string - """ - - if len(self.labels) == 0: - return b'@' - if len(self.labels) == 1 and self.labels[0] == b'': - return b'.' - if omit_final_dot and self.is_absolute(): - l = self.labels[:-1] - else: - l = self.labels - s = b'.'.join(map(_escapify, l)) - return s - - def to_unicode(self, omit_final_dot=False, idna_codec=None): - """Convert name to Unicode text format. - - IDN ACE labels are converted to Unicode. - - @param omit_final_dot: If True, don't emit the final dot (denoting the - root label) for absolute names. The default is False. - @type omit_final_dot: bool - @param: idna_codec: IDNA encoder/decoder. If None, the default IDNA - 2003 - encoder/decoder is used. - @type idna_codec: dns.name.IDNA - @rtype: string - """ - - if len(self.labels) == 0: - return u'@' - if len(self.labels) == 1 and self.labels[0] == b'': - return u'.' - if omit_final_dot and self.is_absolute(): - l = self.labels[:-1] - else: - l = self.labels - if idna_codec is None: - idna_codec = IDNA_2003 - return u'.'.join([idna_codec.decode(x) for x in l]) - - def to_digestable(self, origin=None): - """Convert name to a format suitable for digesting in hashes. - - The name is canonicalized and converted to uncompressed wire format. - - @param origin: If the name is relative and origin is not None, then - origin will be appended to it. - @type origin: dns.name.Name object - @raises NeedAbsoluteNameOrOrigin: All names in wire format are - absolute. If self is a relative name, then an origin must be supplied; - if it is missing, then this exception is raised - @rtype: string - """ - - if not self.is_absolute(): - if origin is None or not origin.is_absolute(): - raise NeedAbsoluteNameOrOrigin - labels = list(self.labels) - labels.extend(list(origin.labels)) - else: - labels = self.labels - dlabels = [struct.pack('!B%ds' % len(x), len(x), x.lower()) - for x in labels] - return b''.join(dlabels) - - def to_wire(self, file=None, compress=None, origin=None): - """Convert name to wire format, possibly compressing it. - - @param file: the file where the name is emitted (typically - a BytesIO file). If None, a string containing the wire name - will be returned. - @type file: file or None - @param compress: The compression table. If None (the default) names - will not be compressed. - @type compress: dict - @param origin: If the name is relative and origin is not None, then - origin will be appended to it. - @type origin: dns.name.Name object - @raises NeedAbsoluteNameOrOrigin: All names in wire format are - absolute. If self is a relative name, then an origin must be supplied; - if it is missing, then this exception is raised - """ - - if file is None: - file = BytesIO() - want_return = True - else: - want_return = False - - if not self.is_absolute(): - if origin is None or not origin.is_absolute(): - raise NeedAbsoluteNameOrOrigin - labels = list(self.labels) - labels.extend(list(origin.labels)) - else: - labels = self.labels - i = 0 - for label in labels: - n = Name(labels[i:]) - i += 1 - if compress is not None: - pos = compress.get(n) - else: - pos = None - if pos is not None: - value = 0xc000 + pos - s = struct.pack('!H', value) - file.write(s) - break - else: - if compress is not None and len(n) > 1: - pos = file.tell() - if pos <= 0x3fff: - compress[n] = pos - l = len(label) - file.write(struct.pack('!B', l)) - if l > 0: - file.write(label) - if want_return: - return file.getvalue() - - def __len__(self): - """The length of the name (in labels). - @rtype: int - """ - - return len(self.labels) - - def __getitem__(self, index): - return self.labels[index] - - def __add__(self, other): - return self.concatenate(other) - - def __sub__(self, other): - return self.relativize(other) - - def split(self, depth): - """Split a name into a prefix and suffix at depth. - - @param depth: the number of labels in the suffix - @type depth: int - @raises ValueError: the depth was not >= 0 and <= the length of the - name. - @returns: the tuple (prefix, suffix) - @rtype: tuple - """ - - l = len(self.labels) - if depth == 0: - return (self, dns.name.empty) - elif depth == l: - return (dns.name.empty, self) - elif depth < 0 or depth > l: - raise ValueError( - 'depth must be >= 0 and <= the length of the name') - return (Name(self[: -depth]), Name(self[-depth:])) - - def concatenate(self, other): - """Return a new name which is the concatenation of self and other. - @rtype: dns.name.Name object - @raises AbsoluteConcatenation: self is absolute and other is - not the empty name - """ - - if self.is_absolute() and len(other) > 0: - raise AbsoluteConcatenation - labels = list(self.labels) - labels.extend(list(other.labels)) - return Name(labels) - - def relativize(self, origin): - """If self is a subdomain of origin, return a new name which is self - relative to origin. Otherwise return self. - @rtype: dns.name.Name object - """ - - if origin is not None and self.is_subdomain(origin): - return Name(self[: -len(origin)]) - else: - return self - - def derelativize(self, origin): - """If self is a relative name, return a new name which is the - concatenation of self and origin. Otherwise return self. - @rtype: dns.name.Name object - """ - - if not self.is_absolute(): - return self.concatenate(origin) - else: - return self - - def choose_relativity(self, origin=None, relativize=True): - """Return a name with the relativity desired by the caller. If - origin is None, then self is returned. Otherwise, if - relativize is true the name is relativized, and if relativize is - false the name is derelativized. - @rtype: dns.name.Name object - """ - - if origin: - if relativize: - return self.relativize(origin) - else: - return self.derelativize(origin) - else: - return self - - def parent(self): - """Return the parent of the name. - @rtype: dns.name.Name object - @raises NoParent: the name is either the root name or the empty name, - and thus has no parent. - """ - if self == root or self == empty: - raise NoParent - return Name(self.labels[1:]) - -root = Name([b'']) -empty = Name([]) - - -def from_unicode(text, origin=root, idna_codec=None): - """Convert unicode text into a Name object. - - Labels are encoded in IDN ACE form. - - @param text: The text to convert into a name. - @type text: Unicode string - @param origin: The origin to append to non-absolute names. - @type origin: dns.name.Name - @param: idna_codec: IDNA encoder/decoder. If None, the default IDNA 2003 - encoder/decoder is used. - @type idna_codec: dns.name.IDNA - @rtype: dns.name.Name object - """ - - if not isinstance(text, text_type): - raise ValueError("input to from_unicode() must be a unicode string") - if not (origin is None or isinstance(origin, Name)): - raise ValueError("origin must be a Name or None") - labels = [] - label = u'' - escaping = False - edigits = 0 - total = 0 - if idna_codec is None: - idna_codec = IDNA_2003 - if text == u'@': - text = u'' - if text: - if text == u'.': - return Name([b'']) # no Unicode "u" on this constant! - for c in text: - if escaping: - if edigits == 0: - if c.isdigit(): - total = int(c) - edigits += 1 - else: - label += c - escaping = False - else: - if not c.isdigit(): - raise BadEscape - total *= 10 - total += int(c) - edigits += 1 - if edigits == 3: - escaping = False - label += unichr(total) - elif c in [u'.', u'\u3002', u'\uff0e', u'\uff61']: - if len(label) == 0: - raise EmptyLabel - labels.append(idna_codec.encode(label)) - label = u'' - elif c == u'\\': - escaping = True - edigits = 0 - total = 0 - else: - label += c - if escaping: - raise BadEscape - if len(label) > 0: - labels.append(idna_codec.encode(label)) - else: - labels.append(b'') - - if (len(labels) == 0 or labels[-1] != b'') and origin is not None: - labels.extend(list(origin.labels)) - return Name(labels) - - -def from_text(text, origin=root, idna_codec=None): - """Convert text into a Name object. - - @param text: The text to convert into a name. - @type text: string - @param origin: The origin to append to non-absolute names. - @type origin: dns.name.Name - @param: idna_codec: IDNA encoder/decoder. If None, the default IDNA 2003 - encoder/decoder is used. - @type idna_codec: dns.name.IDNA - @rtype: dns.name.Name object - """ - - if isinstance(text, text_type): - return from_unicode(text, origin, idna_codec) - if not isinstance(text, binary_type): - raise ValueError("input to from_text() must be a string") - if not (origin is None or isinstance(origin, Name)): - raise ValueError("origin must be a Name or None") - labels = [] - label = b'' - escaping = False - edigits = 0 - total = 0 - if text == b'@': - text = b'' - if text: - if text == b'.': - return Name([b'']) - for c in bytearray(text): - byte_ = struct.pack('!B', c) - if escaping: - if edigits == 0: - if byte_.isdigit(): - total = int(byte_) - edigits += 1 - else: - label += byte_ - escaping = False - else: - if not byte_.isdigit(): - raise BadEscape - total *= 10 - total += int(byte_) - edigits += 1 - if edigits == 3: - escaping = False - label += struct.pack('!B', total) - elif byte_ == b'.': - if len(label) == 0: - raise EmptyLabel - labels.append(label) - label = b'' - elif byte_ == b'\\': - escaping = True - edigits = 0 - total = 0 - else: - label += byte_ - if escaping: - raise BadEscape - if len(label) > 0: - labels.append(label) - else: - labels.append(b'') - if (len(labels) == 0 or labels[-1] != b'') and origin is not None: - labels.extend(list(origin.labels)) - return Name(labels) - - -def from_wire(message, current): - """Convert possibly compressed wire format into a Name. - @param message: the entire DNS message - @type message: string - @param current: the offset of the beginning of the name from the start - of the message - @type current: int - @raises dns.name.BadPointer: a compression pointer did not point backwards - in the message - @raises dns.name.BadLabelType: an invalid label type was encountered. - @returns: a tuple consisting of the name that was read and the number - of bytes of the wire format message which were consumed reading it - @rtype: (dns.name.Name object, int) tuple - """ - - if not isinstance(message, binary_type): - raise ValueError("input to from_wire() must be a byte string") - message = dns.wiredata.maybe_wrap(message) - labels = [] - biggest_pointer = current - hops = 0 - count = message[current] - current += 1 - cused = 1 - while count != 0: - if count < 64: - labels.append(message[current: current + count].unwrap()) - current += count - if hops == 0: - cused += count - elif count >= 192: - current = (count & 0x3f) * 256 + message[current] - if hops == 0: - cused += 1 - if current >= biggest_pointer: - raise BadPointer - biggest_pointer = current - hops += 1 - else: - raise BadLabelType - count = message[current] - current += 1 - if hops == 0: - cused += 1 - labels.append('') - return (Name(labels), cused) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/node.py python-eventlet-0.24.1/eventlet/support/dns/node.py --- python-eventlet-0.20.0/eventlet/support/dns/node.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/node.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,178 +0,0 @@ -# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS nodes. A node is a set of rdatasets.""" - -from io import StringIO - -import dns.rdataset -import dns.rdatatype -import dns.renderer - - -class Node(object): - - """A DNS node. - - A node is a set of rdatasets - - @ivar rdatasets: the node's rdatasets - @type rdatasets: list of dns.rdataset.Rdataset objects""" - - __slots__ = ['rdatasets'] - - def __init__(self): - """Initialize a DNS node. - """ - - self.rdatasets = [] - - def to_text(self, name, **kw): - """Convert a node to text format. - - Each rdataset at the node is printed. Any keyword arguments - to this method are passed on to the rdataset's to_text() method. - @param name: the owner name of the rdatasets - @type name: dns.name.Name object - @rtype: string - """ - - s = StringIO() - for rds in self.rdatasets: - if len(rds) > 0: - s.write(rds.to_text(name, **kw)) - s.write(u'\n') - return s.getvalue()[:-1] - - def __repr__(self): - return '' - - def __eq__(self, other): - """Two nodes are equal if they have the same rdatasets. - - @rtype: bool - """ - # - # This is inefficient. Good thing we don't need to do it much. - # - for rd in self.rdatasets: - if rd not in other.rdatasets: - return False - for rd in other.rdatasets: - if rd not in self.rdatasets: - return False - return True - - def __ne__(self, other): - return not self.__eq__(other) - - def __len__(self): - return len(self.rdatasets) - - def __iter__(self): - return iter(self.rdatasets) - - def find_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE, - create=False): - """Find an rdataset matching the specified properties in the - current node. - - @param rdclass: The class of the rdataset - @type rdclass: int - @param rdtype: The type of the rdataset - @type rdtype: int - @param covers: The covered type. Usually this value is - dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or - dns.rdatatype.RRSIG, then the covers value will be the rdata - type the SIG/RRSIG covers. The library treats the SIG and RRSIG - types as if they were a family of - types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). This makes RRSIGs much - easier to work with than if RRSIGs covering different rdata - types were aggregated into a single RRSIG rdataset. - @type covers: int - @param create: If True, create the rdataset if it is not found. - @type create: bool - @raises KeyError: An rdataset of the desired type and class does - not exist and I{create} is not True. - @rtype: dns.rdataset.Rdataset object - """ - - for rds in self.rdatasets: - if rds.match(rdclass, rdtype, covers): - return rds - if not create: - raise KeyError - rds = dns.rdataset.Rdataset(rdclass, rdtype) - self.rdatasets.append(rds) - return rds - - def get_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE, - create=False): - """Get an rdataset matching the specified properties in the - current node. - - None is returned if an rdataset of the specified type and - class does not exist and I{create} is not True. - - @param rdclass: The class of the rdataset - @type rdclass: int - @param rdtype: The type of the rdataset - @type rdtype: int - @param covers: The covered type. - @type covers: int - @param create: If True, create the rdataset if it is not found. - @type create: bool - @rtype: dns.rdataset.Rdataset object or None - """ - - try: - rds = self.find_rdataset(rdclass, rdtype, covers, create) - except KeyError: - rds = None - return rds - - def delete_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE): - """Delete the rdataset matching the specified properties in the - current node. - - If a matching rdataset does not exist, it is not an error. - - @param rdclass: The class of the rdataset - @type rdclass: int - @param rdtype: The type of the rdataset - @type rdtype: int - @param covers: The covered type. - @type covers: int - """ - - rds = self.get_rdataset(rdclass, rdtype, covers) - if rds is not None: - self.rdatasets.remove(rds) - - def replace_rdataset(self, replacement): - """Replace an rdataset. - - It is not an error if there is no rdataset matching I{replacement}. - - Ownership of the I{replacement} object is transferred to the node; - in other words, this method does not store a copy of I{replacement} - at the node, it stores I{replacement} itself. - """ - - if not isinstance(replacement, dns.rdataset.Rdataset): - raise ValueError('replacement is not an rdataset') - self.delete_rdataset(replacement.rdclass, replacement.rdtype, - replacement.covers) - self.rdatasets.append(replacement) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/opcode.py python-eventlet-0.24.1/eventlet/support/dns/opcode.py --- python-eventlet-0.20.0/eventlet/support/dns/opcode.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/opcode.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,107 +0,0 @@ -# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Opcodes.""" - -import dns.exception - -QUERY = 0 -IQUERY = 1 -STATUS = 2 -NOTIFY = 4 -UPDATE = 5 - -_by_text = { - 'QUERY': QUERY, - 'IQUERY': IQUERY, - 'STATUS': STATUS, - 'NOTIFY': NOTIFY, - 'UPDATE': UPDATE -} - -# We construct the inverse mapping programmatically to ensure that we -# cannot make any mistakes (e.g. omissions, cut-and-paste errors) that -# would cause the mapping not to be true inverse. - -_by_value = dict((y, x) for x, y in _by_text.items()) - - -class UnknownOpcode(dns.exception.DNSException): - - """An DNS opcode is unknown.""" - - -def from_text(text): - """Convert text into an opcode. - - @param text: the textual opcode - @type text: string - @raises UnknownOpcode: the opcode is unknown - @rtype: int - """ - - if text.isdigit(): - value = int(text) - if value >= 0 and value <= 15: - return value - value = _by_text.get(text.upper()) - if value is None: - raise UnknownOpcode - return value - - -def from_flags(flags): - """Extract an opcode from DNS message flags. - - @param flags: int - @rtype: int - """ - - return (flags & 0x7800) >> 11 - - -def to_flags(value): - """Convert an opcode to a value suitable for ORing into DNS message - flags. - @rtype: int - """ - - return (value << 11) & 0x7800 - - -def to_text(value): - """Convert an opcode to text. - - @param value: the opcdoe - @type value: int - @raises UnknownOpcode: the opcode is unknown - @rtype: string - """ - - text = _by_value.get(value) - if text is None: - text = str(value) - return text - - -def is_update(flags): - """True if the opcode in flags is UPDATE. - - @param flags: DNS flags - @type flags: int - @rtype: bool - """ - - return from_flags(flags) == UPDATE diff -Nru python-eventlet-0.20.0/eventlet/support/dns/query.py python-eventlet-0.24.1/eventlet/support/dns/query.py --- python-eventlet-0.20.0/eventlet/support/dns/query.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/query.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,539 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Talk to a DNS server.""" - -from __future__ import generators - -import errno -import select -import socket -import struct -import sys -import time - -import dns.exception -import dns.inet -import dns.name -import dns.message -import dns.rdataclass -import dns.rdatatype -from ._compat import long, string_types - -if sys.version_info > (3,): - select_error = OSError -else: - select_error = select.error - -# Function used to create a socket. Can be overridden if needed in special -# situations. -socket_factory = socket.socket - -class UnexpectedSource(dns.exception.DNSException): - - """A DNS query response came from an unexpected address or port.""" - - -class BadResponse(dns.exception.FormError): - - """A DNS query response does not respond to the question asked.""" - - -def _compute_expiration(timeout): - if timeout is None: - return None - else: - return time.time() + timeout - - -def _poll_for(fd, readable, writable, error, timeout): - """Poll polling backend. - @param fd: File descriptor - @type fd: int - @param readable: Whether to wait for readability - @type readable: bool - @param writable: Whether to wait for writability - @type writable: bool - @param timeout: Deadline timeout (expiration time, in seconds) - @type timeout: float - @return True on success, False on timeout - """ - event_mask = 0 - if readable: - event_mask |= select.POLLIN - if writable: - event_mask |= select.POLLOUT - if error: - event_mask |= select.POLLERR - - pollable = select.poll() - pollable.register(fd, event_mask) - - if timeout: - event_list = pollable.poll(long(timeout * 1000)) - else: - event_list = pollable.poll() - - return bool(event_list) - - -def _select_for(fd, readable, writable, error, timeout): - """Select polling backend. - @param fd: File descriptor - @type fd: int - @param readable: Whether to wait for readability - @type readable: bool - @param writable: Whether to wait for writability - @type writable: bool - @param timeout: Deadline timeout (expiration time, in seconds) - @type timeout: float - @return True on success, False on timeout - """ - rset, wset, xset = [], [], [] - - if readable: - rset = [fd] - if writable: - wset = [fd] - if error: - xset = [fd] - - if timeout is None: - (rcount, wcount, xcount) = select.select(rset, wset, xset) - else: - (rcount, wcount, xcount) = select.select(rset, wset, xset, timeout) - - return bool((rcount or wcount or xcount)) - - -def _wait_for(fd, readable, writable, error, expiration): - done = False - while not done: - if expiration is None: - timeout = None - else: - timeout = expiration - time.time() - if timeout <= 0.0: - raise dns.exception.Timeout - try: - if not _polling_backend(fd, readable, writable, error, timeout): - raise dns.exception.Timeout - except select_error as e: - if e.args[0] != errno.EINTR: - raise e - done = True - - -def _set_polling_backend(fn): - """ - Internal API. Do not use. - """ - global _polling_backend - - _polling_backend = fn - -if hasattr(select, 'poll'): - # Prefer poll() on platforms that support it because it has no - # limits on the maximum value of a file descriptor (plus it will - # be more efficient for high values). - _polling_backend = _poll_for -else: - _polling_backend = _select_for - - -def _wait_for_readable(s, expiration): - _wait_for(s, True, False, True, expiration) - - -def _wait_for_writable(s, expiration): - _wait_for(s, False, True, True, expiration) - - -def _addresses_equal(af, a1, a2): - # Convert the first value of the tuple, which is a textual format - # address into binary form, so that we are not confused by different - # textual representations of the same address - n1 = dns.inet.inet_pton(af, a1[0]) - n2 = dns.inet.inet_pton(af, a2[0]) - return n1 == n2 and a1[1:] == a2[1:] - - -def _destination_and_source(af, where, port, source, source_port): - # Apply defaults and compute destination and source tuples - # suitable for use in connect(), sendto(), or bind(). - if af is None: - try: - af = dns.inet.af_for_address(where) - except Exception: - af = dns.inet.AF_INET - if af == dns.inet.AF_INET: - destination = (where, port) - if source is not None or source_port != 0: - if source is None: - source = '0.0.0.0' - source = (source, source_port) - elif af == dns.inet.AF_INET6: - destination = (where, port, 0, 0) - if source is not None or source_port != 0: - if source is None: - source = '::' - source = (source, source_port, 0, 0) - return (af, destination, source) - - -def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, - ignore_unexpected=False, one_rr_per_rrset=False): - """Return the response obtained after sending a query via UDP. - - @param q: the query - @type q: dns.message.Message - @param where: where to send the message - @type where: string containing an IPv4 or IPv6 address - @param timeout: The number of seconds to wait before the query times out. - If None, the default, wait forever. - @type timeout: float - @param port: The port to which to send the message. The default is 53. - @type port: int - @param af: the address family to use. The default is None, which - causes the address family to use to be inferred from the form of where. - If the inference attempt fails, AF_INET is used. - @type af: int - @rtype: dns.message.Message object - @param source: source address. The default is the wildcard address. - @type source: string - @param source_port: The port from which to send the message. - The default is 0. - @type source_port: int - @param ignore_unexpected: If True, ignore responses from unexpected - sources. The default is False. - @type ignore_unexpected: bool - @param one_rr_per_rrset: Put each RR into its own RRset - @type one_rr_per_rrset: bool - """ - - wire = q.to_wire() - (af, destination, source) = _destination_and_source(af, where, port, - source, source_port) - s = socket_factory(af, socket.SOCK_DGRAM, 0) - begin_time = None - try: - expiration = _compute_expiration(timeout) - s.setblocking(0) - if source is not None: - s.bind(source) - _wait_for_writable(s, expiration) - begin_time = time.time() - s.sendto(wire, destination) - while 1: - _wait_for_readable(s, expiration) - (wire, from_address) = s.recvfrom(65535) - if _addresses_equal(af, from_address, destination) or \ - (dns.inet.is_multicast(where) and - from_address[1:] == destination[1:]): - break - if not ignore_unexpected: - raise UnexpectedSource('got a response from ' - '%s instead of %s' % (from_address, - destination)) - finally: - if begin_time is None: - response_time = 0 - else: - response_time = time.time() - begin_time - s.close() - r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, - one_rr_per_rrset=one_rr_per_rrset) - r.time = response_time - if not q.is_response(r): - raise BadResponse - return r - - -def _net_read(sock, count, expiration): - """Read the specified number of bytes from sock. Keep trying until we - either get the desired amount, or we hit EOF. - A Timeout exception will be raised if the operation is not completed - by the expiration time. - """ - s = b'' - while count > 0: - _wait_for_readable(sock, expiration) - n = sock.recv(count) - if n == b'': - raise EOFError - count = count - len(n) - s = s + n - return s - - -def _net_write(sock, data, expiration): - """Write the specified data to the socket. - A Timeout exception will be raised if the operation is not completed - by the expiration time. - """ - current = 0 - l = len(data) - while current < l: - _wait_for_writable(sock, expiration) - current += sock.send(data[current:]) - - -def _connect(s, address): - try: - s.connect(address) - except socket.error: - (ty, v) = sys.exc_info()[:2] - - if hasattr(v, 'errno'): - v_err = v.errno - else: - v_err = v[0] - if v_err not in [errno.EINPROGRESS, errno.EWOULDBLOCK, errno.EALREADY]: - raise v - - -def tcp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, - one_rr_per_rrset=False): - """Return the response obtained after sending a query via TCP. - - @param q: the query - @type q: dns.message.Message object - @param where: where to send the message - @type where: string containing an IPv4 or IPv6 address - @param timeout: The number of seconds to wait before the query times out. - If None, the default, wait forever. - @type timeout: float - @param port: The port to which to send the message. The default is 53. - @type port: int - @param af: the address family to use. The default is None, which - causes the address family to use to be inferred from the form of where. - If the inference attempt fails, AF_INET is used. - @type af: int - @rtype: dns.message.Message object - @param source: source address. The default is the wildcard address. - @type source: string - @param source_port: The port from which to send the message. - The default is 0. - @type source_port: int - @param one_rr_per_rrset: Put each RR into its own RRset - @type one_rr_per_rrset: bool - """ - - wire = q.to_wire() - (af, destination, source) = _destination_and_source(af, where, port, - source, source_port) - s = socket_factory(af, socket.SOCK_STREAM, 0) - begin_time = None - try: - expiration = _compute_expiration(timeout) - s.setblocking(0) - begin_time = time.time() - if source is not None: - s.bind(source) - _connect(s, destination) - - l = len(wire) - - # copying the wire into tcpmsg is inefficient, but lets us - # avoid writev() or doing a short write that would get pushed - # onto the net - tcpmsg = struct.pack("!H", l) + wire - _net_write(s, tcpmsg, expiration) - ldata = _net_read(s, 2, expiration) - (l,) = struct.unpack("!H", ldata) - wire = _net_read(s, l, expiration) - finally: - if begin_time is None: - response_time = 0 - else: - response_time = time.time() - begin_time - s.close() - r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, - one_rr_per_rrset=one_rr_per_rrset) - r.time = response_time - if not q.is_response(r): - raise BadResponse - return r - - -def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN, - timeout=None, port=53, keyring=None, keyname=None, relativize=True, - af=None, lifetime=None, source=None, source_port=0, serial=0, - use_udp=False, keyalgorithm=dns.tsig.default_algorithm): - """Return a generator for the responses to a zone transfer. - - @param where: where to send the message - @type where: string containing an IPv4 or IPv6 address - @param zone: The name of the zone to transfer - @type zone: dns.name.Name object or string - @param rdtype: The type of zone transfer. The default is - dns.rdatatype.AXFR. - @type rdtype: int or string - @param rdclass: The class of the zone transfer. The default is - dns.rdataclass.IN. - @type rdclass: int or string - @param timeout: The number of seconds to wait for each response message. - If None, the default, wait forever. - @type timeout: float - @param port: The port to which to send the message. The default is 53. - @type port: int - @param keyring: The TSIG keyring to use - @type keyring: dict - @param keyname: The name of the TSIG key to use - @type keyname: dns.name.Name object or string - @param relativize: If True, all names in the zone will be relativized to - the zone origin. It is essential that the relativize setting matches - the one specified to dns.zone.from_xfr(). - @type relativize: bool - @param af: the address family to use. The default is None, which - causes the address family to use to be inferred from the form of where. - If the inference attempt fails, AF_INET is used. - @type af: int - @param lifetime: The total number of seconds to spend doing the transfer. - If None, the default, then there is no limit on the time the transfer may - take. - @type lifetime: float - @rtype: generator of dns.message.Message objects. - @param source: source address. The default is the wildcard address. - @type source: string - @param source_port: The port from which to send the message. - The default is 0. - @type source_port: int - @param serial: The SOA serial number to use as the base for an IXFR diff - sequence (only meaningful if rdtype == dns.rdatatype.IXFR). - @type serial: int - @param use_udp: Use UDP (only meaningful for IXFR) - @type use_udp: bool - @param keyalgorithm: The TSIG algorithm to use; defaults to - dns.tsig.default_algorithm - @type keyalgorithm: string - """ - - if isinstance(zone, string_types): - zone = dns.name.from_text(zone) - if isinstance(rdtype, string_types): - rdtype = dns.rdatatype.from_text(rdtype) - q = dns.message.make_query(zone, rdtype, rdclass) - if rdtype == dns.rdatatype.IXFR: - rrset = dns.rrset.from_text(zone, 0, 'IN', 'SOA', - '. . %u 0 0 0 0' % serial) - q.authority.append(rrset) - if keyring is not None: - q.use_tsig(keyring, keyname, algorithm=keyalgorithm) - wire = q.to_wire() - (af, destination, source) = _destination_and_source(af, where, port, - source, source_port) - if use_udp: - if rdtype != dns.rdatatype.IXFR: - raise ValueError('cannot do a UDP AXFR') - s = socket_factory(af, socket.SOCK_DGRAM, 0) - else: - s = socket_factory(af, socket.SOCK_STREAM, 0) - s.setblocking(0) - if source is not None: - s.bind(source) - expiration = _compute_expiration(lifetime) - _connect(s, destination) - l = len(wire) - if use_udp: - _wait_for_writable(s, expiration) - s.send(wire) - else: - tcpmsg = struct.pack("!H", l) + wire - _net_write(s, tcpmsg, expiration) - done = False - delete_mode = True - expecting_SOA = False - soa_rrset = None - if relativize: - origin = zone - oname = dns.name.empty - else: - origin = None - oname = zone - tsig_ctx = None - first = True - while not done: - mexpiration = _compute_expiration(timeout) - if mexpiration is None or mexpiration > expiration: - mexpiration = expiration - if use_udp: - _wait_for_readable(s, expiration) - (wire, from_address) = s.recvfrom(65535) - else: - ldata = _net_read(s, 2, mexpiration) - (l,) = struct.unpack("!H", ldata) - wire = _net_read(s, l, mexpiration) - is_ixfr = (rdtype == dns.rdatatype.IXFR) - r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, - xfr=True, origin=origin, tsig_ctx=tsig_ctx, - multi=True, first=first, - one_rr_per_rrset=is_ixfr) - tsig_ctx = r.tsig_ctx - first = False - answer_index = 0 - if soa_rrset is None: - if not r.answer or r.answer[0].name != oname: - raise dns.exception.FormError( - "No answer or RRset not for qname") - rrset = r.answer[0] - if rrset.rdtype != dns.rdatatype.SOA: - raise dns.exception.FormError("first RRset is not an SOA") - answer_index = 1 - soa_rrset = rrset.copy() - if rdtype == dns.rdatatype.IXFR: - if soa_rrset[0].serial <= serial: - # - # We're already up-to-date. - # - done = True - else: - expecting_SOA = True - # - # Process SOAs in the answer section (other than the initial - # SOA in the first message). - # - for rrset in r.answer[answer_index:]: - if done: - raise dns.exception.FormError("answers after final SOA") - if rrset.rdtype == dns.rdatatype.SOA and rrset.name == oname: - if expecting_SOA: - if rrset[0].serial != serial: - raise dns.exception.FormError( - "IXFR base serial mismatch") - expecting_SOA = False - elif rdtype == dns.rdatatype.IXFR: - delete_mode = not delete_mode - # - # If this SOA RRset is equal to the first we saw then we're - # finished. If this is an IXFR we also check that we're seeing - # the record in the expected part of the response. - # - if rrset == soa_rrset and \ - (rdtype == dns.rdatatype.AXFR or - (rdtype == dns.rdatatype.IXFR and delete_mode)): - done = True - elif expecting_SOA: - # - # We made an IXFR request and are expecting another - # SOA RR, but saw something else, so this must be an - # AXFR response. - # - rdtype = dns.rdatatype.AXFR - expecting_SOA = False - if done and q.keyring and not r.had_tsig: - raise dns.exception.FormError("missing TSIG") - yield r - s.close() diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rcode.py python-eventlet-0.24.1/eventlet/support/dns/rcode.py --- python-eventlet-0.20.0/eventlet/support/dns/rcode.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rcode.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,125 +0,0 @@ -# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Result Codes.""" - -import dns.exception -from ._compat import long - - -NOERROR = 0 -FORMERR = 1 -SERVFAIL = 2 -NXDOMAIN = 3 -NOTIMP = 4 -REFUSED = 5 -YXDOMAIN = 6 -YXRRSET = 7 -NXRRSET = 8 -NOTAUTH = 9 -NOTZONE = 10 -BADVERS = 16 - -_by_text = { - 'NOERROR': NOERROR, - 'FORMERR': FORMERR, - 'SERVFAIL': SERVFAIL, - 'NXDOMAIN': NXDOMAIN, - 'NOTIMP': NOTIMP, - 'REFUSED': REFUSED, - 'YXDOMAIN': YXDOMAIN, - 'YXRRSET': YXRRSET, - 'NXRRSET': NXRRSET, - 'NOTAUTH': NOTAUTH, - 'NOTZONE': NOTZONE, - 'BADVERS': BADVERS -} - -# We construct the inverse mapping programmatically to ensure that we -# cannot make any mistakes (e.g. omissions, cut-and-paste errors) that -# would cause the mapping not to be a true inverse. - -_by_value = dict((y, x) for x, y in _by_text.items()) - - -class UnknownRcode(dns.exception.DNSException): - - """A DNS rcode is unknown.""" - - -def from_text(text): - """Convert text into an rcode. - - @param text: the textual rcode - @type text: string - @raises UnknownRcode: the rcode is unknown - @rtype: int - """ - - if text.isdigit(): - v = int(text) - if v >= 0 and v <= 4095: - return v - v = _by_text.get(text.upper()) - if v is None: - raise UnknownRcode - return v - - -def from_flags(flags, ednsflags): - """Return the rcode value encoded by flags and ednsflags. - - @param flags: the DNS flags - @type flags: int - @param ednsflags: the EDNS flags - @type ednsflags: int - @raises ValueError: rcode is < 0 or > 4095 - @rtype: int - """ - - value = (flags & 0x000f) | ((ednsflags >> 20) & 0xff0) - if value < 0 or value > 4095: - raise ValueError('rcode must be >= 0 and <= 4095') - return value - - -def to_flags(value): - """Return a (flags, ednsflags) tuple which encodes the rcode. - - @param value: the rcode - @type value: int - @raises ValueError: rcode is < 0 or > 4095 - @rtype: (int, int) tuple - """ - - if value < 0 or value > 4095: - raise ValueError('rcode must be >= 0 and <= 4095') - v = value & 0xf - ev = long(value & 0xff0) << 20 - return (v, ev) - - -def to_text(value): - """Convert rcode into text. - - @param value: the rcode - @type value: int - @rtype: string - """ - - text = _by_value.get(value) - if text is None: - text = str(value) - return text diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdataclass.py python-eventlet-0.24.1/eventlet/support/dns/rdataclass.py --- python-eventlet-0.20.0/eventlet/support/dns/rdataclass.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdataclass.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,118 +0,0 @@ -# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Rdata Classes. - -@var _by_text: The rdata class textual name to value mapping -@type _by_text: dict -@var _by_value: The rdata class value to textual name mapping -@type _by_value: dict -@var _metaclasses: If an rdataclass is a metaclass, there will be a mapping -whose key is the rdatatype value and whose value is True in this dictionary. -@type _metaclasses: dict""" - -import re - -import dns.exception - -RESERVED0 = 0 -IN = 1 -CH = 3 -HS = 4 -NONE = 254 -ANY = 255 - -_by_text = { - 'RESERVED0': RESERVED0, - 'IN': IN, - 'CH': CH, - 'HS': HS, - 'NONE': NONE, - 'ANY': ANY -} - -# We construct the inverse mapping programmatically to ensure that we -# cannot make any mistakes (e.g. omissions, cut-and-paste errors) that -# would cause the mapping not to be true inverse. - -_by_value = dict((y, x) for x, y in _by_text.items()) - -# Now that we've built the inverse map, we can add class aliases to -# the _by_text mapping. - -_by_text.update({ - 'INTERNET': IN, - 'CHAOS': CH, - 'HESIOD': HS -}) - -_metaclasses = { - NONE: True, - ANY: True -} - -_unknown_class_pattern = re.compile('CLASS([0-9]+)$', re.I) - - -class UnknownRdataclass(dns.exception.DNSException): - - """A DNS class is unknown.""" - - -def from_text(text): - """Convert text into a DNS rdata class value. - @param text: the text - @type text: string - @rtype: int - @raises dns.rdataclass.UnknownRdataclass: the class is unknown - @raises ValueError: the rdata class value is not >= 0 and <= 65535 - """ - - value = _by_text.get(text.upper()) - if value is None: - match = _unknown_class_pattern.match(text) - if match is None: - raise UnknownRdataclass - value = int(match.group(1)) - if value < 0 or value > 65535: - raise ValueError("class must be between >= 0 and <= 65535") - return value - - -def to_text(value): - """Convert a DNS rdata class to text. - @param value: the rdata class value - @type value: int - @rtype: string - @raises ValueError: the rdata class value is not >= 0 and <= 65535 - """ - - if value < 0 or value > 65535: - raise ValueError("class must be between >= 0 and <= 65535") - text = _by_value.get(value) - if text is None: - text = 'CLASS' + repr(value) - return text - - -def is_metaclass(rdclass): - """True if the class is a metaclass. - @param rdclass: the rdata class - @type rdclass: int - @rtype: bool""" - - if rdclass in _metaclasses: - return True - return False diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdata.py python-eventlet-0.24.1/eventlet/support/dns/rdata.py --- python-eventlet-0.20.0/eventlet/support/dns/rdata.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdata.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,458 +0,0 @@ -# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS rdata. - -@var _rdata_modules: A dictionary mapping a (rdclass, rdtype) tuple to -the module which implements that type. -@type _rdata_modules: dict -@var _module_prefix: The prefix to use when forming modules names. The -default is 'dns.rdtypes'. Changing this value will break the library. -@type _module_prefix: string -@var _hex_chunk: At most this many octets that will be represented in each -chunk of hexstring that _hexify() produces before whitespace occurs. -@type _hex_chunk: int""" - -from io import BytesIO -import base64 -import binascii - -import dns.exception -import dns.name -import dns.rdataclass -import dns.rdatatype -import dns.tokenizer -import dns.wiredata -from ._compat import xrange, string_types, text_type - -_hex_chunksize = 32 - - -def _hexify(data, chunksize=_hex_chunksize): - """Convert a binary string into its hex encoding, broken up into chunks - of I{chunksize} characters separated by a space. - - @param data: the binary string - @type data: string - @param chunksize: the chunk size. Default is L{dns.rdata._hex_chunksize} - @rtype: string - """ - - line = binascii.hexlify(data) - return b' '.join([line[i:i + chunksize] - for i - in range(0, len(line), chunksize)]).decode() - -_base64_chunksize = 32 - - -def _base64ify(data, chunksize=_base64_chunksize): - """Convert a binary string into its base64 encoding, broken up into chunks - of I{chunksize} characters separated by a space. - - @param data: the binary string - @type data: string - @param chunksize: the chunk size. Default is - L{dns.rdata._base64_chunksize} - @rtype: string - """ - - line = base64.b64encode(data) - return b' '.join([line[i:i + chunksize] - for i - in range(0, len(line), chunksize)]).decode() - -__escaped = bytearray(b'"\\') - -def _escapify(qstring): - """Escape the characters in a quoted string which need it. - - @param qstring: the string - @type qstring: string - @returns: the escaped string - @rtype: string - """ - - if isinstance(qstring, text_type): - qstring = qstring.encode() - if not isinstance(qstring, bytearray): - qstring = bytearray(qstring) - - text = '' - for c in qstring: - if c in __escaped: - text += '\\' + chr(c) - elif c >= 0x20 and c < 0x7F: - text += chr(c) - else: - text += '\\%03d' % c - return text - - -def _truncate_bitmap(what): - """Determine the index of greatest byte that isn't all zeros, and - return the bitmap that contains all the bytes less than that index. - - @param what: a string of octets representing a bitmap. - @type what: string - @rtype: string - """ - - for i in xrange(len(what) - 1, -1, -1): - if what[i] != 0: - return what[0: i + 1] - return what[0:1] - - -class Rdata(object): - - """Base class for all DNS rdata types. - """ - - __slots__ = ['rdclass', 'rdtype'] - - def __init__(self, rdclass, rdtype): - """Initialize an rdata. - @param rdclass: The rdata class - @type rdclass: int - @param rdtype: The rdata type - @type rdtype: int - """ - - self.rdclass = rdclass - self.rdtype = rdtype - - def covers(self): - """DNS SIG/RRSIG rdatas apply to a specific type; this type is - returned by the covers() function. If the rdata type is not - SIG or RRSIG, dns.rdatatype.NONE is returned. This is useful when - creating rdatasets, allowing the rdataset to contain only RRSIGs - of a particular type, e.g. RRSIG(NS). - @rtype: int - """ - - return dns.rdatatype.NONE - - def extended_rdatatype(self): - """Return a 32-bit type value, the least significant 16 bits of - which are the ordinary DNS type, and the upper 16 bits of which are - the "covered" type, if any. - @rtype: int - """ - - return self.covers() << 16 | self.rdtype - - def to_text(self, origin=None, relativize=True, **kw): - """Convert an rdata to text format. - @rtype: string - """ - raise NotImplementedError - - def to_wire(self, file, compress=None, origin=None): - """Convert an rdata to wire format. - @rtype: string - """ - - raise NotImplementedError - - def to_digestable(self, origin=None): - """Convert rdata to a format suitable for digesting in hashes. This - is also the DNSSEC canonical form.""" - f = BytesIO() - self.to_wire(f, None, origin) - return f.getvalue() - - def validate(self): - """Check that the current contents of the rdata's fields are - valid. If you change an rdata by assigning to its fields, - it is a good idea to call validate() when you are done making - changes. - """ - dns.rdata.from_text(self.rdclass, self.rdtype, self.to_text()) - - def __repr__(self): - covers = self.covers() - if covers == dns.rdatatype.NONE: - ctext = '' - else: - ctext = '(' + dns.rdatatype.to_text(covers) + ')' - return '' - - def __str__(self): - return self.to_text() - - def _cmp(self, other): - """Compare an rdata with another rdata of the same rdtype and - rdclass. Return < 0 if self < other in the DNSSEC ordering, - 0 if self == other, and > 0 if self > other. - """ - our = self.to_digestable(dns.name.root) - their = other.to_digestable(dns.name.root) - if our == their: - return 0 - if our > their: - return 1 - - return -1 - - def __eq__(self, other): - if not isinstance(other, Rdata): - return False - if self.rdclass != other.rdclass or self.rdtype != other.rdtype: - return False - return self._cmp(other) == 0 - - def __ne__(self, other): - if not isinstance(other, Rdata): - return True - if self.rdclass != other.rdclass or self.rdtype != other.rdtype: - return True - return self._cmp(other) != 0 - - def __lt__(self, other): - if not isinstance(other, Rdata) or \ - self.rdclass != other.rdclass or self.rdtype != other.rdtype: - - return NotImplemented - return self._cmp(other) < 0 - - def __le__(self, other): - if not isinstance(other, Rdata) or \ - self.rdclass != other.rdclass or self.rdtype != other.rdtype: - return NotImplemented - return self._cmp(other) <= 0 - - def __ge__(self, other): - if not isinstance(other, Rdata) or \ - self.rdclass != other.rdclass or self.rdtype != other.rdtype: - return NotImplemented - return self._cmp(other) >= 0 - - def __gt__(self, other): - if not isinstance(other, Rdata) or \ - self.rdclass != other.rdclass or self.rdtype != other.rdtype: - return NotImplemented - return self._cmp(other) > 0 - - def __hash__(self): - return hash(self.to_digestable(dns.name.root)) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - """Build an rdata object from text format. - - @param rdclass: The rdata class - @type rdclass: int - @param rdtype: The rdata type - @type rdtype: int - @param tok: The tokenizer - @type tok: dns.tokenizer.Tokenizer - @param origin: The origin to use for relative names - @type origin: dns.name.Name - @param relativize: should names be relativized? - @type relativize: bool - @rtype: dns.rdata.Rdata instance - """ - - raise NotImplementedError - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - """Build an rdata object from wire format - - @param rdclass: The rdata class - @type rdclass: int - @param rdtype: The rdata type - @type rdtype: int - @param wire: The wire-format message - @type wire: string - @param current: The offset in wire of the beginning of the rdata. - @type current: int - @param rdlen: The length of the wire-format rdata - @type rdlen: int - @param origin: The origin to use for relative names - @type origin: dns.name.Name - @rtype: dns.rdata.Rdata instance - """ - - raise NotImplementedError - - def choose_relativity(self, origin=None, relativize=True): - """Convert any domain names in the rdata to the specified - relativization. - """ - - pass - - -class GenericRdata(Rdata): - - """Generate Rdata Class - - This class is used for rdata types for which we have no better - implementation. It implements the DNS "unknown RRs" scheme. - """ - - __slots__ = ['data'] - - def __init__(self, rdclass, rdtype, data): - super(GenericRdata, self).__init__(rdclass, rdtype) - self.data = data - - def to_text(self, origin=None, relativize=True, **kw): - return r'\# %d ' % len(self.data) + _hexify(self.data) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - token = tok.get() - if not token.is_identifier() or token.value != '\#': - raise dns.exception.SyntaxError( - r'generic rdata does not start with \#') - length = tok.get_int() - chunks = [] - while 1: - token = tok.get() - if token.is_eol_or_eof(): - break - chunks.append(token.value.encode()) - hex = b''.join(chunks) - data = binascii.unhexlify(hex) - if len(data) != length: - raise dns.exception.SyntaxError( - 'generic rdata hex data has wrong length') - return cls(rdclass, rdtype, data) - - def to_wire(self, file, compress=None, origin=None): - file.write(self.data) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - return cls(rdclass, rdtype, wire[current: current + rdlen]) - -_rdata_modules = {} -_module_prefix = 'dns.rdtypes' - - -def get_rdata_class(rdclass, rdtype): - - def import_module(name): - mod = __import__(name) - components = name.split('.') - for comp in components[1:]: - mod = getattr(mod, comp) - return mod - - mod = _rdata_modules.get((rdclass, rdtype)) - rdclass_text = dns.rdataclass.to_text(rdclass) - rdtype_text = dns.rdatatype.to_text(rdtype) - rdtype_text = rdtype_text.replace('-', '_') - if not mod: - mod = _rdata_modules.get((dns.rdatatype.ANY, rdtype)) - if not mod: - try: - mod = import_module('.'.join([_module_prefix, - rdclass_text, rdtype_text])) - _rdata_modules[(rdclass, rdtype)] = mod - except ImportError: - try: - mod = import_module('.'.join([_module_prefix, - 'ANY', rdtype_text])) - _rdata_modules[(dns.rdataclass.ANY, rdtype)] = mod - except ImportError: - mod = None - if mod: - cls = getattr(mod, rdtype_text) - else: - cls = GenericRdata - return cls - - -def from_text(rdclass, rdtype, tok, origin=None, relativize=True): - """Build an rdata object from text format. - - This function attempts to dynamically load a class which - implements the specified rdata class and type. If there is no - class-and-type-specific implementation, the GenericRdata class - is used. - - Once a class is chosen, its from_text() class method is called - with the parameters to this function. - - If I{tok} is a string, then a tokenizer is created and the string - is used as its input. - - @param rdclass: The rdata class - @type rdclass: int - @param rdtype: The rdata type - @type rdtype: int - @param tok: The tokenizer or input text - @type tok: dns.tokenizer.Tokenizer or string - @param origin: The origin to use for relative names - @type origin: dns.name.Name - @param relativize: Should names be relativized? - @type relativize: bool - @rtype: dns.rdata.Rdata instance""" - - if isinstance(tok, string_types): - tok = dns.tokenizer.Tokenizer(tok) - cls = get_rdata_class(rdclass, rdtype) - if cls != GenericRdata: - # peek at first token - token = tok.get() - tok.unget(token) - if token.is_identifier() and \ - token.value == r'\#': - # - # Known type using the generic syntax. Extract the - # wire form from the generic syntax, and then run - # from_wire on it. - # - rdata = GenericRdata.from_text(rdclass, rdtype, tok, origin, - relativize) - return from_wire(rdclass, rdtype, rdata.data, 0, len(rdata.data), - origin) - return cls.from_text(rdclass, rdtype, tok, origin, relativize) - - -def from_wire(rdclass, rdtype, wire, current, rdlen, origin=None): - """Build an rdata object from wire format - - This function attempts to dynamically load a class which - implements the specified rdata class and type. If there is no - class-and-type-specific implementation, the GenericRdata class - is used. - - Once a class is chosen, its from_wire() class method is called - with the parameters to this function. - - @param rdclass: The rdata class - @type rdclass: int - @param rdtype: The rdata type - @type rdtype: int - @param wire: The wire-format message - @type wire: string - @param current: The offset in wire of the beginning of the rdata. - @type current: int - @param rdlen: The length of the wire-format rdata - @type rdlen: int - @param origin: The origin to use for relative names - @type origin: dns.name.Name - @rtype: dns.rdata.Rdata instance""" - - wire = dns.wiredata.maybe_wrap(wire) - cls = get_rdata_class(rdclass, rdtype) - return cls.from_wire(rdclass, rdtype, wire, current, rdlen, origin) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdataset.py python-eventlet-0.24.1/eventlet/support/dns/rdataset.py --- python-eventlet-0.20.0/eventlet/support/dns/rdataset.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdataset.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,338 +0,0 @@ -# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS rdatasets (an rdataset is a set of rdatas of a given type and class)""" - -import random -from io import StringIO -import struct - -import dns.exception -import dns.rdatatype -import dns.rdataclass -import dns.rdata -import dns.set -from ._compat import string_types - -# define SimpleSet here for backwards compatibility -SimpleSet = dns.set.Set - - -class DifferingCovers(dns.exception.DNSException): - - """An attempt was made to add a DNS SIG/RRSIG whose covered type - is not the same as that of the other rdatas in the rdataset.""" - - -class IncompatibleTypes(dns.exception.DNSException): - - """An attempt was made to add DNS RR data of an incompatible type.""" - - -class Rdataset(dns.set.Set): - - """A DNS rdataset. - - @ivar rdclass: The class of the rdataset - @type rdclass: int - @ivar rdtype: The type of the rdataset - @type rdtype: int - @ivar covers: The covered type. Usually this value is - dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or - dns.rdatatype.RRSIG, then the covers value will be the rdata - type the SIG/RRSIG covers. The library treats the SIG and RRSIG - types as if they were a family of - types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). This makes RRSIGs much - easier to work with than if RRSIGs covering different rdata - types were aggregated into a single RRSIG rdataset. - @type covers: int - @ivar ttl: The DNS TTL (Time To Live) value - @type ttl: int - """ - - __slots__ = ['rdclass', 'rdtype', 'covers', 'ttl'] - - def __init__(self, rdclass, rdtype, covers=dns.rdatatype.NONE): - """Create a new rdataset of the specified class and type. - - @see: the description of the class instance variables for the - meaning of I{rdclass} and I{rdtype}""" - - super(Rdataset, self).__init__() - self.rdclass = rdclass - self.rdtype = rdtype - self.covers = covers - self.ttl = 0 - - def _clone(self): - obj = super(Rdataset, self)._clone() - obj.rdclass = self.rdclass - obj.rdtype = self.rdtype - obj.covers = self.covers - obj.ttl = self.ttl - return obj - - def update_ttl(self, ttl): - """Set the TTL of the rdataset to be the lesser of the set's current - TTL or the specified TTL. If the set contains no rdatas, set the TTL - to the specified TTL. - @param ttl: The TTL - @type ttl: int""" - - if len(self) == 0: - self.ttl = ttl - elif ttl < self.ttl: - self.ttl = ttl - - def add(self, rd, ttl=None): - """Add the specified rdata to the rdataset. - - If the optional I{ttl} parameter is supplied, then - self.update_ttl(ttl) will be called prior to adding the rdata. - - @param rd: The rdata - @type rd: dns.rdata.Rdata object - @param ttl: The TTL - @type ttl: int""" - - # - # If we're adding a signature, do some special handling to - # check that the signature covers the same type as the - # other rdatas in this rdataset. If this is the first rdata - # in the set, initialize the covers field. - # - if self.rdclass != rd.rdclass or self.rdtype != rd.rdtype: - raise IncompatibleTypes - if ttl is not None: - self.update_ttl(ttl) - if self.rdtype == dns.rdatatype.RRSIG or \ - self.rdtype == dns.rdatatype.SIG: - covers = rd.covers() - if len(self) == 0 and self.covers == dns.rdatatype.NONE: - self.covers = covers - elif self.covers != covers: - raise DifferingCovers - if dns.rdatatype.is_singleton(rd.rdtype) and len(self) > 0: - self.clear() - super(Rdataset, self).add(rd) - - def union_update(self, other): - self.update_ttl(other.ttl) - super(Rdataset, self).union_update(other) - - def intersection_update(self, other): - self.update_ttl(other.ttl) - super(Rdataset, self).intersection_update(other) - - def update(self, other): - """Add all rdatas in other to self. - - @param other: The rdataset from which to update - @type other: dns.rdataset.Rdataset object""" - - self.update_ttl(other.ttl) - super(Rdataset, self).update(other) - - def __repr__(self): - if self.covers == 0: - ctext = '' - else: - ctext = '(' + dns.rdatatype.to_text(self.covers) + ')' - return '' - - def __str__(self): - return self.to_text() - - def __eq__(self, other): - """Two rdatasets are equal if they have the same class, type, and - covers, and contain the same rdata. - @rtype: bool""" - - if not isinstance(other, Rdataset): - return False - if self.rdclass != other.rdclass or \ - self.rdtype != other.rdtype or \ - self.covers != other.covers: - return False - return super(Rdataset, self).__eq__(other) - - def __ne__(self, other): - return not self.__eq__(other) - - def to_text(self, name=None, origin=None, relativize=True, - override_rdclass=None, **kw): - """Convert the rdataset into DNS master file format. - - @see: L{dns.name.Name.choose_relativity} for more information - on how I{origin} and I{relativize} determine the way names - are emitted. - - Any additional keyword arguments are passed on to the rdata - to_text() method. - - @param name: If name is not None, emit a RRs with I{name} as - the owner name. - @type name: dns.name.Name object - @param origin: The origin for relative names, or None. - @type origin: dns.name.Name object - @param relativize: True if names should names be relativized - @type relativize: bool""" - if name is not None: - name = name.choose_relativity(origin, relativize) - ntext = str(name) - pad = ' ' - else: - ntext = '' - pad = '' - s = StringIO() - if override_rdclass is not None: - rdclass = override_rdclass - else: - rdclass = self.rdclass - if len(self) == 0: - # - # Empty rdatasets are used for the question section, and in - # some dynamic updates, so we don't need to print out the TTL - # (which is meaningless anyway). - # - s.write(u'%s%s%s %s\n' % (ntext, pad, - dns.rdataclass.to_text(rdclass), - dns.rdatatype.to_text(self.rdtype))) - else: - for rd in self: - s.write(u'%s%s%d %s %s %s\n' % - (ntext, pad, self.ttl, dns.rdataclass.to_text(rdclass), - dns.rdatatype.to_text(self.rdtype), - rd.to_text(origin=origin, relativize=relativize, - **kw))) - # - # We strip off the final \n for the caller's convenience in printing - # - return s.getvalue()[:-1] - - def to_wire(self, name, file, compress=None, origin=None, - override_rdclass=None, want_shuffle=True): - """Convert the rdataset to wire format. - - @param name: The owner name of the RRset that will be emitted - @type name: dns.name.Name object - @param file: The file to which the wire format data will be appended - @type file: file - @param compress: The compression table to use; the default is None. - @type compress: dict - @param origin: The origin to be appended to any relative names when - they are emitted. The default is None. - @returns: the number of records emitted - @rtype: int - """ - - if override_rdclass is not None: - rdclass = override_rdclass - want_shuffle = False - else: - rdclass = self.rdclass - file.seek(0, 2) - if len(self) == 0: - name.to_wire(file, compress, origin) - stuff = struct.pack("!HHIH", self.rdtype, rdclass, 0, 0) - file.write(stuff) - return 1 - else: - if want_shuffle: - l = list(self) - random.shuffle(l) - else: - l = self - for rd in l: - name.to_wire(file, compress, origin) - stuff = struct.pack("!HHIH", self.rdtype, rdclass, - self.ttl, 0) - file.write(stuff) - start = file.tell() - rd.to_wire(file, compress, origin) - end = file.tell() - assert end - start < 65536 - file.seek(start - 2) - stuff = struct.pack("!H", end - start) - file.write(stuff) - file.seek(0, 2) - return len(self) - - def match(self, rdclass, rdtype, covers): - """Returns True if this rdataset matches the specified class, type, - and covers""" - if self.rdclass == rdclass and \ - self.rdtype == rdtype and \ - self.covers == covers: - return True - return False - - -def from_text_list(rdclass, rdtype, ttl, text_rdatas): - """Create an rdataset with the specified class, type, and TTL, and with - the specified list of rdatas in text format. - - @rtype: dns.rdataset.Rdataset object - """ - - if isinstance(rdclass, string_types): - rdclass = dns.rdataclass.from_text(rdclass) - if isinstance(rdtype, string_types): - rdtype = dns.rdatatype.from_text(rdtype) - r = Rdataset(rdclass, rdtype) - r.update_ttl(ttl) - for t in text_rdatas: - rd = dns.rdata.from_text(r.rdclass, r.rdtype, t) - r.add(rd) - return r - - -def from_text(rdclass, rdtype, ttl, *text_rdatas): - """Create an rdataset with the specified class, type, and TTL, and with - the specified rdatas in text format. - - @rtype: dns.rdataset.Rdataset object - """ - - return from_text_list(rdclass, rdtype, ttl, text_rdatas) - - -def from_rdata_list(ttl, rdatas): - """Create an rdataset with the specified TTL, and with - the specified list of rdata objects. - - @rtype: dns.rdataset.Rdataset object - """ - - if len(rdatas) == 0: - raise ValueError("rdata list must not be empty") - r = None - for rd in rdatas: - if r is None: - r = Rdataset(rd.rdclass, rd.rdtype) - r.update_ttl(ttl) - r.add(rd) - return r - - -def from_rdata(ttl, *rdatas): - """Create an rdataset with the specified TTL, and with - the specified rdata objects. - - @rtype: dns.rdataset.Rdataset object - """ - - return from_rdata_list(ttl, rdatas) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdatatype.py python-eventlet-0.24.1/eventlet/support/dns/rdatatype.py --- python-eventlet-0.20.0/eventlet/support/dns/rdatatype.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdatatype.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,255 +0,0 @@ -# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Rdata Types. - -@var _by_text: The rdata type textual name to value mapping -@type _by_text: dict -@var _by_value: The rdata type value to textual name mapping -@type _by_value: dict -@var _metatypes: If an rdatatype is a metatype, there will be a mapping -whose key is the rdatatype value and whose value is True in this dictionary. -@type _metatypes: dict -@var _singletons: If an rdatatype is a singleton, there will be a mapping -whose key is the rdatatype value and whose value is True in this dictionary. -@type _singletons: dict""" - -import re - -import dns.exception - -NONE = 0 -A = 1 -NS = 2 -MD = 3 -MF = 4 -CNAME = 5 -SOA = 6 -MB = 7 -MG = 8 -MR = 9 -NULL = 10 -WKS = 11 -PTR = 12 -HINFO = 13 -MINFO = 14 -MX = 15 -TXT = 16 -RP = 17 -AFSDB = 18 -X25 = 19 -ISDN = 20 -RT = 21 -NSAP = 22 -NSAP_PTR = 23 -SIG = 24 -KEY = 25 -PX = 26 -GPOS = 27 -AAAA = 28 -LOC = 29 -NXT = 30 -SRV = 33 -NAPTR = 35 -KX = 36 -CERT = 37 -A6 = 38 -DNAME = 39 -OPT = 41 -APL = 42 -DS = 43 -SSHFP = 44 -IPSECKEY = 45 -RRSIG = 46 -NSEC = 47 -DNSKEY = 48 -DHCID = 49 -NSEC3 = 50 -NSEC3PARAM = 51 -TLSA = 52 -HIP = 55 -CDS = 59 -CDNSKEY = 60 -CSYNC = 62 -SPF = 99 -UNSPEC = 103 -EUI48 = 108 -EUI64 = 109 -TKEY = 249 -TSIG = 250 -IXFR = 251 -AXFR = 252 -MAILB = 253 -MAILA = 254 -ANY = 255 -URI = 256 -CAA = 257 -AVC = 258 -TA = 32768 -DLV = 32769 - -_by_text = { - 'NONE': NONE, - 'A': A, - 'NS': NS, - 'MD': MD, - 'MF': MF, - 'CNAME': CNAME, - 'SOA': SOA, - 'MB': MB, - 'MG': MG, - 'MR': MR, - 'NULL': NULL, - 'WKS': WKS, - 'PTR': PTR, - 'HINFO': HINFO, - 'MINFO': MINFO, - 'MX': MX, - 'TXT': TXT, - 'RP': RP, - 'AFSDB': AFSDB, - 'X25': X25, - 'ISDN': ISDN, - 'RT': RT, - 'NSAP': NSAP, - 'NSAP-PTR': NSAP_PTR, - 'SIG': SIG, - 'KEY': KEY, - 'PX': PX, - 'GPOS': GPOS, - 'AAAA': AAAA, - 'LOC': LOC, - 'NXT': NXT, - 'SRV': SRV, - 'NAPTR': NAPTR, - 'KX': KX, - 'CERT': CERT, - 'A6': A6, - 'DNAME': DNAME, - 'OPT': OPT, - 'APL': APL, - 'DS': DS, - 'SSHFP': SSHFP, - 'IPSECKEY': IPSECKEY, - 'RRSIG': RRSIG, - 'NSEC': NSEC, - 'DNSKEY': DNSKEY, - 'DHCID': DHCID, - 'NSEC3': NSEC3, - 'NSEC3PARAM': NSEC3PARAM, - 'TLSA': TLSA, - 'HIP': HIP, - 'CDS': CDS, - 'CDNSKEY': CDNSKEY, - 'CSYNC': CSYNC, - 'SPF': SPF, - 'UNSPEC': UNSPEC, - 'EUI48': EUI48, - 'EUI64': EUI64, - 'TKEY': TKEY, - 'TSIG': TSIG, - 'IXFR': IXFR, - 'AXFR': AXFR, - 'MAILB': MAILB, - 'MAILA': MAILA, - 'ANY': ANY, - 'URI': URI, - 'CAA': CAA, - 'AVC': AVC, - 'TA': TA, - 'DLV': DLV, -} - -# We construct the inverse mapping programmatically to ensure that we -# cannot make any mistakes (e.g. omissions, cut-and-paste errors) that -# would cause the mapping not to be true inverse. - -_by_value = dict((y, x) for x, y in _by_text.items()) - - -_metatypes = { - OPT: True -} - -_singletons = { - SOA: True, - NXT: True, - DNAME: True, - NSEC: True, - # CNAME is technically a singleton, but we allow multiple CNAMEs. -} - -_unknown_type_pattern = re.compile('TYPE([0-9]+)$', re.I) - - -class UnknownRdatatype(dns.exception.DNSException): - - """DNS resource record type is unknown.""" - - -def from_text(text): - """Convert text into a DNS rdata type value. - @param text: the text - @type text: string - @raises dns.rdatatype.UnknownRdatatype: the type is unknown - @raises ValueError: the rdata type value is not >= 0 and <= 65535 - @rtype: int""" - - value = _by_text.get(text.upper()) - if value is None: - match = _unknown_type_pattern.match(text) - if match is None: - raise UnknownRdatatype - value = int(match.group(1)) - if value < 0 or value > 65535: - raise ValueError("type must be between >= 0 and <= 65535") - return value - - -def to_text(value): - """Convert a DNS rdata type to text. - @param value: the rdata type value - @type value: int - @raises ValueError: the rdata type value is not >= 0 and <= 65535 - @rtype: string""" - - if value < 0 or value > 65535: - raise ValueError("type must be between >= 0 and <= 65535") - text = _by_value.get(value) - if text is None: - text = 'TYPE' + repr(value) - return text - - -def is_metatype(rdtype): - """True if the type is a metatype. - @param rdtype: the type - @type rdtype: int - @rtype: bool""" - - if rdtype >= TKEY and rdtype <= ANY or rdtype in _metatypes: - return True - return False - - -def is_singleton(rdtype): - """True if the type is a singleton. - @param rdtype: the type - @type rdtype: int - @rtype: bool""" - - if rdtype in _singletons: - return True - return False diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/AFSDB.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/AFSDB.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/AFSDB.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/AFSDB.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.mxbase - - -class AFSDB(dns.rdtypes.mxbase.UncompressedDowncasingMX): - - """AFSDB record - - @ivar subtype: the subtype value - @type subtype: int - @ivar hostname: the hostname name - @type hostname: dns.name.Name object""" - - # Use the property mechanism to make "subtype" an alias for the - # "preference" attribute, and "hostname" an alias for the "exchange" - # attribute. - # - # This lets us inherit the UncompressedMX implementation but lets - # the caller use appropriate attribute names for the rdata type. - # - # We probably lose some performance vs. a cut-and-paste - # implementation, but this way we don't copy code, and that's - # good. - - def get_subtype(self): - return self.preference - - def set_subtype(self, subtype): - self.preference = subtype - - subtype = property(get_subtype, set_subtype) - - def get_hostname(self): - return self.exchange - - def set_hostname(self, hostname): - self.exchange = hostname - - hostname = property(get_hostname, set_hostname) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/AVC.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/AVC.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/AVC.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/AVC.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -# Copyright (C) 2016 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.txtbase - - -class AVC(dns.rdtypes.txtbase.TXTBase): - - """AVC record - - @see: U{http://www.iana.org/assignments/dns-parameters/AVC/avc-completed-template}""" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/CAA.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/CAA.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/CAA.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/CAA.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.rdata -import dns.tokenizer - - -class CAA(dns.rdata.Rdata): - - """CAA (Certification Authority Authorization) record - - @ivar flags: the flags - @type flags: int - @ivar tag: the tag - @type tag: string - @ivar value: the value - @type value: string - @see: RFC 6844""" - - __slots__ = ['flags', 'tag', 'value'] - - def __init__(self, rdclass, rdtype, flags, tag, value): - super(CAA, self).__init__(rdclass, rdtype) - self.flags = flags - self.tag = tag - self.value = value - - def to_text(self, origin=None, relativize=True, **kw): - return '%u %s "%s"' % (self.flags, - dns.rdata._escapify(self.tag), - dns.rdata._escapify(self.value)) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - flags = tok.get_uint8() - tag = tok.get_string().encode() - if len(tag) > 255: - raise dns.exception.SyntaxError("tag too long") - if not tag.isalnum(): - raise dns.exception.SyntaxError("tag is not alphanumeric") - value = tok.get_string().encode() - return cls(rdclass, rdtype, flags, tag, value) - - def to_wire(self, file, compress=None, origin=None): - file.write(struct.pack('!B', self.flags)) - l = len(self.tag) - assert l < 256 - file.write(struct.pack('!B', l)) - file.write(self.tag) - file.write(self.value) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - (flags, l) = struct.unpack('!BB', wire[current: current + 2]) - current += 2 - tag = wire[current: current + l] - value = wire[current + l:current + rdlen - 2] - return cls(rdclass, rdtype, flags, tag, value) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/CDNSKEY.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/CDNSKEY.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/CDNSKEY.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/CDNSKEY.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.dnskeybase -from dns.rdtypes.dnskeybase import flags_to_text_set, flags_from_text_set - - -__all__ = ['flags_to_text_set', 'flags_from_text_set'] - - -class CDNSKEY(dns.rdtypes.dnskeybase.DNSKEYBase): - - """CDNSKEY record""" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/CDS.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/CDS.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/CDS.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/CDS.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.dsbase - - -class CDS(dns.rdtypes.dsbase.DSBase): - - """CDS record""" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/CERT.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/CERT.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/CERT.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/CERT.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,121 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct -import base64 - -import dns.exception -import dns.dnssec -import dns.rdata -import dns.tokenizer - -_ctype_by_value = { - 1: 'PKIX', - 2: 'SPKI', - 3: 'PGP', - 253: 'URI', - 254: 'OID', -} - -_ctype_by_name = { - 'PKIX': 1, - 'SPKI': 2, - 'PGP': 3, - 'URI': 253, - 'OID': 254, -} - - -def _ctype_from_text(what): - v = _ctype_by_name.get(what) - if v is not None: - return v - return int(what) - - -def _ctype_to_text(what): - v = _ctype_by_value.get(what) - if v is not None: - return v - return str(what) - - -class CERT(dns.rdata.Rdata): - - """CERT record - - @ivar certificate_type: certificate type - @type certificate_type: int - @ivar key_tag: key tag - @type key_tag: int - @ivar algorithm: algorithm - @type algorithm: int - @ivar certificate: the certificate or CRL - @type certificate: string - @see: RFC 2538""" - - __slots__ = ['certificate_type', 'key_tag', 'algorithm', 'certificate'] - - def __init__(self, rdclass, rdtype, certificate_type, key_tag, algorithm, - certificate): - super(CERT, self).__init__(rdclass, rdtype) - self.certificate_type = certificate_type - self.key_tag = key_tag - self.algorithm = algorithm - self.certificate = certificate - - def to_text(self, origin=None, relativize=True, **kw): - certificate_type = _ctype_to_text(self.certificate_type) - return "%s %d %s %s" % (certificate_type, self.key_tag, - dns.dnssec.algorithm_to_text(self.algorithm), - dns.rdata._base64ify(self.certificate)) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - certificate_type = _ctype_from_text(tok.get_string()) - key_tag = tok.get_uint16() - algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) - if algorithm < 0 or algorithm > 255: - raise dns.exception.SyntaxError("bad algorithm type") - chunks = [] - while 1: - t = tok.get().unescape() - if t.is_eol_or_eof(): - break - if not t.is_identifier(): - raise dns.exception.SyntaxError - chunks.append(t.value.encode()) - b64 = b''.join(chunks) - certificate = base64.b64decode(b64) - return cls(rdclass, rdtype, certificate_type, key_tag, - algorithm, certificate) - - def to_wire(self, file, compress=None, origin=None): - prefix = struct.pack("!HHB", self.certificate_type, self.key_tag, - self.algorithm) - file.write(prefix) - file.write(self.certificate) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - prefix = wire[current: current + 5].unwrap() - current += 5 - rdlen -= 5 - if rdlen < 0: - raise dns.exception.FormError - (certificate_type, key_tag, algorithm) = struct.unpack("!HHB", prefix) - certificate = wire[current: current + rdlen].unwrap() - return cls(rdclass, rdtype, certificate_type, key_tag, algorithm, - certificate) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/CNAME.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/CNAME.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/CNAME.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/CNAME.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.nsbase - - -class CNAME(dns.rdtypes.nsbase.NSBase): - - """CNAME record - - Note: although CNAME is officially a singleton type, dnspython allows - non-singleton CNAME rdatasets because such sets have been commonly - used by BIND and other nameservers for load balancing.""" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/CSYNC.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/CSYNC.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/CSYNC.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/CSYNC.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,124 +0,0 @@ -# Copyright (C) 2004-2007, 2009-2011, 2016 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.rdata -import dns.rdatatype -import dns.name -from dns._compat import xrange - -class CSYNC(dns.rdata.Rdata): - - """CSYNC record - - @ivar serial: the SOA serial number - @type serial: int - @ivar flags: the CSYNC flags - @type flags: int - @ivar windows: the windowed bitmap list - @type windows: list of (window number, string) tuples""" - - __slots__ = ['serial', 'flags', 'windows'] - - def __init__(self, rdclass, rdtype, serial, flags, windows): - super(CSYNC, self).__init__(rdclass, rdtype) - self.serial = serial - self.flags = flags - self.windows = windows - - def to_text(self, origin=None, relativize=True, **kw): - text = '' - for (window, bitmap) in self.windows: - bits = [] - for i in xrange(0, len(bitmap)): - byte = bitmap[i] - for j in xrange(0, 8): - if byte & (0x80 >> j): - bits.append(dns.rdatatype.to_text(window * 256 + - i * 8 + j)) - text += (' ' + ' '.join(bits)) - return '%d %d%s' % (self.serial, self.flags, text) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - serial = tok.get_uint32() - flags = tok.get_uint16() - rdtypes = [] - while 1: - token = tok.get().unescape() - if token.is_eol_or_eof(): - break - nrdtype = dns.rdatatype.from_text(token.value) - if nrdtype == 0: - raise dns.exception.SyntaxError("CSYNC with bit 0") - if nrdtype > 65535: - raise dns.exception.SyntaxError("CSYNC with bit > 65535") - rdtypes.append(nrdtype) - rdtypes.sort() - window = 0 - octets = 0 - prior_rdtype = 0 - bitmap = bytearray(b'\0' * 32) - windows = [] - for nrdtype in rdtypes: - if nrdtype == prior_rdtype: - continue - prior_rdtype = nrdtype - new_window = nrdtype // 256 - if new_window != window: - windows.append((window, bitmap[0:octets])) - bitmap = bytearray(b'\0' * 32) - window = new_window - offset = nrdtype % 256 - byte = offset // 8 - bit = offset % 8 - octets = byte + 1 - bitmap[byte] = bitmap[byte] | (0x80 >> bit) - - windows.append((window, bitmap[0:octets])) - return cls(rdclass, rdtype, serial, flags, windows) - - def to_wire(self, file, compress=None, origin=None): - file.write(struct.pack('!IH', self.serial, self.flags)) - for (window, bitmap) in self.windows: - file.write(struct.pack('!BB', window, len(bitmap))) - file.write(bitmap) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - if rdlen < 6: - raise dns.exception.FormError("CSYNC too short") - (serial, flags) = struct.unpack("!IH", wire[current: current + 6]) - current += 6 - rdlen -= 6 - windows = [] - while rdlen > 0: - if rdlen < 3: - raise dns.exception.FormError("CSYNC too short") - window = wire[current] - octets = wire[current + 1] - if octets == 0 or octets > 32: - raise dns.exception.FormError("bad CSYNC octets") - current += 2 - rdlen -= 2 - if rdlen < octets: - raise dns.exception.FormError("bad CSYNC bitmap length") - bitmap = bytearray(wire[current: current + octets].unwrap()) - current += octets - rdlen -= octets - windows.append((window, bitmap)) - return cls(rdclass, rdtype, serial, flags, windows) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/DLV.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/DLV.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/DLV.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/DLV.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -# Copyright (C) 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.dsbase - - -class DLV(dns.rdtypes.dsbase.DSBase): - - """DLV record""" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/DNAME.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/DNAME.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/DNAME.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/DNAME.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.nsbase - - -class DNAME(dns.rdtypes.nsbase.UncompressedNS): - - """DNAME record""" - - def to_digestable(self, origin=None): - return self.target.to_digestable(origin) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/DNSKEY.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/DNSKEY.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/DNSKEY.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/DNSKEY.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.dnskeybase -from dns.rdtypes.dnskeybase import flags_to_text_set, flags_from_text_set - - -__all__ = ['flags_to_text_set', 'flags_from_text_set'] - - -class DNSKEY(dns.rdtypes.dnskeybase.DNSKEYBase): - - """DNSKEY record""" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/DS.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/DS.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/DS.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/DS.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.dsbase - - -class DS(dns.rdtypes.dsbase.DSBase): - - """DS record""" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/EUI48.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/EUI48.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/EUI48.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/EUI48.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# Copyright (C) 2015 Red Hat, Inc. -# Author: Petr Spacek -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED 'AS IS' AND RED HAT DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.euibase - - -class EUI48(dns.rdtypes.euibase.EUIBase): - - """EUI48 record - - @ivar fingerprint: 48-bit Extended Unique Identifier (EUI-48) - @type fingerprint: string - @see: rfc7043.txt""" - - byte_len = 6 # 0123456789ab (in hex) - text_len = byte_len * 3 - 1 # 01-23-45-67-89-ab diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/EUI64.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/EUI64.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/EUI64.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/EUI64.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# Copyright (C) 2015 Red Hat, Inc. -# Author: Petr Spacek -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED 'AS IS' AND RED HAT DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.euibase - - -class EUI64(dns.rdtypes.euibase.EUIBase): - - """EUI64 record - - @ivar fingerprint: 64-bit Extended Unique Identifier (EUI-64) - @type fingerprint: string - @see: rfc7043.txt""" - - byte_len = 8 # 0123456789abcdef (in hex) - text_len = byte_len * 3 - 1 # 01-23-45-67-89-ab-cd-ef diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/GPOS.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/GPOS.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/GPOS.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/GPOS.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,160 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.rdata -import dns.tokenizer -from dns._compat import long, text_type - - -def _validate_float_string(what): - if what[0] == b'-'[0] or what[0] == b'+'[0]: - what = what[1:] - if what.isdigit(): - return - (left, right) = what.split(b'.') - if left == b'' and right == b'': - raise dns.exception.FormError - if not left == b'' and not left.decode().isdigit(): - raise dns.exception.FormError - if not right == b'' and not right.decode().isdigit(): - raise dns.exception.FormError - - -def _sanitize(value): - if isinstance(value, text_type): - return value.encode() - return value - - -class GPOS(dns.rdata.Rdata): - - """GPOS record - - @ivar latitude: latitude - @type latitude: string - @ivar longitude: longitude - @type longitude: string - @ivar altitude: altitude - @type altitude: string - @see: RFC 1712""" - - __slots__ = ['latitude', 'longitude', 'altitude'] - - def __init__(self, rdclass, rdtype, latitude, longitude, altitude): - super(GPOS, self).__init__(rdclass, rdtype) - if isinstance(latitude, float) or \ - isinstance(latitude, int) or \ - isinstance(latitude, long): - latitude = str(latitude) - if isinstance(longitude, float) or \ - isinstance(longitude, int) or \ - isinstance(longitude, long): - longitude = str(longitude) - if isinstance(altitude, float) or \ - isinstance(altitude, int) or \ - isinstance(altitude, long): - altitude = str(altitude) - latitude = _sanitize(latitude) - longitude = _sanitize(longitude) - altitude = _sanitize(altitude) - _validate_float_string(latitude) - _validate_float_string(longitude) - _validate_float_string(altitude) - self.latitude = latitude - self.longitude = longitude - self.altitude = altitude - - def to_text(self, origin=None, relativize=True, **kw): - return '%s %s %s' % (self.latitude.decode(), - self.longitude.decode(), - self.altitude.decode()) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - latitude = tok.get_string() - longitude = tok.get_string() - altitude = tok.get_string() - tok.get_eol() - return cls(rdclass, rdtype, latitude, longitude, altitude) - - def to_wire(self, file, compress=None, origin=None): - l = len(self.latitude) - assert l < 256 - file.write(struct.pack('!B', l)) - file.write(self.latitude) - l = len(self.longitude) - assert l < 256 - file.write(struct.pack('!B', l)) - file.write(self.longitude) - l = len(self.altitude) - assert l < 256 - file.write(struct.pack('!B', l)) - file.write(self.altitude) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - l = wire[current] - current += 1 - rdlen -= 1 - if l > rdlen: - raise dns.exception.FormError - latitude = wire[current: current + l].unwrap() - current += l - rdlen -= l - l = wire[current] - current += 1 - rdlen -= 1 - if l > rdlen: - raise dns.exception.FormError - longitude = wire[current: current + l].unwrap() - current += l - rdlen -= l - l = wire[current] - current += 1 - rdlen -= 1 - if l != rdlen: - raise dns.exception.FormError - altitude = wire[current: current + l].unwrap() - return cls(rdclass, rdtype, latitude, longitude, altitude) - - def _get_float_latitude(self): - return float(self.latitude) - - def _set_float_latitude(self, value): - self.latitude = str(value) - - float_latitude = property(_get_float_latitude, _set_float_latitude, - doc="latitude as a floating point value") - - def _get_float_longitude(self): - return float(self.longitude) - - def _set_float_longitude(self, value): - self.longitude = str(value) - - float_longitude = property(_get_float_longitude, _set_float_longitude, - doc="longitude as a floating point value") - - def _get_float_altitude(self): - return float(self.altitude) - - def _set_float_altitude(self, value): - self.altitude = str(value) - - float_altitude = property(_get_float_altitude, _set_float_altitude, - doc="altitude as a floating point value") diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/HINFO.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/HINFO.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/HINFO.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/HINFO.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.rdata -import dns.tokenizer -from dns._compat import text_type - - -class HINFO(dns.rdata.Rdata): - - """HINFO record - - @ivar cpu: the CPU type - @type cpu: string - @ivar os: the OS type - @type os: string - @see: RFC 1035""" - - __slots__ = ['cpu', 'os'] - - def __init__(self, rdclass, rdtype, cpu, os): - super(HINFO, self).__init__(rdclass, rdtype) - if isinstance(cpu, text_type): - self.cpu = cpu.encode() - else: - self.cpu = cpu - if isinstance(os, text_type): - self.os = os.encode() - else: - self.os = os - - def to_text(self, origin=None, relativize=True, **kw): - return '"%s" "%s"' % (dns.rdata._escapify(self.cpu), - dns.rdata._escapify(self.os)) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - cpu = tok.get_string() - os = tok.get_string() - tok.get_eol() - return cls(rdclass, rdtype, cpu, os) - - def to_wire(self, file, compress=None, origin=None): - l = len(self.cpu) - assert l < 256 - file.write(struct.pack('!B', l)) - file.write(self.cpu) - l = len(self.os) - assert l < 256 - file.write(struct.pack('!B', l)) - file.write(self.os) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - l = wire[current] - current += 1 - rdlen -= 1 - if l > rdlen: - raise dns.exception.FormError - cpu = wire[current:current + l].unwrap() - current += l - rdlen -= l - l = wire[current] - current += 1 - rdlen -= 1 - if l != rdlen: - raise dns.exception.FormError - os = wire[current: current + l].unwrap() - return cls(rdclass, rdtype, cpu, os) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/HIP.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/HIP.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/HIP.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/HIP.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -# Copyright (C) 2010, 2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct -import base64 -import binascii - -import dns.exception -import dns.rdata -import dns.rdatatype - - -class HIP(dns.rdata.Rdata): - - """HIP record - - @ivar hit: the host identity tag - @type hit: string - @ivar algorithm: the public key cryptographic algorithm - @type algorithm: int - @ivar key: the public key - @type key: string - @ivar servers: the rendezvous servers - @type servers: list of dns.name.Name objects - @see: RFC 5205""" - - __slots__ = ['hit', 'algorithm', 'key', 'servers'] - - def __init__(self, rdclass, rdtype, hit, algorithm, key, servers): - super(HIP, self).__init__(rdclass, rdtype) - self.hit = hit - self.algorithm = algorithm - self.key = key - self.servers = servers - - def to_text(self, origin=None, relativize=True, **kw): - hit = binascii.hexlify(self.hit).decode() - key = base64.b64encode(self.key).replace(b'\n', b'').decode() - text = u'' - servers = [] - for server in self.servers: - servers.append(server.choose_relativity(origin, relativize)) - if len(servers) > 0: - text += (u' ' + u' '.join((x.to_unicode() for x in servers))) - return u'%u %s %s%s' % (self.algorithm, hit, key, text) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - algorithm = tok.get_uint8() - hit = binascii.unhexlify(tok.get_string().encode()) - if len(hit) > 255: - raise dns.exception.SyntaxError("HIT too long") - key = base64.b64decode(tok.get_string().encode()) - servers = [] - while 1: - token = tok.get() - if token.is_eol_or_eof(): - break - server = dns.name.from_text(token.value, origin) - server.choose_relativity(origin, relativize) - servers.append(server) - return cls(rdclass, rdtype, hit, algorithm, key, servers) - - def to_wire(self, file, compress=None, origin=None): - lh = len(self.hit) - lk = len(self.key) - file.write(struct.pack("!BBH", lh, self.algorithm, lk)) - file.write(self.hit) - file.write(self.key) - for server in self.servers: - server.to_wire(file, None, origin) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - (lh, algorithm, lk) = struct.unpack('!BBH', - wire[current: current + 4]) - current += 4 - rdlen -= 4 - hit = wire[current: current + lh].unwrap() - current += lh - rdlen -= lh - key = wire[current: current + lk].unwrap() - current += lk - rdlen -= lk - servers = [] - while rdlen > 0: - (server, cused) = dns.name.from_wire(wire[: current + rdlen], - current) - current += cused - rdlen -= cused - if origin is not None: - server = server.relativize(origin) - servers.append(server) - return cls(rdclass, rdtype, hit, algorithm, key, servers) - - def choose_relativity(self, origin=None, relativize=True): - servers = [] - for server in self.servers: - server = server.choose_relativity(origin, relativize) - servers.append(server) - self.servers = servers diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/__init__.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/__init__.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/__init__.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Class ANY (generic) rdata type classes.""" - -__all__ = [ - 'AFSDB', - 'CDNSKEY', - 'CDS', - 'CERT', - 'CNAME', - 'DLV', - 'DNAME', - 'DNSKEY', - 'DS', - 'EUI48', - 'EUI64', - 'GPOS', - 'HINFO', - 'HIP', - 'ISDN', - 'LOC', - 'MX', - 'NS', - 'NSEC', - 'NSEC3', - 'NSEC3PARAM', - 'TLSA', - 'PTR', - 'RP', - 'RRSIG', - 'RT', - 'SOA', - 'SPF', - 'SSHFP', - 'TXT', - 'X25', -] diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/ISDN.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/ISDN.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/ISDN.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/ISDN.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.rdata -import dns.tokenizer -from dns._compat import text_type - - -class ISDN(dns.rdata.Rdata): - - """ISDN record - - @ivar address: the ISDN address - @type address: string - @ivar subaddress: the ISDN subaddress (or '' if not present) - @type subaddress: string - @see: RFC 1183""" - - __slots__ = ['address', 'subaddress'] - - def __init__(self, rdclass, rdtype, address, subaddress): - super(ISDN, self).__init__(rdclass, rdtype) - if isinstance(address, text_type): - self.address = address.encode() - else: - self.address = address - if isinstance(address, text_type): - self.subaddress = subaddress.encode() - else: - self.subaddress = subaddress - - def to_text(self, origin=None, relativize=True, **kw): - if self.subaddress: - return '"%s" "%s"' % (dns.rdata._escapify(self.address), - dns.rdata._escapify(self.subaddress)) - else: - return '"%s"' % dns.rdata._escapify(self.address) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - address = tok.get_string() - t = tok.get() - if not t.is_eol_or_eof(): - tok.unget(t) - subaddress = tok.get_string() - else: - tok.unget(t) - subaddress = '' - tok.get_eol() - return cls(rdclass, rdtype, address, subaddress) - - def to_wire(self, file, compress=None, origin=None): - l = len(self.address) - assert l < 256 - file.write(struct.pack('!B', l)) - file.write(self.address) - l = len(self.subaddress) - if l > 0: - assert l < 256 - file.write(struct.pack('!B', l)) - file.write(self.subaddress) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - l = wire[current] - current += 1 - rdlen -= 1 - if l > rdlen: - raise dns.exception.FormError - address = wire[current: current + l].unwrap() - current += l - rdlen -= l - if rdlen > 0: - l = wire[current] - current += 1 - rdlen -= 1 - if l != rdlen: - raise dns.exception.FormError - subaddress = wire[current: current + l].unwrap() - else: - subaddress = '' - return cls(rdclass, rdtype, address, subaddress) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/LOC.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/LOC.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/LOC.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/LOC.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,325 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -from __future__ import division - -import struct - -import dns.exception -import dns.rdata -from dns._compat import long, xrange, round_py2_compat - - -_pows = tuple(long(10**i) for i in range(0, 11)) - -# default values are in centimeters -_default_size = 100.0 -_default_hprec = 1000000.0 -_default_vprec = 1000.0 - - -def _exponent_of(what, desc): - if what == 0: - return 0 - exp = None - for i in xrange(len(_pows)): - if what // _pows[i] == long(0): - exp = i - 1 - break - if exp is None or exp < 0: - raise dns.exception.SyntaxError("%s value out of bounds" % desc) - return exp - - -def _float_to_tuple(what): - if what < 0: - sign = -1 - what *= -1 - else: - sign = 1 - what = round_py2_compat(what * 3600000) - degrees = int(what // 3600000) - what -= degrees * 3600000 - minutes = int(what // 60000) - what -= minutes * 60000 - seconds = int(what // 1000) - what -= int(seconds * 1000) - what = int(what) - return (degrees, minutes, seconds, what, sign) - - -def _tuple_to_float(what): - value = float(what[0]) - value += float(what[1]) / 60.0 - value += float(what[2]) / 3600.0 - value += float(what[3]) / 3600000.0 - return float(what[4]) * value - - -def _encode_size(what, desc): - what = long(what) - exponent = _exponent_of(what, desc) & 0xF - base = what // pow(10, exponent) & 0xF - return base * 16 + exponent - - -def _decode_size(what, desc): - exponent = what & 0x0F - if exponent > 9: - raise dns.exception.SyntaxError("bad %s exponent" % desc) - base = (what & 0xF0) >> 4 - if base > 9: - raise dns.exception.SyntaxError("bad %s base" % desc) - return long(base) * pow(10, exponent) - - -class LOC(dns.rdata.Rdata): - - """LOC record - - @ivar latitude: latitude - @type latitude: (int, int, int, int, sign) tuple specifying the degrees, minutes, - seconds, milliseconds, and sign of the coordinate. - @ivar longitude: longitude - @type longitude: (int, int, int, int, sign) tuple specifying the degrees, - minutes, seconds, milliseconds, and sign of the coordinate. - @ivar altitude: altitude - @type altitude: float - @ivar size: size of the sphere - @type size: float - @ivar horizontal_precision: horizontal precision - @type horizontal_precision: float - @ivar vertical_precision: vertical precision - @type vertical_precision: float - @see: RFC 1876""" - - __slots__ = ['latitude', 'longitude', 'altitude', 'size', - 'horizontal_precision', 'vertical_precision'] - - def __init__(self, rdclass, rdtype, latitude, longitude, altitude, - size=_default_size, hprec=_default_hprec, - vprec=_default_vprec): - """Initialize a LOC record instance. - - The parameters I{latitude} and I{longitude} may be either a 4-tuple - of integers specifying (degrees, minutes, seconds, milliseconds), - or they may be floating point values specifying the number of - degrees. The other parameters are floats. Size, horizontal precision, - and vertical precision are specified in centimeters.""" - - super(LOC, self).__init__(rdclass, rdtype) - if isinstance(latitude, int) or isinstance(latitude, long): - latitude = float(latitude) - if isinstance(latitude, float): - latitude = _float_to_tuple(latitude) - self.latitude = latitude - if isinstance(longitude, int) or isinstance(longitude, long): - longitude = float(longitude) - if isinstance(longitude, float): - longitude = _float_to_tuple(longitude) - self.longitude = longitude - self.altitude = float(altitude) - self.size = float(size) - self.horizontal_precision = float(hprec) - self.vertical_precision = float(vprec) - - def to_text(self, origin=None, relativize=True, **kw): - if self.latitude[4] > 0: - lat_hemisphere = 'N' - else: - lat_hemisphere = 'S' - if self.longitude[4] > 0: - long_hemisphere = 'E' - else: - long_hemisphere = 'W' - text = "%d %d %d.%03d %s %d %d %d.%03d %s %0.2fm" % ( - self.latitude[0], self.latitude[1], - self.latitude[2], self.latitude[3], lat_hemisphere, - self.longitude[0], self.longitude[1], self.longitude[2], - self.longitude[3], long_hemisphere, - self.altitude / 100.0 - ) - - # do not print default values - if self.size != _default_size or \ - self.horizontal_precision != _default_hprec or \ - self.vertical_precision != _default_vprec: - text += " %0.2fm %0.2fm %0.2fm" % ( - self.size / 100.0, self.horizontal_precision / 100.0, - self.vertical_precision / 100.0 - ) - return text - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - latitude = [0, 0, 0, 0, 1] - longitude = [0, 0, 0, 0, 1] - size = _default_size - hprec = _default_hprec - vprec = _default_vprec - - latitude[0] = tok.get_int() - t = tok.get_string() - if t.isdigit(): - latitude[1] = int(t) - t = tok.get_string() - if '.' in t: - (seconds, milliseconds) = t.split('.') - if not seconds.isdigit(): - raise dns.exception.SyntaxError( - 'bad latitude seconds value') - latitude[2] = int(seconds) - if latitude[2] >= 60: - raise dns.exception.SyntaxError('latitude seconds >= 60') - l = len(milliseconds) - if l == 0 or l > 3 or not milliseconds.isdigit(): - raise dns.exception.SyntaxError( - 'bad latitude milliseconds value') - if l == 1: - m = 100 - elif l == 2: - m = 10 - else: - m = 1 - latitude[3] = m * int(milliseconds) - t = tok.get_string() - elif t.isdigit(): - latitude[2] = int(t) - t = tok.get_string() - if t == 'S': - latitude[4] = -1 - elif t != 'N': - raise dns.exception.SyntaxError('bad latitude hemisphere value') - - longitude[0] = tok.get_int() - t = tok.get_string() - if t.isdigit(): - longitude[1] = int(t) - t = tok.get_string() - if '.' in t: - (seconds, milliseconds) = t.split('.') - if not seconds.isdigit(): - raise dns.exception.SyntaxError( - 'bad longitude seconds value') - longitude[2] = int(seconds) - if longitude[2] >= 60: - raise dns.exception.SyntaxError('longitude seconds >= 60') - l = len(milliseconds) - if l == 0 or l > 3 or not milliseconds.isdigit(): - raise dns.exception.SyntaxError( - 'bad longitude milliseconds value') - if l == 1: - m = 100 - elif l == 2: - m = 10 - else: - m = 1 - longitude[3] = m * int(milliseconds) - t = tok.get_string() - elif t.isdigit(): - longitude[2] = int(t) - t = tok.get_string() - if t == 'W': - longitude[4] = -1 - elif t != 'E': - raise dns.exception.SyntaxError('bad longitude hemisphere value') - - t = tok.get_string() - if t[-1] == 'm': - t = t[0: -1] - altitude = float(t) * 100.0 # m -> cm - - token = tok.get().unescape() - if not token.is_eol_or_eof(): - value = token.value - if value[-1] == 'm': - value = value[0: -1] - size = float(value) * 100.0 # m -> cm - token = tok.get().unescape() - if not token.is_eol_or_eof(): - value = token.value - if value[-1] == 'm': - value = value[0: -1] - hprec = float(value) * 100.0 # m -> cm - token = tok.get().unescape() - if not token.is_eol_or_eof(): - value = token.value - if value[-1] == 'm': - value = value[0: -1] - vprec = float(value) * 100.0 # m -> cm - tok.get_eol() - - return cls(rdclass, rdtype, latitude, longitude, altitude, - size, hprec, vprec) - - def to_wire(self, file, compress=None, origin=None): - milliseconds = (self.latitude[0] * 3600000 + - self.latitude[1] * 60000 + - self.latitude[2] * 1000 + - self.latitude[3]) * self.latitude[4] - latitude = long(0x80000000) + milliseconds - milliseconds = (self.longitude[0] * 3600000 + - self.longitude[1] * 60000 + - self.longitude[2] * 1000 + - self.longitude[3]) * self.longitude[4] - longitude = long(0x80000000) + milliseconds - altitude = long(self.altitude) + long(10000000) - size = _encode_size(self.size, "size") - hprec = _encode_size(self.horizontal_precision, "horizontal precision") - vprec = _encode_size(self.vertical_precision, "vertical precision") - wire = struct.pack("!BBBBIII", 0, size, hprec, vprec, latitude, - longitude, altitude) - file.write(wire) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - (version, size, hprec, vprec, latitude, longitude, altitude) = \ - struct.unpack("!BBBBIII", wire[current: current + rdlen]) - if latitude > long(0x80000000): - latitude = float(latitude - long(0x80000000)) / 3600000 - else: - latitude = -1 * float(long(0x80000000) - latitude) / 3600000 - if latitude < -90.0 or latitude > 90.0: - raise dns.exception.FormError("bad latitude") - if longitude > long(0x80000000): - longitude = float(longitude - long(0x80000000)) / 3600000 - else: - longitude = -1 * float(long(0x80000000) - longitude) / 3600000 - if longitude < -180.0 or longitude > 180.0: - raise dns.exception.FormError("bad longitude") - altitude = float(altitude) - 10000000.0 - size = _decode_size(size, "size") - hprec = _decode_size(hprec, "horizontal precision") - vprec = _decode_size(vprec, "vertical precision") - return cls(rdclass, rdtype, latitude, longitude, altitude, - size, hprec, vprec) - - def _get_float_latitude(self): - return _tuple_to_float(self.latitude) - - def _set_float_latitude(self, value): - self.latitude = _float_to_tuple(value) - - float_latitude = property(_get_float_latitude, _set_float_latitude, - doc="latitude as a floating point value") - - def _get_float_longitude(self): - return _tuple_to_float(self.longitude) - - def _set_float_longitude(self, value): - self.longitude = _float_to_tuple(value) - - float_longitude = property(_get_float_longitude, _set_float_longitude, - doc="longitude as a floating point value") diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/MX.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/MX.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/MX.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/MX.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.mxbase - - -class MX(dns.rdtypes.mxbase.MXBase): - - """MX record""" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/NSEC3PARAM.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/NSEC3PARAM.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/NSEC3PARAM.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/NSEC3PARAM.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct -import binascii - -import dns.exception -import dns.rdata -from dns._compat import text_type - - -class NSEC3PARAM(dns.rdata.Rdata): - - """NSEC3PARAM record - - @ivar algorithm: the hash algorithm number - @type algorithm: int - @ivar flags: the flags - @type flags: int - @ivar iterations: the number of iterations - @type iterations: int - @ivar salt: the salt - @type salt: string""" - - __slots__ = ['algorithm', 'flags', 'iterations', 'salt'] - - def __init__(self, rdclass, rdtype, algorithm, flags, iterations, salt): - super(NSEC3PARAM, self).__init__(rdclass, rdtype) - self.algorithm = algorithm - self.flags = flags - self.iterations = iterations - if isinstance(salt, text_type): - self.salt = salt.encode() - else: - self.salt = salt - - def to_text(self, origin=None, relativize=True, **kw): - if self.salt == b'': - salt = '-' - else: - salt = binascii.hexlify(self.salt).decode() - return '%u %u %u %s' % (self.algorithm, self.flags, self.iterations, - salt) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - algorithm = tok.get_uint8() - flags = tok.get_uint8() - iterations = tok.get_uint16() - salt = tok.get_string() - if salt == '-': - salt = '' - else: - salt = binascii.unhexlify(salt.encode()) - tok.get_eol() - return cls(rdclass, rdtype, algorithm, flags, iterations, salt) - - def to_wire(self, file, compress=None, origin=None): - l = len(self.salt) - file.write(struct.pack("!BBHB", self.algorithm, self.flags, - self.iterations, l)) - file.write(self.salt) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - (algorithm, flags, iterations, slen) = \ - struct.unpack('!BBHB', - wire[current: current + 5]) - current += 5 - rdlen -= 5 - salt = wire[current: current + slen].unwrap() - current += slen - rdlen -= slen - if rdlen != 0: - raise dns.exception.FormError - return cls(rdclass, rdtype, algorithm, flags, iterations, salt) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/NSEC3.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/NSEC3.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/NSEC3.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/NSEC3.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,191 +0,0 @@ -# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import base64 -import binascii -import string -import struct - -import dns.exception -import dns.rdata -import dns.rdatatype -from dns._compat import xrange, text_type - -try: - b32_hex_to_normal = string.maketrans('0123456789ABCDEFGHIJKLMNOPQRSTUV', - 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567') - b32_normal_to_hex = string.maketrans('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', - '0123456789ABCDEFGHIJKLMNOPQRSTUV') -except AttributeError: - b32_hex_to_normal = bytes.maketrans(b'0123456789ABCDEFGHIJKLMNOPQRSTUV', - b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567') - b32_normal_to_hex = bytes.maketrans(b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', - b'0123456789ABCDEFGHIJKLMNOPQRSTUV') - -# hash algorithm constants -SHA1 = 1 - -# flag constants -OPTOUT = 1 - - -class NSEC3(dns.rdata.Rdata): - - """NSEC3 record - - @ivar algorithm: the hash algorithm number - @type algorithm: int - @ivar flags: the flags - @type flags: int - @ivar iterations: the number of iterations - @type iterations: int - @ivar salt: the salt - @type salt: string - @ivar next: the next name hash - @type next: string - @ivar windows: the windowed bitmap list - @type windows: list of (window number, string) tuples""" - - __slots__ = ['algorithm', 'flags', 'iterations', 'salt', 'next', 'windows'] - - def __init__(self, rdclass, rdtype, algorithm, flags, iterations, salt, - next, windows): - super(NSEC3, self).__init__(rdclass, rdtype) - self.algorithm = algorithm - self.flags = flags - self.iterations = iterations - if isinstance(salt, text_type): - self.salt = salt.encode() - else: - self.salt = salt - self.next = next - self.windows = windows - - def to_text(self, origin=None, relativize=True, **kw): - next = base64.b32encode(self.next).translate( - b32_normal_to_hex).lower().decode() - if self.salt == b'': - salt = '-' - else: - salt = binascii.hexlify(self.salt).decode() - text = u'' - for (window, bitmap) in self.windows: - bits = [] - for i in xrange(0, len(bitmap)): - byte = bitmap[i] - for j in xrange(0, 8): - if byte & (0x80 >> j): - bits.append(dns.rdatatype.to_text(window * 256 + - i * 8 + j)) - text += (u' ' + u' '.join(bits)) - return u'%u %u %u %s %s%s' % (self.algorithm, self.flags, - self.iterations, salt, next, text) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - algorithm = tok.get_uint8() - flags = tok.get_uint8() - iterations = tok.get_uint16() - salt = tok.get_string() - if salt == u'-': - salt = b'' - else: - salt = binascii.unhexlify(salt.encode('ascii')) - next = tok.get_string().encode( - 'ascii').upper().translate(b32_hex_to_normal) - next = base64.b32decode(next) - rdtypes = [] - while 1: - token = tok.get().unescape() - if token.is_eol_or_eof(): - break - nrdtype = dns.rdatatype.from_text(token.value) - if nrdtype == 0: - raise dns.exception.SyntaxError("NSEC3 with bit 0") - if nrdtype > 65535: - raise dns.exception.SyntaxError("NSEC3 with bit > 65535") - rdtypes.append(nrdtype) - rdtypes.sort() - window = 0 - octets = 0 - prior_rdtype = 0 - bitmap = bytearray(b'\0' * 32) - windows = [] - for nrdtype in rdtypes: - if nrdtype == prior_rdtype: - continue - prior_rdtype = nrdtype - new_window = nrdtype // 256 - if new_window != window: - if octets != 0: - windows.append((window, ''.join(bitmap[0:octets]))) - bitmap = bytearray(b'\0' * 32) - window = new_window - offset = nrdtype % 256 - byte = offset // 8 - bit = offset % 8 - octets = byte + 1 - bitmap[byte] = bitmap[byte] | (0x80 >> bit) - if octets != 0: - windows.append((window, bitmap[0:octets])) - return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next, - windows) - - def to_wire(self, file, compress=None, origin=None): - l = len(self.salt) - file.write(struct.pack("!BBHB", self.algorithm, self.flags, - self.iterations, l)) - file.write(self.salt) - l = len(self.next) - file.write(struct.pack("!B", l)) - file.write(self.next) - for (window, bitmap) in self.windows: - file.write(struct.pack("!BB", window, len(bitmap))) - file.write(bitmap) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - (algorithm, flags, iterations, slen) = \ - struct.unpack('!BBHB', wire[current: current + 5]) - - current += 5 - rdlen -= 5 - salt = wire[current: current + slen].unwrap() - current += slen - rdlen -= slen - nlen = wire[current] - current += 1 - rdlen -= 1 - next = wire[current: current + nlen].unwrap() - current += nlen - rdlen -= nlen - windows = [] - while rdlen > 0: - if rdlen < 3: - raise dns.exception.FormError("NSEC3 too short") - window = wire[current] - octets = wire[current + 1] - if octets == 0 or octets > 32: - raise dns.exception.FormError("bad NSEC3 octets") - current += 2 - rdlen -= 2 - if rdlen < octets: - raise dns.exception.FormError("bad NSEC3 bitmap length") - bitmap = bytearray(wire[current: current + octets].unwrap()) - current += octets - rdlen -= octets - windows.append((window, bitmap)) - return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next, - windows) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/NSEC.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/NSEC.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/NSEC.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/NSEC.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,126 +0,0 @@ -# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.rdata -import dns.rdatatype -import dns.name -from dns._compat import xrange - - -class NSEC(dns.rdata.Rdata): - - """NSEC record - - @ivar next: the next name - @type next: dns.name.Name object - @ivar windows: the windowed bitmap list - @type windows: list of (window number, string) tuples""" - - __slots__ = ['next', 'windows'] - - def __init__(self, rdclass, rdtype, next, windows): - super(NSEC, self).__init__(rdclass, rdtype) - self.next = next - self.windows = windows - - def to_text(self, origin=None, relativize=True, **kw): - next = self.next.choose_relativity(origin, relativize) - text = '' - for (window, bitmap) in self.windows: - bits = [] - for i in xrange(0, len(bitmap)): - byte = bitmap[i] - for j in xrange(0, 8): - if byte & (0x80 >> j): - bits.append(dns.rdatatype.to_text(window * 256 + - i * 8 + j)) - text += (' ' + ' '.join(bits)) - return '%s%s' % (next, text) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - next = tok.get_name() - next = next.choose_relativity(origin, relativize) - rdtypes = [] - while 1: - token = tok.get().unescape() - if token.is_eol_or_eof(): - break - nrdtype = dns.rdatatype.from_text(token.value) - if nrdtype == 0: - raise dns.exception.SyntaxError("NSEC with bit 0") - if nrdtype > 65535: - raise dns.exception.SyntaxError("NSEC with bit > 65535") - rdtypes.append(nrdtype) - rdtypes.sort() - window = 0 - octets = 0 - prior_rdtype = 0 - bitmap = bytearray(b'\0' * 32) - windows = [] - for nrdtype in rdtypes: - if nrdtype == prior_rdtype: - continue - prior_rdtype = nrdtype - new_window = nrdtype // 256 - if new_window != window: - windows.append((window, bitmap[0:octets])) - bitmap = bytearray(b'\0' * 32) - window = new_window - offset = nrdtype % 256 - byte = offset // 8 - bit = offset % 8 - octets = byte + 1 - bitmap[byte] = bitmap[byte] | (0x80 >> bit) - - windows.append((window, bitmap[0:octets])) - return cls(rdclass, rdtype, next, windows) - - def to_wire(self, file, compress=None, origin=None): - self.next.to_wire(file, None, origin) - for (window, bitmap) in self.windows: - file.write(struct.pack('!BB', window, len(bitmap))) - file.write(bitmap) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - (next, cused) = dns.name.from_wire(wire[: current + rdlen], current) - current += cused - rdlen -= cused - windows = [] - while rdlen > 0: - if rdlen < 3: - raise dns.exception.FormError("NSEC too short") - window = wire[current] - octets = wire[current + 1] - if octets == 0 or octets > 32: - raise dns.exception.FormError("bad NSEC octets") - current += 2 - rdlen -= 2 - if rdlen < octets: - raise dns.exception.FormError("bad NSEC bitmap length") - bitmap = bytearray(wire[current: current + octets].unwrap()) - current += octets - rdlen -= octets - windows.append((window, bitmap)) - if origin is not None: - next = next.relativize(origin) - return cls(rdclass, rdtype, next, windows) - - def choose_relativity(self, origin=None, relativize=True): - self.next = self.next.choose_relativity(origin, relativize) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/NS.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/NS.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/NS.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/NS.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.nsbase - - -class NS(dns.rdtypes.nsbase.NSBase): - - """NS record""" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/PTR.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/PTR.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/PTR.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/PTR.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.nsbase - - -class PTR(dns.rdtypes.nsbase.NSBase): - - """PTR record""" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/RP.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/RP.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/RP.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/RP.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.exception -import dns.rdata -import dns.name - - -class RP(dns.rdata.Rdata): - - """RP record - - @ivar mbox: The responsible person's mailbox - @type mbox: dns.name.Name object - @ivar txt: The owner name of a node with TXT records, or the root name - if no TXT records are associated with this RP. - @type txt: dns.name.Name object - @see: RFC 1183""" - - __slots__ = ['mbox', 'txt'] - - def __init__(self, rdclass, rdtype, mbox, txt): - super(RP, self).__init__(rdclass, rdtype) - self.mbox = mbox - self.txt = txt - - def to_text(self, origin=None, relativize=True, **kw): - mbox = self.mbox.choose_relativity(origin, relativize) - txt = self.txt.choose_relativity(origin, relativize) - return "%s %s" % (str(mbox), str(txt)) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - mbox = tok.get_name() - txt = tok.get_name() - mbox = mbox.choose_relativity(origin, relativize) - txt = txt.choose_relativity(origin, relativize) - tok.get_eol() - return cls(rdclass, rdtype, mbox, txt) - - def to_wire(self, file, compress=None, origin=None): - self.mbox.to_wire(file, None, origin) - self.txt.to_wire(file, None, origin) - - def to_digestable(self, origin=None): - return self.mbox.to_digestable(origin) + \ - self.txt.to_digestable(origin) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - (mbox, cused) = dns.name.from_wire(wire[: current + rdlen], - current) - current += cused - rdlen -= cused - if rdlen <= 0: - raise dns.exception.FormError - (txt, cused) = dns.name.from_wire(wire[: current + rdlen], - current) - if cused != rdlen: - raise dns.exception.FormError - if origin is not None: - mbox = mbox.relativize(origin) - txt = txt.relativize(origin) - return cls(rdclass, rdtype, mbox, txt) - - def choose_relativity(self, origin=None, relativize=True): - self.mbox = self.mbox.choose_relativity(origin, relativize) - self.txt = self.txt.choose_relativity(origin, relativize) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/RRSIG.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/RRSIG.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/RRSIG.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/RRSIG.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,156 +0,0 @@ -# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import base64 -import calendar -import struct -import time - -import dns.dnssec -import dns.exception -import dns.rdata -import dns.rdatatype - - -class BadSigTime(dns.exception.DNSException): - - """Time in DNS SIG or RRSIG resource record cannot be parsed.""" - - -def sigtime_to_posixtime(what): - if len(what) != 14: - raise BadSigTime - year = int(what[0:4]) - month = int(what[4:6]) - day = int(what[6:8]) - hour = int(what[8:10]) - minute = int(what[10:12]) - second = int(what[12:14]) - return calendar.timegm((year, month, day, hour, minute, second, - 0, 0, 0)) - - -def posixtime_to_sigtime(what): - return time.strftime('%Y%m%d%H%M%S', time.gmtime(what)) - - -class RRSIG(dns.rdata.Rdata): - - """RRSIG record - - @ivar type_covered: the rdata type this signature covers - @type type_covered: int - @ivar algorithm: the algorithm used for the sig - @type algorithm: int - @ivar labels: number of labels - @type labels: int - @ivar original_ttl: the original TTL - @type original_ttl: long - @ivar expiration: signature expiration time - @type expiration: long - @ivar inception: signature inception time - @type inception: long - @ivar key_tag: the key tag - @type key_tag: int - @ivar signer: the signer - @type signer: dns.name.Name object - @ivar signature: the signature - @type signature: string""" - - __slots__ = ['type_covered', 'algorithm', 'labels', 'original_ttl', - 'expiration', 'inception', 'key_tag', 'signer', - 'signature'] - - def __init__(self, rdclass, rdtype, type_covered, algorithm, labels, - original_ttl, expiration, inception, key_tag, signer, - signature): - super(RRSIG, self).__init__(rdclass, rdtype) - self.type_covered = type_covered - self.algorithm = algorithm - self.labels = labels - self.original_ttl = original_ttl - self.expiration = expiration - self.inception = inception - self.key_tag = key_tag - self.signer = signer - self.signature = signature - - def covers(self): - return self.type_covered - - def to_text(self, origin=None, relativize=True, **kw): - return '%s %d %d %d %s %s %d %s %s' % ( - dns.rdatatype.to_text(self.type_covered), - self.algorithm, - self.labels, - self.original_ttl, - posixtime_to_sigtime(self.expiration), - posixtime_to_sigtime(self.inception), - self.key_tag, - self.signer.choose_relativity(origin, relativize), - dns.rdata._base64ify(self.signature) - ) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - type_covered = dns.rdatatype.from_text(tok.get_string()) - algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) - labels = tok.get_int() - original_ttl = tok.get_ttl() - expiration = sigtime_to_posixtime(tok.get_string()) - inception = sigtime_to_posixtime(tok.get_string()) - key_tag = tok.get_int() - signer = tok.get_name() - signer = signer.choose_relativity(origin, relativize) - chunks = [] - while 1: - t = tok.get().unescape() - if t.is_eol_or_eof(): - break - if not t.is_identifier(): - raise dns.exception.SyntaxError - chunks.append(t.value.encode()) - b64 = b''.join(chunks) - signature = base64.b64decode(b64) - return cls(rdclass, rdtype, type_covered, algorithm, labels, - original_ttl, expiration, inception, key_tag, signer, - signature) - - def to_wire(self, file, compress=None, origin=None): - header = struct.pack('!HBBIIIH', self.type_covered, - self.algorithm, self.labels, - self.original_ttl, self.expiration, - self.inception, self.key_tag) - file.write(header) - self.signer.to_wire(file, None, origin) - file.write(self.signature) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - header = struct.unpack('!HBBIIIH', wire[current: current + 18]) - current += 18 - rdlen -= 18 - (signer, cused) = dns.name.from_wire(wire[: current + rdlen], current) - current += cused - rdlen -= cused - if origin is not None: - signer = signer.relativize(origin) - signature = wire[current: current + rdlen].unwrap() - return cls(rdclass, rdtype, header[0], header[1], header[2], - header[3], header[4], header[5], header[6], signer, - signature) - - def choose_relativity(self, origin=None, relativize=True): - self.signer = self.signer.choose_relativity(origin, relativize) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/RT.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/RT.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/RT.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/RT.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.mxbase - - -class RT(dns.rdtypes.mxbase.UncompressedDowncasingMX): - - """RT record""" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/SOA.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/SOA.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/SOA.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/SOA.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,114 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.rdata -import dns.name - - -class SOA(dns.rdata.Rdata): - - """SOA record - - @ivar mname: the SOA MNAME (master name) field - @type mname: dns.name.Name object - @ivar rname: the SOA RNAME (responsible name) field - @type rname: dns.name.Name object - @ivar serial: The zone's serial number - @type serial: int - @ivar refresh: The zone's refresh value (in seconds) - @type refresh: int - @ivar retry: The zone's retry value (in seconds) - @type retry: int - @ivar expire: The zone's expiration value (in seconds) - @type expire: int - @ivar minimum: The zone's negative caching time (in seconds, called - "minimum" for historical reasons) - @type minimum: int - @see: RFC 1035""" - - __slots__ = ['mname', 'rname', 'serial', 'refresh', 'retry', 'expire', - 'minimum'] - - def __init__(self, rdclass, rdtype, mname, rname, serial, refresh, retry, - expire, minimum): - super(SOA, self).__init__(rdclass, rdtype) - self.mname = mname - self.rname = rname - self.serial = serial - self.refresh = refresh - self.retry = retry - self.expire = expire - self.minimum = minimum - - def to_text(self, origin=None, relativize=True, **kw): - mname = self.mname.choose_relativity(origin, relativize) - rname = self.rname.choose_relativity(origin, relativize) - return '%s %s %d %d %d %d %d' % ( - mname, rname, self.serial, self.refresh, self.retry, - self.expire, self.minimum) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - mname = tok.get_name() - rname = tok.get_name() - mname = mname.choose_relativity(origin, relativize) - rname = rname.choose_relativity(origin, relativize) - serial = tok.get_uint32() - refresh = tok.get_ttl() - retry = tok.get_ttl() - expire = tok.get_ttl() - minimum = tok.get_ttl() - tok.get_eol() - return cls(rdclass, rdtype, mname, rname, serial, refresh, retry, - expire, minimum) - - def to_wire(self, file, compress=None, origin=None): - self.mname.to_wire(file, compress, origin) - self.rname.to_wire(file, compress, origin) - five_ints = struct.pack('!IIIII', self.serial, self.refresh, - self.retry, self.expire, self.minimum) - file.write(five_ints) - - def to_digestable(self, origin=None): - return self.mname.to_digestable(origin) + \ - self.rname.to_digestable(origin) + \ - struct.pack('!IIIII', self.serial, self.refresh, - self.retry, self.expire, self.minimum) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - (mname, cused) = dns.name.from_wire(wire[: current + rdlen], current) - current += cused - rdlen -= cused - (rname, cused) = dns.name.from_wire(wire[: current + rdlen], current) - current += cused - rdlen -= cused - if rdlen != 20: - raise dns.exception.FormError - five_ints = struct.unpack('!IIIII', - wire[current: current + rdlen]) - if origin is not None: - mname = mname.relativize(origin) - rname = rname.relativize(origin) - return cls(rdclass, rdtype, mname, rname, - five_ints[0], five_ints[1], five_ints[2], five_ints[3], - five_ints[4]) - - def choose_relativity(self, origin=None, relativize=True): - self.mname = self.mname.choose_relativity(origin, relativize) - self.rname = self.rname.choose_relativity(origin, relativize) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/SPF.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/SPF.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/SPF.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/SPF.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.txtbase - - -class SPF(dns.rdtypes.txtbase.TXTBase): - - """SPF record - - @see: RFC 4408""" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/SSHFP.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/SSHFP.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/SSHFP.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/SSHFP.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -# Copyright (C) 2005-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct -import binascii - -import dns.rdata -import dns.rdatatype - - -class SSHFP(dns.rdata.Rdata): - - """SSHFP record - - @ivar algorithm: the algorithm - @type algorithm: int - @ivar fp_type: the digest type - @type fp_type: int - @ivar fingerprint: the fingerprint - @type fingerprint: string - @see: draft-ietf-secsh-dns-05.txt""" - - __slots__ = ['algorithm', 'fp_type', 'fingerprint'] - - def __init__(self, rdclass, rdtype, algorithm, fp_type, - fingerprint): - super(SSHFP, self).__init__(rdclass, rdtype) - self.algorithm = algorithm - self.fp_type = fp_type - self.fingerprint = fingerprint - - def to_text(self, origin=None, relativize=True, **kw): - return '%d %d %s' % (self.algorithm, - self.fp_type, - dns.rdata._hexify(self.fingerprint, - chunksize=128)) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - algorithm = tok.get_uint8() - fp_type = tok.get_uint8() - chunks = [] - while 1: - t = tok.get().unescape() - if t.is_eol_or_eof(): - break - if not t.is_identifier(): - raise dns.exception.SyntaxError - chunks.append(t.value.encode()) - fingerprint = b''.join(chunks) - fingerprint = binascii.unhexlify(fingerprint) - return cls(rdclass, rdtype, algorithm, fp_type, fingerprint) - - def to_wire(self, file, compress=None, origin=None): - header = struct.pack("!BB", self.algorithm, self.fp_type) - file.write(header) - file.write(self.fingerprint) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - header = struct.unpack("!BB", wire[current: current + 2]) - current += 2 - rdlen -= 2 - fingerprint = wire[current: current + rdlen].unwrap() - return cls(rdclass, rdtype, header[0], header[1], fingerprint) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/TLSA.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/TLSA.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/TLSA.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/TLSA.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -# Copyright (C) 2005-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct -import binascii - -import dns.rdata -import dns.rdatatype - - -class TLSA(dns.rdata.Rdata): - - """TLSA record - - @ivar usage: The certificate usage - @type usage: int - @ivar selector: The selector field - @type selector: int - @ivar mtype: The 'matching type' field - @type mtype: int - @ivar cert: The 'Certificate Association Data' field - @type cert: string - @see: RFC 6698""" - - __slots__ = ['usage', 'selector', 'mtype', 'cert'] - - def __init__(self, rdclass, rdtype, usage, selector, - mtype, cert): - super(TLSA, self).__init__(rdclass, rdtype) - self.usage = usage - self.selector = selector - self.mtype = mtype - self.cert = cert - - def to_text(self, origin=None, relativize=True, **kw): - return '%d %d %d %s' % (self.usage, - self.selector, - self.mtype, - dns.rdata._hexify(self.cert, - chunksize=128)) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - usage = tok.get_uint8() - selector = tok.get_uint8() - mtype = tok.get_uint8() - cert_chunks = [] - while 1: - t = tok.get().unescape() - if t.is_eol_or_eof(): - break - if not t.is_identifier(): - raise dns.exception.SyntaxError - cert_chunks.append(t.value.encode()) - cert = b''.join(cert_chunks) - cert = binascii.unhexlify(cert) - return cls(rdclass, rdtype, usage, selector, mtype, cert) - - def to_wire(self, file, compress=None, origin=None): - header = struct.pack("!BBB", self.usage, self.selector, self.mtype) - file.write(header) - file.write(self.cert) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - header = struct.unpack("!BBB", wire[current: current + 3]) - current += 3 - rdlen -= 3 - cert = wire[current: current + rdlen].unwrap() - return cls(rdclass, rdtype, header[0], header[1], header[2], cert) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/TXT.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/TXT.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/TXT.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/TXT.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.txtbase - - -class TXT(dns.rdtypes.txtbase.TXTBase): - - """TXT record""" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/URI.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/URI.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/URI.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/URI.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# Copyright (C) 2015 Red Hat, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.rdata -import dns.name -from dns._compat import text_type - - -class URI(dns.rdata.Rdata): - - """URI record - - @ivar priority: the priority - @type priority: int - @ivar weight: the weight - @type weight: int - @ivar target: the target host - @type target: dns.name.Name object - @see: draft-faltstrom-uri-13""" - - __slots__ = ['priority', 'weight', 'target'] - - def __init__(self, rdclass, rdtype, priority, weight, target): - super(URI, self).__init__(rdclass, rdtype) - self.priority = priority - self.weight = weight - if len(target) < 1: - raise dns.exception.SyntaxError("URI target cannot be empty") - if isinstance(target, text_type): - self.target = target.encode() - else: - self.target = target - - def to_text(self, origin=None, relativize=True, **kw): - return '%d %d "%s"' % (self.priority, self.weight, - self.target.decode()) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - priority = tok.get_uint16() - weight = tok.get_uint16() - target = tok.get().unescape() - if not (target.is_quoted_string() or target.is_identifier()): - raise dns.exception.SyntaxError("URI target must be a string") - tok.get_eol() - return cls(rdclass, rdtype, priority, weight, target.value) - - def to_wire(self, file, compress=None, origin=None): - two_ints = struct.pack("!HH", self.priority, self.weight) - file.write(two_ints) - file.write(self.target) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - if rdlen < 5: - raise dns.exception.FormError('URI RR is shorter than 5 octets') - - (priority, weight) = struct.unpack('!HH', wire[current: current + 4]) - current += 4 - rdlen -= 4 - target = wire[current: current + rdlen] - current += rdlen - - return cls(rdclass, rdtype, priority, weight, target) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/X25.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/X25.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/ANY/X25.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/ANY/X25.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.rdata -import dns.tokenizer -from dns._compat import text_type - - -class X25(dns.rdata.Rdata): - - """X25 record - - @ivar address: the PSDN address - @type address: string - @see: RFC 1183""" - - __slots__ = ['address'] - - def __init__(self, rdclass, rdtype, address): - super(X25, self).__init__(rdclass, rdtype) - if isinstance(address, text_type): - self.address = address.encode() - else: - self.address = address - - def to_text(self, origin=None, relativize=True, **kw): - return '"%s"' % dns.rdata._escapify(self.address) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - address = tok.get_string() - tok.get_eol() - return cls(rdclass, rdtype, address) - - def to_wire(self, file, compress=None, origin=None): - l = len(self.address) - assert l < 256 - file.write(struct.pack('!B', l)) - file.write(self.address) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - l = wire[current] - current += 1 - rdlen -= 1 - if l != rdlen: - raise dns.exception.FormError - address = wire[current: current + l].unwrap() - return cls(rdclass, rdtype, address) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/dnskeybase.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/dnskeybase.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/dnskeybase.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/dnskeybase.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,136 +0,0 @@ -# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import base64 -import struct - -import dns.exception -import dns.dnssec -import dns.rdata - -# wildcard import -__all__ = ["SEP", "REVOKE", "ZONE", - "flags_to_text_set", "flags_from_text_set"] - -# flag constants -SEP = 0x0001 -REVOKE = 0x0080 -ZONE = 0x0100 - -_flag_by_text = { - 'SEP': SEP, - 'REVOKE': REVOKE, - 'ZONE': ZONE -} - -# We construct the inverse mapping programmatically to ensure that we -# cannot make any mistakes (e.g. omissions, cut-and-paste errors) that -# would cause the mapping not to be true inverse. -_flag_by_value = dict((y, x) for x, y in _flag_by_text.items()) - - -def flags_to_text_set(flags): - """Convert a DNSKEY flags value to set texts - @rtype: set([string])""" - - flags_set = set() - mask = 0x1 - while mask <= 0x8000: - if flags & mask: - text = _flag_by_value.get(mask) - if not text: - text = hex(mask) - flags_set.add(text) - mask <<= 1 - return flags_set - - -def flags_from_text_set(texts_set): - """Convert set of DNSKEY flag mnemonic texts to DNSKEY flag value - @rtype: int""" - - flags = 0 - for text in texts_set: - try: - flags += _flag_by_text[text] - except KeyError: - raise NotImplementedError( - "DNSKEY flag '%s' is not supported" % text) - return flags - - -class DNSKEYBase(dns.rdata.Rdata): - - """Base class for rdata that is like a DNSKEY record - - @ivar flags: the key flags - @type flags: int - @ivar protocol: the protocol for which this key may be used - @type protocol: int - @ivar algorithm: the algorithm used for the key - @type algorithm: int - @ivar key: the public key - @type key: string""" - - __slots__ = ['flags', 'protocol', 'algorithm', 'key'] - - def __init__(self, rdclass, rdtype, flags, protocol, algorithm, key): - super(DNSKEYBase, self).__init__(rdclass, rdtype) - self.flags = flags - self.protocol = protocol - self.algorithm = algorithm - self.key = key - - def to_text(self, origin=None, relativize=True, **kw): - return '%d %d %d %s' % (self.flags, self.protocol, self.algorithm, - dns.rdata._base64ify(self.key)) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - flags = tok.get_uint16() - protocol = tok.get_uint8() - algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) - chunks = [] - while 1: - t = tok.get().unescape() - if t.is_eol_or_eof(): - break - if not t.is_identifier(): - raise dns.exception.SyntaxError - chunks.append(t.value.encode()) - b64 = b''.join(chunks) - key = base64.b64decode(b64) - return cls(rdclass, rdtype, flags, protocol, algorithm, key) - - def to_wire(self, file, compress=None, origin=None): - header = struct.pack("!HBB", self.flags, self.protocol, self.algorithm) - file.write(header) - file.write(self.key) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - if rdlen < 4: - raise dns.exception.FormError - header = struct.unpack('!HBB', wire[current: current + 4]) - current += 4 - rdlen -= 4 - key = wire[current: current + rdlen].unwrap() - return cls(rdclass, rdtype, header[0], header[1], header[2], - key) - - def flags_to_text_set(self): - """Convert a DNSKEY flags value to set texts - @rtype: set([string])""" - return flags_to_text_set(self.flags) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/dsbase.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/dsbase.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/dsbase.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/dsbase.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -# Copyright (C) 2010, 2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct -import binascii - -import dns.rdata -import dns.rdatatype - - -class DSBase(dns.rdata.Rdata): - - """Base class for rdata that is like a DS record - - @ivar key_tag: the key tag - @type key_tag: int - @ivar algorithm: the algorithm - @type algorithm: int - @ivar digest_type: the digest type - @type digest_type: int - @ivar digest: the digest - @type digest: int - @see: draft-ietf-dnsext-delegation-signer-14.txt""" - - __slots__ = ['key_tag', 'algorithm', 'digest_type', 'digest'] - - def __init__(self, rdclass, rdtype, key_tag, algorithm, digest_type, - digest): - super(DSBase, self).__init__(rdclass, rdtype) - self.key_tag = key_tag - self.algorithm = algorithm - self.digest_type = digest_type - self.digest = digest - - def to_text(self, origin=None, relativize=True, **kw): - return '%d %d %d %s' % (self.key_tag, self.algorithm, - self.digest_type, - dns.rdata._hexify(self.digest, - chunksize=128)) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - key_tag = tok.get_uint16() - algorithm = tok.get_uint8() - digest_type = tok.get_uint8() - chunks = [] - while 1: - t = tok.get().unescape() - if t.is_eol_or_eof(): - break - if not t.is_identifier(): - raise dns.exception.SyntaxError - chunks.append(t.value.encode()) - digest = b''.join(chunks) - digest = binascii.unhexlify(digest) - return cls(rdclass, rdtype, key_tag, algorithm, digest_type, - digest) - - def to_wire(self, file, compress=None, origin=None): - header = struct.pack("!HBB", self.key_tag, self.algorithm, - self.digest_type) - file.write(header) - file.write(self.digest) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - header = struct.unpack("!HBB", wire[current: current + 4]) - current += 4 - rdlen -= 4 - digest = wire[current: current + rdlen].unwrap() - return cls(rdclass, rdtype, header[0], header[1], header[2], digest) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/euibase.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/euibase.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/euibase.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/euibase.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -# Copyright (C) 2015 Red Hat, Inc. -# Author: Petr Spacek -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED 'AS IS' AND RED HAT DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import binascii - -import dns.rdata -from dns._compat import xrange - - -class EUIBase(dns.rdata.Rdata): - - """EUIxx record - - @ivar fingerprint: xx-bit Extended Unique Identifier (EUI-xx) - @type fingerprint: string - @see: rfc7043.txt""" - - __slots__ = ['eui'] - # define these in subclasses - # byte_len = 6 # 0123456789ab (in hex) - # text_len = byte_len * 3 - 1 # 01-23-45-67-89-ab - - def __init__(self, rdclass, rdtype, eui): - super(EUIBase, self).__init__(rdclass, rdtype) - if len(eui) != self.byte_len: - raise dns.exception.FormError('EUI%s rdata has to have %s bytes' - % (self.byte_len * 8, self.byte_len)) - self.eui = eui - - def to_text(self, origin=None, relativize=True, **kw): - return dns.rdata._hexify(self.eui, chunksize=2).replace(' ', '-') - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - text = tok.get_string() - tok.get_eol() - if len(text) != cls.text_len: - raise dns.exception.SyntaxError( - 'Input text must have %s characters' % cls.text_len) - expected_dash_idxs = xrange(2, cls.byte_len * 3 - 1, 3) - for i in expected_dash_idxs: - if text[i] != '-': - raise dns.exception.SyntaxError('Dash expected at position %s' - % i) - text = text.replace('-', '') - try: - data = binascii.unhexlify(text.encode()) - except (ValueError, TypeError) as ex: - raise dns.exception.SyntaxError('Hex decoding error: %s' % str(ex)) - return cls(rdclass, rdtype, data) - - def to_wire(self, file, compress=None, origin=None): - file.write(self.eui) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - eui = wire[current:current + rdlen].unwrap() - return cls(rdclass, rdtype, eui) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/AAAA.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/AAAA.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/AAAA.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/AAAA.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.exception -import dns.inet -import dns.rdata -import dns.tokenizer - - -class AAAA(dns.rdata.Rdata): - - """AAAA record. - - @ivar address: an IPv6 address - @type address: string (in the standard IPv6 format)""" - - __slots__ = ['address'] - - def __init__(self, rdclass, rdtype, address): - super(AAAA, self).__init__(rdclass, rdtype) - # check that it's OK - dns.inet.inet_pton(dns.inet.AF_INET6, address) - self.address = address - - def to_text(self, origin=None, relativize=True, **kw): - return self.address - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - address = tok.get_identifier() - tok.get_eol() - return cls(rdclass, rdtype, address) - - def to_wire(self, file, compress=None, origin=None): - file.write(dns.inet.inet_pton(dns.inet.AF_INET6, self.address)) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - address = dns.inet.inet_ntop(dns.inet.AF_INET6, - wire[current: current + rdlen]) - return cls(rdclass, rdtype, address) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/APL.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/APL.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/APL.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/APL.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,161 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct -import binascii - -import dns.exception -import dns.inet -import dns.rdata -import dns.tokenizer -from dns._compat import xrange - - -class APLItem(object): - - """An APL list item. - - @ivar family: the address family (IANA address family registry) - @type family: int - @ivar negation: is this item negated? - @type negation: bool - @ivar address: the address - @type address: string - @ivar prefix: the prefix length - @type prefix: int - """ - - __slots__ = ['family', 'negation', 'address', 'prefix'] - - def __init__(self, family, negation, address, prefix): - self.family = family - self.negation = negation - self.address = address - self.prefix = prefix - - def __str__(self): - if self.negation: - return "!%d:%s/%s" % (self.family, self.address, self.prefix) - else: - return "%d:%s/%s" % (self.family, self.address, self.prefix) - - def to_wire(self, file): - if self.family == 1: - address = dns.inet.inet_pton(dns.inet.AF_INET, self.address) - elif self.family == 2: - address = dns.inet.inet_pton(dns.inet.AF_INET6, self.address) - else: - address = binascii.unhexlify(self.address) - # - # Truncate least significant zero bytes. - # - last = 0 - for i in xrange(len(address) - 1, -1, -1): - if address[i] != chr(0): - last = i + 1 - break - address = address[0: last] - l = len(address) - assert l < 128 - if self.negation: - l |= 0x80 - header = struct.pack('!HBB', self.family, self.prefix, l) - file.write(header) - file.write(address) - - -class APL(dns.rdata.Rdata): - - """APL record. - - @ivar items: a list of APL items - @type items: list of APL_Item - @see: RFC 3123""" - - __slots__ = ['items'] - - def __init__(self, rdclass, rdtype, items): - super(APL, self).__init__(rdclass, rdtype) - self.items = items - - def to_text(self, origin=None, relativize=True, **kw): - return ' '.join(map(str, self.items)) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - items = [] - while 1: - token = tok.get().unescape() - if token.is_eol_or_eof(): - break - item = token.value - if item[0] == '!': - negation = True - item = item[1:] - else: - negation = False - (family, rest) = item.split(':', 1) - family = int(family) - (address, prefix) = rest.split('/', 1) - prefix = int(prefix) - item = APLItem(family, negation, address, prefix) - items.append(item) - - return cls(rdclass, rdtype, items) - - def to_wire(self, file, compress=None, origin=None): - for item in self.items: - item.to_wire(file) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - items = [] - while 1: - if rdlen == 0: - break - if rdlen < 4: - raise dns.exception.FormError - header = struct.unpack('!HBB', wire[current: current + 4]) - afdlen = header[2] - if afdlen > 127: - negation = True - afdlen -= 128 - else: - negation = False - current += 4 - rdlen -= 4 - if rdlen < afdlen: - raise dns.exception.FormError - address = wire[current: current + afdlen].unwrap() - l = len(address) - if header[0] == 1: - if l < 4: - address += '\x00' * (4 - l) - address = dns.inet.inet_ntop(dns.inet.AF_INET, address) - elif header[0] == 2: - if l < 16: - address += '\x00' * (16 - l) - address = dns.inet.inet_ntop(dns.inet.AF_INET6, address) - else: - # - # This isn't really right according to the RFC, but it - # seems better than throwing an exception - # - address = address.encode('hex_codec') - current += afdlen - rdlen -= afdlen - item = APLItem(header[0], negation, address, header[1]) - items.append(item) - return cls(rdclass, rdtype, items) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/A.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/A.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/A.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/A.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.exception -import dns.ipv4 -import dns.rdata -import dns.tokenizer - - -class A(dns.rdata.Rdata): - - """A record. - - @ivar address: an IPv4 address - @type address: string (in the standard "dotted quad" format)""" - - __slots__ = ['address'] - - def __init__(self, rdclass, rdtype, address): - super(A, self).__init__(rdclass, rdtype) - # check that it's OK - dns.ipv4.inet_aton(address) - self.address = address - - def to_text(self, origin=None, relativize=True, **kw): - return self.address - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - address = tok.get_identifier() - tok.get_eol() - return cls(rdclass, rdtype, address) - - def to_wire(self, file, compress=None, origin=None): - file.write(dns.ipv4.inet_aton(self.address)) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - address = dns.ipv4.inet_ntoa(wire[current: current + rdlen]).decode() - return cls(rdclass, rdtype, address) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/DHCID.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/DHCID.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/DHCID.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/DHCID.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import base64 - -import dns.exception - - -class DHCID(dns.rdata.Rdata): - - """DHCID record - - @ivar data: the data (the content of the RR is opaque as far as the - DNS is concerned) - @type data: string - @see: RFC 4701""" - - __slots__ = ['data'] - - def __init__(self, rdclass, rdtype, data): - super(DHCID, self).__init__(rdclass, rdtype) - self.data = data - - def to_text(self, origin=None, relativize=True, **kw): - return dns.rdata._base64ify(self.data) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - chunks = [] - while 1: - t = tok.get().unescape() - if t.is_eol_or_eof(): - break - if not t.is_identifier(): - raise dns.exception.SyntaxError - chunks.append(t.value.encode()) - b64 = b''.join(chunks) - data = base64.b64decode(b64) - return cls(rdclass, rdtype, data) - - def to_wire(self, file, compress=None, origin=None): - file.write(self.data) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - data = wire[current: current + rdlen].unwrap() - return cls(rdclass, rdtype, data) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/__init__.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/__init__.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/__init__.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Class IN rdata type classes.""" - -__all__ = [ - 'A', - 'AAAA', - 'APL', - 'DHCID', - 'KX', - 'NAPTR', - 'NSAP', - 'NSAP_PTR', - 'PX', - 'SRV', - 'WKS', -] diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/IPSECKEY.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/IPSECKEY.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/IPSECKEY.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/IPSECKEY.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,148 +0,0 @@ -# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct -import base64 - -import dns.exception -import dns.inet -import dns.name - - -class IPSECKEY(dns.rdata.Rdata): - - """IPSECKEY record - - @ivar precedence: the precedence for this key data - @type precedence: int - @ivar gateway_type: the gateway type - @type gateway_type: int - @ivar algorithm: the algorithm to use - @type algorithm: int - @ivar gateway: the public key - @type gateway: None, IPv4 address, IPV6 address, or domain name - @ivar key: the public key - @type key: string - @see: RFC 4025""" - - __slots__ = ['precedence', 'gateway_type', 'algorithm', 'gateway', 'key'] - - def __init__(self, rdclass, rdtype, precedence, gateway_type, algorithm, - gateway, key): - super(IPSECKEY, self).__init__(rdclass, rdtype) - if gateway_type == 0: - if gateway != '.' and gateway is not None: - raise SyntaxError('invalid gateway for gateway type 0') - gateway = None - elif gateway_type == 1: - # check that it's OK - dns.inet.inet_pton(dns.inet.AF_INET, gateway) - elif gateway_type == 2: - # check that it's OK - dns.inet.inet_pton(dns.inet.AF_INET6, gateway) - elif gateway_type == 3: - pass - else: - raise SyntaxError( - 'invalid IPSECKEY gateway type: %d' % gateway_type) - self.precedence = precedence - self.gateway_type = gateway_type - self.algorithm = algorithm - self.gateway = gateway - self.key = key - - def to_text(self, origin=None, relativize=True, **kw): - if self.gateway_type == 0: - gateway = '.' - elif self.gateway_type == 1: - gateway = self.gateway - elif self.gateway_type == 2: - gateway = self.gateway - elif self.gateway_type == 3: - gateway = str(self.gateway.choose_relativity(origin, relativize)) - else: - raise ValueError('invalid gateway type') - return '%d %d %d %s %s' % (self.precedence, self.gateway_type, - self.algorithm, gateway, - dns.rdata._base64ify(self.key)) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - precedence = tok.get_uint8() - gateway_type = tok.get_uint8() - algorithm = tok.get_uint8() - if gateway_type == 3: - gateway = tok.get_name().choose_relativity(origin, relativize) - else: - gateway = tok.get_string() - chunks = [] - while 1: - t = tok.get().unescape() - if t.is_eol_or_eof(): - break - if not t.is_identifier(): - raise dns.exception.SyntaxError - chunks.append(t.value.encode()) - b64 = b''.join(chunks) - key = base64.b64decode(b64) - return cls(rdclass, rdtype, precedence, gateway_type, algorithm, - gateway, key) - - def to_wire(self, file, compress=None, origin=None): - header = struct.pack("!BBB", self.precedence, self.gateway_type, - self.algorithm) - file.write(header) - if self.gateway_type == 0: - pass - elif self.gateway_type == 1: - file.write(dns.inet.inet_pton(dns.inet.AF_INET, self.gateway)) - elif self.gateway_type == 2: - file.write(dns.inet.inet_pton(dns.inet.AF_INET6, self.gateway)) - elif self.gateway_type == 3: - self.gateway.to_wire(file, None, origin) - else: - raise ValueError('invalid gateway type') - file.write(self.key) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - if rdlen < 3: - raise dns.exception.FormError - header = struct.unpack('!BBB', wire[current: current + 3]) - gateway_type = header[1] - current += 3 - rdlen -= 3 - if gateway_type == 0: - gateway = None - elif gateway_type == 1: - gateway = dns.inet.inet_ntop(dns.inet.AF_INET, - wire[current: current + 4]) - current += 4 - rdlen -= 4 - elif gateway_type == 2: - gateway = dns.inet.inet_ntop(dns.inet.AF_INET6, - wire[current: current + 16]) - current += 16 - rdlen -= 16 - elif gateway_type == 3: - (gateway, cused) = dns.name.from_wire(wire[: current + rdlen], - current) - current += cused - rdlen -= cused - else: - raise dns.exception.FormError('invalid IPSECKEY gateway type') - key = wire[current: current + rdlen].unwrap() - return cls(rdclass, rdtype, header[0], gateway_type, header[2], - gateway, key) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/KX.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/KX.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/KX.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/KX.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.mxbase - - -class KX(dns.rdtypes.mxbase.UncompressedMX): - - """KX record""" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/NAPTR.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/NAPTR.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/NAPTR.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/NAPTR.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,125 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.name -import dns.rdata -from dns._compat import xrange, text_type - - -def _write_string(file, s): - l = len(s) - assert l < 256 - file.write(struct.pack('!B', l)) - file.write(s) - - -def _sanitize(value): - if isinstance(value, text_type): - return value.encode() - return value - - -class NAPTR(dns.rdata.Rdata): - - """NAPTR record - - @ivar order: order - @type order: int - @ivar preference: preference - @type preference: int - @ivar flags: flags - @type flags: string - @ivar service: service - @type service: string - @ivar regexp: regular expression - @type regexp: string - @ivar replacement: replacement name - @type replacement: dns.name.Name object - @see: RFC 3403""" - - __slots__ = ['order', 'preference', 'flags', 'service', 'regexp', - 'replacement'] - - def __init__(self, rdclass, rdtype, order, preference, flags, service, - regexp, replacement): - super(NAPTR, self).__init__(rdclass, rdtype) - self.flags = _sanitize(flags) - self.service = _sanitize(service) - self.regexp = _sanitize(regexp) - self.order = order - self.preference = preference - self.replacement = replacement - - def to_text(self, origin=None, relativize=True, **kw): - replacement = self.replacement.choose_relativity(origin, relativize) - return '%d %d "%s" "%s" "%s" %s' % \ - (self.order, self.preference, - dns.rdata._escapify(self.flags), - dns.rdata._escapify(self.service), - dns.rdata._escapify(self.regexp), - replacement) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - order = tok.get_uint16() - preference = tok.get_uint16() - flags = tok.get_string() - service = tok.get_string() - regexp = tok.get_string() - replacement = tok.get_name() - replacement = replacement.choose_relativity(origin, relativize) - tok.get_eol() - return cls(rdclass, rdtype, order, preference, flags, service, - regexp, replacement) - - def to_wire(self, file, compress=None, origin=None): - two_ints = struct.pack("!HH", self.order, self.preference) - file.write(two_ints) - _write_string(file, self.flags) - _write_string(file, self.service) - _write_string(file, self.regexp) - self.replacement.to_wire(file, compress, origin) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - (order, preference) = struct.unpack('!HH', wire[current: current + 4]) - current += 4 - rdlen -= 4 - strings = [] - for i in xrange(3): - l = wire[current] - current += 1 - rdlen -= 1 - if l > rdlen or rdlen < 0: - raise dns.exception.FormError - s = wire[current: current + l].unwrap() - current += l - rdlen -= l - strings.append(s) - (replacement, cused) = dns.name.from_wire(wire[: current + rdlen], - current) - if cused != rdlen: - raise dns.exception.FormError - if origin is not None: - replacement = replacement.relativize(origin) - return cls(rdclass, rdtype, order, preference, strings[0], strings[1], - strings[2], replacement) - - def choose_relativity(self, origin=None, relativize=True): - self.replacement = self.replacement.choose_relativity(origin, - relativize) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/NSAP_PTR.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/NSAP_PTR.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/NSAP_PTR.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/NSAP_PTR.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.rdtypes.nsbase - - -class NSAP_PTR(dns.rdtypes.nsbase.UncompressedNS): - - """NSAP-PTR record""" diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/NSAP.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/NSAP.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/NSAP.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/NSAP.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import binascii - -import dns.exception -import dns.rdata -import dns.tokenizer - - -class NSAP(dns.rdata.Rdata): - - """NSAP record. - - @ivar address: a NASP - @type address: string - @see: RFC 1706""" - - __slots__ = ['address'] - - def __init__(self, rdclass, rdtype, address): - super(NSAP, self).__init__(rdclass, rdtype) - self.address = address - - def to_text(self, origin=None, relativize=True, **kw): - return "0x%s" % binascii.hexlify(self.address).decode() - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - address = tok.get_string() - tok.get_eol() - if address[0:2] != '0x': - raise dns.exception.SyntaxError('string does not start with 0x') - address = address[2:].replace('.', '') - if len(address) % 2 != 0: - raise dns.exception.SyntaxError('hexstring has odd length') - address = binascii.unhexlify(address.encode()) - return cls(rdclass, rdtype, address) - - def to_wire(self, file, compress=None, origin=None): - file.write(self.address) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - address = wire[current: current + rdlen].unwrap() - return cls(rdclass, rdtype, address) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/PX.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/PX.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/PX.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/PX.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.rdata -import dns.name - - -class PX(dns.rdata.Rdata): - - """PX record. - - @ivar preference: the preference value - @type preference: int - @ivar map822: the map822 name - @type map822: dns.name.Name object - @ivar mapx400: the mapx400 name - @type mapx400: dns.name.Name object - @see: RFC 2163""" - - __slots__ = ['preference', 'map822', 'mapx400'] - - def __init__(self, rdclass, rdtype, preference, map822, mapx400): - super(PX, self).__init__(rdclass, rdtype) - self.preference = preference - self.map822 = map822 - self.mapx400 = mapx400 - - def to_text(self, origin=None, relativize=True, **kw): - map822 = self.map822.choose_relativity(origin, relativize) - mapx400 = self.mapx400.choose_relativity(origin, relativize) - return '%d %s %s' % (self.preference, map822, mapx400) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - preference = tok.get_uint16() - map822 = tok.get_name() - map822 = map822.choose_relativity(origin, relativize) - mapx400 = tok.get_name(None) - mapx400 = mapx400.choose_relativity(origin, relativize) - tok.get_eol() - return cls(rdclass, rdtype, preference, map822, mapx400) - - def to_wire(self, file, compress=None, origin=None): - pref = struct.pack("!H", self.preference) - file.write(pref) - self.map822.to_wire(file, None, origin) - self.mapx400.to_wire(file, None, origin) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - (preference, ) = struct.unpack('!H', wire[current: current + 2]) - current += 2 - rdlen -= 2 - (map822, cused) = dns.name.from_wire(wire[: current + rdlen], - current) - if cused > rdlen: - raise dns.exception.FormError - current += cused - rdlen -= cused - if origin is not None: - map822 = map822.relativize(origin) - (mapx400, cused) = dns.name.from_wire(wire[: current + rdlen], - current) - if cused != rdlen: - raise dns.exception.FormError - if origin is not None: - mapx400 = mapx400.relativize(origin) - return cls(rdclass, rdtype, preference, map822, mapx400) - - def choose_relativity(self, origin=None, relativize=True): - self.map822 = self.map822.choose_relativity(origin, relativize) - self.mapx400 = self.mapx400.choose_relativity(origin, relativize) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/SRV.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/SRV.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/SRV.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/SRV.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.rdata -import dns.name - - -class SRV(dns.rdata.Rdata): - - """SRV record - - @ivar priority: the priority - @type priority: int - @ivar weight: the weight - @type weight: int - @ivar port: the port of the service - @type port: int - @ivar target: the target host - @type target: dns.name.Name object - @see: RFC 2782""" - - __slots__ = ['priority', 'weight', 'port', 'target'] - - def __init__(self, rdclass, rdtype, priority, weight, port, target): - super(SRV, self).__init__(rdclass, rdtype) - self.priority = priority - self.weight = weight - self.port = port - self.target = target - - def to_text(self, origin=None, relativize=True, **kw): - target = self.target.choose_relativity(origin, relativize) - return '%d %d %d %s' % (self.priority, self.weight, self.port, - target) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - priority = tok.get_uint16() - weight = tok.get_uint16() - port = tok.get_uint16() - target = tok.get_name(None) - target = target.choose_relativity(origin, relativize) - tok.get_eol() - return cls(rdclass, rdtype, priority, weight, port, target) - - def to_wire(self, file, compress=None, origin=None): - three_ints = struct.pack("!HHH", self.priority, self.weight, self.port) - file.write(three_ints) - self.target.to_wire(file, compress, origin) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - (priority, weight, port) = struct.unpack('!HHH', - wire[current: current + 6]) - current += 6 - rdlen -= 6 - (target, cused) = dns.name.from_wire(wire[: current + rdlen], - current) - if cused != rdlen: - raise dns.exception.FormError - if origin is not None: - target = target.relativize(origin) - return cls(rdclass, rdtype, priority, weight, port, target) - - def choose_relativity(self, origin=None, relativize=True): - self.target = self.target.choose_relativity(origin, relativize) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/WKS.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/WKS.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/IN/WKS.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/IN/WKS.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import socket -import struct - -import dns.ipv4 -import dns.rdata -from dns._compat import xrange - -_proto_tcp = socket.getprotobyname('tcp') -_proto_udp = socket.getprotobyname('udp') - - -class WKS(dns.rdata.Rdata): - - """WKS record - - @ivar address: the address - @type address: string - @ivar protocol: the protocol - @type protocol: int - @ivar bitmap: the bitmap - @type bitmap: string - @see: RFC 1035""" - - __slots__ = ['address', 'protocol', 'bitmap'] - - def __init__(self, rdclass, rdtype, address, protocol, bitmap): - super(WKS, self).__init__(rdclass, rdtype) - self.address = address - self.protocol = protocol - if not isinstance(bitmap, bytearray): - self.bitmap = bytearray(bitmap) - else: - self.bitmap = bitmap - - def to_text(self, origin=None, relativize=True, **kw): - bits = [] - for i in xrange(0, len(self.bitmap)): - byte = self.bitmap[i] - for j in xrange(0, 8): - if byte & (0x80 >> j): - bits.append(str(i * 8 + j)) - text = ' '.join(bits) - return '%s %d %s' % (self.address, self.protocol, text) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - address = tok.get_string() - protocol = tok.get_string() - if protocol.isdigit(): - protocol = int(protocol) - else: - protocol = socket.getprotobyname(protocol) - bitmap = bytearray() - while 1: - token = tok.get().unescape() - if token.is_eol_or_eof(): - break - if token.value.isdigit(): - serv = int(token.value) - else: - if protocol != _proto_udp and protocol != _proto_tcp: - raise NotImplementedError("protocol must be TCP or UDP") - if protocol == _proto_udp: - protocol_text = "udp" - else: - protocol_text = "tcp" - serv = socket.getservbyname(token.value, protocol_text) - i = serv // 8 - l = len(bitmap) - if l < i + 1: - for j in xrange(l, i + 1): - bitmap.append(0) - bitmap[i] = bitmap[i] | (0x80 >> (serv % 8)) - bitmap = dns.rdata._truncate_bitmap(bitmap) - return cls(rdclass, rdtype, address, protocol, bitmap) - - def to_wire(self, file, compress=None, origin=None): - file.write(dns.ipv4.inet_aton(self.address)) - protocol = struct.pack('!B', self.protocol) - file.write(protocol) - file.write(self.bitmap) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - address = dns.ipv4.inet_ntoa(wire[current: current + 4]) - protocol, = struct.unpack('!B', wire[current + 4: current + 5]) - current += 5 - rdlen -= 5 - bitmap = wire[current: current + rdlen].unwrap() - return cls(rdclass, rdtype, address, protocol, bitmap) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/__init__.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/__init__.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/__init__.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS rdata type classes""" - -__all__ = [ - 'ANY', - 'IN', - 'euibase', - 'mxbase', - 'nsbase', -] diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/mxbase.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/mxbase.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/mxbase.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/mxbase.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,101 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""MX-like base classes.""" - -from io import BytesIO -import struct - -import dns.exception -import dns.rdata -import dns.name - - -class MXBase(dns.rdata.Rdata): - - """Base class for rdata that is like an MX record. - - @ivar preference: the preference value - @type preference: int - @ivar exchange: the exchange name - @type exchange: dns.name.Name object""" - - __slots__ = ['preference', 'exchange'] - - def __init__(self, rdclass, rdtype, preference, exchange): - super(MXBase, self).__init__(rdclass, rdtype) - self.preference = preference - self.exchange = exchange - - def to_text(self, origin=None, relativize=True, **kw): - exchange = self.exchange.choose_relativity(origin, relativize) - return '%d %s' % (self.preference, exchange) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - preference = tok.get_uint16() - exchange = tok.get_name() - exchange = exchange.choose_relativity(origin, relativize) - tok.get_eol() - return cls(rdclass, rdtype, preference, exchange) - - def to_wire(self, file, compress=None, origin=None): - pref = struct.pack("!H", self.preference) - file.write(pref) - self.exchange.to_wire(file, compress, origin) - - def to_digestable(self, origin=None): - return struct.pack("!H", self.preference) + \ - self.exchange.to_digestable(origin) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - (preference, ) = struct.unpack('!H', wire[current: current + 2]) - current += 2 - rdlen -= 2 - (exchange, cused) = dns.name.from_wire(wire[: current + rdlen], - current) - if cused != rdlen: - raise dns.exception.FormError - if origin is not None: - exchange = exchange.relativize(origin) - return cls(rdclass, rdtype, preference, exchange) - - def choose_relativity(self, origin=None, relativize=True): - self.exchange = self.exchange.choose_relativity(origin, relativize) - - -class UncompressedMX(MXBase): - - """Base class for rdata that is like an MX record, but whose name - is not compressed when converted to DNS wire format, and whose - digestable form is not downcased.""" - - def to_wire(self, file, compress=None, origin=None): - super(UncompressedMX, self).to_wire(file, None, origin) - - def to_digestable(self, origin=None): - f = BytesIO() - self.to_wire(f, None, origin) - return f.getvalue() - - -class UncompressedDowncasingMX(MXBase): - - """Base class for rdata that is like an MX record, but whose name - is not compressed when convert to DNS wire format.""" - - def to_wire(self, file, compress=None, origin=None): - super(UncompressedDowncasingMX, self).to_wire(file, None, origin) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/nsbase.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/nsbase.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/nsbase.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/nsbase.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""NS-like base classes.""" - -from io import BytesIO - -import dns.exception -import dns.rdata -import dns.name - - -class NSBase(dns.rdata.Rdata): - - """Base class for rdata that is like an NS record. - - @ivar target: the target name of the rdata - @type target: dns.name.Name object""" - - __slots__ = ['target'] - - def __init__(self, rdclass, rdtype, target): - super(NSBase, self).__init__(rdclass, rdtype) - self.target = target - - def to_text(self, origin=None, relativize=True, **kw): - target = self.target.choose_relativity(origin, relativize) - return str(target) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - target = tok.get_name() - target = target.choose_relativity(origin, relativize) - tok.get_eol() - return cls(rdclass, rdtype, target) - - def to_wire(self, file, compress=None, origin=None): - self.target.to_wire(file, compress, origin) - - def to_digestable(self, origin=None): - return self.target.to_digestable(origin) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - (target, cused) = dns.name.from_wire(wire[: current + rdlen], - current) - if cused != rdlen: - raise dns.exception.FormError - if origin is not None: - target = target.relativize(origin) - return cls(rdclass, rdtype, target) - - def choose_relativity(self, origin=None, relativize=True): - self.target = self.target.choose_relativity(origin, relativize) - - -class UncompressedNS(NSBase): - - """Base class for rdata that is like an NS record, but whose name - is not compressed when convert to DNS wire format, and whose - digestable form is not downcased.""" - - def to_wire(self, file, compress=None, origin=None): - super(UncompressedNS, self).to_wire(file, None, origin) - - def to_digestable(self, origin=None): - f = BytesIO() - self.to_wire(f, None, origin) - return f.getvalue() diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rdtypes/txtbase.py python-eventlet-0.24.1/eventlet/support/dns/rdtypes/txtbase.py --- python-eventlet-0.20.0/eventlet/support/dns/rdtypes/txtbase.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rdtypes/txtbase.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ -# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""TXT-like base class.""" - -import struct - -import dns.exception -import dns.rdata -import dns.tokenizer -from dns._compat import binary_type - - -class TXTBase(dns.rdata.Rdata): - - """Base class for rdata that is like a TXT record - - @ivar strings: the text strings - @type strings: list of string - @see: RFC 1035""" - - __slots__ = ['strings'] - - def __init__(self, rdclass, rdtype, strings): - super(TXTBase, self).__init__(rdclass, rdtype) - if isinstance(strings, str): - strings = [strings] - self.strings = strings[:] - - def to_text(self, origin=None, relativize=True, **kw): - txt = '' - prefix = '' - for s in self.strings: - txt += '%s"%s"' % (prefix, dns.rdata._escapify(s)) - prefix = ' ' - return txt - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): - strings = [] - while 1: - token = tok.get().unescape() - if token.is_eol_or_eof(): - break - if not (token.is_quoted_string() or token.is_identifier()): - raise dns.exception.SyntaxError("expected a string") - if len(token.value) > 255: - raise dns.exception.SyntaxError("string too long") - value = token.value - if isinstance(value, binary_type): - strings.append(value) - else: - strings.append(value.encode()) - if len(strings) == 0: - raise dns.exception.UnexpectedEnd - return cls(rdclass, rdtype, strings) - - def to_wire(self, file, compress=None, origin=None): - for s in self.strings: - l = len(s) - assert l < 256 - file.write(struct.pack('!B', l)) - file.write(s) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): - strings = [] - while rdlen > 0: - l = wire[current] - current += 1 - rdlen -= 1 - if l > rdlen: - raise dns.exception.FormError - s = wire[current: current + l].unwrap() - current += l - rdlen -= l - strings.append(s) - return cls(rdclass, rdtype, strings) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/renderer.py python-eventlet-0.24.1/eventlet/support/dns/renderer.py --- python-eventlet-0.20.0/eventlet/support/dns/renderer.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/renderer.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,329 +0,0 @@ -# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Help for building DNS wire format messages""" - -from io import BytesIO -import struct -import random -import time - -import dns.exception -import dns.tsig -from ._compat import long - - -QUESTION = 0 -ANSWER = 1 -AUTHORITY = 2 -ADDITIONAL = 3 - - -class Renderer(object): - - """Helper class for building DNS wire-format messages. - - Most applications can use the higher-level L{dns.message.Message} - class and its to_wire() method to generate wire-format messages. - This class is for those applications which need finer control - over the generation of messages. - - Typical use:: - - r = dns.renderer.Renderer(id=1, flags=0x80, max_size=512) - r.add_question(qname, qtype, qclass) - r.add_rrset(dns.renderer.ANSWER, rrset_1) - r.add_rrset(dns.renderer.ANSWER, rrset_2) - r.add_rrset(dns.renderer.AUTHORITY, ns_rrset) - r.add_edns(0, 0, 4096) - r.add_rrset(dns.renderer.ADDTIONAL, ad_rrset_1) - r.add_rrset(dns.renderer.ADDTIONAL, ad_rrset_2) - r.write_header() - r.add_tsig(keyname, secret, 300, 1, 0, '', request_mac) - wire = r.get_wire() - - @ivar output: where rendering is written - @type output: BytesIO object - @ivar id: the message id - @type id: int - @ivar flags: the message flags - @type flags: int - @ivar max_size: the maximum size of the message - @type max_size: int - @ivar origin: the origin to use when rendering relative names - @type origin: dns.name.Name object - @ivar compress: the compression table - @type compress: dict - @ivar section: the section currently being rendered - @type section: int (dns.renderer.QUESTION, dns.renderer.ANSWER, - dns.renderer.AUTHORITY, or dns.renderer.ADDITIONAL) - @ivar counts: list of the number of RRs in each section - @type counts: int list of length 4 - @ivar mac: the MAC of the rendered message (if TSIG was used) - @type mac: string - """ - - def __init__(self, id=None, flags=0, max_size=65535, origin=None): - """Initialize a new renderer. - - @param id: the message id - @type id: int - @param flags: the DNS message flags - @type flags: int - @param max_size: the maximum message size; the default is 65535. - If rendering results in a message greater than I{max_size}, - then L{dns.exception.TooBig} will be raised. - @type max_size: int - @param origin: the origin to use when rendering relative names - @type origin: dns.name.Name or None. - """ - - self.output = BytesIO() - if id is None: - self.id = random.randint(0, 65535) - else: - self.id = id - self.flags = flags - self.max_size = max_size - self.origin = origin - self.compress = {} - self.section = QUESTION - self.counts = [0, 0, 0, 0] - self.output.write(b'\x00' * 12) - self.mac = '' - - def _rollback(self, where): - """Truncate the output buffer at offset I{where}, and remove any - compression table entries that pointed beyond the truncation - point. - - @param where: the offset - @type where: int - """ - - self.output.seek(where) - self.output.truncate() - keys_to_delete = [] - for k, v in self.compress.items(): - if v >= where: - keys_to_delete.append(k) - for k in keys_to_delete: - del self.compress[k] - - def _set_section(self, section): - """Set the renderer's current section. - - Sections must be rendered order: QUESTION, ANSWER, AUTHORITY, - ADDITIONAL. Sections may be empty. - - @param section: the section - @type section: int - @raises dns.exception.FormError: an attempt was made to set - a section value less than the current section. - """ - - if self.section != section: - if self.section > section: - raise dns.exception.FormError - self.section = section - - def add_question(self, qname, rdtype, rdclass=dns.rdataclass.IN): - """Add a question to the message. - - @param qname: the question name - @type qname: dns.name.Name - @param rdtype: the question rdata type - @type rdtype: int - @param rdclass: the question rdata class - @type rdclass: int - """ - - self._set_section(QUESTION) - before = self.output.tell() - qname.to_wire(self.output, self.compress, self.origin) - self.output.write(struct.pack("!HH", rdtype, rdclass)) - after = self.output.tell() - if after >= self.max_size: - self._rollback(before) - raise dns.exception.TooBig - self.counts[QUESTION] += 1 - - def add_rrset(self, section, rrset, **kw): - """Add the rrset to the specified section. - - Any keyword arguments are passed on to the rdataset's to_wire() - routine. - - @param section: the section - @type section: int - @param rrset: the rrset - @type rrset: dns.rrset.RRset object - """ - - self._set_section(section) - before = self.output.tell() - n = rrset.to_wire(self.output, self.compress, self.origin, **kw) - after = self.output.tell() - if after >= self.max_size: - self._rollback(before) - raise dns.exception.TooBig - self.counts[section] += n - - def add_rdataset(self, section, name, rdataset, **kw): - """Add the rdataset to the specified section, using the specified - name as the owner name. - - Any keyword arguments are passed on to the rdataset's to_wire() - routine. - - @param section: the section - @type section: int - @param name: the owner name - @type name: dns.name.Name object - @param rdataset: the rdataset - @type rdataset: dns.rdataset.Rdataset object - """ - - self._set_section(section) - before = self.output.tell() - n = rdataset.to_wire(name, self.output, self.compress, self.origin, - **kw) - after = self.output.tell() - if after >= self.max_size: - self._rollback(before) - raise dns.exception.TooBig - self.counts[section] += n - - def add_edns(self, edns, ednsflags, payload, options=None): - """Add an EDNS OPT record to the message. - - @param edns: The EDNS level to use. - @type edns: int - @param ednsflags: EDNS flag values. - @type ednsflags: int - @param payload: The EDNS sender's payload field, which is the maximum - size of UDP datagram the sender can handle. - @type payload: int - @param options: The EDNS options list - @type options: list of dns.edns.Option instances - @see: RFC 2671 - """ - - # make sure the EDNS version in ednsflags agrees with edns - ednsflags &= long(0xFF00FFFF) - ednsflags |= (edns << 16) - self._set_section(ADDITIONAL) - before = self.output.tell() - self.output.write(struct.pack('!BHHIH', 0, dns.rdatatype.OPT, payload, - ednsflags, 0)) - if options is not None: - lstart = self.output.tell() - for opt in options: - stuff = struct.pack("!HH", opt.otype, 0) - self.output.write(stuff) - start = self.output.tell() - opt.to_wire(self.output) - end = self.output.tell() - assert end - start < 65536 - self.output.seek(start - 2) - stuff = struct.pack("!H", end - start) - self.output.write(stuff) - self.output.seek(0, 2) - lend = self.output.tell() - assert lend - lstart < 65536 - self.output.seek(lstart - 2) - stuff = struct.pack("!H", lend - lstart) - self.output.write(stuff) - self.output.seek(0, 2) - after = self.output.tell() - if after >= self.max_size: - self._rollback(before) - raise dns.exception.TooBig - self.counts[ADDITIONAL] += 1 - - def add_tsig(self, keyname, secret, fudge, id, tsig_error, other_data, - request_mac, algorithm=dns.tsig.default_algorithm): - """Add a TSIG signature to the message. - - @param keyname: the TSIG key name - @type keyname: dns.name.Name object - @param secret: the secret to use - @type secret: string - @param fudge: TSIG time fudge - @type fudge: int - @param id: the message id to encode in the tsig signature - @type id: int - @param tsig_error: TSIG error code; default is 0. - @type tsig_error: int - @param other_data: TSIG other data. - @type other_data: string - @param request_mac: This message is a response to the request which - had the specified MAC. - @type request_mac: string - @param algorithm: the TSIG algorithm to use - @type algorithm: dns.name.Name object - """ - - self._set_section(ADDITIONAL) - before = self.output.tell() - s = self.output.getvalue() - (tsig_rdata, self.mac, ctx) = dns.tsig.sign(s, - keyname, - secret, - int(time.time()), - fudge, - id, - tsig_error, - other_data, - request_mac, - algorithm=algorithm) - keyname.to_wire(self.output, self.compress, self.origin) - self.output.write(struct.pack('!HHIH', dns.rdatatype.TSIG, - dns.rdataclass.ANY, 0, 0)) - rdata_start = self.output.tell() - self.output.write(tsig_rdata) - after = self.output.tell() - assert after - rdata_start < 65536 - if after >= self.max_size: - self._rollback(before) - raise dns.exception.TooBig - self.output.seek(rdata_start - 2) - self.output.write(struct.pack('!H', after - rdata_start)) - self.counts[ADDITIONAL] += 1 - self.output.seek(10) - self.output.write(struct.pack('!H', self.counts[ADDITIONAL])) - self.output.seek(0, 2) - - def write_header(self): - """Write the DNS message header. - - Writing the DNS message header is done after all sections - have been rendered, but before the optional TSIG signature - is added. - """ - - self.output.seek(0) - self.output.write(struct.pack('!HHHHHH', self.id, self.flags, - self.counts[0], self.counts[1], - self.counts[2], self.counts[3])) - self.output.seek(0, 2) - - def get_wire(self): - """Return the wire format message. - - @rtype: string - """ - - return self.output.getvalue() diff -Nru python-eventlet-0.20.0/eventlet/support/dns/resolver.py python-eventlet-0.24.1/eventlet/support/dns/resolver.py --- python-eventlet-0.20.0/eventlet/support/dns/resolver.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/resolver.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,1407 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS stub resolver. - -@var default_resolver: The default resolver object -@type default_resolver: dns.resolver.Resolver object""" - -import socket -import sys -import time -import random - -try: - import threading as _threading -except ImportError: - import dummy_threading as _threading - -import dns.exception -import dns.flags -import dns.ipv4 -import dns.ipv6 -import dns.message -import dns.name -import dns.query -import dns.rcode -import dns.rdataclass -import dns.rdatatype -import dns.reversename -import dns.tsig -from ._compat import xrange, string_types - -if sys.platform == 'win32': - try: - import winreg as _winreg - except ImportError: - import _winreg # pylint: disable=import-error - -class NXDOMAIN(dns.exception.DNSException): - - """The DNS query name does not exist.""" - supp_kwargs = set(['qnames', 'responses']) - fmt = None # we have our own __str__ implementation - - def _check_kwargs(self, qnames, responses=None): - if not isinstance(qnames, (list, tuple, set)): - raise AttributeError("qnames must be a list, tuple or set") - if len(qnames) == 0: - raise AttributeError("qnames must contain at least one element") - if responses is None: - responses = {} - elif not isinstance(responses, dict): - raise AttributeError("responses must be a dict(qname=response)") - kwargs = dict(qnames=qnames, responses=responses) - return kwargs - - def __str__(self): - if 'qnames' not in self.kwargs: - return super(NXDOMAIN, self).__str__() - qnames = self.kwargs['qnames'] - if len(qnames) > 1: - msg = 'None of DNS query names exist' - else: - msg = self.__doc__[:-1] - qnames = ', '.join(map(str, qnames)) - return "%s: %s" % (msg, qnames) - - def canonical_name(self): - if not 'qnames' in self.kwargs: - raise TypeError("parametrized exception required") - IN = dns.rdataclass.IN - CNAME = dns.rdatatype.CNAME - cname = None - for qname in self.kwargs['qnames']: - response = self.kwargs['responses'][qname] - for answer in response.answer: - if answer.rdtype != CNAME or answer.rdclass != IN: - continue - cname = answer.items[0].target.to_text() - if cname is not None: - return dns.name.from_text(cname) - return self.kwargs['qnames'][0] - canonical_name = property(canonical_name, doc=( - "Return the unresolved canonical name.")) - - def __add__(self, e_nx): - """Augment by results from another NXDOMAIN exception.""" - qnames0 = list(self.kwargs.get('qnames', [])) - responses0 = dict(self.kwargs.get('responses', {})) - responses1 = e_nx.kwargs.get('responses', {}) - for qname1 in e_nx.kwargs.get('qnames', []): - if qname1 not in qnames0: - qnames0.append(qname1) - if qname1 in responses1: - responses0[qname1] = responses1[qname1] - return NXDOMAIN(qnames=qnames0, responses=responses0) - - -class YXDOMAIN(dns.exception.DNSException): - - """The DNS query name is too long after DNAME substitution.""" - -# The definition of the Timeout exception has moved from here to the -# dns.exception module. We keep dns.resolver.Timeout defined for -# backwards compatibility. - -Timeout = dns.exception.Timeout - - -class NoAnswer(dns.exception.DNSException): - - """The DNS response does not contain an answer to the question.""" - fmt = 'The DNS response does not contain an answer ' + \ - 'to the question: {query}' - supp_kwargs = set(['response']) - - def _fmt_kwargs(self, **kwargs): - return super(NoAnswer, self)._fmt_kwargs( - query=kwargs['response'].question) - - -class NoNameservers(dns.exception.DNSException): - - """All nameservers failed to answer the query. - - errors: list of servers and respective errors - The type of errors is - [(server ip address, any object convertible to string)]. - Non-empty errors list will add explanatory message () - """ - - msg = "All nameservers failed to answer the query." - fmt = "%s {query}: {errors}" % msg[:-1] - supp_kwargs = set(['request', 'errors']) - - def _fmt_kwargs(self, **kwargs): - srv_msgs = [] - for err in kwargs['errors']: - srv_msgs.append('Server %s %s port %s answered %s' % (err[0], - 'TCP' if err[1] else 'UDP', err[2], err[3])) - return super(NoNameservers, self)._fmt_kwargs( - query=kwargs['request'].question, errors='; '.join(srv_msgs)) - - -class NotAbsolute(dns.exception.DNSException): - - """An absolute domain name is required but a relative name was provided.""" - - -class NoRootSOA(dns.exception.DNSException): - - """There is no SOA RR at the DNS root name. This should never happen!""" - - -class NoMetaqueries(dns.exception.DNSException): - - """DNS metaqueries are not allowed.""" - - -class Answer(object): - - """DNS stub resolver answer - - Instances of this class bundle up the result of a successful DNS - resolution. - - For convenience, the answer object implements much of the sequence - protocol, forwarding to its rrset. E.g. "for a in answer" is - equivalent to "for a in answer.rrset", "answer[i]" is equivalent - to "answer.rrset[i]", and "answer[i:j]" is equivalent to - "answer.rrset[i:j]". - - Note that CNAMEs or DNAMEs in the response may mean that answer - node's name might not be the query name. - - @ivar qname: The query name - @type qname: dns.name.Name object - @ivar rdtype: The query type - @type rdtype: int - @ivar rdclass: The query class - @type rdclass: int - @ivar response: The response message - @type response: dns.message.Message object - @ivar rrset: The answer - @type rrset: dns.rrset.RRset object - @ivar expiration: The time when the answer expires - @type expiration: float (seconds since the epoch) - @ivar canonical_name: The canonical name of the query name - @type canonical_name: dns.name.Name object - """ - - def __init__(self, qname, rdtype, rdclass, response, - raise_on_no_answer=True): - self.qname = qname - self.rdtype = rdtype - self.rdclass = rdclass - self.response = response - min_ttl = -1 - rrset = None - for count in xrange(0, 15): - try: - rrset = response.find_rrset(response.answer, qname, - rdclass, rdtype) - if min_ttl == -1 or rrset.ttl < min_ttl: - min_ttl = rrset.ttl - break - except KeyError: - if rdtype != dns.rdatatype.CNAME: - try: - crrset = response.find_rrset(response.answer, - qname, - rdclass, - dns.rdatatype.CNAME) - if min_ttl == -1 or crrset.ttl < min_ttl: - min_ttl = crrset.ttl - for rd in crrset: - qname = rd.target - break - continue - except KeyError: - if raise_on_no_answer: - raise NoAnswer(response=response) - if raise_on_no_answer: - raise NoAnswer(response=response) - if rrset is None and raise_on_no_answer: - raise NoAnswer(response=response) - self.canonical_name = qname - self.rrset = rrset - if rrset is None: - while 1: - # Look for a SOA RR whose owner name is a superdomain - # of qname. - try: - srrset = response.find_rrset(response.authority, qname, - rdclass, dns.rdatatype.SOA) - if min_ttl == -1 or srrset.ttl < min_ttl: - min_ttl = srrset.ttl - if srrset[0].minimum < min_ttl: - min_ttl = srrset[0].minimum - break - except KeyError: - try: - qname = qname.parent() - except dns.name.NoParent: - break - self.expiration = time.time() + min_ttl - - def __getattr__(self, attr): - if attr == 'name': - return self.rrset.name - elif attr == 'ttl': - return self.rrset.ttl - elif attr == 'covers': - return self.rrset.covers - elif attr == 'rdclass': - return self.rrset.rdclass - elif attr == 'rdtype': - return self.rrset.rdtype - else: - raise AttributeError(attr) - - def __len__(self): - return self.rrset and len(self.rrset) or 0 - - def __iter__(self): - return self.rrset and iter(self.rrset) or iter(tuple()) - - def __getitem__(self, i): - return self.rrset[i] - - def __delitem__(self, i): - del self.rrset[i] - - -class Cache(object): - - """Simple DNS answer cache. - - @ivar data: A dictionary of cached data - @type data: dict - @ivar cleaning_interval: The number of seconds between cleanings. The - default is 300 (5 minutes). - @type cleaning_interval: float - @ivar next_cleaning: The time the cache should next be cleaned (in seconds - since the epoch.) - @type next_cleaning: float - """ - - def __init__(self, cleaning_interval=300.0): - """Initialize a DNS cache. - - @param cleaning_interval: the number of seconds between periodic - cleanings. The default is 300.0 - @type cleaning_interval: float. - """ - - self.data = {} - self.cleaning_interval = cleaning_interval - self.next_cleaning = time.time() + self.cleaning_interval - self.lock = _threading.Lock() - - def _maybe_clean(self): - """Clean the cache if it's time to do so.""" - - now = time.time() - if self.next_cleaning <= now: - keys_to_delete = [] - for (k, v) in self.data.items(): - if v.expiration <= now: - keys_to_delete.append(k) - for k in keys_to_delete: - del self.data[k] - now = time.time() - self.next_cleaning = now + self.cleaning_interval - - def get(self, key): - """Get the answer associated with I{key}. Returns None if - no answer is cached for the key. - @param key: the key - @type key: (dns.name.Name, int, int) tuple whose values are the - query name, rdtype, and rdclass. - @rtype: dns.resolver.Answer object or None - """ - - try: - self.lock.acquire() - self._maybe_clean() - v = self.data.get(key) - if v is None or v.expiration <= time.time(): - return None - return v - finally: - self.lock.release() - - def put(self, key, value): - """Associate key and value in the cache. - @param key: the key - @type key: (dns.name.Name, int, int) tuple whose values are the - query name, rdtype, and rdclass. - @param value: The answer being cached - @type value: dns.resolver.Answer object - """ - - try: - self.lock.acquire() - self._maybe_clean() - self.data[key] = value - finally: - self.lock.release() - - def flush(self, key=None): - """Flush the cache. - - If I{key} is specified, only that item is flushed. Otherwise - the entire cache is flushed. - - @param key: the key to flush - @type key: (dns.name.Name, int, int) tuple or None - """ - - try: - self.lock.acquire() - if key is not None: - if key in self.data: - del self.data[key] - else: - self.data = {} - self.next_cleaning = time.time() + self.cleaning_interval - finally: - self.lock.release() - - -class LRUCacheNode(object): - - """LRUCache node. - """ - - def __init__(self, key, value): - self.key = key - self.value = value - self.prev = self - self.next = self - - def link_before(self, node): - self.prev = node.prev - self.next = node - node.prev.next = self - node.prev = self - - def link_after(self, node): - self.prev = node - self.next = node.next - node.next.prev = self - node.next = self - - def unlink(self): - self.next.prev = self.prev - self.prev.next = self.next - - -class LRUCache(object): - - """Bounded least-recently-used DNS answer cache. - - This cache is better than the simple cache (above) if you're - running a web crawler or other process that does a lot of - resolutions. The LRUCache has a maximum number of nodes, and when - it is full, the least-recently used node is removed to make space - for a new one. - - @ivar data: A dictionary of cached data - @type data: dict - @ivar sentinel: sentinel node for circular doubly linked list of nodes - @type sentinel: LRUCacheNode object - @ivar max_size: The maximum number of nodes - @type max_size: int - """ - - def __init__(self, max_size=100000): - """Initialize a DNS cache. - - @param max_size: The maximum number of nodes to cache; the default is - 100,000. Must be greater than 1. - @type max_size: int - """ - self.data = {} - self.set_max_size(max_size) - self.sentinel = LRUCacheNode(None, None) - self.lock = _threading.Lock() - - def set_max_size(self, max_size): - if max_size < 1: - max_size = 1 - self.max_size = max_size - - def get(self, key): - """Get the answer associated with I{key}. Returns None if - no answer is cached for the key. - @param key: the key - @type key: (dns.name.Name, int, int) tuple whose values are the - query name, rdtype, and rdclass. - @rtype: dns.resolver.Answer object or None - """ - try: - self.lock.acquire() - node = self.data.get(key) - if node is None: - return None - # Unlink because we're either going to move the node to the front - # of the LRU list or we're going to free it. - node.unlink() - if node.value.expiration <= time.time(): - del self.data[node.key] - return None - node.link_after(self.sentinel) - return node.value - finally: - self.lock.release() - - def put(self, key, value): - """Associate key and value in the cache. - @param key: the key - @type key: (dns.name.Name, int, int) tuple whose values are the - query name, rdtype, and rdclass. - @param value: The answer being cached - @type value: dns.resolver.Answer object - """ - try: - self.lock.acquire() - node = self.data.get(key) - if node is not None: - node.unlink() - del self.data[node.key] - while len(self.data) >= self.max_size: - node = self.sentinel.prev - node.unlink() - del self.data[node.key] - node = LRUCacheNode(key, value) - node.link_after(self.sentinel) - self.data[key] = node - finally: - self.lock.release() - - def flush(self, key=None): - """Flush the cache. - - If I{key} is specified, only that item is flushed. Otherwise - the entire cache is flushed. - - @param key: the key to flush - @type key: (dns.name.Name, int, int) tuple or None - """ - try: - self.lock.acquire() - if key is not None: - node = self.data.get(key) - if node is not None: - node.unlink() - del self.data[node.key] - else: - node = self.sentinel.next - while node != self.sentinel: - next = node.next - node.prev = None - node.next = None - node = next - self.data = {} - finally: - self.lock.release() - - -class Resolver(object): - - """DNS stub resolver - - @ivar domain: The domain of this host - @type domain: dns.name.Name object - @ivar nameservers: A list of nameservers to query. Each nameserver is - a string which contains the IP address of a nameserver. - @type nameservers: list of strings - @ivar search: The search list. If the query name is a relative name, - the resolver will construct an absolute query name by appending the search - names one by one to the query name. - @type search: list of dns.name.Name objects - @ivar port: The port to which to send queries. The default is 53. - @type port: int - @ivar timeout: The number of seconds to wait for a response from a - server, before timing out. - @type timeout: float - @ivar lifetime: The total number of seconds to spend trying to get an - answer to the question. If the lifetime expires, a Timeout exception - will occur. - @type lifetime: float - @ivar keyring: The TSIG keyring to use. The default is None. - @type keyring: dict - @ivar keyname: The TSIG keyname to use. The default is None. - @type keyname: dns.name.Name object - @ivar keyalgorithm: The TSIG key algorithm to use. The default is - dns.tsig.default_algorithm. - @type keyalgorithm: string - @ivar edns: The EDNS level to use. The default is -1, no Edns. - @type edns: int - @ivar ednsflags: The EDNS flags - @type ednsflags: int - @ivar payload: The EDNS payload size. The default is 0. - @type payload: int - @ivar flags: The message flags to use. The default is None (i.e. not - overwritten) - @type flags: int - @ivar cache: The cache to use. The default is None. - @type cache: dns.resolver.Cache object - @ivar retry_servfail: should we retry a nameserver if it says SERVFAIL? - The default is 'false'. - @type retry_servfail: bool - """ - - def __init__(self, filename='/etc/resolv.conf', configure=True): - """Initialize a resolver instance. - - @param filename: The filename of a configuration file in - standard /etc/resolv.conf format. This parameter is meaningful - only when I{configure} is true and the platform is POSIX. - @type filename: string or file object - @param configure: If True (the default), the resolver instance - is configured in the normal fashion for the operating system - the resolver is running on. (I.e. a /etc/resolv.conf file on - POSIX systems and from the registry on Windows systems.) - @type configure: bool""" - - self.domain = None - self.nameservers = None - self.nameserver_ports = None - self.port = None - self.search = None - self.timeout = None - self.lifetime = None - self.keyring = None - self.keyname = None - self.keyalgorithm = None - self.edns = None - self.ednsflags = None - self.payload = None - self.cache = None - self.flags = None - self.retry_servfail = False - self.rotate = False - - self.reset() - if configure: - if sys.platform == 'win32': - self.read_registry() - elif filename: - self.read_resolv_conf(filename) - - def reset(self): - """Reset all resolver configuration to the defaults.""" - self.domain = \ - dns.name.Name(dns.name.from_text(socket.gethostname())[1:]) - if len(self.domain) == 0: - self.domain = dns.name.root - self.nameservers = [] - self.nameserver_ports = {} - self.port = 53 - self.search = [] - self.timeout = 2.0 - self.lifetime = 30.0 - self.keyring = None - self.keyname = None - self.keyalgorithm = dns.tsig.default_algorithm - self.edns = -1 - self.ednsflags = 0 - self.payload = 0 - self.cache = None - self.flags = None - self.retry_servfail = False - self.rotate = False - - def read_resolv_conf(self, f): - """Process f as a file in the /etc/resolv.conf format. If f is - a string, it is used as the name of the file to open; otherwise it - is treated as the file itself.""" - if isinstance(f, string_types): - try: - f = open(f, 'r') - except IOError: - # /etc/resolv.conf doesn't exist, can't be read, etc. - # We'll just use the default resolver configuration. - self.nameservers = ['127.0.0.1'] - return - want_close = True - else: - want_close = False - try: - for l in f: - if len(l) == 0 or l[0] == '#' or l[0] == ';': - continue - tokens = l.split() - - # Any line containing less than 2 tokens is malformed - if len(tokens) < 2: - continue - - if tokens[0] == 'nameserver': - self.nameservers.append(tokens[1]) - elif tokens[0] == 'domain': - self.domain = dns.name.from_text(tokens[1]) - elif tokens[0] == 'search': - for suffix in tokens[1:]: - self.search.append(dns.name.from_text(suffix)) - elif tokens[0] == 'options': - if 'rotate' in tokens[1:]: - self.rotate = True - finally: - if want_close: - f.close() - if len(self.nameservers) == 0: - self.nameservers.append('127.0.0.1') - - def _determine_split_char(self, entry): - # - # The windows registry irritatingly changes the list element - # delimiter in between ' ' and ',' (and vice-versa) in various - # versions of windows. - # - if entry.find(' ') >= 0: - split_char = ' ' - elif entry.find(',') >= 0: - split_char = ',' - else: - # probably a singleton; treat as a space-separated list. - split_char = ' ' - return split_char - - def _config_win32_nameservers(self, nameservers): - """Configure a NameServer registry entry.""" - # we call str() on nameservers to convert it from unicode to ascii - nameservers = str(nameservers) - split_char = self._determine_split_char(nameservers) - ns_list = nameservers.split(split_char) - for ns in ns_list: - if ns not in self.nameservers: - self.nameservers.append(ns) - - def _config_win32_domain(self, domain): - """Configure a Domain registry entry.""" - # we call str() on domain to convert it from unicode to ascii - self.domain = dns.name.from_text(str(domain)) - - def _config_win32_search(self, search): - """Configure a Search registry entry.""" - # we call str() on search to convert it from unicode to ascii - search = str(search) - split_char = self._determine_split_char(search) - search_list = search.split(split_char) - for s in search_list: - if s not in self.search: - self.search.append(dns.name.from_text(s)) - - def _config_win32_fromkey(self, key): - """Extract DNS info from a registry key.""" - try: - servers, rtype = _winreg.QueryValueEx(key, 'NameServer') - except WindowsError: # pylint: disable=undefined-variable - servers = None - if servers: - self._config_win32_nameservers(servers) - try: - dom, rtype = _winreg.QueryValueEx(key, 'Domain') - if dom: - self._config_win32_domain(dom) - except WindowsError: # pylint: disable=undefined-variable - pass - else: - try: - servers, rtype = _winreg.QueryValueEx(key, 'DhcpNameServer') - except WindowsError: # pylint: disable=undefined-variable - servers = None - if servers: - self._config_win32_nameservers(servers) - try: - dom, rtype = _winreg.QueryValueEx(key, 'DhcpDomain') - if dom: - self._config_win32_domain(dom) - except WindowsError: # pylint: disable=undefined-variable - pass - try: - search, rtype = _winreg.QueryValueEx(key, 'SearchList') - except WindowsError: # pylint: disable=undefined-variable - search = None - if search: - self._config_win32_search(search) - - def read_registry(self): - """Extract resolver configuration from the Windows registry.""" - lm = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - want_scan = False - try: - try: - # XP, 2000 - tcp_params = _winreg.OpenKey(lm, - r'SYSTEM\CurrentControlSet' - r'\Services\Tcpip\Parameters') - want_scan = True - except EnvironmentError: - # ME - tcp_params = _winreg.OpenKey(lm, - r'SYSTEM\CurrentControlSet' - r'\Services\VxD\MSTCP') - try: - self._config_win32_fromkey(tcp_params) - finally: - tcp_params.Close() - if want_scan: - interfaces = _winreg.OpenKey(lm, - r'SYSTEM\CurrentControlSet' - r'\Services\Tcpip\Parameters' - r'\Interfaces') - try: - i = 0 - while True: - try: - guid = _winreg.EnumKey(interfaces, i) - i += 1 - key = _winreg.OpenKey(interfaces, guid) - if not self._win32_is_nic_enabled(lm, guid, key): - continue - try: - self._config_win32_fromkey(key) - finally: - key.Close() - except EnvironmentError: - break - finally: - interfaces.Close() - finally: - lm.Close() - - def _win32_is_nic_enabled(self, lm, guid, interface_key): - # Look in the Windows Registry to determine whether the network - # interface corresponding to the given guid is enabled. - # - # (Code contributed by Paul Marks, thanks!) - # - try: - # This hard-coded location seems to be consistent, at least - # from Windows 2000 through Vista. - connection_key = _winreg.OpenKey( - lm, - r'SYSTEM\CurrentControlSet\Control\Network' - r'\{4D36E972-E325-11CE-BFC1-08002BE10318}' - r'\%s\Connection' % guid) - - try: - # The PnpInstanceID points to a key inside Enum - (pnp_id, ttype) = _winreg.QueryValueEx( - connection_key, 'PnpInstanceID') - - if ttype != _winreg.REG_SZ: - raise ValueError - - device_key = _winreg.OpenKey( - lm, r'SYSTEM\CurrentControlSet\Enum\%s' % pnp_id) - - try: - # Get ConfigFlags for this device - (flags, ttype) = _winreg.QueryValueEx( - device_key, 'ConfigFlags') - - if ttype != _winreg.REG_DWORD: - raise ValueError - - # Based on experimentation, bit 0x1 indicates that the - # device is disabled. - return not flags & 0x1 - - finally: - device_key.Close() - finally: - connection_key.Close() - except (EnvironmentError, ValueError): - # Pre-vista, enabled interfaces seem to have a non-empty - # NTEContextList; this was how dnspython detected enabled - # nics before the code above was contributed. We've retained - # the old method since we don't know if the code above works - # on Windows 95/98/ME. - try: - (nte, ttype) = _winreg.QueryValueEx(interface_key, - 'NTEContextList') - return nte is not None - except WindowsError: # pylint: disable=undefined-variable - return False - - def _compute_timeout(self, start): - now = time.time() - duration = now - start - if duration < 0: - if duration < -1: - # Time going backwards is bad. Just give up. - raise Timeout(timeout=duration) - else: - # Time went backwards, but only a little. This can - # happen, e.g. under vmware with older linux kernels. - # Pretend it didn't happen. - now = start - if duration >= self.lifetime: - raise Timeout(timeout=duration) - return min(self.lifetime - duration, self.timeout) - - def query(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, - tcp=False, source=None, raise_on_no_answer=True, source_port=0): - """Query nameservers to find the answer to the question. - - The I{qname}, I{rdtype}, and I{rdclass} parameters may be objects - of the appropriate type, or strings that can be converted into objects - of the appropriate type. E.g. For I{rdtype} the integer 2 and the - the string 'NS' both mean to query for records with DNS rdata type NS. - - @param qname: the query name - @type qname: dns.name.Name object or string - @param rdtype: the query type - @type rdtype: int or string - @param rdclass: the query class - @type rdclass: int or string - @param tcp: use TCP to make the query (default is False). - @type tcp: bool - @param source: bind to this IP address (defaults to machine default - IP). - @type source: IP address in dotted quad notation - @param raise_on_no_answer: raise NoAnswer if there's no answer - (defaults is True). - @type raise_on_no_answer: bool - @param source_port: The port from which to send the message. - The default is 0. - @type source_port: int - @rtype: dns.resolver.Answer instance - @raises Timeout: no answers could be found in the specified lifetime - @raises NXDOMAIN: the query name does not exist - @raises YXDOMAIN: the query name is too long after DNAME substitution - @raises NoAnswer: the response did not contain an answer and - raise_on_no_answer is True. - @raises NoNameservers: no non-broken nameservers are available to - answer the question.""" - - if isinstance(qname, string_types): - qname = dns.name.from_text(qname, None) - if isinstance(rdtype, string_types): - rdtype = dns.rdatatype.from_text(rdtype) - if dns.rdatatype.is_metatype(rdtype): - raise NoMetaqueries - if isinstance(rdclass, string_types): - rdclass = dns.rdataclass.from_text(rdclass) - if dns.rdataclass.is_metaclass(rdclass): - raise NoMetaqueries - qnames_to_try = [] - if qname.is_absolute(): - qnames_to_try.append(qname) - else: - if len(qname) > 1: - qnames_to_try.append(qname.concatenate(dns.name.root)) - if self.search: - for suffix in self.search: - qnames_to_try.append(qname.concatenate(suffix)) - else: - qnames_to_try.append(qname.concatenate(self.domain)) - all_nxdomain = True - nxdomain_responses = {} - start = time.time() - _qname = None # make pylint happy - for _qname in qnames_to_try: - if self.cache: - answer = self.cache.get((_qname, rdtype, rdclass)) - if answer is not None: - if answer.rrset is None and raise_on_no_answer: - raise NoAnswer(response=answer.response) - else: - return answer - request = dns.message.make_query(_qname, rdtype, rdclass) - if self.keyname is not None: - request.use_tsig(self.keyring, self.keyname, - algorithm=self.keyalgorithm) - request.use_edns(self.edns, self.ednsflags, self.payload) - if self.flags is not None: - request.flags = self.flags - response = None - # - # make a copy of the servers list so we can alter it later. - # - nameservers = self.nameservers[:] - errors = [] - if self.rotate: - random.shuffle(nameservers) - backoff = 0.10 - while response is None: - if len(nameservers) == 0: - raise NoNameservers(request=request, errors=errors) - for nameserver in nameservers[:]: - timeout = self._compute_timeout(start) - port = self.nameserver_ports.get(nameserver, self.port) - try: - tcp_attempt = tcp - if tcp: - response = dns.query.tcp(request, nameserver, - timeout, port, - source=source, - source_port=source_port) - else: - response = dns.query.udp(request, nameserver, - timeout, port, - source=source, - source_port=source_port) - if response.flags & dns.flags.TC: - # Response truncated; retry with TCP. - tcp_attempt = True - timeout = self._compute_timeout(start) - response = \ - dns.query.tcp(request, nameserver, - timeout, port, - source=source, - source_port=source_port) - except (socket.error, dns.exception.Timeout) as ex: - # - # Communication failure or timeout. Go to the - # next server - # - errors.append((nameserver, tcp_attempt, port, ex, - response)) - response = None - continue - except dns.query.UnexpectedSource as ex: - # - # Who knows? Keep going. - # - errors.append((nameserver, tcp_attempt, port, ex, - response)) - response = None - continue - except dns.exception.FormError as ex: - # - # We don't understand what this server is - # saying. Take it out of the mix and - # continue. - # - nameservers.remove(nameserver) - errors.append((nameserver, tcp_attempt, port, ex, - response)) - response = None - continue - except EOFError as ex: - # - # We're using TCP and they hung up on us. - # Probably they don't support TCP (though - # they're supposed to!). Take it out of the - # mix and continue. - # - nameservers.remove(nameserver) - errors.append((nameserver, tcp_attempt, port, ex, - response)) - response = None - continue - rcode = response.rcode() - if rcode == dns.rcode.YXDOMAIN: - ex = YXDOMAIN() - errors.append((nameserver, tcp_attempt, port, ex, - response)) - raise ex - if rcode == dns.rcode.NOERROR or \ - rcode == dns.rcode.NXDOMAIN: - break - # - # We got a response, but we're not happy with the - # rcode in it. Remove the server from the mix if - # the rcode isn't SERVFAIL. - # - if rcode != dns.rcode.SERVFAIL or not self.retry_servfail: - nameservers.remove(nameserver) - errors.append((nameserver, tcp_attempt, port, - dns.rcode.to_text(rcode), response)) - response = None - if response is not None: - break - # - # All nameservers failed! - # - if len(nameservers) > 0: - # - # But we still have servers to try. Sleep a bit - # so we don't pound them! - # - timeout = self._compute_timeout(start) - sleep_time = min(timeout, backoff) - backoff *= 2 - time.sleep(sleep_time) - if response.rcode() == dns.rcode.NXDOMAIN: - nxdomain_responses[_qname] = response - continue - all_nxdomain = False - break - if all_nxdomain: - raise NXDOMAIN(qnames=qnames_to_try, responses=nxdomain_responses) - answer = Answer(_qname, rdtype, rdclass, response, - raise_on_no_answer) - if self.cache: - self.cache.put((_qname, rdtype, rdclass), answer) - return answer - - def use_tsig(self, keyring, keyname=None, - algorithm=dns.tsig.default_algorithm): - """Add a TSIG signature to the query. - - @param keyring: The TSIG keyring to use; defaults to None. - @type keyring: dict - @param keyname: The name of the TSIG key to use; defaults to None. - The key must be defined in the keyring. If a keyring is specified - but a keyname is not, then the key used will be the first key in the - keyring. Note that the order of keys in a dictionary is not defined, - so applications should supply a keyname when a keyring is used, unless - they know the keyring contains only one key. - @param algorithm: The TSIG key algorithm to use. The default - is dns.tsig.default_algorithm. - @type algorithm: string""" - self.keyring = keyring - if keyname is None: - self.keyname = list(self.keyring.keys())[0] - else: - self.keyname = keyname - self.keyalgorithm = algorithm - - def use_edns(self, edns, ednsflags, payload): - """Configure Edns. - - @param edns: The EDNS level to use. The default is -1, no Edns. - @type edns: int - @param ednsflags: The EDNS flags - @type ednsflags: int - @param payload: The EDNS payload size. The default is 0. - @type payload: int""" - - if edns is None: - edns = -1 - self.edns = edns - self.ednsflags = ednsflags - self.payload = payload - - def set_flags(self, flags): - """Overrides the default flags with your own - - @param flags: The flags to overwrite the default with - @type flags: int""" - self.flags = flags - -default_resolver = None - - -def get_default_resolver(): - """Get the default resolver, initializing it if necessary.""" - if default_resolver is None: - reset_default_resolver() - return default_resolver - - -def reset_default_resolver(): - """Re-initialize default resolver. - - resolv.conf will be re-read immediatelly. - """ - global default_resolver - default_resolver = Resolver() - - -def query(qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, - tcp=False, source=None, raise_on_no_answer=True, - source_port=0): - """Query nameservers to find the answer to the question. - - This is a convenience function that uses the default resolver - object to make the query. - @see: L{dns.resolver.Resolver.query} for more information on the - parameters.""" - return get_default_resolver().query(qname, rdtype, rdclass, tcp, source, - raise_on_no_answer, source_port) - - -def zone_for_name(name, rdclass=dns.rdataclass.IN, tcp=False, resolver=None): - """Find the name of the zone which contains the specified name. - - @param name: the query name - @type name: absolute dns.name.Name object or string - @param rdclass: The query class - @type rdclass: int - @param tcp: use TCP to make the query (default is False). - @type tcp: bool - @param resolver: the resolver to use - @type resolver: dns.resolver.Resolver object or None - @rtype: dns.name.Name""" - - if isinstance(name, string_types): - name = dns.name.from_text(name, dns.name.root) - if resolver is None: - resolver = get_default_resolver() - if not name.is_absolute(): - raise NotAbsolute(name) - while 1: - try: - answer = resolver.query(name, dns.rdatatype.SOA, rdclass, tcp) - if answer.rrset.name == name: - return name - # otherwise we were CNAMEd or DNAMEd and need to look higher - except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): - pass - try: - name = name.parent() - except dns.name.NoParent: - raise NoRootSOA - -# -# Support for overriding the system resolver for all python code in the -# running process. -# - -_protocols_for_socktype = { - socket.SOCK_DGRAM: [socket.SOL_UDP], - socket.SOCK_STREAM: [socket.SOL_TCP], -} - -_resolver = None -_original_getaddrinfo = socket.getaddrinfo -_original_getnameinfo = socket.getnameinfo -_original_getfqdn = socket.getfqdn -_original_gethostbyname = socket.gethostbyname -_original_gethostbyname_ex = socket.gethostbyname_ex -_original_gethostbyaddr = socket.gethostbyaddr - - -def _getaddrinfo(host=None, service=None, family=socket.AF_UNSPEC, socktype=0, - proto=0, flags=0): - if flags & (socket.AI_ADDRCONFIG | socket.AI_V4MAPPED) != 0: - raise NotImplementedError - if host is None and service is None: - raise socket.gaierror(socket.EAI_NONAME) - v6addrs = [] - v4addrs = [] - canonical_name = None - try: - # Is host None or a V6 address literal? - if host is None: - canonical_name = 'localhost' - if flags & socket.AI_PASSIVE != 0: - v6addrs.append('::') - v4addrs.append('0.0.0.0') - else: - v6addrs.append('::1') - v4addrs.append('127.0.0.1') - else: - parts = host.split('%') - if len(parts) == 2: - ahost = parts[0] - else: - ahost = host - addr = dns.ipv6.inet_aton(ahost) - v6addrs.append(host) - canonical_name = host - except Exception: - try: - # Is it a V4 address literal? - addr = dns.ipv4.inet_aton(host) - v4addrs.append(host) - canonical_name = host - except Exception: - if flags & socket.AI_NUMERICHOST == 0: - try: - if family == socket.AF_INET6 or family == socket.AF_UNSPEC: - v6 = _resolver.query(host, dns.rdatatype.AAAA, - raise_on_no_answer=False) - # Note that setting host ensures we query the same name - # for A as we did for AAAA. - host = v6.qname - canonical_name = v6.canonical_name.to_text(True) - if v6.rrset is not None: - for rdata in v6.rrset: - v6addrs.append(rdata.address) - if family == socket.AF_INET or family == socket.AF_UNSPEC: - v4 = _resolver.query(host, dns.rdatatype.A, - raise_on_no_answer=False) - host = v4.qname - canonical_name = v4.canonical_name.to_text(True) - if v4.rrset is not None: - for rdata in v4.rrset: - v4addrs.append(rdata.address) - except dns.resolver.NXDOMAIN: - raise socket.gaierror(socket.EAI_NONAME) - except: - raise socket.gaierror(socket.EAI_SYSTEM) - port = None - try: - # Is it a port literal? - if service is None: - port = 0 - else: - port = int(service) - except Exception: - if flags & socket.AI_NUMERICSERV == 0: - try: - port = socket.getservbyname(service) - except Exception: - pass - if port is None: - raise socket.gaierror(socket.EAI_NONAME) - tuples = [] - if socktype == 0: - socktypes = [socket.SOCK_DGRAM, socket.SOCK_STREAM] - else: - socktypes = [socktype] - if flags & socket.AI_CANONNAME != 0: - cname = canonical_name - else: - cname = '' - if family == socket.AF_INET6 or family == socket.AF_UNSPEC: - for addr in v6addrs: - for socktype in socktypes: - for proto in _protocols_for_socktype[socktype]: - tuples.append((socket.AF_INET6, socktype, proto, - cname, (addr, port, 0, 0))) - if family == socket.AF_INET or family == socket.AF_UNSPEC: - for addr in v4addrs: - for socktype in socktypes: - for proto in _protocols_for_socktype[socktype]: - tuples.append((socket.AF_INET, socktype, proto, - cname, (addr, port))) - if len(tuples) == 0: - raise socket.gaierror(socket.EAI_NONAME) - return tuples - - -def _getnameinfo(sockaddr, flags=0): - host = sockaddr[0] - port = sockaddr[1] - if len(sockaddr) == 4: - scope = sockaddr[3] - family = socket.AF_INET6 - else: - scope = None - family = socket.AF_INET - tuples = _getaddrinfo(host, port, family, socket.SOCK_STREAM, - socket.SOL_TCP, 0) - if len(tuples) > 1: - raise socket.error('sockaddr resolved to multiple addresses') - addr = tuples[0][4][0] - if flags & socket.NI_DGRAM: - pname = 'udp' - else: - pname = 'tcp' - qname = dns.reversename.from_address(addr) - if flags & socket.NI_NUMERICHOST == 0: - try: - answer = _resolver.query(qname, 'PTR') - hostname = answer.rrset[0].target.to_text(True) - except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): - if flags & socket.NI_NAMEREQD: - raise socket.gaierror(socket.EAI_NONAME) - hostname = addr - if scope is not None: - hostname += '%' + str(scope) - else: - hostname = addr - if scope is not None: - hostname += '%' + str(scope) - if flags & socket.NI_NUMERICSERV: - service = str(port) - else: - service = socket.getservbyport(port, pname) - return (hostname, service) - - -def _getfqdn(name=None): - if name is None: - name = socket.gethostname() - try: - return _getnameinfo(_getaddrinfo(name, 80)[0][4])[0] - except Exception: - return name - - -def _gethostbyname(name): - return _gethostbyname_ex(name)[2][0] - - -def _gethostbyname_ex(name): - aliases = [] - addresses = [] - tuples = _getaddrinfo(name, 0, socket.AF_INET, socket.SOCK_STREAM, - socket.SOL_TCP, socket.AI_CANONNAME) - canonical = tuples[0][3] - for item in tuples: - addresses.append(item[4][0]) - # XXX we just ignore aliases - return (canonical, aliases, addresses) - - -def _gethostbyaddr(ip): - try: - dns.ipv6.inet_aton(ip) - sockaddr = (ip, 80, 0, 0) - family = socket.AF_INET6 - except Exception: - sockaddr = (ip, 80) - family = socket.AF_INET - (name, port) = _getnameinfo(sockaddr, socket.NI_NAMEREQD) - aliases = [] - addresses = [] - tuples = _getaddrinfo(name, 0, family, socket.SOCK_STREAM, socket.SOL_TCP, - socket.AI_CANONNAME) - canonical = tuples[0][3] - for item in tuples: - addresses.append(item[4][0]) - # XXX we just ignore aliases - return (canonical, aliases, addresses) - - -def override_system_resolver(resolver=None): - """Override the system resolver routines in the socket module with - versions which use dnspython's resolver. - - This can be useful in testing situations where you want to control - the resolution behavior of python code without having to change - the system's resolver settings (e.g. /etc/resolv.conf). - - The resolver to use may be specified; if it's not, the default - resolver will be used. - - @param resolver: the resolver to use - @type resolver: dns.resolver.Resolver object or None - """ - if resolver is None: - resolver = get_default_resolver() - global _resolver - _resolver = resolver - socket.getaddrinfo = _getaddrinfo - socket.getnameinfo = _getnameinfo - socket.getfqdn = _getfqdn - socket.gethostbyname = _gethostbyname - socket.gethostbyname_ex = _gethostbyname_ex - socket.gethostbyaddr = _gethostbyaddr - - -def restore_system_resolver(): - """Undo the effects of override_system_resolver(). - """ - global _resolver - _resolver = None - socket.getaddrinfo = _original_getaddrinfo - socket.getnameinfo = _original_getnameinfo - socket.getfqdn = _original_getfqdn - socket.gethostbyname = _original_gethostbyname - socket.gethostbyname_ex = _original_gethostbyname_ex - socket.gethostbyaddr = _original_gethostbyaddr diff -Nru python-eventlet-0.20.0/eventlet/support/dns/reversename.py python-eventlet-0.24.1/eventlet/support/dns/reversename.py --- python-eventlet-0.20.0/eventlet/support/dns/reversename.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/reversename.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Reverse Map Names. - -@var ipv4_reverse_domain: The DNS IPv4 reverse-map domain, in-addr.arpa. -@type ipv4_reverse_domain: dns.name.Name object -@var ipv6_reverse_domain: The DNS IPv6 reverse-map domain, ip6.arpa. -@type ipv6_reverse_domain: dns.name.Name object -""" - -import binascii -import sys - -import dns.name -import dns.ipv6 -import dns.ipv4 - -ipv4_reverse_domain = dns.name.from_text('in-addr.arpa.') -ipv6_reverse_domain = dns.name.from_text('ip6.arpa.') - - -def from_address(text): - """Convert an IPv4 or IPv6 address in textual form into a Name object whose - value is the reverse-map domain name of the address. - @param text: an IPv4 or IPv6 address in textual form (e.g. '127.0.0.1', - '::1') - @type text: str - @rtype: dns.name.Name object - """ - try: - v6 = dns.ipv6.inet_aton(text) - if dns.ipv6.is_mapped(v6): - if sys.version_info >= (3,): - parts = ['%d' % byte for byte in v6[12:]] - else: - parts = ['%d' % ord(byte) for byte in v6[12:]] - origin = ipv4_reverse_domain - else: - parts = [x for x in str(binascii.hexlify(v6).decode())] - origin = ipv6_reverse_domain - except Exception: - parts = ['%d' % - byte for byte in bytearray(dns.ipv4.inet_aton(text))] - origin = ipv4_reverse_domain - parts.reverse() - return dns.name.from_text('.'.join(parts), origin=origin) - - -def to_address(name): - """Convert a reverse map domain name into textual address form. - @param name: an IPv4 or IPv6 address in reverse-map form. - @type name: dns.name.Name object - @rtype: str - """ - if name.is_subdomain(ipv4_reverse_domain): - name = name.relativize(ipv4_reverse_domain) - labels = list(name.labels) - labels.reverse() - text = b'.'.join(labels) - # run through inet_aton() to check syntax and make pretty. - return dns.ipv4.inet_ntoa(dns.ipv4.inet_aton(text)) - elif name.is_subdomain(ipv6_reverse_domain): - name = name.relativize(ipv6_reverse_domain) - labels = list(name.labels) - labels.reverse() - parts = [] - i = 0 - l = len(labels) - while i < l: - parts.append(b''.join(labels[i:i + 4])) - i += 4 - text = b':'.join(parts) - # run through inet_aton() to check syntax and make pretty. - return dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text)) - else: - raise dns.exception.SyntaxError('unknown reverse-map address family') diff -Nru python-eventlet-0.20.0/eventlet/support/dns/rrset.py python-eventlet-0.24.1/eventlet/support/dns/rrset.py --- python-eventlet-0.20.0/eventlet/support/dns/rrset.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/rrset.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,182 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS RRsets (an RRset is a named rdataset)""" - - -import dns.name -import dns.rdataset -import dns.rdataclass -import dns.renderer -from ._compat import string_types - - -class RRset(dns.rdataset.Rdataset): - - """A DNS RRset (named rdataset). - - RRset inherits from Rdataset, and RRsets can be treated as - Rdatasets in most cases. There are, however, a few notable - exceptions. RRsets have different to_wire() and to_text() method - arguments, reflecting the fact that RRsets always have an owner - name. - """ - - __slots__ = ['name', 'deleting'] - - def __init__(self, name, rdclass, rdtype, covers=dns.rdatatype.NONE, - deleting=None): - """Create a new RRset.""" - - super(RRset, self).__init__(rdclass, rdtype, covers) - self.name = name - self.deleting = deleting - - def _clone(self): - obj = super(RRset, self)._clone() - obj.name = self.name - obj.deleting = self.deleting - return obj - - def __repr__(self): - if self.covers == 0: - ctext = '' - else: - ctext = '(' + dns.rdatatype.to_text(self.covers) + ')' - if self.deleting is not None: - dtext = ' delete=' + dns.rdataclass.to_text(self.deleting) - else: - dtext = '' - return '' - - def __str__(self): - return self.to_text() - - def __eq__(self, other): - """Two RRsets are equal if they have the same name and the same - rdataset - - @rtype: bool""" - if not isinstance(other, RRset): - return False - if self.name != other.name: - return False - return super(RRset, self).__eq__(other) - - def match(self, name, rdclass, rdtype, covers, deleting=None): - """Returns True if this rrset matches the specified class, type, - covers, and deletion state.""" - - if not super(RRset, self).match(rdclass, rdtype, covers): - return False - if self.name != name or self.deleting != deleting: - return False - return True - - def to_text(self, origin=None, relativize=True, **kw): - """Convert the RRset into DNS master file format. - - @see: L{dns.name.Name.choose_relativity} for more information - on how I{origin} and I{relativize} determine the way names - are emitted. - - Any additional keyword arguments are passed on to the rdata - to_text() method. - - @param origin: The origin for relative names, or None. - @type origin: dns.name.Name object - @param relativize: True if names should names be relativized - @type relativize: bool""" - - return super(RRset, self).to_text(self.name, origin, relativize, - self.deleting, **kw) - - def to_wire(self, file, compress=None, origin=None, **kw): - """Convert the RRset to wire format.""" - - return super(RRset, self).to_wire(self.name, file, compress, origin, - self.deleting, **kw) - - def to_rdataset(self): - """Convert an RRset into an Rdataset. - - @rtype: dns.rdataset.Rdataset object - """ - return dns.rdataset.from_rdata_list(self.ttl, list(self)) - - -def from_text_list(name, ttl, rdclass, rdtype, text_rdatas, - idna_codec=None): - """Create an RRset with the specified name, TTL, class, and type, and with - the specified list of rdatas in text format. - - @rtype: dns.rrset.RRset object - """ - - if isinstance(name, string_types): - name = dns.name.from_text(name, None, idna_codec=idna_codec) - if isinstance(rdclass, string_types): - rdclass = dns.rdataclass.from_text(rdclass) - if isinstance(rdtype, string_types): - rdtype = dns.rdatatype.from_text(rdtype) - r = RRset(name, rdclass, rdtype) - r.update_ttl(ttl) - for t in text_rdatas: - rd = dns.rdata.from_text(r.rdclass, r.rdtype, t) - r.add(rd) - return r - - -def from_text(name, ttl, rdclass, rdtype, *text_rdatas): - """Create an RRset with the specified name, TTL, class, and type and with - the specified rdatas in text format. - - @rtype: dns.rrset.RRset object - """ - - return from_text_list(name, ttl, rdclass, rdtype, text_rdatas) - - -def from_rdata_list(name, ttl, rdatas, idna_codec=None): - """Create an RRset with the specified name and TTL, and with - the specified list of rdata objects. - - @rtype: dns.rrset.RRset object - """ - - if isinstance(name, string_types): - name = dns.name.from_text(name, None, idna_codec=idna_codec) - - if len(rdatas) == 0: - raise ValueError("rdata list must not be empty") - r = None - for rd in rdatas: - if r is None: - r = RRset(name, rd.rdclass, rd.rdtype) - r.update_ttl(ttl) - r.add(rd) - return r - - -def from_rdata(name, ttl, *rdatas): - """Create an RRset with the specified name and TTL, and with - the specified rdata objects. - - @rtype: dns.rrset.RRset object - """ - - return from_rdata_list(name, ttl, rdatas) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/set.py python-eventlet-0.24.1/eventlet/support/dns/set.py --- python-eventlet-0.20.0/eventlet/support/dns/set.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/set.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,259 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""A simple Set class.""" - - -class Set(object): - - """A simple set class. - - Sets are not in Python until 2.3, and rdata are not immutable so - we cannot use sets.Set anyway. This class implements subset of - the 2.3 Set interface using a list as the container. - - @ivar items: A list of the items which are in the set - @type items: list""" - - __slots__ = ['items'] - - def __init__(self, items=None): - """Initialize the set. - - @param items: the initial set of items - @type items: any iterable or None - """ - - self.items = [] - if items is not None: - for item in items: - self.add(item) - - def __repr__(self): - return "dns.simpleset.Set(%s)" % repr(self.items) - - def add(self, item): - """Add an item to the set.""" - if item not in self.items: - self.items.append(item) - - def remove(self, item): - """Remove an item from the set.""" - self.items.remove(item) - - def discard(self, item): - """Remove an item from the set if present.""" - try: - self.items.remove(item) - except ValueError: - pass - - def _clone(self): - """Make a (shallow) copy of the set. - - There is a 'clone protocol' that subclasses of this class - should use. To make a copy, first call your super's _clone() - method, and use the object returned as the new instance. Then - make shallow copies of the attributes defined in the subclass. - - This protocol allows us to write the set algorithms that - return new instances (e.g. union) once, and keep using them in - subclasses. - """ - - cls = self.__class__ - obj = cls.__new__(cls) - obj.items = list(self.items) - return obj - - def __copy__(self): - """Make a (shallow) copy of the set.""" - return self._clone() - - def copy(self): - """Make a (shallow) copy of the set.""" - return self._clone() - - def union_update(self, other): - """Update the set, adding any elements from other which are not - already in the set. - @param other: the collection of items with which to update the set - @type other: Set object - """ - if not isinstance(other, Set): - raise ValueError('other must be a Set instance') - if self is other: - return - for item in other.items: - self.add(item) - - def intersection_update(self, other): - """Update the set, removing any elements from other which are not - in both sets. - @param other: the collection of items with which to update the set - @type other: Set object - """ - if not isinstance(other, Set): - raise ValueError('other must be a Set instance') - if self is other: - return - # we make a copy of the list so that we can remove items from - # the list without breaking the iterator. - for item in list(self.items): - if item not in other.items: - self.items.remove(item) - - def difference_update(self, other): - """Update the set, removing any elements from other which are in - the set. - @param other: the collection of items with which to update the set - @type other: Set object - """ - if not isinstance(other, Set): - raise ValueError('other must be a Set instance') - if self is other: - self.items = [] - else: - for item in other.items: - self.discard(item) - - def union(self, other): - """Return a new set which is the union of I{self} and I{other}. - - @param other: the other set - @type other: Set object - @rtype: the same type as I{self} - """ - - obj = self._clone() - obj.union_update(other) - return obj - - def intersection(self, other): - """Return a new set which is the intersection of I{self} and I{other}. - - @param other: the other set - @type other: Set object - @rtype: the same type as I{self} - """ - - obj = self._clone() - obj.intersection_update(other) - return obj - - def difference(self, other): - """Return a new set which I{self} - I{other}, i.e. the items - in I{self} which are not also in I{other}. - - @param other: the other set - @type other: Set object - @rtype: the same type as I{self} - """ - - obj = self._clone() - obj.difference_update(other) - return obj - - def __or__(self, other): - return self.union(other) - - def __and__(self, other): - return self.intersection(other) - - def __add__(self, other): - return self.union(other) - - def __sub__(self, other): - return self.difference(other) - - def __ior__(self, other): - self.union_update(other) - return self - - def __iand__(self, other): - self.intersection_update(other) - return self - - def __iadd__(self, other): - self.union_update(other) - return self - - def __isub__(self, other): - self.difference_update(other) - return self - - def update(self, other): - """Update the set, adding any elements from other which are not - already in the set. - @param other: the collection of items with which to update the set - @type other: any iterable type""" - for item in other: - self.add(item) - - def clear(self): - """Make the set empty.""" - self.items = [] - - def __eq__(self, other): - # Yes, this is inefficient but the sets we're dealing with are - # usually quite small, so it shouldn't hurt too much. - for item in self.items: - if item not in other.items: - return False - for item in other.items: - if item not in self.items: - return False - return True - - def __ne__(self, other): - return not self.__eq__(other) - - def __len__(self): - return len(self.items) - - def __iter__(self): - return iter(self.items) - - def __getitem__(self, i): - return self.items[i] - - def __delitem__(self, i): - del self.items[i] - - def issubset(self, other): - """Is I{self} a subset of I{other}? - - @rtype: bool - """ - - if not isinstance(other, Set): - raise ValueError('other must be a Set instance') - for item in self.items: - if item not in other.items: - return False - return True - - def issuperset(self, other): - """Is I{self} a superset of I{other}? - - @rtype: bool - """ - - if not isinstance(other, Set): - raise ValueError('other must be a Set instance') - for item in other.items: - if item not in self.items: - return False - return True diff -Nru python-eventlet-0.20.0/eventlet/support/dns/tokenizer.py python-eventlet-0.24.1/eventlet/support/dns/tokenizer.py --- python-eventlet-0.20.0/eventlet/support/dns/tokenizer.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/tokenizer.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,564 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Tokenize DNS master file format""" - -from io import StringIO -import sys - -import dns.exception -import dns.name -import dns.ttl -from ._compat import long, text_type, binary_type - -_DELIMITERS = { - ' ': True, - '\t': True, - '\n': True, - ';': True, - '(': True, - ')': True, - '"': True} - -_QUOTING_DELIMITERS = {'"': True} - -EOF = 0 -EOL = 1 -WHITESPACE = 2 -IDENTIFIER = 3 -QUOTED_STRING = 4 -COMMENT = 5 -DELIMITER = 6 - - -class UngetBufferFull(dns.exception.DNSException): - - """An attempt was made to unget a token when the unget buffer was full.""" - - -class Token(object): - - """A DNS master file format token. - - @ivar ttype: The token type - @type ttype: int - @ivar value: The token value - @type value: string - @ivar has_escape: Does the token value contain escapes? - @type has_escape: bool - """ - - def __init__(self, ttype, value='', has_escape=False): - """Initialize a token instance. - - @param ttype: The token type - @type ttype: int - @param value: The token value - @type value: string - @param has_escape: Does the token value contain escapes? - @type has_escape: bool - """ - self.ttype = ttype - self.value = value - self.has_escape = has_escape - - def is_eof(self): - return self.ttype == EOF - - def is_eol(self): - return self.ttype == EOL - - def is_whitespace(self): - return self.ttype == WHITESPACE - - def is_identifier(self): - return self.ttype == IDENTIFIER - - def is_quoted_string(self): - return self.ttype == QUOTED_STRING - - def is_comment(self): - return self.ttype == COMMENT - - def is_delimiter(self): - return self.ttype == DELIMITER - - def is_eol_or_eof(self): - return self.ttype == EOL or self.ttype == EOF - - def __eq__(self, other): - if not isinstance(other, Token): - return False - return (self.ttype == other.ttype and - self.value == other.value) - - def __ne__(self, other): - if not isinstance(other, Token): - return True - return (self.ttype != other.ttype or - self.value != other.value) - - def __str__(self): - return '%d "%s"' % (self.ttype, self.value) - - def unescape(self): - if not self.has_escape: - return self - unescaped = '' - l = len(self.value) - i = 0 - while i < l: - c = self.value[i] - i += 1 - if c == '\\': - if i >= l: - raise dns.exception.UnexpectedEnd - c = self.value[i] - i += 1 - if c.isdigit(): - if i >= l: - raise dns.exception.UnexpectedEnd - c2 = self.value[i] - i += 1 - if i >= l: - raise dns.exception.UnexpectedEnd - c3 = self.value[i] - i += 1 - if not (c2.isdigit() and c3.isdigit()): - raise dns.exception.SyntaxError - c = chr(int(c) * 100 + int(c2) * 10 + int(c3)) - unescaped += c - return Token(self.ttype, unescaped) - - # compatibility for old-style tuple tokens - - def __len__(self): - return 2 - - def __iter__(self): - return iter((self.ttype, self.value)) - - def __getitem__(self, i): - if i == 0: - return self.ttype - elif i == 1: - return self.value - else: - raise IndexError - - -class Tokenizer(object): - - """A DNS master file format tokenizer. - - A token is a (type, value) tuple, where I{type} is an int, and - I{value} is a string. The valid types are EOF, EOL, WHITESPACE, - IDENTIFIER, QUOTED_STRING, COMMENT, and DELIMITER. - - @ivar file: The file to tokenize - @type file: file - @ivar ungotten_char: The most recently ungotten character, or None. - @type ungotten_char: string - @ivar ungotten_token: The most recently ungotten token, or None. - @type ungotten_token: (int, string) token tuple - @ivar multiline: The current multiline level. This value is increased - by one every time a '(' delimiter is read, and decreased by one every time - a ')' delimiter is read. - @type multiline: int - @ivar quoting: This variable is true if the tokenizer is currently - reading a quoted string. - @type quoting: bool - @ivar eof: This variable is true if the tokenizer has encountered EOF. - @type eof: bool - @ivar delimiters: The current delimiter dictionary. - @type delimiters: dict - @ivar line_number: The current line number - @type line_number: int - @ivar filename: A filename that will be returned by the L{where} method. - @type filename: string - """ - - def __init__(self, f=sys.stdin, filename=None): - """Initialize a tokenizer instance. - - @param f: The file to tokenize. The default is sys.stdin. - This parameter may also be a string, in which case the tokenizer - will take its input from the contents of the string. - @type f: file or string - @param filename: the name of the filename that the L{where} method - will return. - @type filename: string - """ - - if isinstance(f, text_type): - f = StringIO(f) - if filename is None: - filename = '' - elif isinstance(f, binary_type): - f = StringIO(f.decode()) - if filename is None: - filename = '' - else: - if filename is None: - if f is sys.stdin: - filename = '' - else: - filename = '' - self.file = f - self.ungotten_char = None - self.ungotten_token = None - self.multiline = 0 - self.quoting = False - self.eof = False - self.delimiters = _DELIMITERS - self.line_number = 1 - self.filename = filename - - def _get_char(self): - """Read a character from input. - @rtype: string - """ - - if self.ungotten_char is None: - if self.eof: - c = '' - else: - c = self.file.read(1) - if c == '': - self.eof = True - elif c == '\n': - self.line_number += 1 - else: - c = self.ungotten_char - self.ungotten_char = None - return c - - def where(self): - """Return the current location in the input. - - @rtype: (string, int) tuple. The first item is the filename of - the input, the second is the current line number. - """ - - return (self.filename, self.line_number) - - def _unget_char(self, c): - """Unget a character. - - The unget buffer for characters is only one character large; it is - an error to try to unget a character when the unget buffer is not - empty. - - @param c: the character to unget - @type c: string - @raises UngetBufferFull: there is already an ungotten char - """ - - if self.ungotten_char is not None: - raise UngetBufferFull - self.ungotten_char = c - - def skip_whitespace(self): - """Consume input until a non-whitespace character is encountered. - - The non-whitespace character is then ungotten, and the number of - whitespace characters consumed is returned. - - If the tokenizer is in multiline mode, then newlines are whitespace. - - @rtype: int - """ - - skipped = 0 - while True: - c = self._get_char() - if c != ' ' and c != '\t': - if (c != '\n') or not self.multiline: - self._unget_char(c) - return skipped - skipped += 1 - - def get(self, want_leading=False, want_comment=False): - """Get the next token. - - @param want_leading: If True, return a WHITESPACE token if the - first character read is whitespace. The default is False. - @type want_leading: bool - @param want_comment: If True, return a COMMENT token if the - first token read is a comment. The default is False. - @type want_comment: bool - @rtype: Token object - @raises dns.exception.UnexpectedEnd: input ended prematurely - @raises dns.exception.SyntaxError: input was badly formed - """ - - if self.ungotten_token is not None: - token = self.ungotten_token - self.ungotten_token = None - if token.is_whitespace(): - if want_leading: - return token - elif token.is_comment(): - if want_comment: - return token - else: - return token - skipped = self.skip_whitespace() - if want_leading and skipped > 0: - return Token(WHITESPACE, ' ') - token = '' - ttype = IDENTIFIER - has_escape = False - while True: - c = self._get_char() - if c == '' or c in self.delimiters: - if c == '' and self.quoting: - raise dns.exception.UnexpectedEnd - if token == '' and ttype != QUOTED_STRING: - if c == '(': - self.multiline += 1 - self.skip_whitespace() - continue - elif c == ')': - if self.multiline <= 0: - raise dns.exception.SyntaxError - self.multiline -= 1 - self.skip_whitespace() - continue - elif c == '"': - if not self.quoting: - self.quoting = True - self.delimiters = _QUOTING_DELIMITERS - ttype = QUOTED_STRING - continue - else: - self.quoting = False - self.delimiters = _DELIMITERS - self.skip_whitespace() - continue - elif c == '\n': - return Token(EOL, '\n') - elif c == ';': - while 1: - c = self._get_char() - if c == '\n' or c == '': - break - token += c - if want_comment: - self._unget_char(c) - return Token(COMMENT, token) - elif c == '': - if self.multiline: - raise dns.exception.SyntaxError( - 'unbalanced parentheses') - return Token(EOF) - elif self.multiline: - self.skip_whitespace() - token = '' - continue - else: - return Token(EOL, '\n') - else: - # This code exists in case we ever want a - # delimiter to be returned. It never produces - # a token currently. - token = c - ttype = DELIMITER - else: - self._unget_char(c) - break - elif self.quoting: - if c == '\\': - c = self._get_char() - if c == '': - raise dns.exception.UnexpectedEnd - if c.isdigit(): - c2 = self._get_char() - if c2 == '': - raise dns.exception.UnexpectedEnd - c3 = self._get_char() - if c == '': - raise dns.exception.UnexpectedEnd - if not (c2.isdigit() and c3.isdigit()): - raise dns.exception.SyntaxError - c = chr(int(c) * 100 + int(c2) * 10 + int(c3)) - elif c == '\n': - raise dns.exception.SyntaxError('newline in quoted string') - elif c == '\\': - # - # It's an escape. Put it and the next character into - # the token; it will be checked later for goodness. - # - token += c - has_escape = True - c = self._get_char() - if c == '' or c == '\n': - raise dns.exception.UnexpectedEnd - token += c - if token == '' and ttype != QUOTED_STRING: - if self.multiline: - raise dns.exception.SyntaxError('unbalanced parentheses') - ttype = EOF - return Token(ttype, token, has_escape) - - def unget(self, token): - """Unget a token. - - The unget buffer for tokens is only one token large; it is - an error to try to unget a token when the unget buffer is not - empty. - - @param token: the token to unget - @type token: Token object - @raises UngetBufferFull: there is already an ungotten token - """ - - if self.ungotten_token is not None: - raise UngetBufferFull - self.ungotten_token = token - - def next(self): - """Return the next item in an iteration. - @rtype: (int, string) - """ - - token = self.get() - if token.is_eof(): - raise StopIteration - return token - - __next__ = next - - def __iter__(self): - return self - - # Helpers - - def get_int(self): - """Read the next token and interpret it as an integer. - - @raises dns.exception.SyntaxError: - @rtype: int - """ - - token = self.get().unescape() - if not token.is_identifier(): - raise dns.exception.SyntaxError('expecting an identifier') - if not token.value.isdigit(): - raise dns.exception.SyntaxError('expecting an integer') - return int(token.value) - - def get_uint8(self): - """Read the next token and interpret it as an 8-bit unsigned - integer. - - @raises dns.exception.SyntaxError: - @rtype: int - """ - - value = self.get_int() - if value < 0 or value > 255: - raise dns.exception.SyntaxError( - '%d is not an unsigned 8-bit integer' % value) - return value - - def get_uint16(self): - """Read the next token and interpret it as a 16-bit unsigned - integer. - - @raises dns.exception.SyntaxError: - @rtype: int - """ - - value = self.get_int() - if value < 0 or value > 65535: - raise dns.exception.SyntaxError( - '%d is not an unsigned 16-bit integer' % value) - return value - - def get_uint32(self): - """Read the next token and interpret it as a 32-bit unsigned - integer. - - @raises dns.exception.SyntaxError: - @rtype: int - """ - - token = self.get().unescape() - if not token.is_identifier(): - raise dns.exception.SyntaxError('expecting an identifier') - if not token.value.isdigit(): - raise dns.exception.SyntaxError('expecting an integer') - value = long(token.value) - if value < 0 or value > long(4294967296): - raise dns.exception.SyntaxError( - '%d is not an unsigned 32-bit integer' % value) - return value - - def get_string(self, origin=None): - """Read the next token and interpret it as a string. - - @raises dns.exception.SyntaxError: - @rtype: string - """ - - token = self.get().unescape() - if not (token.is_identifier() or token.is_quoted_string()): - raise dns.exception.SyntaxError('expecting a string') - return token.value - - def get_identifier(self, origin=None): - """Read the next token and raise an exception if it is not an identifier. - - @raises dns.exception.SyntaxError: - @rtype: string - """ - - token = self.get().unescape() - if not token.is_identifier(): - raise dns.exception.SyntaxError('expecting an identifier') - return token.value - - def get_name(self, origin=None): - """Read the next token and interpret it as a DNS name. - - @raises dns.exception.SyntaxError: - @rtype: dns.name.Name object""" - - token = self.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError('expecting an identifier') - return dns.name.from_text(token.value, origin) - - def get_eol(self): - """Read the next token and raise an exception if it isn't EOL or - EOF. - - @raises dns.exception.SyntaxError: - @rtype: string - """ - - token = self.get() - if not token.is_eol_or_eof(): - raise dns.exception.SyntaxError( - 'expected EOL or EOF, got %d "%s"' % (token.ttype, - token.value)) - return token.value - - def get_ttl(self): - token = self.get().unescape() - if not token.is_identifier(): - raise dns.exception.SyntaxError('expecting an identifier') - return dns.ttl.from_text(token.value) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/tsigkeyring.py python-eventlet-0.24.1/eventlet/support/dns/tsigkeyring.py --- python-eventlet-0.20.0/eventlet/support/dns/tsigkeyring.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/tsigkeyring.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""A place to store TSIG keys.""" - -from dns._compat import maybe_decode, maybe_encode - -import base64 - -import dns.name - - -def from_text(textring): - """Convert a dictionary containing (textual DNS name, base64 secret) pairs - into a binary keyring which has (dns.name.Name, binary secret) pairs. - @rtype: dict""" - - keyring = {} - for keytext in textring: - keyname = dns.name.from_text(keytext) - secret = base64.decodestring(maybe_encode(textring[keytext])) - keyring[keyname] = secret - return keyring - - -def to_text(keyring): - """Convert a dictionary containing (dns.name.Name, binary secret) pairs - into a text keyring which has (textual DNS name, base64 secret) pairs. - @rtype: dict""" - - textring = {} - for keyname in keyring: - keytext = maybe_decode(keyname.to_text()) - secret = maybe_decode(base64.encodestring(keyring[keyname])) - textring[keytext] = secret - return textring diff -Nru python-eventlet-0.20.0/eventlet/support/dns/tsig.py python-eventlet-0.24.1/eventlet/support/dns/tsig.py --- python-eventlet-0.20.0/eventlet/support/dns/tsig.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/tsig.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,234 +0,0 @@ -# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS TSIG support.""" - -import hmac -import struct - -import dns.exception -import dns.hash -import dns.rdataclass -import dns.name -from ._compat import long, string_types, text_type - -class BadTime(dns.exception.DNSException): - - """The current time is not within the TSIG's validity time.""" - - -class BadSignature(dns.exception.DNSException): - - """The TSIG signature fails to verify.""" - - -class PeerError(dns.exception.DNSException): - - """Base class for all TSIG errors generated by the remote peer""" - - -class PeerBadKey(PeerError): - - """The peer didn't know the key we used""" - - -class PeerBadSignature(PeerError): - - """The peer didn't like the signature we sent""" - - -class PeerBadTime(PeerError): - - """The peer didn't like the time we sent""" - - -class PeerBadTruncation(PeerError): - - """The peer didn't like amount of truncation in the TSIG we sent""" - -# TSIG Algorithms - -HMAC_MD5 = dns.name.from_text("HMAC-MD5.SIG-ALG.REG.INT") -HMAC_SHA1 = dns.name.from_text("hmac-sha1") -HMAC_SHA224 = dns.name.from_text("hmac-sha224") -HMAC_SHA256 = dns.name.from_text("hmac-sha256") -HMAC_SHA384 = dns.name.from_text("hmac-sha384") -HMAC_SHA512 = dns.name.from_text("hmac-sha512") - -_hashes = { - HMAC_SHA224: 'SHA224', - HMAC_SHA256: 'SHA256', - HMAC_SHA384: 'SHA384', - HMAC_SHA512: 'SHA512', - HMAC_SHA1: 'SHA1', - HMAC_MD5: 'MD5', -} - -default_algorithm = HMAC_MD5 - -BADSIG = 16 -BADKEY = 17 -BADTIME = 18 -BADTRUNC = 22 - - -def sign(wire, keyname, secret, time, fudge, original_id, error, - other_data, request_mac, ctx=None, multi=False, first=True, - algorithm=default_algorithm): - """Return a (tsig_rdata, mac, ctx) tuple containing the HMAC TSIG rdata - for the input parameters, the HMAC MAC calculated by applying the - TSIG signature algorithm, and the TSIG digest context. - @rtype: (string, string, hmac.HMAC object) - @raises ValueError: I{other_data} is too long - @raises NotImplementedError: I{algorithm} is not supported - """ - - if isinstance(other_data, text_type): - other_data = other_data.encode() - (algorithm_name, digestmod) = get_algorithm(algorithm) - if first: - ctx = hmac.new(secret, digestmod=digestmod) - ml = len(request_mac) - if ml > 0: - ctx.update(struct.pack('!H', ml)) - ctx.update(request_mac) - id = struct.pack('!H', original_id) - ctx.update(id) - ctx.update(wire[2:]) - if first: - ctx.update(keyname.to_digestable()) - ctx.update(struct.pack('!H', dns.rdataclass.ANY)) - ctx.update(struct.pack('!I', 0)) - long_time = time + long(0) - upper_time = (long_time >> 32) & long(0xffff) - lower_time = long_time & long(0xffffffff) - time_mac = struct.pack('!HIH', upper_time, lower_time, fudge) - pre_mac = algorithm_name + time_mac - ol = len(other_data) - if ol > 65535: - raise ValueError('TSIG Other Data is > 65535 bytes') - post_mac = struct.pack('!HH', error, ol) + other_data - if first: - ctx.update(pre_mac) - ctx.update(post_mac) - else: - ctx.update(time_mac) - mac = ctx.digest() - mpack = struct.pack('!H', len(mac)) - tsig_rdata = pre_mac + mpack + mac + id + post_mac - if multi: - ctx = hmac.new(secret, digestmod=digestmod) - ml = len(mac) - ctx.update(struct.pack('!H', ml)) - ctx.update(mac) - else: - ctx = None - return (tsig_rdata, mac, ctx) - - -def hmac_md5(wire, keyname, secret, time, fudge, original_id, error, - other_data, request_mac, ctx=None, multi=False, first=True, - algorithm=default_algorithm): - return sign(wire, keyname, secret, time, fudge, original_id, error, - other_data, request_mac, ctx, multi, first, algorithm) - - -def validate(wire, keyname, secret, now, request_mac, tsig_start, tsig_rdata, - tsig_rdlen, ctx=None, multi=False, first=True): - """Validate the specified TSIG rdata against the other input parameters. - - @raises FormError: The TSIG is badly formed. - @raises BadTime: There is too much time skew between the client and the - server. - @raises BadSignature: The TSIG signature did not validate - @rtype: hmac.HMAC object""" - - (adcount,) = struct.unpack("!H", wire[10:12]) - if adcount == 0: - raise dns.exception.FormError - adcount -= 1 - new_wire = wire[0:10] + struct.pack("!H", adcount) + wire[12:tsig_start] - current = tsig_rdata - (aname, used) = dns.name.from_wire(wire, current) - current = current + used - (upper_time, lower_time, fudge, mac_size) = \ - struct.unpack("!HIHH", wire[current:current + 10]) - time = ((upper_time + long(0)) << 32) + (lower_time + long(0)) - current += 10 - mac = wire[current:current + mac_size] - current += mac_size - (original_id, error, other_size) = \ - struct.unpack("!HHH", wire[current:current + 6]) - current += 6 - other_data = wire[current:current + other_size] - current += other_size - if current != tsig_rdata + tsig_rdlen: - raise dns.exception.FormError - if error != 0: - if error == BADSIG: - raise PeerBadSignature - elif error == BADKEY: - raise PeerBadKey - elif error == BADTIME: - raise PeerBadTime - elif error == BADTRUNC: - raise PeerBadTruncation - else: - raise PeerError('unknown TSIG error code %d' % error) - time_low = time - fudge - time_high = time + fudge - if now < time_low or now > time_high: - raise BadTime - (junk, our_mac, ctx) = sign(new_wire, keyname, secret, time, fudge, - original_id, error, other_data, - request_mac, ctx, multi, first, aname) - if our_mac != mac: - raise BadSignature - return ctx - - -def get_algorithm(algorithm): - """Returns the wire format string and the hash module to use for the - specified TSIG algorithm - - @rtype: (string, hash constructor) - @raises NotImplementedError: I{algorithm} is not supported - """ - - if isinstance(algorithm, string_types): - algorithm = dns.name.from_text(algorithm) - - try: - return (algorithm.to_digestable(), dns.hash.hashes[_hashes[algorithm]]) - except KeyError: - raise NotImplementedError("TSIG algorithm " + str(algorithm) + - " is not supported") - - -def get_algorithm_and_mac(wire, tsig_rdata, tsig_rdlen): - """Return the tsig algorithm for the specified tsig_rdata - @raises FormError: The TSIG is badly formed. - """ - current = tsig_rdata - (aname, used) = dns.name.from_wire(wire, current) - current = current + used - (upper_time, lower_time, fudge, mac_size) = \ - struct.unpack("!HIHH", wire[current:current + 10]) - current += 10 - mac = wire[current:current + mac_size] - current += mac_size - if current > tsig_rdata + tsig_rdlen: - raise dns.exception.FormError - return (aname, mac) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/ttl.py python-eventlet-0.24.1/eventlet/support/dns/ttl.py --- python-eventlet-0.20.0/eventlet/support/dns/ttl.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/ttl.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS TTL conversion.""" - -import dns.exception -from ._compat import long - - -class BadTTL(dns.exception.SyntaxError): - - """DNS TTL value is not well-formed.""" - - -def from_text(text): - """Convert the text form of a TTL to an integer. - - The BIND 8 units syntax for TTLs (e.g. '1w6d4h3m10s') is supported. - - @param text: the textual TTL - @type text: string - @raises dns.ttl.BadTTL: the TTL is not well-formed - @rtype: int - """ - - if text.isdigit(): - total = long(text) - else: - if not text[0].isdigit(): - raise BadTTL - total = long(0) - current = long(0) - for c in text: - if c.isdigit(): - current *= 10 - current += long(c) - else: - c = c.lower() - if c == 'w': - total += current * long(604800) - elif c == 'd': - total += current * long(86400) - elif c == 'h': - total += current * long(3600) - elif c == 'm': - total += current * long(60) - elif c == 's': - total += current - else: - raise BadTTL("unknown unit '%s'" % c) - current = 0 - if not current == 0: - raise BadTTL("trailing integer") - if total < long(0) or total > long(2147483647): - raise BadTTL("TTL should be between 0 and 2^31 - 1 (inclusive)") - return total diff -Nru python-eventlet-0.20.0/eventlet/support/dns/update.py python-eventlet-0.24.1/eventlet/support/dns/update.py --- python-eventlet-0.20.0/eventlet/support/dns/update.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/update.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,249 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Dynamic Update Support""" - - -import dns.message -import dns.name -import dns.opcode -import dns.rdata -import dns.rdataclass -import dns.rdataset -import dns.tsig -from ._compat import string_types - - -class Update(dns.message.Message): - - def __init__(self, zone, rdclass=dns.rdataclass.IN, keyring=None, - keyname=None, keyalgorithm=dns.tsig.default_algorithm): - """Initialize a new DNS Update object. - - @param zone: The zone which is being updated. - @type zone: A dns.name.Name or string - @param rdclass: The class of the zone; defaults to dns.rdataclass.IN. - @type rdclass: An int designating the class, or a string whose value - is the name of a class. - @param keyring: The TSIG keyring to use; defaults to None. - @type keyring: dict - @param keyname: The name of the TSIG key to use; defaults to None. - The key must be defined in the keyring. If a keyring is specified - but a keyname is not, then the key used will be the first key in the - keyring. Note that the order of keys in a dictionary is not defined, - so applications should supply a keyname when a keyring is used, unless - they know the keyring contains only one key. - @type keyname: dns.name.Name or string - @param keyalgorithm: The TSIG algorithm to use; defaults to - dns.tsig.default_algorithm. Constants for TSIG algorithms are defined - in dns.tsig, and the currently implemented algorithms are - HMAC_MD5, HMAC_SHA1, HMAC_SHA224, HMAC_SHA256, HMAC_SHA384, and - HMAC_SHA512. - @type keyalgorithm: string - """ - super(Update, self).__init__() - self.flags |= dns.opcode.to_flags(dns.opcode.UPDATE) - if isinstance(zone, string_types): - zone = dns.name.from_text(zone) - self.origin = zone - if isinstance(rdclass, string_types): - rdclass = dns.rdataclass.from_text(rdclass) - self.zone_rdclass = rdclass - self.find_rrset(self.question, self.origin, rdclass, dns.rdatatype.SOA, - create=True, force_unique=True) - if keyring is not None: - self.use_tsig(keyring, keyname, algorithm=keyalgorithm) - - def _add_rr(self, name, ttl, rd, deleting=None, section=None): - """Add a single RR to the update section.""" - - if section is None: - section = self.authority - covers = rd.covers() - rrset = self.find_rrset(section, name, self.zone_rdclass, rd.rdtype, - covers, deleting, True, True) - rrset.add(rd, ttl) - - def _add(self, replace, section, name, *args): - """Add records. The first argument is the replace mode. If - false, RRs are added to an existing RRset; if true, the RRset - is replaced with the specified contents. The second - argument is the section to add to. The third argument - is always a name. The other arguments can be: - - - rdataset... - - - ttl, rdata... - - - ttl, rdtype, string...""" - - if isinstance(name, string_types): - name = dns.name.from_text(name, None) - if isinstance(args[0], dns.rdataset.Rdataset): - for rds in args: - if replace: - self.delete(name, rds.rdtype) - for rd in rds: - self._add_rr(name, rds.ttl, rd, section=section) - else: - args = list(args) - ttl = int(args.pop(0)) - if isinstance(args[0], dns.rdata.Rdata): - if replace: - self.delete(name, args[0].rdtype) - for rd in args: - self._add_rr(name, ttl, rd, section=section) - else: - rdtype = args.pop(0) - if isinstance(rdtype, string_types): - rdtype = dns.rdatatype.from_text(rdtype) - if replace: - self.delete(name, rdtype) - for s in args: - rd = dns.rdata.from_text(self.zone_rdclass, rdtype, s, - self.origin) - self._add_rr(name, ttl, rd, section=section) - - def add(self, name, *args): - """Add records. The first argument is always a name. The other - arguments can be: - - - rdataset... - - - ttl, rdata... - - - ttl, rdtype, string...""" - self._add(False, self.authority, name, *args) - - def delete(self, name, *args): - """Delete records. The first argument is always a name. The other - arguments can be: - - - I{nothing} - - - rdataset... - - - rdata... - - - rdtype, [string...]""" - - if isinstance(name, string_types): - name = dns.name.from_text(name, None) - if len(args) == 0: - self.find_rrset(self.authority, name, dns.rdataclass.ANY, - dns.rdatatype.ANY, dns.rdatatype.NONE, - dns.rdatatype.ANY, True, True) - elif isinstance(args[0], dns.rdataset.Rdataset): - for rds in args: - for rd in rds: - self._add_rr(name, 0, rd, dns.rdataclass.NONE) - else: - args = list(args) - if isinstance(args[0], dns.rdata.Rdata): - for rd in args: - self._add_rr(name, 0, rd, dns.rdataclass.NONE) - else: - rdtype = args.pop(0) - if isinstance(rdtype, string_types): - rdtype = dns.rdatatype.from_text(rdtype) - if len(args) == 0: - self.find_rrset(self.authority, name, - self.zone_rdclass, rdtype, - dns.rdatatype.NONE, - dns.rdataclass.ANY, - True, True) - else: - for s in args: - rd = dns.rdata.from_text(self.zone_rdclass, rdtype, s, - self.origin) - self._add_rr(name, 0, rd, dns.rdataclass.NONE) - - def replace(self, name, *args): - """Replace records. The first argument is always a name. The other - arguments can be: - - - rdataset... - - - ttl, rdata... - - - ttl, rdtype, string... - - Note that if you want to replace the entire node, you should do - a delete of the name followed by one or more calls to add.""" - - self._add(True, self.authority, name, *args) - - def present(self, name, *args): - """Require that an owner name (and optionally an rdata type, - or specific rdataset) exists as a prerequisite to the - execution of the update. The first argument is always a name. - The other arguments can be: - - - rdataset... - - - rdata... - - - rdtype, string...""" - - if isinstance(name, string_types): - name = dns.name.from_text(name, None) - if len(args) == 0: - self.find_rrset(self.answer, name, - dns.rdataclass.ANY, dns.rdatatype.ANY, - dns.rdatatype.NONE, None, - True, True) - elif isinstance(args[0], dns.rdataset.Rdataset) or \ - isinstance(args[0], dns.rdata.Rdata) or \ - len(args) > 1: - if not isinstance(args[0], dns.rdataset.Rdataset): - # Add a 0 TTL - args = list(args) - args.insert(0, 0) - self._add(False, self.answer, name, *args) - else: - rdtype = args[0] - if isinstance(rdtype, string_types): - rdtype = dns.rdatatype.from_text(rdtype) - self.find_rrset(self.answer, name, - dns.rdataclass.ANY, rdtype, - dns.rdatatype.NONE, None, - True, True) - - def absent(self, name, rdtype=None): - """Require that an owner name (and optionally an rdata type) does - not exist as a prerequisite to the execution of the update.""" - - if isinstance(name, string_types): - name = dns.name.from_text(name, None) - if rdtype is None: - self.find_rrset(self.answer, name, - dns.rdataclass.NONE, dns.rdatatype.ANY, - dns.rdatatype.NONE, None, - True, True) - else: - if isinstance(rdtype, string_types): - rdtype = dns.rdatatype.from_text(rdtype) - self.find_rrset(self.answer, name, - dns.rdataclass.NONE, rdtype, - dns.rdatatype.NONE, None, - True, True) - - def to_wire(self, origin=None, max_size=65535): - """Return a string containing the update in DNS compressed wire - format. - @rtype: string""" - if origin is None: - origin = self.origin - return super(Update, self).to_wire(origin, max_size) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/version.py python-eventlet-0.24.1/eventlet/support/dns/version.py --- python-eventlet-0.20.0/eventlet/support/dns/version.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/version.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""dnspython release version information.""" - -MAJOR = 1 -MINOR = 15 -MICRO = 0 -RELEASELEVEL = 0x0f -SERIAL = 0 - -if RELEASELEVEL == 0x0f: - version = '%d.%d.%d' % (MAJOR, MINOR, MICRO) -elif RELEASELEVEL == 0x00: - version = '%d.%d.%dx%d' % \ - (MAJOR, MINOR, MICRO, SERIAL) -else: - version = '%d.%d.%d%x%d' % \ - (MAJOR, MINOR, MICRO, RELEASELEVEL, SERIAL) - -hexversion = MAJOR << 24 | MINOR << 16 | MICRO << 8 | RELEASELEVEL << 4 | \ - SERIAL diff -Nru python-eventlet-0.20.0/eventlet/support/dns/wiredata.py python-eventlet-0.24.1/eventlet/support/dns/wiredata.py --- python-eventlet-0.20.0/eventlet/support/dns/wiredata.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/wiredata.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,103 +0,0 @@ -# Copyright (C) 2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Wire Data Helper""" - -import sys - -import dns.exception -from ._compat import binary_type, string_types - -# Figure out what constant python passes for an unspecified slice bound. -# It's supposed to be sys.maxint, yet on 64-bit windows sys.maxint is 2^31 - 1 -# but Python uses 2^63 - 1 as the constant. Rather than making pointless -# extra comparisons, duplicating code, or weakening WireData, we just figure -# out what constant Python will use. - - -class _SliceUnspecifiedBound(binary_type): - - def __getitem__(self, key): - return key.stop - - if sys.version_info < (3,): - def __getslice__(self, i, j): # pylint: disable=getslice-method - return self.__getitem__(slice(i, j)) - -_unspecified_bound = _SliceUnspecifiedBound()[1:] - - -class WireData(binary_type): - # WireData is a string with stricter slicing - - def __getitem__(self, key): - try: - if isinstance(key, slice): - # make sure we are not going outside of valid ranges, - # do stricter control of boundaries than python does - # by default - start = key.start - stop = key.stop - - if sys.version_info < (3,): - if stop == _unspecified_bound: - # handle the case where the right bound is unspecified - stop = len(self) - - if start < 0 or stop < 0: - raise dns.exception.FormError - # If it's not an empty slice, access left and right bounds - # to make sure they're valid - if start != stop: - super(WireData, self).__getitem__(start) - super(WireData, self).__getitem__(stop - 1) - else: - for index in (start, stop): - if index is None: - continue - elif abs(index) > len(self): - raise dns.exception.FormError - - return WireData(super(WireData, self).__getitem__( - slice(start, stop))) - return bytearray(self.unwrap())[key] - except IndexError: - raise dns.exception.FormError - - if sys.version_info < (3,): - def __getslice__(self, i, j): # pylint: disable=getslice-method - return self.__getitem__(slice(i, j)) - - def __iter__(self): - i = 0 - while 1: - try: - yield self[i] - i += 1 - except dns.exception.FormError: - raise StopIteration - - def unwrap(self): - return binary_type(self) - - -def maybe_wrap(wire): - if isinstance(wire, WireData): - return wire - elif isinstance(wire, binary_type): - return WireData(wire) - elif isinstance(wire, string_types): - return WireData(wire.encode()) - raise ValueError("unhandled type %s" % type(wire)) diff -Nru python-eventlet-0.20.0/eventlet/support/dns/zone.py python-eventlet-0.24.1/eventlet/support/dns/zone.py --- python-eventlet-0.20.0/eventlet/support/dns/zone.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/dns/zone.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,1087 +0,0 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Zones.""" - -from __future__ import generators - -import sys -import re -import os -from io import BytesIO - -import dns.exception -import dns.name -import dns.node -import dns.rdataclass -import dns.rdatatype -import dns.rdata -import dns.rrset -import dns.tokenizer -import dns.ttl -import dns.grange -from ._compat import string_types, text_type - - -_py3 = sys.version_info > (3,) - - -class BadZone(dns.exception.DNSException): - - """The DNS zone is malformed.""" - - -class NoSOA(BadZone): - - """The DNS zone has no SOA RR at its origin.""" - - -class NoNS(BadZone): - - """The DNS zone has no NS RRset at its origin.""" - - -class UnknownOrigin(BadZone): - - """The DNS zone's origin is unknown.""" - - -class Zone(object): - - """A DNS zone. - - A Zone is a mapping from names to nodes. The zone object may be - treated like a Python dictionary, e.g. zone[name] will retrieve - the node associated with that name. The I{name} may be a - dns.name.Name object, or it may be a string. In the either case, - if the name is relative it is treated as relative to the origin of - the zone. - - @ivar rdclass: The zone's rdata class; the default is class IN. - @type rdclass: int - @ivar origin: The origin of the zone. - @type origin: dns.name.Name object - @ivar nodes: A dictionary mapping the names of nodes in the zone to the - nodes themselves. - @type nodes: dict - @ivar relativize: should names in the zone be relativized? - @type relativize: bool - @cvar node_factory: the factory used to create a new node - @type node_factory: class or callable - """ - - node_factory = dns.node.Node - - __slots__ = ['rdclass', 'origin', 'nodes', 'relativize'] - - def __init__(self, origin, rdclass=dns.rdataclass.IN, relativize=True): - """Initialize a zone object. - - @param origin: The origin of the zone. - @type origin: dns.name.Name object - @param rdclass: The zone's rdata class; the default is class IN. - @type rdclass: int""" - - if origin is not None: - if isinstance(origin, string_types): - origin = dns.name.from_text(origin) - elif not isinstance(origin, dns.name.Name): - raise ValueError("origin parameter must be convertible to a " - "DNS name") - if not origin.is_absolute(): - raise ValueError("origin parameter must be an absolute name") - self.origin = origin - self.rdclass = rdclass - self.nodes = {} - self.relativize = relativize - - def __eq__(self, other): - """Two zones are equal if they have the same origin, class, and - nodes. - @rtype: bool - """ - - if not isinstance(other, Zone): - return False - if self.rdclass != other.rdclass or \ - self.origin != other.origin or \ - self.nodes != other.nodes: - return False - return True - - def __ne__(self, other): - """Are two zones not equal? - @rtype: bool - """ - - return not self.__eq__(other) - - def _validate_name(self, name): - if isinstance(name, string_types): - name = dns.name.from_text(name, None) - elif not isinstance(name, dns.name.Name): - raise KeyError("name parameter must be convertible to a DNS name") - if name.is_absolute(): - if not name.is_subdomain(self.origin): - raise KeyError( - "name parameter must be a subdomain of the zone origin") - if self.relativize: - name = name.relativize(self.origin) - return name - - def __getitem__(self, key): - key = self._validate_name(key) - return self.nodes[key] - - def __setitem__(self, key, value): - key = self._validate_name(key) - self.nodes[key] = value - - def __delitem__(self, key): - key = self._validate_name(key) - del self.nodes[key] - - def __iter__(self): - return self.nodes.__iter__() - - def iterkeys(self): - if _py3: - return self.nodes.keys() - else: - return self.nodes.iterkeys() # pylint: disable=dict-iter-method - - def keys(self): - return self.nodes.keys() - - def itervalues(self): - if _py3: - return self.nodes.values() - else: - return self.nodes.itervalues() # pylint: disable=dict-iter-method - - def values(self): - return self.nodes.values() - - def items(self): - return self.nodes.items() - - iteritems = items - - def get(self, key): - key = self._validate_name(key) - return self.nodes.get(key) - - def __contains__(self, other): - return other in self.nodes - - def find_node(self, name, create=False): - """Find a node in the zone, possibly creating it. - - @param name: the name of the node to find - @type name: dns.name.Name object or string - @param create: should the node be created if it doesn't exist? - @type create: bool - @raises KeyError: the name is not known and create was not specified. - @rtype: dns.node.Node object - """ - - name = self._validate_name(name) - node = self.nodes.get(name) - if node is None: - if not create: - raise KeyError - node = self.node_factory() - self.nodes[name] = node - return node - - def get_node(self, name, create=False): - """Get a node in the zone, possibly creating it. - - This method is like L{find_node}, except it returns None instead - of raising an exception if the node does not exist and creation - has not been requested. - - @param name: the name of the node to find - @type name: dns.name.Name object or string - @param create: should the node be created if it doesn't exist? - @type create: bool - @rtype: dns.node.Node object or None - """ - - try: - node = self.find_node(name, create) - except KeyError: - node = None - return node - - def delete_node(self, name): - """Delete the specified node if it exists. - - It is not an error if the node does not exist. - """ - - name = self._validate_name(name) - if name in self.nodes: - del self.nodes[name] - - def find_rdataset(self, name, rdtype, covers=dns.rdatatype.NONE, - create=False): - """Look for rdata with the specified name and type in the zone, - and return an rdataset encapsulating it. - - The I{name}, I{rdtype}, and I{covers} parameters may be - strings, in which case they will be converted to their proper - type. - - The rdataset returned is not a copy; changes to it will change - the zone. - - KeyError is raised if the name or type are not found. - Use L{get_rdataset} if you want to have None returned instead. - - @param name: the owner name to look for - @type name: DNS.name.Name object or string - @param rdtype: the rdata type desired - @type rdtype: int or string - @param covers: the covered type (defaults to None) - @type covers: int or string - @param create: should the node and rdataset be created if they do not - exist? - @type create: bool - @raises KeyError: the node or rdata could not be found - @rtype: dns.rrset.RRset object - """ - - name = self._validate_name(name) - if isinstance(rdtype, string_types): - rdtype = dns.rdatatype.from_text(rdtype) - if isinstance(covers, string_types): - covers = dns.rdatatype.from_text(covers) - node = self.find_node(name, create) - return node.find_rdataset(self.rdclass, rdtype, covers, create) - - def get_rdataset(self, name, rdtype, covers=dns.rdatatype.NONE, - create=False): - """Look for rdata with the specified name and type in the zone, - and return an rdataset encapsulating it. - - The I{name}, I{rdtype}, and I{covers} parameters may be - strings, in which case they will be converted to their proper - type. - - The rdataset returned is not a copy; changes to it will change - the zone. - - None is returned if the name or type are not found. - Use L{find_rdataset} if you want to have KeyError raised instead. - - @param name: the owner name to look for - @type name: DNS.name.Name object or string - @param rdtype: the rdata type desired - @type rdtype: int or string - @param covers: the covered type (defaults to None) - @type covers: int or string - @param create: should the node and rdataset be created if they do not - exist? - @type create: bool - @rtype: dns.rrset.RRset object - """ - - try: - rdataset = self.find_rdataset(name, rdtype, covers, create) - except KeyError: - rdataset = None - return rdataset - - def delete_rdataset(self, name, rdtype, covers=dns.rdatatype.NONE): - """Delete the rdataset matching I{rdtype} and I{covers}, if it - exists at the node specified by I{name}. - - The I{name}, I{rdtype}, and I{covers} parameters may be - strings, in which case they will be converted to their proper - type. - - It is not an error if the node does not exist, or if there is no - matching rdataset at the node. - - If the node has no rdatasets after the deletion, it will itself - be deleted. - - @param name: the owner name to look for - @type name: DNS.name.Name object or string - @param rdtype: the rdata type desired - @type rdtype: int or string - @param covers: the covered type (defaults to None) - @type covers: int or string - """ - - name = self._validate_name(name) - if isinstance(rdtype, string_types): - rdtype = dns.rdatatype.from_text(rdtype) - if isinstance(covers, string_types): - covers = dns.rdatatype.from_text(covers) - node = self.get_node(name) - if node is not None: - node.delete_rdataset(self.rdclass, rdtype, covers) - if len(node) == 0: - self.delete_node(name) - - def replace_rdataset(self, name, replacement): - """Replace an rdataset at name. - - It is not an error if there is no rdataset matching I{replacement}. - - Ownership of the I{replacement} object is transferred to the zone; - in other words, this method does not store a copy of I{replacement} - at the node, it stores I{replacement} itself. - - If the I{name} node does not exist, it is created. - - @param name: the owner name - @type name: DNS.name.Name object or string - @param replacement: the replacement rdataset - @type replacement: dns.rdataset.Rdataset - """ - - if replacement.rdclass != self.rdclass: - raise ValueError('replacement.rdclass != zone.rdclass') - node = self.find_node(name, True) - node.replace_rdataset(replacement) - - def find_rrset(self, name, rdtype, covers=dns.rdatatype.NONE): - """Look for rdata with the specified name and type in the zone, - and return an RRset encapsulating it. - - The I{name}, I{rdtype}, and I{covers} parameters may be - strings, in which case they will be converted to their proper - type. - - This method is less efficient than the similar - L{find_rdataset} because it creates an RRset instead of - returning the matching rdataset. It may be more convenient - for some uses since it returns an object which binds the owner - name to the rdata. - - This method may not be used to create new nodes or rdatasets; - use L{find_rdataset} instead. - - KeyError is raised if the name or type are not found. - Use L{get_rrset} if you want to have None returned instead. - - @param name: the owner name to look for - @type name: DNS.name.Name object or string - @param rdtype: the rdata type desired - @type rdtype: int or string - @param covers: the covered type (defaults to None) - @type covers: int or string - @raises KeyError: the node or rdata could not be found - @rtype: dns.rrset.RRset object - """ - - name = self._validate_name(name) - if isinstance(rdtype, string_types): - rdtype = dns.rdatatype.from_text(rdtype) - if isinstance(covers, string_types): - covers = dns.rdatatype.from_text(covers) - rdataset = self.nodes[name].find_rdataset(self.rdclass, rdtype, covers) - rrset = dns.rrset.RRset(name, self.rdclass, rdtype, covers) - rrset.update(rdataset) - return rrset - - def get_rrset(self, name, rdtype, covers=dns.rdatatype.NONE): - """Look for rdata with the specified name and type in the zone, - and return an RRset encapsulating it. - - The I{name}, I{rdtype}, and I{covers} parameters may be - strings, in which case they will be converted to their proper - type. - - This method is less efficient than the similar L{get_rdataset} - because it creates an RRset instead of returning the matching - rdataset. It may be more convenient for some uses since it - returns an object which binds the owner name to the rdata. - - This method may not be used to create new nodes or rdatasets; - use L{find_rdataset} instead. - - None is returned if the name or type are not found. - Use L{find_rrset} if you want to have KeyError raised instead. - - @param name: the owner name to look for - @type name: DNS.name.Name object or string - @param rdtype: the rdata type desired - @type rdtype: int or string - @param covers: the covered type (defaults to None) - @type covers: int or string - @rtype: dns.rrset.RRset object - """ - - try: - rrset = self.find_rrset(name, rdtype, covers) - except KeyError: - rrset = None - return rrset - - def iterate_rdatasets(self, rdtype=dns.rdatatype.ANY, - covers=dns.rdatatype.NONE): - """Return a generator which yields (name, rdataset) tuples for - all rdatasets in the zone which have the specified I{rdtype} - and I{covers}. If I{rdtype} is dns.rdatatype.ANY, the default, - then all rdatasets will be matched. - - @param rdtype: int or string - @type rdtype: int or string - @param covers: the covered type (defaults to None) - @type covers: int or string - """ - - if isinstance(rdtype, string_types): - rdtype = dns.rdatatype.from_text(rdtype) - if isinstance(covers, string_types): - covers = dns.rdatatype.from_text(covers) - for (name, node) in self.iteritems(): - for rds in node: - if rdtype == dns.rdatatype.ANY or \ - (rds.rdtype == rdtype and rds.covers == covers): - yield (name, rds) - - def iterate_rdatas(self, rdtype=dns.rdatatype.ANY, - covers=dns.rdatatype.NONE): - """Return a generator which yields (name, ttl, rdata) tuples for - all rdatas in the zone which have the specified I{rdtype} - and I{covers}. If I{rdtype} is dns.rdatatype.ANY, the default, - then all rdatas will be matched. - - @param rdtype: int or string - @type rdtype: int or string - @param covers: the covered type (defaults to None) - @type covers: int or string - """ - - if isinstance(rdtype, string_types): - rdtype = dns.rdatatype.from_text(rdtype) - if isinstance(covers, string_types): - covers = dns.rdatatype.from_text(covers) - for (name, node) in self.iteritems(): - for rds in node: - if rdtype == dns.rdatatype.ANY or \ - (rds.rdtype == rdtype and rds.covers == covers): - for rdata in rds: - yield (name, rds.ttl, rdata) - - def to_file(self, f, sorted=True, relativize=True, nl=None): - """Write a zone to a file. - - @param f: file or string. If I{f} is a string, it is treated - as the name of a file to open. - @param sorted: if True, the file will be written with the - names sorted in DNSSEC order from least to greatest. Otherwise - the names will be written in whatever order they happen to have - in the zone's dictionary. - @param relativize: if True, domain names in the output will be - relativized to the zone's origin (if possible). - @type relativize: bool - @param nl: The end of line string. If not specified, the - output will use the platform's native end-of-line marker (i.e. - LF on POSIX, CRLF on Windows, CR on Macintosh). - @type nl: string or None - """ - - if isinstance(f, string_types): - f = open(f, 'wb') - want_close = True - else: - want_close = False - - # must be in this way, f.encoding may contain None, or even attribute - # may not be there - file_enc = getattr(f, 'encoding', None) - if file_enc is None: - file_enc = 'utf-8' - - if nl is None: - nl_b = os.linesep.encode(file_enc) # binary mode, '\n' is not enough - nl = u'\n' - elif isinstance(nl, string_types): - nl_b = nl.encode(file_enc) - else: - nl_b = nl - nl = nl.decode() - - try: - if sorted: - names = list(self.keys()) - names.sort() - else: - names = self.iterkeys() - for n in names: - l = self[n].to_text(n, origin=self.origin, - relativize=relativize) - if isinstance(l, text_type): - l_b = l.encode(file_enc) - else: - l_b = l - l = l.decode() - - try: - f.write(l_b) - f.write(nl_b) - except TypeError: # textual mode - f.write(l) - f.write(nl) - finally: - if want_close: - f.close() - - def to_text(self, sorted=True, relativize=True, nl=None): - """Return a zone's text as though it were written to a file. - - @param sorted: if True, the file will be written with the - names sorted in DNSSEC order from least to greatest. Otherwise - the names will be written in whatever order they happen to have - in the zone's dictionary. - @param relativize: if True, domain names in the output will be - relativized to the zone's origin (if possible). - @type relativize: bool - @param nl: The end of line string. If not specified, the - output will use the platform's native end-of-line marker (i.e. - LF on POSIX, CRLF on Windows, CR on Macintosh). - @type nl: string or None - """ - temp_buffer = BytesIO() - self.to_file(temp_buffer, sorted, relativize, nl) - return_value = temp_buffer.getvalue() - temp_buffer.close() - return return_value - - def check_origin(self): - """Do some simple checking of the zone's origin. - - @raises dns.zone.NoSOA: there is no SOA RR - @raises dns.zone.NoNS: there is no NS RRset - @raises KeyError: there is no origin node - """ - if self.relativize: - name = dns.name.empty - else: - name = self.origin - if self.get_rdataset(name, dns.rdatatype.SOA) is None: - raise NoSOA - if self.get_rdataset(name, dns.rdatatype.NS) is None: - raise NoNS - - -class _MasterReader(object): - - """Read a DNS master file - - @ivar tok: The tokenizer - @type tok: dns.tokenizer.Tokenizer object - @ivar ttl: The default TTL - @type ttl: int - @ivar last_name: The last name read - @type last_name: dns.name.Name object - @ivar current_origin: The current origin - @type current_origin: dns.name.Name object - @ivar relativize: should names in the zone be relativized? - @type relativize: bool - @ivar zone: the zone - @type zone: dns.zone.Zone object - @ivar saved_state: saved reader state (used when processing $INCLUDE) - @type saved_state: list of (tokenizer, current_origin, last_name, file) - tuples. - @ivar current_file: the file object of the $INCLUDed file being parsed - (None if no $INCLUDE is active). - @ivar allow_include: is $INCLUDE allowed? - @type allow_include: bool - @ivar check_origin: should sanity checks of the origin node be done? - The default is True. - @type check_origin: bool - """ - - def __init__(self, tok, origin, rdclass, relativize, zone_factory=Zone, - allow_include=False, check_origin=True): - if isinstance(origin, string_types): - origin = dns.name.from_text(origin) - self.tok = tok - self.current_origin = origin - self.relativize = relativize - self.ttl = 0 - self.last_name = self.current_origin - self.zone = zone_factory(origin, rdclass, relativize=relativize) - self.saved_state = [] - self.current_file = None - self.allow_include = allow_include - self.check_origin = check_origin - - def _eat_line(self): - while 1: - token = self.tok.get() - if token.is_eol_or_eof(): - break - - def _rr_line(self): - """Process one line from a DNS master file.""" - # Name - if self.current_origin is None: - raise UnknownOrigin - token = self.tok.get(want_leading=True) - if not token.is_whitespace(): - self.last_name = dns.name.from_text( - token.value, self.current_origin) - else: - token = self.tok.get() - if token.is_eol_or_eof(): - # treat leading WS followed by EOL/EOF as if they were EOL/EOF. - return - self.tok.unget(token) - name = self.last_name - if not name.is_subdomain(self.zone.origin): - self._eat_line() - return - if self.relativize: - name = name.relativize(self.zone.origin) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - # TTL - try: - ttl = dns.ttl.from_text(token.value) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except dns.ttl.BadTTL: - ttl = self.ttl - # Class - try: - rdclass = dns.rdataclass.from_text(token.value) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except dns.exception.SyntaxError: - raise dns.exception.SyntaxError - except Exception: - rdclass = self.zone.rdclass - if rdclass != self.zone.rdclass: - raise dns.exception.SyntaxError("RR class is not zone's class") - # Type - try: - rdtype = dns.rdatatype.from_text(token.value) - except: - raise dns.exception.SyntaxError( - "unknown rdatatype '%s'" % token.value) - n = self.zone.nodes.get(name) - if n is None: - n = self.zone.node_factory() - self.zone.nodes[name] = n - try: - rd = dns.rdata.from_text(rdclass, rdtype, self.tok, - self.current_origin, False) - except dns.exception.SyntaxError: - # Catch and reraise. - (ty, va) = sys.exc_info()[:2] - raise va - except: - # All exceptions that occur in the processing of rdata - # are treated as syntax errors. This is not strictly - # correct, but it is correct almost all of the time. - # We convert them to syntax errors so that we can emit - # helpful filename:line info. - (ty, va) = sys.exc_info()[:2] - raise dns.exception.SyntaxError( - "caught exception %s: %s" % (str(ty), str(va))) - - rd.choose_relativity(self.zone.origin, self.relativize) - covers = rd.covers() - rds = n.find_rdataset(rdclass, rdtype, covers, True) - rds.add(rd, ttl) - - def _parse_modify(self, side): - # Here we catch everything in '{' '}' in a group so we can replace it - # with ''. - is_generate1 = re.compile("^.*\$({(\+|-?)(\d+),(\d+),(.)}).*$") - is_generate2 = re.compile("^.*\$({(\+|-?)(\d+)}).*$") - is_generate3 = re.compile("^.*\$({(\+|-?)(\d+),(\d+)}).*$") - # Sometimes there are modifiers in the hostname. These come after - # the dollar sign. They are in the form: ${offset[,width[,base]]}. - # Make names - g1 = is_generate1.match(side) - if g1: - mod, sign, offset, width, base = g1.groups() - if sign == '': - sign = '+' - g2 = is_generate2.match(side) - if g2: - mod, sign, offset = g2.groups() - if sign == '': - sign = '+' - width = 0 - base = 'd' - g3 = is_generate3.match(side) - if g3: - mod, sign, offset, width = g1.groups() - if sign == '': - sign = '+' - width = g1.groups()[2] - base = 'd' - - if not (g1 or g2 or g3): - mod = '' - sign = '+' - offset = 0 - width = 0 - base = 'd' - - if base != 'd': - raise NotImplementedError() - - return mod, sign, offset, width, base - - def _generate_line(self): - # range lhs [ttl] [class] type rhs [ comment ] - """Process one line containing the GENERATE statement from a DNS - master file.""" - if self.current_origin is None: - raise UnknownOrigin - - token = self.tok.get() - # Range (required) - try: - start, stop, step = dns.grange.from_text(token.value) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except: - raise dns.exception.SyntaxError - - # lhs (required) - try: - lhs = token.value - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except: - raise dns.exception.SyntaxError - - # TTL - try: - ttl = dns.ttl.from_text(token.value) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except dns.ttl.BadTTL: - ttl = self.ttl - # Class - try: - rdclass = dns.rdataclass.from_text(token.value) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except dns.exception.SyntaxError: - raise dns.exception.SyntaxError - except Exception: - rdclass = self.zone.rdclass - if rdclass != self.zone.rdclass: - raise dns.exception.SyntaxError("RR class is not zone's class") - # Type - try: - rdtype = dns.rdatatype.from_text(token.value) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except Exception: - raise dns.exception.SyntaxError("unknown rdatatype '%s'" % - token.value) - - # lhs (required) - try: - rhs = token.value - except: - raise dns.exception.SyntaxError - - lmod, lsign, loffset, lwidth, lbase = self._parse_modify(lhs) - rmod, rsign, roffset, rwidth, rbase = self._parse_modify(rhs) - for i in range(start, stop + 1, step): - # +1 because bind is inclusive and python is exclusive - - if lsign == u'+': - lindex = i + int(loffset) - elif lsign == u'-': - lindex = i - int(loffset) - - if rsign == u'-': - rindex = i - int(roffset) - elif rsign == u'+': - rindex = i + int(roffset) - - lzfindex = str(lindex).zfill(int(lwidth)) - rzfindex = str(rindex).zfill(int(rwidth)) - - name = lhs.replace(u'$%s' % (lmod), lzfindex) - rdata = rhs.replace(u'$%s' % (rmod), rzfindex) - - self.last_name = dns.name.from_text(name, self.current_origin) - name = self.last_name - if not name.is_subdomain(self.zone.origin): - self._eat_line() - return - if self.relativize: - name = name.relativize(self.zone.origin) - - n = self.zone.nodes.get(name) - if n is None: - n = self.zone.node_factory() - self.zone.nodes[name] = n - try: - rd = dns.rdata.from_text(rdclass, rdtype, rdata, - self.current_origin, False) - except dns.exception.SyntaxError: - # Catch and reraise. - (ty, va) = sys.exc_info()[:2] - raise va - except: - # All exceptions that occur in the processing of rdata - # are treated as syntax errors. This is not strictly - # correct, but it is correct almost all of the time. - # We convert them to syntax errors so that we can emit - # helpful filename:line info. - (ty, va) = sys.exc_info()[:2] - raise dns.exception.SyntaxError("caught exception %s: %s" % - (str(ty), str(va))) - - rd.choose_relativity(self.zone.origin, self.relativize) - covers = rd.covers() - rds = n.find_rdataset(rdclass, rdtype, covers, True) - rds.add(rd, ttl) - - def read(self): - """Read a DNS master file and build a zone object. - - @raises dns.zone.NoSOA: No SOA RR was found at the zone origin - @raises dns.zone.NoNS: No NS RRset was found at the zone origin - """ - - try: - while 1: - token = self.tok.get(True, True) - if token.is_eof(): - if self.current_file is not None: - self.current_file.close() - if len(self.saved_state) > 0: - (self.tok, - self.current_origin, - self.last_name, - self.current_file, - self.ttl) = self.saved_state.pop(-1) - continue - break - elif token.is_eol(): - continue - elif token.is_comment(): - self.tok.get_eol() - continue - elif token.value[0] == u'$': - c = token.value.upper() - if c == u'$TTL': - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError("bad $TTL") - self.ttl = dns.ttl.from_text(token.value) - self.tok.get_eol() - elif c == u'$ORIGIN': - self.current_origin = self.tok.get_name() - self.tok.get_eol() - if self.zone.origin is None: - self.zone.origin = self.current_origin - elif c == u'$INCLUDE' and self.allow_include: - token = self.tok.get() - filename = token.value - token = self.tok.get() - if token.is_identifier(): - new_origin =\ - dns.name.from_text(token.value, - self.current_origin) - self.tok.get_eol() - elif not token.is_eol_or_eof(): - raise dns.exception.SyntaxError( - "bad origin in $INCLUDE") - else: - new_origin = self.current_origin - self.saved_state.append((self.tok, - self.current_origin, - self.last_name, - self.current_file, - self.ttl)) - self.current_file = open(filename, 'r') - self.tok = dns.tokenizer.Tokenizer(self.current_file, - filename) - self.current_origin = new_origin - elif c == u'$GENERATE': - self._generate_line() - else: - raise dns.exception.SyntaxError( - "Unknown master file directive '" + c + "'") - continue - self.tok.unget(token) - self._rr_line() - except dns.exception.SyntaxError as detail: - (filename, line_number) = self.tok.where() - if detail is None: - detail = "syntax error" - raise dns.exception.SyntaxError( - "%s:%d: %s" % (filename, line_number, detail)) - - # Now that we're done reading, do some basic checking of the zone. - if self.check_origin: - self.zone.check_origin() - - -def from_text(text, origin=None, rdclass=dns.rdataclass.IN, - relativize=True, zone_factory=Zone, filename=None, - allow_include=False, check_origin=True): - """Build a zone object from a master file format string. - - @param text: the master file format input - @type text: string. - @param origin: The origin of the zone; if not specified, the first - $ORIGIN statement in the master file will determine the origin of the - zone. - @type origin: dns.name.Name object or string - @param rdclass: The zone's rdata class; the default is class IN. - @type rdclass: int - @param relativize: should names be relativized? The default is True - @type relativize: bool - @param zone_factory: The zone factory to use - @type zone_factory: function returning a Zone - @param filename: The filename to emit when describing where an error - occurred; the default is ''. - @type filename: string - @param allow_include: is $INCLUDE allowed? - @type allow_include: bool - @param check_origin: should sanity checks of the origin node be done? - The default is True. - @type check_origin: bool - @raises dns.zone.NoSOA: No SOA RR was found at the zone origin - @raises dns.zone.NoNS: No NS RRset was found at the zone origin - @rtype: dns.zone.Zone object - """ - - # 'text' can also be a file, but we don't publish that fact - # since it's an implementation detail. The official file - # interface is from_file(). - - if filename is None: - filename = '' - tok = dns.tokenizer.Tokenizer(text, filename) - reader = _MasterReader(tok, origin, rdclass, relativize, zone_factory, - allow_include=allow_include, - check_origin=check_origin) - reader.read() - return reader.zone - - -def from_file(f, origin=None, rdclass=dns.rdataclass.IN, - relativize=True, zone_factory=Zone, filename=None, - allow_include=True, check_origin=True): - """Read a master file and build a zone object. - - @param f: file or string. If I{f} is a string, it is treated - as the name of a file to open. - @param origin: The origin of the zone; if not specified, the first - $ORIGIN statement in the master file will determine the origin of the - zone. - @type origin: dns.name.Name object or string - @param rdclass: The zone's rdata class; the default is class IN. - @type rdclass: int - @param relativize: should names be relativized? The default is True - @type relativize: bool - @param zone_factory: The zone factory to use - @type zone_factory: function returning a Zone - @param filename: The filename to emit when describing where an error - occurred; the default is '', or the value of I{f} if I{f} is a - string. - @type filename: string - @param allow_include: is $INCLUDE allowed? - @type allow_include: bool - @param check_origin: should sanity checks of the origin node be done? - The default is True. - @type check_origin: bool - @raises dns.zone.NoSOA: No SOA RR was found at the zone origin - @raises dns.zone.NoNS: No NS RRset was found at the zone origin - @rtype: dns.zone.Zone object - """ - - str_type = string_types - opts = 'rU' - - if isinstance(f, str_type): - if filename is None: - filename = f - f = open(f, opts) - want_close = True - else: - if filename is None: - filename = '' - want_close = False - - try: - z = from_text(f, origin, rdclass, relativize, zone_factory, - filename, allow_include, check_origin) - finally: - if want_close: - f.close() - return z - - -def from_xfr(xfr, zone_factory=Zone, relativize=True, check_origin=True): - """Convert the output of a zone transfer generator into a zone object. - - @param xfr: The xfr generator - @type xfr: generator of dns.message.Message objects - @param relativize: should names be relativized? The default is True. - It is essential that the relativize setting matches the one specified - to dns.query.xfr(). - @type relativize: bool - @param check_origin: should sanity checks of the origin node be done? - The default is True. - @type check_origin: bool - @raises dns.zone.NoSOA: No SOA RR was found at the zone origin - @raises dns.zone.NoNS: No NS RRset was found at the zone origin - @rtype: dns.zone.Zone object - """ - - z = None - for r in xfr: - if z is None: - if relativize: - origin = r.origin - else: - origin = r.answer[0].name - rdclass = r.answer[0].rdclass - z = zone_factory(origin, rdclass, relativize=relativize) - for rrset in r.answer: - znode = z.nodes.get(rrset.name) - if not znode: - znode = z.node_factory() - z.nodes[rrset.name] = znode - zrds = znode.find_rdataset(rrset.rdclass, rrset.rdtype, - rrset.covers, True) - zrds.update_ttl(rrset.ttl) - for rd in rrset: - rd.choose_relativity(z.origin, relativize) - zrds.add(rd) - if check_origin: - z.check_origin() - return z diff -Nru python-eventlet-0.20.0/eventlet/support/greendns.py python-eventlet-0.24.1/eventlet/support/greendns.py --- python-eventlet-0.20.0/eventlet/support/greendns.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/greendns.py 2018-08-06 16:17:47.000000000 +0000 @@ -32,15 +32,17 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +import re import struct import sys +import eventlet from eventlet import patcher from eventlet.green import _socket_nodns from eventlet.green import os from eventlet.green import time from eventlet.green import select -from eventlet.support import six +import six def import_patched(module_name): @@ -48,8 +50,6 @@ # regular evenlet.green.socket imports *this* module and if we imported # it back we'd end with an import cycle (socket -> greendns -> socket). # We break this import cycle by providing a restricted socket module. - # if (module_name + '.').startswith('dns.'): - # module_name = 'eventlet.support.' + module_name modules = { 'select': select, 'time': time, @@ -59,10 +59,10 @@ return patcher.import_patched(module_name, **modules) -sys.path.insert(0, os.path.abspath(os.path.dirname(__file__))) dns = import_patched('dns') for pkg in dns.__all__: setattr(dns, pkg, import_patched('dns.' + pkg)) +dns.rdtypes.__all__.extend(['dnskeybase', 'dsbase', 'txtbase']) for pkg in dns.rdtypes.__all__: setattr(dns.rdtypes, pkg, import_patched('dns.rdtypes.' + pkg)) for pkg in dns.rdtypes.IN.__all__: @@ -70,7 +70,6 @@ for pkg in dns.rdtypes.ANY.__all__: setattr(dns.rdtypes.ANY, pkg, import_patched('dns.rdtypes.ANY.' + pkg)) del import_patched -sys.path.pop(0) socket = _socket_nodns @@ -79,8 +78,14 @@ HOSTS_TTL = 10.0 EAI_EAGAIN_ERROR = socket.gaierror(socket.EAI_AGAIN, 'Lookup timed out') -EAI_NODATA_ERROR = socket.gaierror(socket.EAI_NODATA, 'No address associated with hostname') EAI_NONAME_ERROR = socket.gaierror(socket.EAI_NONAME, 'Name or service not known') +# EAI_NODATA was removed from RFC3493, it's now replaced with EAI_NONAME +# socket.EAI_NODATA is not defined on FreeBSD, probably on some other platforms too. +# https://lists.freebsd.org/pipermail/freebsd-ports/2003-October/005757.html +EAI_NODATA_ERROR = EAI_NONAME_ERROR +if (os.environ.get('EVENTLET_DEPRECATED_EAI_NODATA', '').lower() in ('1', 'y', 'yes') + and hasattr(socket, 'EAI_NODATA')): + EAI_NODATA_ERROR = socket.gaierror(socket.EAI_NODATA, 'No address associated with hostname') def is_ipv4_addr(host): @@ -148,10 +153,18 @@ :interval: The time between checking for hosts file modification """ + LINES_RE = re.compile(r""" + \s* # Leading space + ([^\r\n#]*?) # The actual match, non-greedy so as not to include trailing space + \s* # Trailing space + (?:[#][^\r\n]+)? # Comments + (?:$|[\r\n]+) # EOF or newline + """, re.VERBOSE) + def __init__(self, fname=None, interval=HOSTS_TTL): self._v4 = {} # name -> ipv4 self._v6 = {} # name -> ipv6 - self._aliases = {} # name -> cannonical_name + self._aliases = {} # name -> canonical_name self.interval = interval self.fname = fname if fname is None: @@ -172,16 +185,15 @@ Note that this performs disk I/O so can be blocking. """ - lines = [] try: - with open(self.fname, 'rU') as fp: - for line in fp: - line = line.strip() - if line and line[0] != '#': - lines.append(line) + with open(self.fname, 'rb') as fp: + fdata = fp.read() except (IOError, OSError): - pass - return lines + return [] + + udata = fdata.decode(errors='ignore') + + return six.moves.filter(None, self.LINES_RE.findall(udata)) def _load(self): """Load hosts file @@ -207,9 +219,10 @@ ipmap = self._v6 else: continue - cname = parts.pop(0) + cname = parts.pop(0).lower() ipmap[cname] = ip for alias in parts: + alias = alias.lower() ipmap[alias] = ip self._aliases[alias] = cname self._last_load = time.time() @@ -236,6 +249,7 @@ qname = dns.name.from_text(qname) else: name = str(qname) + name = name.lower() rrset = dns.rrset.RRset(qname, rdclass, rdtype) rrset.ttl = self._last_load + self.interval - now if rdclass == dns.rdataclass.IN and rdtype == dns.rdatatype.A: @@ -303,17 +317,67 @@ self._resolver.cache = dns.resolver.LRUCache() def query(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, - tcp=False, source=None, raise_on_no_answer=True): - """Query the resolver, using /etc/hosts if enabled""" + tcp=False, source=None, raise_on_no_answer=True, + _hosts_rdtypes=(dns.rdatatype.A, dns.rdatatype.AAAA), + use_network=True): + """Query the resolver, using /etc/hosts if enabled. + + Behavior: + 1. if hosts is enabled and contains answer, return it now + 2. query nameservers for qname if use_network is True + 3. if qname did not contain dots, pretend it was top-level domain, + query "foobar." and append to previous result + """ + result = [None, None, 0] + if qname is None: qname = '0.0.0.0' - if rdclass == dns.rdataclass.IN and self._hosts: + if isinstance(qname, six.string_types): + qname = dns.name.from_text(qname, None) + + def step(fun, *args, **kwargs): try: - return self._hosts.query(qname, rdtype) - except dns.resolver.NoAnswer: - pass - return self._resolver.query(qname, rdtype, rdclass, - tcp, source, raise_on_no_answer) + a = fun(*args, **kwargs) + except Exception as e: + result[1] = e + return False + if a.rrset is not None and len(a.rrset): + if result[0] is None: + result[0] = a + else: + result[0].rrset.union_update(a.rrset) + result[2] += len(a.rrset) + return True + + def end(): + if result[0] is not None: + if raise_on_no_answer and result[2] == 0: + raise dns.resolver.NoAnswer + return result[0] + if result[1] is not None: + if raise_on_no_answer or not isinstance(result[1], dns.resolver.NoAnswer): + raise result[1] + raise dns.resolver.NXDOMAIN(qnames=(qname,)) + + if (self._hosts and (rdclass == dns.rdataclass.IN) and (rdtype in _hosts_rdtypes)): + if step(self._hosts.query, qname, rdtype, raise_on_no_answer=False): + if (result[0] is not None) or (result[1] is not None) or (not use_network): + return end() + + # Main query + step(self._resolver.query, qname, rdtype, rdclass, tcp, source, raise_on_no_answer=False) + + # `resolv.conf` docs say unqualified names must resolve from search (or local) domain. + # However, common OS `getaddrinfo()` implementations append trailing dot (e.g. `db -> db.`) + # and ask nameservers, as if top-level domain was queried. + # This step follows established practice. + # https://github.com/nameko/nameko/issues/392 + # https://github.com/eventlet/eventlet/issues/363 + if len(qname) == 1: + step(self._resolver.query, qname.concatenate(dns.name.root), + rdtype, rdclass, tcp, source, raise_on_no_answer=False) + + return end() def getaliases(self, hostname): """Return a list of all the aliases of a given hostname""" @@ -335,10 +399,12 @@ resolver = ResolverProxy(hosts_resolver=HostsResolver()) -def resolve(name, family=socket.AF_INET, raises=True): - """Resolve a name for a given family using the global resolver proxy +def resolve(name, family=socket.AF_INET, raises=True, _proxy=None, + use_network=True): + """Resolve a name for a given family using the global resolver proxy. - This method is called by the global getaddrinfo() function. + This method is called by the global getaddrinfo() function. If use_network + is False, only resolution via hosts file will be performed. Return a dns.resolver.Answer instance. If there is no answer it's rrset will be emtpy. @@ -350,9 +416,13 @@ else: raise socket.gaierror(socket.EAI_FAMILY, 'Address family not supported') + + if _proxy is None: + _proxy = resolver try: try: - return resolver.query(name, rdtype, raise_on_no_answer=raises) + return _proxy.query(name, rdtype, raise_on_no_answer=raises, + use_network=use_network) except dns.resolver.NXDOMAIN: if not raises: return HostsAnswer(dns.name.Name(name), @@ -403,16 +473,19 @@ addrs = [] if family == socket.AF_UNSPEC: err = None - for qfamily in [socket.AF_INET6, socket.AF_INET]: - try: - answer = resolve(host, qfamily, False) - except socket.gaierror as e: - if e.errno not in (socket.EAI_AGAIN, socket.EAI_NODATA): - raise - err = e - else: - if answer.rrset: - addrs.extend(rr.address for rr in answer.rrset) + for use_network in [False, True]: + for qfamily in [socket.AF_INET6, socket.AF_INET]: + try: + answer = resolve(host, qfamily, False, use_network=use_network) + except socket.gaierror as e: + if e.errno not in (socket.EAI_AGAIN, EAI_NONAME_ERROR.errno, EAI_NODATA_ERROR.errno): + raise + err = e + else: + if answer.rrset: + addrs.extend(rr.address for rr in answer.rrset) + if addrs: + break if err is not None and not addrs: raise err elif family == socket.AF_INET6 and flags & socket.AI_V4MAPPED: @@ -545,13 +618,13 @@ def _net_read(sock, count, expiration): - """coro friendly replacement for dns.query._net_write + """coro friendly replacement for dns.query._net_read Read the specified number of bytes from sock. Keep trying until we either get the desired amount, or we hit EOF. A Timeout exception will be raised if the operation is not completed by the expiration time. """ - s = '' + s = bytearray() while count > 0: try: n = sock.recv(count) @@ -559,10 +632,12 @@ # Q: Do we also need to catch coro.CoroutineSocketWake and pass? if expiration - time.time() <= 0.0: raise dns.exception.Timeout - if n == '': + eventlet.sleep(0.01) + continue + if n == b'': raise EOFError count = count - len(n) - s = s + n + s += n return s @@ -622,7 +697,12 @@ if source is not None: source = (source, source_port) elif af == dns.inet.AF_INET6: - destination = (where, port, 0, 0) + # Purge any stray zeroes in source address. When doing the tuple comparison + # below, we need to always ensure both our target and where we receive replies + # from are compared with all zeroes removed so that we don't erroneously fail. + # e.g. ('00::1', 53, 0, 0) != ('::1', 53, 0, 0) + where_trunc = dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(where)) + destination = (where_trunc, port, 0, 0) if source is not None: source = (source, source_port, 0, 0) @@ -632,19 +712,39 @@ expiration = dns.query._compute_expiration(timeout) if source is not None: s.bind(source) - try: - s.sendto(wire, destination) - except socket.timeout: - # Q: Do we also need to catch coro.CoroutineSocketWake and pass? - if expiration - time.time() <= 0.0: - raise dns.exception.Timeout - while 1: + while True: try: - (wire, from_address) = s.recvfrom(65535) + s.sendto(wire, destination) + break except socket.timeout: # Q: Do we also need to catch coro.CoroutineSocketWake and pass? if expiration - time.time() <= 0.0: raise dns.exception.Timeout + eventlet.sleep(0.01) + continue + + tried = False + while True: + # If we've tried to receive at least once, check to see if our + # timer expired + if tried and (expiration - time.time() <= 0.0): + raise dns.exception.Timeout + # Sleep if we are retrying the operation due to a bad source + # address or a socket timeout. + if tried: + eventlet.sleep(0.01) + tried = True + + try: + (wire, from_address) = s.recvfrom(65535) + except socket.timeout: + # Q: Do we also need to catch coro.CoroutineSocketWake and pass? + continue + if dns.inet.af_for_address(from_address[0]) == dns.inet.AF_INET6: + # Purge all possible zeroes for ipv6 to match above logic + addr = from_address[0] + addr = dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(addr)) + from_address = (addr, from_address[1], from_address[2], from_address[3]) if from_address == destination: break if not ignore_unexpected: @@ -705,12 +805,16 @@ expiration = dns.query._compute_expiration(timeout) if source is not None: s.bind(source) - try: - s.connect(destination) - except socket.timeout: - # Q: Do we also need to catch coro.CoroutineSocketWake and pass? - if expiration - time.time() <= 0.0: - raise dns.exception.Timeout + while True: + try: + s.connect(destination) + break + except socket.timeout: + # Q: Do we also need to catch coro.CoroutineSocketWake and pass? + if expiration - time.time() <= 0.0: + raise dns.exception.Timeout + eventlet.sleep(0.01) + continue l = len(wire) # copying the wire into tcpmsg is inefficient, but lets us @@ -720,7 +824,7 @@ _net_write(s, tcpmsg, expiration) ldata = _net_read(s, 2, expiration) (l,) = struct.unpack("!H", ldata) - wire = _net_read(s, l, expiration) + wire = bytes(_net_read(s, l, expiration)) finally: s.close() r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac) diff -Nru python-eventlet-0.20.0/eventlet/support/__init__.py python-eventlet-0.24.1/eventlet/support/__init__.py --- python-eventlet-0.20.0/eventlet/support/__init__.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/__init__.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,7 +1,12 @@ +import inspect +import functools import sys -from contextlib import contextmanager +import warnings -from eventlet.support import greenlets, six +from eventlet.support import greenlets + + +_MISSING = object() def get_errno(exc): @@ -43,13 +48,31 @@ PY33 = sys.version_info[:2] == (3, 3) -@contextmanager -def capture_stderr(): - stream = six.StringIO() - original = sys.stderr - try: - sys.stderr = stream - yield stream - finally: - sys.stderr = original - stream.seek(0) + +def wrap_deprecated(old, new): + def _resolve(s): + return 'eventlet.'+s if '.' not in s else s + msg = '''\ +{old} is deprecated and will be removed in next version. Use {new} instead. +Autoupgrade: fgrep -rl '{old}' . |xargs -t sed --in-place='' -e 's/{old}/{new}/' +'''.format(old=_resolve(old), new=_resolve(new)) + + def wrapper(base): + klass = None + if inspect.isclass(base): + class klass(base): + pass + klass.__name__ = base.__name__ + klass.__module__ = base.__module__ + + @functools.wraps(base) + def wrapped(*a, **kw): + warnings.warn(msg, DeprecationWarning, stacklevel=5) + return base(*a, **kw) + + if klass is not None: + klass.__init__ = wrapped + return klass + + return wrapped + return wrapper diff -Nru python-eventlet-0.20.0/eventlet/support/psycopg2_patcher.py python-eventlet-0.24.1/eventlet/support/psycopg2_patcher.py --- python-eventlet-0.20.0/eventlet/support/psycopg2_patcher.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/psycopg2_patcher.py 2018-08-06 16:17:47.000000000 +0000 @@ -27,7 +27,7 @@ import psycopg2 from psycopg2 import extensions -from eventlet.hubs import trampoline +import eventlet.hubs def make_psycopg_green(): @@ -47,9 +47,9 @@ if state == extensions.POLL_OK: break elif state == extensions.POLL_READ: - trampoline(conn.fileno(), read=True) + eventlet.hubs.trampoline(conn.fileno(), read=True) elif state == extensions.POLL_WRITE: - trampoline(conn.fileno(), write=True) + eventlet.hubs.trampoline(conn.fileno(), write=True) else: raise psycopg2.OperationalError( "Bad result from poll: %r" % state) diff -Nru python-eventlet-0.20.0/eventlet/support/six.py python-eventlet-0.24.1/eventlet/support/six.py --- python-eventlet-0.20.0/eventlet/support/six.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/support/six.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,762 +0,0 @@ -"""Utilities for writing code that runs on Python 2 and 3""" - -# Copyright (c) 2010-2014 Benjamin Peterson -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -from __future__ import absolute_import - -import functools -import operator -import sys -import types - -__author__ = "Benjamin Peterson " -__version__ = "1.8.0" - - -# Useful for very coarse version differentiation. -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 - -if PY3: - string_types = str, - integer_types = int, - class_types = type, - text_type = str - binary_type = bytes - - MAXSIZE = sys.maxsize -else: - string_types = basestring, - integer_types = (int, long) - class_types = (type, types.ClassType) - text_type = unicode - binary_type = str - - if sys.platform.startswith("java"): - # Jython always uses 32 bits. - MAXSIZE = int((1 << 31) - 1) - else: - # It's possible to have sizeof(long) != sizeof(Py_ssize_t). - class X(object): - def __len__(self): - return 1 << 31 - try: - len(X()) - except OverflowError: - # 32-bit - MAXSIZE = int((1 << 31) - 1) - else: - # 64-bit - MAXSIZE = int((1 << 63) - 1) - del X - - -def _add_doc(func, doc): - """Add documentation to a function.""" - func.__doc__ = doc - - -def _import_module(name): - """Import module, returning the module after the last dot.""" - __import__(name) - return sys.modules[name] - - -class _LazyDescr(object): - - def __init__(self, name): - self.name = name - - def __get__(self, obj, tp): - result = self._resolve() - setattr(obj, self.name, result) # Invokes __set__. - # This is a bit ugly, but it avoids running this again. - delattr(obj.__class__, self.name) - return result - - -class MovedModule(_LazyDescr): - - def __init__(self, name, old, new=None): - super(MovedModule, self).__init__(name) - if PY3: - if new is None: - new = name - self.mod = new - else: - self.mod = old - - def _resolve(self): - return _import_module(self.mod) - - def __getattr__(self, attr): - _module = self._resolve() - value = getattr(_module, attr) - setattr(self, attr, value) - return value - - -class _LazyModule(types.ModuleType): - - def __init__(self, name): - super(_LazyModule, self).__init__(name) - self.__doc__ = self.__class__.__doc__ - - def __dir__(self): - attrs = ["__doc__", "__name__"] - attrs += [attr.name for attr in self._moved_attributes] - return attrs - - # Subclasses should override this - _moved_attributes = [] - - -class MovedAttribute(_LazyDescr): - - def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): - super(MovedAttribute, self).__init__(name) - if PY3: - if new_mod is None: - new_mod = name - self.mod = new_mod - if new_attr is None: - if old_attr is None: - new_attr = name - else: - new_attr = old_attr - self.attr = new_attr - else: - self.mod = old_mod - if old_attr is None: - old_attr = name - self.attr = old_attr - - def _resolve(self): - module = _import_module(self.mod) - return getattr(module, self.attr) - - -class _SixMetaPathImporter(object): - """ - A meta path importer to import six.moves and its submodules. - - This class implements a PEP302 finder and loader. It should be compatible - with Python 2.5 and all existing versions of Python3 - """ - def __init__(self, six_module_name): - self.name = six_module_name - self.known_modules = {} - - def _add_module(self, mod, *fullnames): - for fullname in fullnames: - self.known_modules[self.name + "." + fullname] = mod - - def _get_module(self, fullname): - return self.known_modules[self.name + "." + fullname] - - def find_module(self, fullname, path=None): - if fullname in self.known_modules: - return self - return None - - def __get_module(self, fullname): - try: - return self.known_modules[fullname] - except KeyError: - raise ImportError("This loader does not know module " + fullname) - - def load_module(self, fullname): - try: - # in case of a reload - return sys.modules[fullname] - except KeyError: - pass - mod = self.__get_module(fullname) - if isinstance(mod, MovedModule): - mod = mod._resolve() - else: - mod.__loader__ = self - sys.modules[fullname] = mod - return mod - - def is_package(self, fullname): - """ - Return true, if the named module is a package. - - We need this method to get correct spec objects with - Python 3.4 (see PEP451) - """ - return hasattr(self.__get_module(fullname), "__path__") - - def get_code(self, fullname): - """Return None - - Required, if is_package is implemented""" - self.__get_module(fullname) # eventually raises ImportError - return None - get_source = get_code # same as get_code - -_importer = _SixMetaPathImporter(__name__) - - -class _MovedItems(_LazyModule): - """Lazy loading of moved objects""" - __path__ = [] # mark as package - - -_moved_attributes = [ - MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), - MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), - MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), - MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), - MovedAttribute("intern", "__builtin__", "sys"), - MovedAttribute("map", "itertools", "builtins", "imap", "map"), - MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("reload_module", "__builtin__", "imp", "reload"), - MovedAttribute("reduce", "__builtin__", "functools"), - MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), - MovedAttribute("StringIO", "StringIO", "io"), - MovedAttribute("UserDict", "UserDict", "collections"), - MovedAttribute("UserList", "UserList", "collections"), - MovedAttribute("UserString", "UserString", "collections"), - MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), - MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), - - MovedModule("builtins", "__builtin__"), - MovedModule("configparser", "ConfigParser"), - MovedModule("copyreg", "copy_reg"), - MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), - MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"), - MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), - MovedModule("http_cookies", "Cookie", "http.cookies"), - MovedModule("html_entities", "htmlentitydefs", "html.entities"), - MovedModule("html_parser", "HTMLParser", "html.parser"), - MovedModule("http_client", "httplib", "http.client"), - MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), - MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), - MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), - MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), - MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), - MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), - MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), - MovedModule("cPickle", "cPickle", "pickle"), - MovedModule("queue", "Queue"), - MovedModule("reprlib", "repr"), - MovedModule("socketserver", "SocketServer"), - MovedModule("_thread", "thread", "_thread"), - MovedModule("tkinter", "Tkinter"), - MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), - MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), - MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), - MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), - MovedModule("tkinter_tix", "Tix", "tkinter.tix"), - MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), - MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), - MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), - MovedModule("tkinter_colorchooser", "tkColorChooser", - "tkinter.colorchooser"), - MovedModule("tkinter_commondialog", "tkCommonDialog", - "tkinter.commondialog"), - MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), - MovedModule("tkinter_font", "tkFont", "tkinter.font"), - MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), - MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", - "tkinter.simpledialog"), - MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), - MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), - MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), - MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), - MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), - MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), - MovedModule("winreg", "_winreg"), -] -for attr in _moved_attributes: - setattr(_MovedItems, attr.name, attr) - if isinstance(attr, MovedModule): - _importer._add_module(attr, "moves." + attr.name) -del attr - -_MovedItems._moved_attributes = _moved_attributes - -moves = _MovedItems(__name__ + ".moves") -_importer._add_module(moves, "moves") - - -class Module_six_moves_urllib_parse(_LazyModule): - """Lazy loading of moved objects in six.moves.urllib_parse""" - - -_urllib_parse_moved_attributes = [ - MovedAttribute("ParseResult", "urlparse", "urllib.parse"), - MovedAttribute("SplitResult", "urlparse", "urllib.parse"), - MovedAttribute("parse_qs", "urlparse", "urllib.parse"), - MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), - MovedAttribute("urldefrag", "urlparse", "urllib.parse"), - MovedAttribute("urljoin", "urlparse", "urllib.parse"), - MovedAttribute("urlparse", "urlparse", "urllib.parse"), - MovedAttribute("urlsplit", "urlparse", "urllib.parse"), - MovedAttribute("urlunparse", "urlparse", "urllib.parse"), - MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), - MovedAttribute("quote", "urllib", "urllib.parse"), - MovedAttribute("quote_plus", "urllib", "urllib.parse"), - MovedAttribute("unquote", "urllib", "urllib.parse"), - MovedAttribute("unquote_plus", "urllib", "urllib.parse"), - MovedAttribute("urlencode", "urllib", "urllib.parse"), - MovedAttribute("splitquery", "urllib", "urllib.parse"), - MovedAttribute("splittag", "urllib", "urllib.parse"), - MovedAttribute("splituser", "urllib", "urllib.parse"), - MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), - MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), - MovedAttribute("uses_params", "urlparse", "urllib.parse"), - MovedAttribute("uses_query", "urlparse", "urllib.parse"), - MovedAttribute("uses_relative", "urlparse", "urllib.parse"), -] -for attr in _urllib_parse_moved_attributes: - setattr(Module_six_moves_urllib_parse, attr.name, attr) -del attr - -Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes - -_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), - "moves.urllib_parse", "moves.urllib.parse") - - -class Module_six_moves_urllib_error(_LazyModule): - """Lazy loading of moved objects in six.moves.urllib_error""" - - -_urllib_error_moved_attributes = [ - MovedAttribute("URLError", "urllib2", "urllib.error"), - MovedAttribute("HTTPError", "urllib2", "urllib.error"), - MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), -] -for attr in _urllib_error_moved_attributes: - setattr(Module_six_moves_urllib_error, attr.name, attr) -del attr - -Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes - -_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), - "moves.urllib_error", "moves.urllib.error") - - -class Module_six_moves_urllib_request(_LazyModule): - """Lazy loading of moved objects in six.moves.urllib_request""" - - -_urllib_request_moved_attributes = [ - MovedAttribute("urlopen", "urllib2", "urllib.request"), - MovedAttribute("install_opener", "urllib2", "urllib.request"), - MovedAttribute("build_opener", "urllib2", "urllib.request"), - MovedAttribute("pathname2url", "urllib", "urllib.request"), - MovedAttribute("url2pathname", "urllib", "urllib.request"), - MovedAttribute("getproxies", "urllib", "urllib.request"), - MovedAttribute("Request", "urllib2", "urllib.request"), - MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), - MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), - MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), - MovedAttribute("BaseHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), - MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), - MovedAttribute("FileHandler", "urllib2", "urllib.request"), - MovedAttribute("FTPHandler", "urllib2", "urllib.request"), - MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), - MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), - MovedAttribute("urlretrieve", "urllib", "urllib.request"), - MovedAttribute("urlcleanup", "urllib", "urllib.request"), - MovedAttribute("URLopener", "urllib", "urllib.request"), - MovedAttribute("FancyURLopener", "urllib", "urllib.request"), - MovedAttribute("proxy_bypass", "urllib", "urllib.request"), -] -for attr in _urllib_request_moved_attributes: - setattr(Module_six_moves_urllib_request, attr.name, attr) -del attr - -Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes - -_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), - "moves.urllib_request", "moves.urllib.request") - - -class Module_six_moves_urllib_response(_LazyModule): - """Lazy loading of moved objects in six.moves.urllib_response""" - - -_urllib_response_moved_attributes = [ - MovedAttribute("addbase", "urllib", "urllib.response"), - MovedAttribute("addclosehook", "urllib", "urllib.response"), - MovedAttribute("addinfo", "urllib", "urllib.response"), - MovedAttribute("addinfourl", "urllib", "urllib.response"), -] -for attr in _urllib_response_moved_attributes: - setattr(Module_six_moves_urllib_response, attr.name, attr) -del attr - -Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes - -_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), - "moves.urllib_response", "moves.urllib.response") - - -class Module_six_moves_urllib_robotparser(_LazyModule): - """Lazy loading of moved objects in six.moves.urllib_robotparser""" - - -_urllib_robotparser_moved_attributes = [ - MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), -] -for attr in _urllib_robotparser_moved_attributes: - setattr(Module_six_moves_urllib_robotparser, attr.name, attr) -del attr - -Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes - -_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), - "moves.urllib_robotparser", "moves.urllib.robotparser") - - -class Module_six_moves_urllib(types.ModuleType): - """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" - __path__ = [] # mark as package - parse = _importer._get_module("moves.urllib_parse") - error = _importer._get_module("moves.urllib_error") - request = _importer._get_module("moves.urllib_request") - response = _importer._get_module("moves.urllib_response") - robotparser = _importer._get_module("moves.urllib_robotparser") - - def __dir__(self): - return ['parse', 'error', 'request', 'response', 'robotparser'] - -_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), - "moves.urllib") - - -def add_move(move): - """Add an item to six.moves.""" - setattr(_MovedItems, move.name, move) - - -def remove_move(name): - """Remove item from six.moves.""" - try: - delattr(_MovedItems, name) - except AttributeError: - try: - del moves.__dict__[name] - except KeyError: - raise AttributeError("no such move, %r" % (name,)) - - -if PY3: - _meth_func = "__func__" - _meth_self = "__self__" - - _func_closure = "__closure__" - _func_code = "__code__" - _func_defaults = "__defaults__" - _func_globals = "__globals__" -else: - _meth_func = "im_func" - _meth_self = "im_self" - - _func_closure = "func_closure" - _func_code = "func_code" - _func_defaults = "func_defaults" - _func_globals = "func_globals" - - -try: - advance_iterator = next -except NameError: - def advance_iterator(it): - return it.next() -next = advance_iterator - - -try: - callable = callable -except NameError: - def callable(obj): - return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) - - -if PY3: - def get_unbound_function(unbound): - return unbound - - create_bound_method = types.MethodType - - Iterator = object -else: - def get_unbound_function(unbound): - return unbound.im_func - - def create_bound_method(func, obj): - return types.MethodType(func, obj, obj.__class__) - - class Iterator(object): - - def next(self): - return type(self).__next__(self) - - callable = callable -_add_doc(get_unbound_function, - """Get the function out of a possibly unbound function""") - - -get_method_function = operator.attrgetter(_meth_func) -get_method_self = operator.attrgetter(_meth_self) -get_function_closure = operator.attrgetter(_func_closure) -get_function_code = operator.attrgetter(_func_code) -get_function_defaults = operator.attrgetter(_func_defaults) -get_function_globals = operator.attrgetter(_func_globals) - - -if PY3: - def iterkeys(d, **kw): - return iter(d.keys(**kw)) - - def itervalues(d, **kw): - return iter(d.values(**kw)) - - def iteritems(d, **kw): - return iter(d.items(**kw)) - - def iterlists(d, **kw): - return iter(d.lists(**kw)) -else: - def iterkeys(d, **kw): - return iter(d.iterkeys(**kw)) - - def itervalues(d, **kw): - return iter(d.itervalues(**kw)) - - def iteritems(d, **kw): - return iter(d.iteritems(**kw)) - - def iterlists(d, **kw): - return iter(d.iterlists(**kw)) - -_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") -_add_doc(itervalues, "Return an iterator over the values of a dictionary.") -_add_doc(iteritems, - "Return an iterator over the (key, value) pairs of a dictionary.") -_add_doc(iterlists, - "Return an iterator over the (key, [values]) pairs of a dictionary.") - - -if PY3: - def b(s): - return s.encode("latin-1") - def u(s): - return s - unichr = chr - if sys.version_info[1] <= 1: - def int2byte(i): - return bytes((i,)) - else: - # This is about 2x faster than the implementation above on 3.2+ - int2byte = operator.methodcaller("to_bytes", 1, "big") - byte2int = operator.itemgetter(0) - indexbytes = operator.getitem - iterbytes = iter - import io - StringIO = io.StringIO - BytesIO = io.BytesIO -else: - def b(s): - return s - # Workaround for standalone backslash - def u(s): - return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") - unichr = unichr - int2byte = chr - def byte2int(bs): - return ord(bs[0]) - def indexbytes(buf, i): - return ord(buf[i]) - def iterbytes(buf): - return (ord(byte) for byte in buf) - import StringIO - StringIO = BytesIO = StringIO.StringIO -_add_doc(b, """Byte literal""") -_add_doc(u, """Text literal""") - - -if PY3: - exec_ = getattr(moves.builtins, "exec") - - - def reraise(tp, value, tb=None): - if value is None: - value = tp() - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - -else: - def exec_(_code_, _globs_=None, _locs_=None): - """Execute code in a namespace.""" - if _globs_ is None: - frame = sys._getframe(1) - _globs_ = frame.f_globals - if _locs_ is None: - _locs_ = frame.f_locals - del frame - elif _locs_ is None: - _locs_ = _globs_ - exec("""exec _code_ in _globs_, _locs_""") - - - exec_("""def reraise(tp, value, tb=None): - raise tp, value, tb -""") - - -print_ = getattr(moves.builtins, "print", None) -if print_ is None: - def print_(*args, **kwargs): - """The new-style print function for Python 2.4 and 2.5.""" - fp = kwargs.pop("file", sys.stdout) - if fp is None: - return - def write(data): - if not isinstance(data, basestring): - data = str(data) - # If the file has an encoding, encode unicode with it. - if (isinstance(fp, file) and - isinstance(data, unicode) and - fp.encoding is not None): - errors = getattr(fp, "errors", None) - if errors is None: - errors = "strict" - data = data.encode(fp.encoding, errors) - fp.write(data) - want_unicode = False - sep = kwargs.pop("sep", None) - if sep is not None: - if isinstance(sep, unicode): - want_unicode = True - elif not isinstance(sep, str): - raise TypeError("sep must be None or a string") - end = kwargs.pop("end", None) - if end is not None: - if isinstance(end, unicode): - want_unicode = True - elif not isinstance(end, str): - raise TypeError("end must be None or a string") - if kwargs: - raise TypeError("invalid keyword arguments to print()") - if not want_unicode: - for arg in args: - if isinstance(arg, unicode): - want_unicode = True - break - if want_unicode: - newline = unicode("\n") - space = unicode(" ") - else: - newline = "\n" - space = " " - if sep is None: - sep = space - if end is None: - end = newline - for i, arg in enumerate(args): - if i: - write(sep) - write(arg) - write(end) - -_add_doc(reraise, """Reraise an exception.""") - -if sys.version_info[0:2] < (3, 4): - def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, - updated=functools.WRAPPER_UPDATES): - def wrapper(f): - f = functools.wraps(wrapped)(f) - f.__wrapped__ = wrapped - return f - return wrapper -else: - wraps = functools.wraps - -def with_metaclass(meta, *bases): - """Create a base class with a metaclass.""" - # This requires a bit of explanation: the basic idea is to make a dummy - # metaclass for one level of class instantiation that replaces itself with - # the actual metaclass. - class metaclass(meta): - def __new__(cls, name, this_bases, d): - return meta(name, bases, d) - return type.__new__(metaclass, 'temporary_class', (), {}) - - -def add_metaclass(metaclass): - """Class decorator for creating a class with a metaclass.""" - def wrapper(cls): - orig_vars = cls.__dict__.copy() - slots = orig_vars.get('__slots__') - if slots is not None: - if isinstance(slots, str): - slots = [slots] - for slots_var in slots: - orig_vars.pop(slots_var) - orig_vars.pop('__dict__', None) - orig_vars.pop('__weakref__', None) - return metaclass(cls.__name__, cls.__bases__, orig_vars) - return wrapper - -# Complete the moves implementation. -# This code is at the end of this module to speed up module loading. -# Turn this module into a package. -__path__ = [] # required for PEP 302 and PEP 451 -__package__ = __name__ # see PEP 366 @ReservedAssignment -if globals().get("__spec__") is not None: - __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable -# Remove other six meta path importers, since they cause problems. This can -# happen if six is removed from sys.modules and then reloaded. (Setuptools does -# this for some reason.) -if sys.meta_path: - for i, importer in enumerate(sys.meta_path): - # Here's some real nastiness: Another "instance" of the six module might - # be floating around. Therefore, we can't use isinstance() to check for - # the six meta path importer, since the other six instance will have - # inserted an importer with different class. - if (type(importer).__name__ == "_SixMetaPathImporter" and - importer.name == __name__): - del sys.meta_path[i] - break - del i, importer -# Finally, add the importer to the meta path import hook. -sys.meta_path.append(_importer) diff -Nru python-eventlet-0.20.0/eventlet/timeout.py python-eventlet-0.24.1/eventlet/timeout.py --- python-eventlet-0.20.0/eventlet/timeout.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/timeout.py 2018-08-06 16:17:47.000000000 +0000 @@ -18,15 +18,18 @@ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE.from eventlet.support import greenlets as greenlet +# THE SOFTWARE. +import functools +import inspect + +import eventlet from eventlet.support import greenlets as greenlet from eventlet.hubs import get_hub -__all__ = ['Timeout', - 'with_timeout'] +__all__ = ['Timeout', 'with_timeout', 'wrap_is_timeout', 'is_timeout'] -_NONE = object() +_MISSING = object() # deriving from BaseException so that "except Exception as e" doesn't catch # Timeout exceptions. @@ -128,20 +131,49 @@ if value is self and self.exception is False: return True + @property + def is_timeout(self): + return True + def with_timeout(seconds, function, *args, **kwds): """Wrap a call to some (yielding) function with a timeout; if the called function fails to return before the timeout, cancel it and return a flag value. """ - timeout_value = kwds.pop("timeout_value", _NONE) + timeout_value = kwds.pop("timeout_value", _MISSING) timeout = Timeout(seconds) try: try: return function(*args, **kwds) except Timeout as ex: - if ex is timeout and timeout_value is not _NONE: + if ex is timeout and timeout_value is not _MISSING: return timeout_value raise finally: timeout.cancel() + + +def wrap_is_timeout(base): + '''Adds `.is_timeout=True` attribute to objects returned by `base()`. + + When `base` is class, attribute is added as read-only property. Returns `base`. + Otherwise, it returns a function that sets attribute on result of `base()` call. + + Wrappers make best effort to be transparent. + ''' + if inspect.isclass(base): + base.is_timeout = property(lambda _: True) + return base + + @functools.wraps(base) + def fun(*args, **kwargs): + ex = base(*args, **kwargs) + ex.is_timeout = True + return ex + return fun + + +def is_timeout(obj): + py3err = getattr(__builtins__, 'TimeoutError', Timeout) + return bool(getattr(obj, 'is_timeout', False)) or isinstance(obj, py3err) diff -Nru python-eventlet-0.20.0/eventlet/tpool.py python-eventlet-0.24.1/eventlet/tpool.py --- python-eventlet-0.20.0/eventlet/tpool.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/tpool.py 2018-08-06 16:17:47.000000000 +0000 @@ -21,7 +21,7 @@ import eventlet from eventlet import event, greenio, greenthread, patcher, timeout -from eventlet.support import six +import six __all__ = ['execute', 'Proxy', 'killall', 'set_num_threads'] @@ -85,6 +85,10 @@ raise except EXC_CLASSES: rv = sys.exc_info() + if sys.version_info >= (3, 4): + traceback.clear_frames(rv[1].__traceback__) + if six.PY2: + sys.exc_clear() # test_leakage_from_tracebacks verifies that the use of # exc_info does not lead to memory leaks _rspq.put((e, rv)) diff -Nru python-eventlet-0.20.0/eventlet/websocket.py python-eventlet-0.24.1/eventlet/websocket.py --- python-eventlet-0.20.0/eventlet/websocket.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/websocket.py 2018-08-06 16:17:47.000000000 +0000 @@ -9,6 +9,8 @@ import sys import time +import zlib + try: from hashlib import md5, sha1 except ImportError: # pragma NO COVER @@ -18,7 +20,8 @@ from eventlet import semaphore from eventlet import wsgi from eventlet.green import socket -from eventlet.support import get_errno, six +from eventlet.support import get_errno +import six # Python 2's utf8 decoding is more lenient than we'd like # In order to pass autobahn's testsuite we need stricter validation @@ -196,6 +199,76 @@ sock.sendall(handshake_reply) return WebSocket(sock, environ, self.protocol_version) + def _parse_extension_header(self, header): + if header is None: + return None + res = {} + for ext in header.split(","): + parts = ext.split(";") + config = {} + for part in parts[1:]: + key_val = part.split("=") + if len(key_val) == 1: + config[key_val[0].strip().lower()] = True + else: + config[key_val[0].strip().lower()] = key_val[1].strip().strip('"').lower() + res.setdefault(parts[0].strip().lower(), []).append(config) + return res + + def _negotiate_permessage_deflate(self, extensions): + if not extensions: + return None + deflate = extensions.get("permessage-deflate") + if deflate is None: + return None + for config in deflate: + # We'll evaluate each config in the client's preferred order and pick + # the first that we can support. + want_config = { + # These are bool options, we can support both + "server_no_context_takeover": config.get("server_no_context_takeover", False), + "client_no_context_takeover": config.get("client_no_context_takeover", False) + } + # These are either bool OR int options. True means the client can accept a value + # for the option, a number means the client wants that specific value. + max_wbits = min(zlib.MAX_WBITS, 15) + mwb = config.get("server_max_window_bits") + if mwb is not None: + if mwb is True: + want_config["server_max_window_bits"] = max_wbits + else: + want_config["server_max_window_bits"] = \ + int(config.get("server_max_window_bits", max_wbits)) + if not (8 <= want_config["server_max_window_bits"] <= 15): + continue + mwb = config.get("client_max_window_bits") + if mwb is not None: + if mwb is True: + want_config["client_max_window_bits"] = max_wbits + else: + want_config["client_max_window_bits"] = \ + int(config.get("client_max_window_bits", max_wbits)) + if not (8 <= want_config["client_max_window_bits"] <= 15): + continue + return want_config + return None + + def _format_extension_header(self, parsed_extensions): + if not parsed_extensions: + return None + parts = [] + for name, config in parsed_extensions.items(): + ext_parts = [six.b(name)] + for key, value in config.items(): + if value is False: + pass + elif value is True: + ext_parts.append(six.b(key)) + else: + ext_parts.append(six.b("%s=%s" % (key, str(value)))) + parts.append(b"; ".join(ext_parts)) + return b", ".join(parts) + def _handle_hybi_request(self, environ): if 'eventlet.input' in environ: sock = environ['eventlet.input'].get_socket() @@ -226,9 +299,6 @@ if p in self.supported_protocols: negotiated_protocol = p break - # extensions = environ.get('HTTP_SEC_WEBSOCKET_EXTENSIONS', None) - # if extensions: - # extensions = [i.strip() for i in extensions.split(',')] key = environ['HTTP_SEC_WEBSOCKET_KEY'] response = base64.b64encode(sha1(six.b(key) + PROTOCOL_GUID).digest()) @@ -238,9 +308,22 @@ b"Sec-WebSocket-Accept: " + response] if negotiated_protocol: handshake_reply.append(b"Sec-WebSocket-Protocol: " + six.b(negotiated_protocol)) + + parsed_extensions = {} + extensions = self._parse_extension_header(environ.get("HTTP_SEC_WEBSOCKET_EXTENSIONS")) + + deflate = self._negotiate_permessage_deflate(extensions) + if deflate is not None: + parsed_extensions["permessage-deflate"] = deflate + + formatted_ext = self._format_extension_header(parsed_extensions) + if formatted_ext is not None: + handshake_reply.append(b"Sec-WebSocket-Extensions: " + formatted_ext) + sock.sendall(b'\r\n'.join(handshake_reply) + b'\r\n\r\n') return RFC6455WebSocket(sock, environ, self.protocol_version, - protocol=negotiated_protocol) + protocol=negotiated_protocol, + extensions=parsed_extensions) def _extract_number(self, value): """ @@ -285,6 +368,12 @@ :param environ: The wsgi environment :param version: The WebSocket spec version to follow (default is 76) """ + self.log = environ.get('wsgi.errors', sys.stderr) + self.log_context = 'server={shost}/{spath} client={caddr}:{cport}'.format( + shost=environ.get('HTTP_HOST'), + spath=environ.get('SCRIPT_NAME', '') + environ.get('PATH_INFO', ''), + caddr=environ.get('REMOTE_ADDR'), cport=environ.get('REMOTE_PORT'), + ) self.socket = sock self.origin = environ.get('HTTP_ORIGIN') self.protocol = environ.get('HTTP_WEBSOCKET_PROTOCOL') @@ -296,8 +385,7 @@ self._msgs = collections.deque() self._sendlock = semaphore.Semaphore() - @staticmethod - def _pack_message(message): + def _pack_message(self, message): """Pack the message inside ``00`` and ``FF`` As per the dataframing section (5.3) for the websocket spec @@ -388,9 +476,14 @@ def close(self): """Forcibly close the websocket; generally it is preferable to return from the handler method.""" - self._send_closing_frame() - self.socket.shutdown(True) - self.socket.close() + try: + self._send_closing_frame(True) + self.socket.shutdown(True) + except SocketError as e: + if e.errno != errno.ENOTCONN: + self.log.write('{ctx} socket shutdown error: {e}'.format(ctx=self.log_context, e=e)) + finally: + self.socket.close() class ConnectionClosedError(Exception): @@ -409,11 +502,15 @@ class RFC6455WebSocket(WebSocket): - def __init__(self, sock, environ, version=13, protocol=None, client=False): + def __init__(self, sock, environ, version=13, protocol=None, client=False, extensions=None): super(RFC6455WebSocket, self).__init__(sock, environ, version) self.iterator = self._iter_frames() self.client = client self.protocol = protocol + self.extensions = extensions or {} + + self._deflate_enc = None + self._deflate_dec = None class UTF8Decoder(object): def __init__(self): @@ -436,6 +533,45 @@ raise ValueError('Data is not valid unicode') return self.decoder.decode(data, final) + def _get_permessage_deflate_enc(self): + options = self.extensions.get("permessage-deflate") + if options is None: + return None + + def _make(): + return zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, + -options.get("client_max_window_bits" if self.client + else "server_max_window_bits", + zlib.MAX_WBITS)) + + if options.get("client_no_context_takeover" if self.client + else "server_no_context_takeover"): + # This option means we have to make a new one every time + return _make() + else: + if self._deflate_enc is None: + self._deflate_enc = _make() + return self._deflate_enc + + def _get_permessage_deflate_dec(self, rsv1): + options = self.extensions.get("permessage-deflate") + if options is None or not rsv1: + return None + + def _make(): + return zlib.decompressobj(-options.get("server_max_window_bits" if self.client + else "client_max_window_bits", + zlib.MAX_WBITS)) + + if options.get("server_no_context_takeover" if self.client + else "client_no_context_takeover"): + # This option means we have to make a new one every time + return _make() + else: + if self._deflate_dec is None: + self._deflate_dec = _make() + return self._deflate_dec + def _get_bytes(self, numbytes): data = b'' while len(data) < numbytes: @@ -446,20 +582,24 @@ return data class Message(object): - def __init__(self, opcode, decoder=None): + def __init__(self, opcode, decoder=None, decompressor=None): self.decoder = decoder self.data = [] self.finished = False self.opcode = opcode + self.decompressor = decompressor def push(self, data, final=False): - if self.decoder: - data = self.decoder.decode(data, final=final) self.finished = final self.data.append(data) def getvalue(self): - return ('' if self.decoder else b'').join(self.data) + data = b"".join(self.data) + if not self.opcode & 8 and self.decompressor: + data = self.decompressor.decompress(data + b'\x00\x00\xff\xff') + if self.decoder: + data = self.decoder.decode(data, self.finished) + return data @staticmethod def _apply_mask(data, mask, length=None, offset=0): @@ -523,16 +663,21 @@ def _recv_frame(self, message=None): recv = self._get_bytes + + # Unpacking the frame described in Section 5.2 of RFC6455 + # (https://tools.ietf.org/html/rfc6455#section-5.2) header = recv(2) a, b = struct.unpack('!BB', header) finished = a >> 7 == 1 rsv123 = a >> 4 & 7 + rsv1 = rsv123 & 4 if rsv123: - # must be zero - raise FailedConnectionError( - 1002, - "RSV1, RSV2, RSV3: MUST be 0 unless an extension is" - " negotiated that defines meanings for non-zero values.") + if rsv1 and "permessage-deflate" not in self.extensions: + # must be zero - unless it's compressed then rsv1 is true + raise FailedConnectionError( + 1002, + "RSV1, RSV2, RSV3: MUST be 0 unless an extension is" + " negotiated that defines meanings for non-zero values.") opcode = a & 15 if opcode not in (0, 1, 2, 8, 9, 0xA): raise FailedConnectionError(1002, "Unknown opcode received.") @@ -569,7 +714,8 @@ received = 0 if not message or opcode & 8: decoder = self.UTF8Decoder() if opcode == 1 else None - message = self.Message(opcode, decoder=decoder) + decompressor = self._get_permessage_deflate_dec(rsv1) + message = self.Message(opcode, decoder=decoder, decompressor=decompressor) if not length: message.push(b'', final=finished) else: @@ -588,13 +734,22 @@ 1007, "Text data must be valid utf-8") return message - @staticmethod - def _pack_message(message, masked=False, + def _pack_message(self, message, masked=False, continuation=False, final=True, control_code=None): is_text = False if isinstance(message, six.text_type): message = message.encode('utf-8') is_text = True + + compress_bit = 0 + compressor = self._get_permessage_deflate_enc() + if message and compressor: + message = compressor.compress(message) + message += compressor.flush(zlib.Z_SYNC_FLUSH) + assert message[-4:] == b"\x00\x00\xff\xff" + message = message[:-4] + compress_bit = 1 << 6 + length = len(message) if not length: # no point masking empty data @@ -608,7 +763,7 @@ raise ProtocolError('Control frame data too large (>125).') header = struct.pack('!B', control_code | 1 << 7) else: - opcode = 0 if continuation else (1 if is_text else 2) + opcode = 0 if continuation else ((1 if is_text else 2) | compress_bit) header = struct.pack('!B', opcode | (1 << 7 if final else 0)) lengthdata = 1 << 7 if masked else 0 if length > 65535: @@ -666,6 +821,11 @@ def close(self, close_data=None): """Forcibly close the websocket; generally it is preferable to return from the handler method.""" - self._send_closing_frame(close_data=close_data) - self.socket.shutdown(socket.SHUT_WR) - self.socket.close() + try: + self._send_closing_frame(close_data=close_data, ignore_send_errors=True) + self.socket.shutdown(socket.SHUT_WR) + except SocketError as e: + if e.errno != errno.ENOTCONN: + self.log.write('{ctx} socket shutdown error: {e}'.format(ctx=self.log_context, e=e)) + finally: + self.socket.close() diff -Nru python-eventlet-0.20.0/eventlet/wsgi.py python-eventlet-0.24.1/eventlet/wsgi.py --- python-eventlet-0.20.0/eventlet/wsgi.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/wsgi.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,5 +1,4 @@ import errno -import functools import os import sys import time @@ -7,13 +6,13 @@ import types import warnings +import eventlet 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 +import six +from six.moves import urllib DEFAULT_MAX_SIMULTANEOUS_REQUESTS = 1024 @@ -25,8 +24,15 @@ # %(client_port)s is also available DEFAULT_LOG_FORMAT = ('%(client_ip)s - - [%(date_time)s] "%(request_line)s"' ' %(status_code)s %(body_length)s %(wall_seconds).6f') +RESPONSE_414 = b'''HTTP/1.0 414 Request URI Too Long\r\n\ +Connection: close\r\n\ +Content-Length: 0\r\n\r\n''' is_accepting = True +STATE_IDLE = 'idle' +STATE_REQUEST = 'request' +STATE_CLOSE = 'close' + __all__ = ['server', 'format_date_time'] # Weekday and month names for HTTP date/time formatting; always English! @@ -53,6 +59,14 @@ return (host, port) +def encode_dance(s): + if not isinstance(s, bytes): + s = s.encode('utf-8', 'replace') + if six.PY2: + return s + return s.decode('latin1') + + # Collections of error codes to compare against. Not all attributes are set # on errno module on all platforms, so some are literals :( BAD_SOCK = set((errno.EBADF, 10053)) @@ -248,10 +262,27 @@ and callable(getattr(log, 'debug', None)): return log else: - return LoggerFileWrapper(log, debug) + return LoggerFileWrapper(log or sys.stderr, debug) + + +class LoggerNull(object): + def __init__(self): + pass + + def error(self, msg, *args, **kwargs): + pass + + def info(self, msg, *args, **kwargs): + pass + + def debug(self, msg, *args, **kwargs): + pass + + def write(self, msg, *args): + pass -class LoggerFileWrapper(object): +class LoggerFileWrapper(LoggerNull): def __init__(self, log, debug): self.log = log self._debug = debug @@ -302,6 +333,17 @@ # so before going back to unbuffered, remove any usage of `writelines`. wbufsize = 16 << 10 + def __init__(self, conn_state, server): + self.request = conn_state[1] + self.client_address = conn_state[0] + self.conn_state = conn_state + self.server = server + self.setup() + try: + self.handle() + finally: + self.finish() + def setup(self): # overriding SocketServer.setup to correctly handle SSL.Connection objects conn = self.connection = self.request @@ -324,35 +366,50 @@ self.wfile = socket._fileobject(conn, "wb", self.wbufsize) else: # it's a SSLObject, or a martian - raise NotImplementedError("wsgi.py doesn't support sockets " - "of type %s" % type(conn)) + raise NotImplementedError( + '''eventlet.wsgi doesn't support sockets of type {0}'''.format(type(conn))) - def handle_one_request(self): - if self.server.max_http_version: - self.protocol_version = self.server.max_http_version + def handle(self): + self.close_connection = True + while True: + self.handle_one_request() + if self.conn_state[2] == STATE_CLOSE: + self.close_connection = 1 + if self.close_connection: + break + + def _read_request_line(self): if self.rfile.closed: self.close_connection = 1 - return + return '' try: - self.raw_requestline = self.rfile.readline(self.server.url_length_limit) - if len(self.raw_requestline) == self.server.url_length_limit: - self.wfile.write( - b"HTTP/1.0 414 Request URI Too Long\r\n" - b"Connection: close\r\nContent-length: 0\r\n\r\n") - self.close_connection = 1 - return + return self.rfile.readline(self.server.url_length_limit) except greenio.SSL.ZeroReturnError: - self.raw_requestline = '' + pass except socket.error as e: - if support.get_errno(e) not in BAD_SOCK: + last_errno = support.get_errno(e) + if last_errno in BROKEN_SOCK: + self.server.log.debug('({0}) connection reset by peer {1!r}'.format( + self.server.pid, + self.client_address)) + elif last_errno not in BAD_SOCK: raise - self.raw_requestline = '' + return '' + def handle_one_request(self): + if self.server.max_http_version: + self.protocol_version = self.server.max_http_version + + self.raw_requestline = self._read_request_line() if not self.raw_requestline: self.close_connection = 1 return + if len(self.raw_requestline) >= self.server.url_length_limit: + self.wfile.write(RESPONSE_414) + self.close_connection = 1 + return orig_rfile = self.rfile try: @@ -582,7 +639,7 @@ pq = self.path.split('?', 1) env['RAW_PATH_INFO'] = pq[0] - env['PATH_INFO'] = urllib.parse.unquote(pq[0]) + env['PATH_INFO'] = encode_dance(urllib.parse.unquote(pq[0])) if len(pq) > 1: env['QUERY_STRING'] = pq[1] @@ -615,7 +672,7 @@ else: headers = [h.split(':', 1) for h in headers] - env['headers_raw'] = headers_raw = tuple((k, v.strip()) for k, v in headers) + env['headers_raw'] = headers_raw = tuple((k, v.strip(' \t\n\r')) for k, v in headers) for k, v in headers_raw: k = k.replace('-', '_').upper() if k in ('CONTENT_TYPE', 'CONTENT_LENGTH'): @@ -678,10 +735,9 @@ self.outstanding_requests = 0 self.socket = socket self.address = address - if log: + self.log = LoggerNull() + if log_output: self.log = get_logger(log, debug) - else: - self.log = get_logger(sys.stderr, debug) self.app = app self.keepalive = keepalive self.environ = environ @@ -721,26 +777,26 @@ d.update(self.environ) return d - def process_request(self, sock_params): + def process_request(self, conn_state): # The actual request handling takes place in __init__, so we need to # set minimum_chunk_size before __init__ executes and we don't want to modify # class variable - sock, address = sock_params proto = new(self.protocol) if self.minimum_chunk_size is not None: proto.minimum_chunk_size = self.minimum_chunk_size proto.capitalize_response_headers = self.capitalize_response_headers try: - proto.__init__(sock, address, self) + proto.__init__(conn_state, self) except socket.timeout: # Expected exceptions are not exceptional - sock.close() + conn_state[1].close() # similar to logging "accepted" in server() - self.log.debug('(%s) timed out %r' % (self.pid, address)) + self.log.debug('({0}) timed out {1!r}'.format(self.pid, conn_state[0])) def log_message(self, message): - warnings.warn('server.log_message is deprecated. Please use server.log.info instead') - self.log.info(message) + raise AttributeError('''\ +eventlet.wsgi.server.log_message was deprecated and deleted. +Please use server.log.info instead.''') try: @@ -849,56 +905,72 @@ :param capitalize_response_headers: Normalize response headers' names to Foo-Bar. Default is True. """ - serv = Server(sock, sock.getsockname(), - site, log, - environ=environ, - max_http_version=max_http_version, - protocol=protocol, - minimum_chunk_size=minimum_chunk_size, - log_x_forwarded_for=log_x_forwarded_for, - keepalive=keepalive, - log_output=log_output, - log_format=log_format, - url_length_limit=url_length_limit, - debug=debug, - socket_timeout=socket_timeout, - capitalize_response_headers=capitalize_response_headers, - ) + serv = Server( + sock, sock.getsockname(), + site, log, + environ=environ, + max_http_version=max_http_version, + protocol=protocol, + minimum_chunk_size=minimum_chunk_size, + log_x_forwarded_for=log_x_forwarded_for, + keepalive=keepalive, + log_output=log_output, + log_format=log_format, + url_length_limit=url_length_limit, + debug=debug, + socket_timeout=socket_timeout, + capitalize_response_headers=capitalize_response_headers, + ) if server_event is not None: + warnings.warn( + 'eventlet.wsgi.Server() server_event kwarg is deprecated and will be removed soon', + DeprecationWarning, stacklevel=2) server_event.send(serv) if max_size is None: max_size = DEFAULT_MAX_SIMULTANEOUS_REQUESTS if custom_pool is not None: pool = custom_pool else: - pool = greenpool.GreenPool(max_size) + pool = eventlet.GreenPool(max_size) + + if not (hasattr(pool, 'spawn') and hasattr(pool, 'waitall')): + raise AttributeError('''\ +eventlet.wsgi.Server pool must provide methods: `spawn`, `waitall`. +If unsure, use eventlet.GreenPool.''') + + # [addr, socket, state] + connections = {} + + def _clean_connection(_, conn): + connections.pop(conn[0], None) + conn[2] = STATE_CLOSE + greenio.shutdown_safe(conn[1]) + conn[1].close() + try: - serv.log.info("(%s) wsgi starting up on %s" % ( - serv.pid, socket_repr(sock))) + serv.log.info('({0}) wsgi starting up on {1}'.format(serv.pid, socket_repr(sock))) while is_accepting: try: - client_socket = sock.accept() - client_socket[0].settimeout(serv.socket_timeout) - serv.log.debug("(%s) accepted %r" % ( - serv.pid, client_socket[1])) - try: - pool.spawn_n(serv.process_request, client_socket) - except AttributeError: - warnings.warn("wsgi's pool should be an instance of " - "eventlet.greenpool.GreenPool, is %s. Please convert your" - " call site to use GreenPool instead" % type(pool), - DeprecationWarning, stacklevel=2) - pool.execute_async(serv.process_request, client_socket) + client_socket, client_addr = sock.accept() + client_socket.settimeout(serv.socket_timeout) + serv.log.debug('({0}) accepted {1!r}'.format(serv.pid, client_addr)) + connections[client_addr] = connection = [client_addr, client_socket, STATE_IDLE] + (pool.spawn(serv.process_request, connection) + .link(_clean_connection, connection)) except ACCEPT_EXCEPTIONS as e: if support.get_errno(e) not in ACCEPT_ERRNO: raise except (KeyboardInterrupt, SystemExit): - serv.log.info("wsgi exiting") + serv.log.info('wsgi exiting') break finally: + for cs in six.itervalues(connections): + prev_state = cs[2] + cs[2] = STATE_CLOSE + if prev_state == STATE_IDLE: + greenio.shutdown_safe(cs[1]) pool.waitall() - serv.log.info("(%s) wsgi exited, is_accepting=%s" % ( - serv.pid, is_accepting)) + serv.log.info('({0}) wsgi exited, is_accepting={1}'.format(serv.pid, is_accepting)) try: # NOTE: It's not clear whether we want this to leave the # socket open or close it. Use cases like Spawning want diff -Nru python-eventlet-0.20.0/eventlet/zipkin/api.py python-eventlet-0.24.1/eventlet/zipkin/api.py --- python-eventlet-0.20.0/eventlet/zipkin/api.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/zipkin/api.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,186 @@ +import os +import sys +import time +import struct +import socket +import random + +from eventlet.green import threading +from eventlet.zipkin._thrift.zipkinCore import ttypes +from eventlet.zipkin._thrift.zipkinCore.constants import SERVER_SEND + + +client = None +_tls = threading.local() # thread local storage + + +def put_annotation(msg, endpoint=None): + """ This is annotation API. + You can add your own annotation from in your code. + Annotation is recorded with timestamp automatically. + e.g.) put_annotation('cache hit for %s' % request) + + :param msg: String message + :param endpoint: host info + """ + if is_sample(): + a = ZipkinDataBuilder.build_annotation(msg, endpoint) + trace_data = get_trace_data() + trace_data.add_annotation(a) + + +def put_key_value(key, value, endpoint=None): + """ This is binary annotation API. + You can add your own key-value extra information from in your code. + Key-value doesn't have a time component. + e.g.) put_key_value('http.uri', '/hoge/index.html') + + :param key: String + :param value: String + :param endpoint: host info + """ + if is_sample(): + b = ZipkinDataBuilder.build_binary_annotation(key, value, endpoint) + trace_data = get_trace_data() + trace_data.add_binary_annotation(b) + + +def is_tracing(): + """ Return whether the current thread is tracking or not """ + return hasattr(_tls, 'trace_data') + + +def is_sample(): + """ Return whether it should record trace information + for the request or not + """ + return is_tracing() and _tls.trace_data.sampled + + +def get_trace_data(): + if is_tracing(): + return _tls.trace_data + + +def set_trace_data(trace_data): + _tls.trace_data = trace_data + + +def init_trace_data(): + if is_tracing(): + del _tls.trace_data + + +def _uniq_id(): + """ + Create a random 64-bit signed integer appropriate + for use as trace and span IDs. + XXX: By experimentation zipkin has trouble recording traces with ids + larger than (2 ** 56) - 1 + """ + return random.randint(0, (2 ** 56) - 1) + + +def generate_trace_id(): + return _uniq_id() + + +def generate_span_id(): + return _uniq_id() + + +class TraceData(object): + + END_ANNOTATION = SERVER_SEND + + def __init__(self, name, trace_id, span_id, parent_id, sampled, endpoint): + """ + :param name: RPC name (String) + :param trace_id: int + :param span_id: int + :param parent_id: int or None + :param sampled: lets the downstream servers know + if I should record trace data for the request (bool) + :param endpoint: zipkin._thrift.zipkinCore.ttypes.EndPoint + """ + self.name = name + self.trace_id = trace_id + self.span_id = span_id + self.parent_id = parent_id + self.sampled = sampled + self.endpoint = endpoint + self.annotations = [] + self.bannotations = [] + self._done = False + + def add_annotation(self, annotation): + if annotation.host is None: + annotation.host = self.endpoint + if not self._done: + self.annotations.append(annotation) + if annotation.value == self.END_ANNOTATION: + self.flush() + + def add_binary_annotation(self, bannotation): + if bannotation.host is None: + bannotation.host = self.endpoint + if not self._done: + self.bannotations.append(bannotation) + + def flush(self): + span = ZipkinDataBuilder.build_span(name=self.name, + trace_id=self.trace_id, + span_id=self.span_id, + parent_id=self.parent_id, + annotations=self.annotations, + bannotations=self.bannotations) + client.send_to_collector(span) + self.annotations = [] + self.bannotations = [] + self._done = True + + +class ZipkinDataBuilder: + @staticmethod + def build_span(name, trace_id, span_id, parent_id, + annotations, bannotations): + return ttypes.Span( + name=name, + trace_id=trace_id, + id=span_id, + parent_id=parent_id, + annotations=annotations, + binary_annotations=bannotations + ) + + @staticmethod + def build_annotation(value, endpoint=None): + if isinstance(value, unicode): + value = value.encode('utf-8') + return ttypes.Annotation(time.time() * 1000 * 1000, + str(value), endpoint) + + @staticmethod + def build_binary_annotation(key, value, endpoint=None): + annotation_type = ttypes.AnnotationType.STRING + return ttypes.BinaryAnnotation(key, value, annotation_type, endpoint) + + @staticmethod + def build_endpoint(ipv4=None, port=None, service_name=None): + if ipv4 is not None: + ipv4 = ZipkinDataBuilder._ipv4_to_int(ipv4) + if service_name is None: + service_name = ZipkinDataBuilder._get_script_name() + return ttypes.Endpoint( + ipv4=ipv4, + port=port, + service_name=service_name + ) + + @staticmethod + def _ipv4_to_int(ipv4): + return struct.unpack('!i', socket.inet_aton(ipv4))[0] + + @staticmethod + def _get_script_name(): + return os.path.basename(sys.argv[0]) diff -Nru python-eventlet-0.20.0/eventlet/zipkin/client.py python-eventlet-0.24.1/eventlet/zipkin/client.py --- python-eventlet-0.20.0/eventlet/zipkin/client.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/zipkin/client.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,56 @@ +import base64 +import warnings + +from scribe import scribe +from thrift.transport import TTransport, TSocket +from thrift.protocol import TBinaryProtocol + +from eventlet import GreenPile + + +CATEGORY = 'zipkin' + + +class ZipkinClient(object): + + def __init__(self, host='127.0.0.1', port=9410): + """ + :param host: zipkin collector IP addoress (default '127.0.0.1') + :param port: zipkin collector port (default 9410) + """ + self.host = host + self.port = port + self.pile = GreenPile(1) + self._connect() + + def _connect(self): + socket = TSocket.TSocket(self.host, self.port) + self.transport = TTransport.TFramedTransport(socket) + protocol = TBinaryProtocol.TBinaryProtocol(self.transport, + False, False) + self.scribe_client = scribe.Client(protocol) + try: + self.transport.open() + except TTransport.TTransportException as e: + warnings.warn(e.message) + + def _build_message(self, thrift_obj): + trans = TTransport.TMemoryBuffer() + protocol = TBinaryProtocol.TBinaryProtocolAccelerated(trans=trans) + thrift_obj.write(protocol) + return base64.b64encode(trans.getvalue()) + + def send_to_collector(self, span): + self.pile.spawn(self._send, span) + + def _send(self, span): + log_entry = scribe.LogEntry(CATEGORY, self._build_message(span)) + try: + self.scribe_client.Log([log_entry]) + except Exception as e: + msg = 'ZipkinClient send error %s' % str(e) + warnings.warn(msg) + self._connect() + + def close(self): + self.transport.close() diff -Nru python-eventlet-0.20.0/eventlet/zipkin/greenthread.py python-eventlet-0.24.1/eventlet/zipkin/greenthread.py --- python-eventlet-0.20.0/eventlet/zipkin/greenthread.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/zipkin/greenthread.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,33 @@ +from eventlet import greenthread + +from eventlet.zipkin import api + + +__original_init__ = greenthread.GreenThread.__init__ +__original_main__ = greenthread.GreenThread.main + + +def _patched__init(self, parent): + # parent thread saves current TraceData from tls to self + if api.is_tracing(): + self.trace_data = api.get_trace_data() + + __original_init__(self, parent) + + +def _patched_main(self, function, args, kwargs): + # child thread inherits TraceData + if hasattr(self, 'trace_data'): + api.set_trace_data(self.trace_data) + + __original_main__(self, function, args, kwargs) + + +def patch(): + greenthread.GreenThread.__init__ = _patched__init + greenthread.GreenThread.main = _patched_main + + +def unpatch(): + greenthread.GreenThread.__init__ = __original_init__ + greenthread.GreenThread.main = __original_main__ diff -Nru python-eventlet-0.20.0/eventlet/zipkin/http.py python-eventlet-0.24.1/eventlet/zipkin/http.py --- python-eventlet-0.20.0/eventlet/zipkin/http.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/zipkin/http.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,61 @@ +import warnings + +import six +from eventlet.green import httplib +from eventlet.zipkin import api + + +# see https://twitter.github.io/zipkin/Instrumenting.html +HDR_TRACE_ID = 'X-B3-TraceId' +HDR_SPAN_ID = 'X-B3-SpanId' +HDR_PARENT_SPAN_ID = 'X-B3-ParentSpanId' +HDR_SAMPLED = 'X-B3-Sampled' + + +if six.PY2: + __org_endheaders__ = httplib.HTTPConnection.endheaders + __org_begin__ = httplib.HTTPResponse.begin + + def _patched_endheaders(self): + if api.is_tracing(): + trace_data = api.get_trace_data() + new_span_id = api.generate_span_id() + self.putheader(HDR_TRACE_ID, hex_str(trace_data.trace_id)) + self.putheader(HDR_SPAN_ID, hex_str(new_span_id)) + self.putheader(HDR_PARENT_SPAN_ID, hex_str(trace_data.span_id)) + self.putheader(HDR_SAMPLED, int(trace_data.sampled)) + api.put_annotation('Client Send') + + __org_endheaders__(self) + + def _patched_begin(self): + __org_begin__(self) + + if api.is_tracing(): + api.put_annotation('Client Recv (%s)' % self.status) + + +def patch(): + if six.PY2: + httplib.HTTPConnection.endheaders = _patched_endheaders + httplib.HTTPResponse.begin = _patched_begin + if six.PY3: + warnings.warn("Since current Python thrift release \ + doesn't support Python 3, eventlet.zipkin.http \ + doesn't also support Python 3 (http.client)") + + +def unpatch(): + if six.PY2: + httplib.HTTPConnection.endheaders = __org_endheaders__ + httplib.HTTPResponse.begin = __org_begin__ + if six.PY3: + pass + + +def hex_str(n): + """ + Thrift uses a binary representation of trace and span ids + HTTP headers use a hexadecimal representation of the same + """ + return '%0.16x' % (n,) diff -Nru python-eventlet-0.20.0/eventlet/zipkin/log.py python-eventlet-0.24.1/eventlet/zipkin/log.py --- python-eventlet-0.20.0/eventlet/zipkin/log.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/zipkin/log.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,19 @@ +import logging + +from eventlet.zipkin import api + + +__original_handle__ = logging.Logger.handle + + +def _patched_handle(self, record): + __original_handle__(self, record) + api.put_annotation(record.getMessage()) + + +def patch(): + logging.Logger.handle = _patched_handle + + +def unpatch(): + logging.Logger.handle = __original_handle__ diff -Nru python-eventlet-0.20.0/eventlet/zipkin/patcher.py python-eventlet-0.24.1/eventlet/zipkin/patcher.py --- python-eventlet-0.20.0/eventlet/zipkin/patcher.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/zipkin/patcher.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,41 @@ +from eventlet.zipkin import http +from eventlet.zipkin import wsgi +from eventlet.zipkin import greenthread +from eventlet.zipkin import log +from eventlet.zipkin import api +from eventlet.zipkin.client import ZipkinClient + + +def enable_trace_patch(host='127.0.0.1', port=9410, + trace_app_log=False, sampling_rate=1.0): + """ Apply monkey patch to trace your WSGI application. + + :param host: Scribe daemon IP address (default: '127.0.0.1') + :param port: Scribe daemon port (default: 9410) + :param trace_app_log: A Boolean indicating if the tracer will trace + application log together or not. This facility assume that + your application uses python standard logging library. + (default: False) + :param sampling_rate: A Float value (0.0~1.0) that indicates + the tracing frequency. If you specify 1.0, all request + are traced (and sent to Zipkin collecotr). + If you specify 0.1, only 1/10 requests are traced. (default: 1.0) + """ + api.client = ZipkinClient(host, port) + + # monkey patch for adding tracing facility + wsgi.patch(sampling_rate) + http.patch() + greenthread.patch() + + # monkey patch for capturing application log + if trace_app_log: + log.patch() + + +def disable_trace_patch(): + http.unpatch() + wsgi.unpatch() + greenthread.unpatch() + log.unpatch() + api.client.close() diff -Nru python-eventlet-0.20.0/eventlet/zipkin/_thrift/zipkinCore/constants.py python-eventlet-0.24.1/eventlet/zipkin/_thrift/zipkinCore/constants.py --- python-eventlet-0.20.0/eventlet/zipkin/_thrift/zipkinCore/constants.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/zipkin/_thrift/zipkinCore/constants.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,14 @@ +# +# Autogenerated by Thrift Compiler (0.8.0) +# +# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING +# +# + +from thrift.Thrift import TType, TMessageType, TException +from ttypes import * + +CLIENT_SEND = "cs" +CLIENT_RECV = "cr" +SERVER_SEND = "ss" +SERVER_RECV = "sr" diff -Nru python-eventlet-0.20.0/eventlet/zipkin/_thrift/zipkinCore/__init__.py python-eventlet-0.24.1/eventlet/zipkin/_thrift/zipkinCore/__init__.py --- python-eventlet-0.20.0/eventlet/zipkin/_thrift/zipkinCore/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/zipkin/_thrift/zipkinCore/__init__.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1 @@ +__all__ = ['ttypes', 'constants'] diff -Nru python-eventlet-0.20.0/eventlet/zipkin/_thrift/zipkinCore/ttypes.py python-eventlet-0.24.1/eventlet/zipkin/_thrift/zipkinCore/ttypes.py --- python-eventlet-0.20.0/eventlet/zipkin/_thrift/zipkinCore/ttypes.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/zipkin/_thrift/zipkinCore/ttypes.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,452 @@ +# +# Autogenerated by Thrift Compiler (0.8.0) +# +# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING +# +# + +from thrift.Thrift import TType, TMessageType, TException + +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol, TProtocol +try: + from thrift.protocol import fastbinary +except: + fastbinary = None + + +class AnnotationType: + BOOL = 0 + BYTES = 1 + I16 = 2 + I32 = 3 + I64 = 4 + DOUBLE = 5 + STRING = 6 + + _VALUES_TO_NAMES = { + 0: "BOOL", + 1: "BYTES", + 2: "I16", + 3: "I32", + 4: "I64", + 5: "DOUBLE", + 6: "STRING", + } + + _NAMES_TO_VALUES = { + "BOOL": 0, + "BYTES": 1, + "I16": 2, + "I32": 3, + "I64": 4, + "DOUBLE": 5, + "STRING": 6, + } + + +class Endpoint: + """ + Attributes: + - ipv4 + - port + - service_name + """ + + thrift_spec = ( + None, # 0 + (1, TType.I32, 'ipv4', None, None, ), # 1 + (2, TType.I16, 'port', None, None, ), # 2 + (3, TType.STRING, 'service_name', None, None, ), # 3 + ) + + def __init__(self, ipv4=None, port=None, service_name=None,): + self.ipv4 = ipv4 + self.port = port + self.service_name = service_name + + def read(self, iprot): + if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None: + fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec)) + return + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + if fid == 1: + if ftype == TType.I32: + self.ipv4 = iprot.readI32(); + else: + iprot.skip(ftype) + elif fid == 2: + if ftype == TType.I16: + self.port = iprot.readI16(); + else: + iprot.skip(ftype) + elif fid == 3: + if ftype == TType.STRING: + self.service_name = iprot.readString(); + else: + iprot.skip(ftype) + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None: + oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec))) + return + oprot.writeStructBegin('Endpoint') + if self.ipv4 is not None: + oprot.writeFieldBegin('ipv4', TType.I32, 1) + oprot.writeI32(self.ipv4) + oprot.writeFieldEnd() + if self.port is not None: + oprot.writeFieldBegin('port', TType.I16, 2) + oprot.writeI16(self.port) + oprot.writeFieldEnd() + if self.service_name is not None: + oprot.writeFieldBegin('service_name', TType.STRING, 3) + oprot.writeString(self.service_name) + oprot.writeFieldEnd() + oprot.writeFieldStop() + oprot.writeStructEnd() + + def validate(self): + return + + + def __repr__(self): + L = ['%s=%r' % (key, value) + for key, value in self.__dict__.iteritems()] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) + +class Annotation: + """ + Attributes: + - timestamp + - value + - host + """ + + thrift_spec = ( + None, # 0 + (1, TType.I64, 'timestamp', None, None, ), # 1 + (2, TType.STRING, 'value', None, None, ), # 2 + (3, TType.STRUCT, 'host', (Endpoint, Endpoint.thrift_spec), None, ), # 3 + ) + + def __init__(self, timestamp=None, value=None, host=None,): + self.timestamp = timestamp + self.value = value + self.host = host + + def read(self, iprot): + if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None: + fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec)) + return + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + if fid == 1: + if ftype == TType.I64: + self.timestamp = iprot.readI64(); + else: + iprot.skip(ftype) + elif fid == 2: + if ftype == TType.STRING: + self.value = iprot.readString(); + else: + iprot.skip(ftype) + elif fid == 3: + if ftype == TType.STRUCT: + self.host = Endpoint() + self.host.read(iprot) + else: + iprot.skip(ftype) + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None: + oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec))) + return + oprot.writeStructBegin('Annotation') + if self.timestamp is not None: + oprot.writeFieldBegin('timestamp', TType.I64, 1) + oprot.writeI64(self.timestamp) + oprot.writeFieldEnd() + if self.value is not None: + oprot.writeFieldBegin('value', TType.STRING, 2) + oprot.writeString(self.value) + oprot.writeFieldEnd() + if self.host is not None: + oprot.writeFieldBegin('host', TType.STRUCT, 3) + self.host.write(oprot) + oprot.writeFieldEnd() + oprot.writeFieldStop() + oprot.writeStructEnd() + + def validate(self): + return + + + def __repr__(self): + L = ['%s=%r' % (key, value) + for key, value in self.__dict__.iteritems()] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) + +class BinaryAnnotation: + """ + Attributes: + - key + - value + - annotation_type + - host + """ + + thrift_spec = ( + None, # 0 + (1, TType.STRING, 'key', None, None, ), # 1 + (2, TType.STRING, 'value', None, None, ), # 2 + (3, TType.I32, 'annotation_type', None, None, ), # 3 + (4, TType.STRUCT, 'host', (Endpoint, Endpoint.thrift_spec), None, ), # 4 + ) + + def __init__(self, key=None, value=None, annotation_type=None, host=None,): + self.key = key + self.value = value + self.annotation_type = annotation_type + self.host = host + + def read(self, iprot): + if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None: + fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec)) + return + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + if fid == 1: + if ftype == TType.STRING: + self.key = iprot.readString(); + else: + iprot.skip(ftype) + elif fid == 2: + if ftype == TType.STRING: + self.value = iprot.readString(); + else: + iprot.skip(ftype) + elif fid == 3: + if ftype == TType.I32: + self.annotation_type = iprot.readI32(); + else: + iprot.skip(ftype) + elif fid == 4: + if ftype == TType.STRUCT: + self.host = Endpoint() + self.host.read(iprot) + else: + iprot.skip(ftype) + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None: + oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec))) + return + oprot.writeStructBegin('BinaryAnnotation') + if self.key is not None: + oprot.writeFieldBegin('key', TType.STRING, 1) + oprot.writeString(self.key) + oprot.writeFieldEnd() + if self.value is not None: + oprot.writeFieldBegin('value', TType.STRING, 2) + oprot.writeString(self.value) + oprot.writeFieldEnd() + if self.annotation_type is not None: + oprot.writeFieldBegin('annotation_type', TType.I32, 3) + oprot.writeI32(self.annotation_type) + oprot.writeFieldEnd() + if self.host is not None: + oprot.writeFieldBegin('host', TType.STRUCT, 4) + self.host.write(oprot) + oprot.writeFieldEnd() + oprot.writeFieldStop() + oprot.writeStructEnd() + + def validate(self): + return + + + def __repr__(self): + L = ['%s=%r' % (key, value) + for key, value in self.__dict__.iteritems()] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) + +class Span: + """ + Attributes: + - trace_id + - name + - id + - parent_id + - annotations + - binary_annotations + """ + + thrift_spec = ( + None, # 0 + (1, TType.I64, 'trace_id', None, None, ), # 1 + None, # 2 + (3, TType.STRING, 'name', None, None, ), # 3 + (4, TType.I64, 'id', None, None, ), # 4 + (5, TType.I64, 'parent_id', None, None, ), # 5 + (6, TType.LIST, 'annotations', (TType.STRUCT,(Annotation, Annotation.thrift_spec)), None, ), # 6 + None, # 7 + (8, TType.LIST, 'binary_annotations', (TType.STRUCT,(BinaryAnnotation, BinaryAnnotation.thrift_spec)), None, ), # 8 + ) + + def __init__(self, trace_id=None, name=None, id=None, parent_id=None, annotations=None, binary_annotations=None,): + self.trace_id = trace_id + self.name = name + self.id = id + self.parent_id = parent_id + self.annotations = annotations + self.binary_annotations = binary_annotations + + def read(self, iprot): + if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None: + fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec)) + return + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + if fid == 1: + if ftype == TType.I64: + self.trace_id = iprot.readI64(); + else: + iprot.skip(ftype) + elif fid == 3: + if ftype == TType.STRING: + self.name = iprot.readString(); + else: + iprot.skip(ftype) + elif fid == 4: + if ftype == TType.I64: + self.id = iprot.readI64(); + else: + iprot.skip(ftype) + elif fid == 5: + if ftype == TType.I64: + self.parent_id = iprot.readI64(); + else: + iprot.skip(ftype) + elif fid == 6: + if ftype == TType.LIST: + self.annotations = [] + (_etype3, _size0) = iprot.readListBegin() + for _i4 in xrange(_size0): + _elem5 = Annotation() + _elem5.read(iprot) + self.annotations.append(_elem5) + iprot.readListEnd() + else: + iprot.skip(ftype) + elif fid == 8: + if ftype == TType.LIST: + self.binary_annotations = [] + (_etype9, _size6) = iprot.readListBegin() + for _i10 in xrange(_size6): + _elem11 = BinaryAnnotation() + _elem11.read(iprot) + self.binary_annotations.append(_elem11) + iprot.readListEnd() + else: + iprot.skip(ftype) + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None: + oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec))) + return + oprot.writeStructBegin('Span') + if self.trace_id is not None: + oprot.writeFieldBegin('trace_id', TType.I64, 1) + oprot.writeI64(self.trace_id) + oprot.writeFieldEnd() + if self.name is not None: + oprot.writeFieldBegin('name', TType.STRING, 3) + oprot.writeString(self.name) + oprot.writeFieldEnd() + if self.id is not None: + oprot.writeFieldBegin('id', TType.I64, 4) + oprot.writeI64(self.id) + oprot.writeFieldEnd() + if self.parent_id is not None: + oprot.writeFieldBegin('parent_id', TType.I64, 5) + oprot.writeI64(self.parent_id) + oprot.writeFieldEnd() + if self.annotations is not None: + oprot.writeFieldBegin('annotations', TType.LIST, 6) + oprot.writeListBegin(TType.STRUCT, len(self.annotations)) + for iter12 in self.annotations: + iter12.write(oprot) + oprot.writeListEnd() + oprot.writeFieldEnd() + if self.binary_annotations is not None: + oprot.writeFieldBegin('binary_annotations', TType.LIST, 8) + oprot.writeListBegin(TType.STRUCT, len(self.binary_annotations)) + for iter13 in self.binary_annotations: + iter13.write(oprot) + oprot.writeListEnd() + oprot.writeFieldEnd() + oprot.writeFieldStop() + oprot.writeStructEnd() + + def validate(self): + return + + + def __repr__(self): + L = ['%s=%r' % (key, value) + for key, value in self.__dict__.iteritems()] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) diff -Nru python-eventlet-0.20.0/eventlet/zipkin/wsgi.py python-eventlet-0.24.1/eventlet/zipkin/wsgi.py --- python-eventlet-0.20.0/eventlet/zipkin/wsgi.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet/zipkin/wsgi.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,78 @@ +import random + +from eventlet import wsgi +from eventlet.zipkin import api +from eventlet.zipkin._thrift.zipkinCore.constants import \ + SERVER_RECV, SERVER_SEND +from eventlet.zipkin.http import \ + HDR_TRACE_ID, HDR_SPAN_ID, HDR_PARENT_SPAN_ID, HDR_SAMPLED + + +_sampler = None +__original_handle_one_response__ = wsgi.HttpProtocol.handle_one_response + + +def _patched_handle_one_response(self): + api.init_trace_data() + trace_id = int_or_none(self.headers.getheader(HDR_TRACE_ID)) + span_id = int_or_none(self.headers.getheader(HDR_SPAN_ID)) + parent_id = int_or_none(self.headers.getheader(HDR_PARENT_SPAN_ID)) + sampled = bool_or_none(self.headers.getheader(HDR_SAMPLED)) + if trace_id is None: # front-end server + trace_id = span_id = api.generate_trace_id() + parent_id = None + sampled = _sampler.sampling() + ip, port = self.request.getsockname()[:2] + ep = api.ZipkinDataBuilder.build_endpoint(ip, port) + trace_data = api.TraceData(name=self.command, + trace_id=trace_id, + span_id=span_id, + parent_id=parent_id, + sampled=sampled, + endpoint=ep) + api.set_trace_data(trace_data) + api.put_annotation(SERVER_RECV) + api.put_key_value('http.uri', self.path) + + __original_handle_one_response__(self) + + if api.is_sample(): + api.put_annotation(SERVER_SEND) + + +class Sampler(object): + def __init__(self, sampling_rate): + self.sampling_rate = sampling_rate + + def sampling(self): + # avoid generating unneeded random numbers + if self.sampling_rate == 1.0: + return True + r = random.random() + if r < self.sampling_rate: + return True + return False + + +def int_or_none(val): + if val is None: + return None + return int(val, 16) + + +def bool_or_none(val): + if val == '1': + return True + if val == '0': + return False + return None + + +def patch(sampling_rate): + global _sampler + _sampler = Sampler(sampling_rate) + wsgi.HttpProtocol.handle_one_response = _patched_handle_one_response + + +def unpatch(): + wsgi.HttpProtocol.handle_one_response = __original_handle_one_response__ diff -Nru python-eventlet-0.20.0/eventlet.egg-info/dependency_links.txt python-eventlet-0.24.1/eventlet.egg-info/dependency_links.txt --- python-eventlet-0.20.0/eventlet.egg-info/dependency_links.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet.egg-info/dependency_links.txt 2018-08-06 16:17:49.000000000 +0000 @@ -0,0 +1 @@ + diff -Nru python-eventlet-0.20.0/eventlet.egg-info/not-zip-safe python-eventlet-0.24.1/eventlet.egg-info/not-zip-safe --- python-eventlet-0.20.0/eventlet.egg-info/not-zip-safe 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet.egg-info/not-zip-safe 2016-12-30 00:43:29.000000000 +0000 @@ -0,0 +1 @@ + diff -Nru python-eventlet-0.20.0/eventlet.egg-info/PKG-INFO python-eventlet-0.24.1/eventlet.egg-info/PKG-INFO --- python-eventlet-0.20.0/eventlet.egg-info/PKG-INFO 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet.egg-info/PKG-INFO 2018-08-06 16:17:49.000000000 +0000 @@ -0,0 +1,99 @@ +Metadata-Version: 1.1 +Name: eventlet +Version: 0.24.1 +Summary: Highly concurrent networking library +Home-page: http://eventlet.net +Author: Linden Lab +Author-email: eventletdev@lists.secondlife.com +License: UNKNOWN +Description-Content-Type: UNKNOWN +Description: Eventlet is a concurrent networking library for Python that allows you to change how you run your code, not how you write it. + + It uses epoll or libevent for highly scalable non-blocking I/O. Coroutines ensure that the developer uses a blocking style of programming that is similar to threading, but provide the benefits of non-blocking I/O. The event dispatch is implicit, which means you can easily use Eventlet from the Python interpreter, or as a small part of a larger application. + + It's easy to get started using Eventlet, and easy to convert existing + applications to use it. Start off by looking at the `examples`_, + `common design patterns`_, and the list of `basic API primitives`_. + + .. _examples: http://eventlet.net/doc/examples.html + .. _common design patterns: http://eventlet.net/doc/design_patterns.html + .. _basic API primitives: http://eventlet.net/doc/basic_usage.html + + + Quick Example + =============== + + Here's something you can try right on the command line:: + + % python + >>> import eventlet + >>> from eventlet.green import urllib2 + >>> gt = eventlet.spawn(urllib2.urlopen, 'http://eventlet.net') + >>> gt2 = eventlet.spawn(urllib2.urlopen, 'http://secondlife.com') + >>> gt2.wait() + >>> gt.wait() + + + Getting Eventlet + ================== + + The easiest way to get Eventlet is to use pip:: + + pip install -U eventlet + + To install latest development version once:: + + pip install -U https://github.com/eventlet/eventlet/archive/master.zip + + + Building the Docs Locally + ========================= + + To build a complete set of HTML documentation, you must have Sphinx, which can be found at http://sphinx.pocoo.org/ (or installed with `pip install Sphinx`):: + + cd doc + make html + + The built html files can be found in doc/_build/html afterward. + + + Twisted + ======= + + Eventlet had Twisted hub in the past, but community interest to this integration has dropped over time, + now it is not supported, so with apologies for any inconvenience we discontinue Twisted integration. + + If you have a project that uses Eventlet with Twisted, your options are: + + * use last working release eventlet==0.14 + * start a new project with only Twisted hub code, identify and fix problems. As of eventlet 0.13, `EVENTLET_HUB` environment variable can point to external modules. + * fork Eventlet, revert Twisted removal, identify and fix problems. This work may be merged back into main project. + + Apologies for any inconvenience. + + + Flair + ===== + + .. image:: https://travis-ci.org/eventlet/eventlet.svg?branch=master + :target: https://travis-ci.org/eventlet/eventlet + + .. image:: https://codecov.io/gh/eventlet/eventlet/branch/master/graph/badge.svg + :target: https://codecov.io/gh/eventlet/eventlet + +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: POSIX +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python +Classifier: Topic :: Internet +Classifier: Topic :: Software Development :: Libraries :: Python Modules diff -Nru python-eventlet-0.20.0/eventlet.egg-info/requires.txt python-eventlet-0.24.1/eventlet.egg-info/requires.txt --- python-eventlet-0.20.0/eventlet.egg-info/requires.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet.egg-info/requires.txt 2018-08-06 16:17:49.000000000 +0000 @@ -0,0 +1,7 @@ +dnspython>=1.15.0 +greenlet>=0.3 +monotonic>=1.4 +six>=1.10.0 + +[:python_version < "3.4"] +enum34 diff -Nru python-eventlet-0.20.0/eventlet.egg-info/SOURCES.txt python-eventlet-0.24.1/eventlet.egg-info/SOURCES.txt --- python-eventlet-0.20.0/eventlet.egg-info/SOURCES.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet.egg-info/SOURCES.txt 2018-08-06 16:17:49.000000000 +0000 @@ -0,0 +1,265 @@ +AUTHORS +LICENSE +MANIFEST.in +NEWS +README.rst +setup.cfg +setup.py +benchmarks/__init__.py +benchmarks/localhost_socket.py +benchmarks/spawn.py +doc/Makefile +doc/authors.rst +doc/basic_usage.rst +doc/common.txt +doc/conf.py +doc/design_patterns.rst +doc/environment.rst +doc/examples.rst +doc/history.rst +doc/hubs.rst +doc/index.rst +doc/modules.rst +doc/patching.rst +doc/ssl.rst +doc/testing.rst +doc/threading.rst +doc/zeromq.rst +doc/images/threading_illustration.png +doc/modules/backdoor.rst +doc/modules/corolocal.rst +doc/modules/dagpool.rst +doc/modules/db_pool.rst +doc/modules/debug.rst +doc/modules/event.rst +doc/modules/greenpool.rst +doc/modules/greenthread.rst +doc/modules/pools.rst +doc/modules/queue.rst +doc/modules/semaphore.rst +doc/modules/timeout.rst +doc/modules/websocket.rst +doc/modules/wsgi.rst +doc/modules/zmq.rst +eventlet/__init__.py +eventlet/backdoor.py +eventlet/convenience.py +eventlet/corolocal.py +eventlet/coros.py +eventlet/dagpool.py +eventlet/db_pool.py +eventlet/debug.py +eventlet/event.py +eventlet/greenpool.py +eventlet/greenthread.py +eventlet/patcher.py +eventlet/pools.py +eventlet/queue.py +eventlet/semaphore.py +eventlet/timeout.py +eventlet/tpool.py +eventlet/websocket.py +eventlet/wsgi.py +eventlet.egg-info/PKG-INFO +eventlet.egg-info/SOURCES.txt +eventlet.egg-info/dependency_links.txt +eventlet.egg-info/not-zip-safe +eventlet.egg-info/requires.txt +eventlet.egg-info/top_level.txt +eventlet/green/BaseHTTPServer.py +eventlet/green/CGIHTTPServer.py +eventlet/green/MySQLdb.py +eventlet/green/Queue.py +eventlet/green/SimpleHTTPServer.py +eventlet/green/SocketServer.py +eventlet/green/__init__.py +eventlet/green/_socket_nodns.py +eventlet/green/asynchat.py +eventlet/green/asyncore.py +eventlet/green/builtin.py +eventlet/green/ftplib.py +eventlet/green/httplib.py +eventlet/green/os.py +eventlet/green/profile.py +eventlet/green/select.py +eventlet/green/selectors.py +eventlet/green/socket.py +eventlet/green/ssl.py +eventlet/green/subprocess.py +eventlet/green/thread.py +eventlet/green/threading.py +eventlet/green/time.py +eventlet/green/urllib2.py +eventlet/green/zmq.py +eventlet/green/OpenSSL/SSL.py +eventlet/green/OpenSSL/__init__.py +eventlet/green/OpenSSL/crypto.py +eventlet/green/OpenSSL/tsafe.py +eventlet/green/OpenSSL/version.py +eventlet/green/http/__init__.py +eventlet/green/http/client.py +eventlet/green/http/cookiejar.py +eventlet/green/http/cookies.py +eventlet/green/http/server.py +eventlet/green/urllib/__init__.py +eventlet/green/urllib/error.py +eventlet/green/urllib/parse.py +eventlet/green/urllib/request.py +eventlet/green/urllib/response.py +eventlet/greenio/__init__.py +eventlet/greenio/base.py +eventlet/greenio/py2.py +eventlet/greenio/py3.py +eventlet/hubs/__init__.py +eventlet/hubs/epolls.py +eventlet/hubs/hub.py +eventlet/hubs/kqueue.py +eventlet/hubs/poll.py +eventlet/hubs/pyevent.py +eventlet/hubs/selects.py +eventlet/hubs/timer.py +eventlet/support/__init__.py +eventlet/support/greendns.py +eventlet/support/greenlets.py +eventlet/support/psycopg2_patcher.py +eventlet/support/pylib.py +eventlet/support/stacklesspypys.py +eventlet/support/stacklesss.py +eventlet/zipkin/__init__.py +eventlet/zipkin/api.py +eventlet/zipkin/client.py +eventlet/zipkin/greenthread.py +eventlet/zipkin/http.py +eventlet/zipkin/log.py +eventlet/zipkin/patcher.py +eventlet/zipkin/wsgi.py +eventlet/zipkin/_thrift/__init__.py +eventlet/zipkin/_thrift/zipkinCore/__init__.py +eventlet/zipkin/_thrift/zipkinCore/constants.py +eventlet/zipkin/_thrift/zipkinCore/ttypes.py +examples/chat_bridge.py +examples/chat_server.py +examples/connect.py +examples/distributed_websocket_chat.py +examples/echoserver.py +examples/feedscraper-testclient.py +examples/feedscraper.py +examples/forwarder.py +examples/producer_consumer.py +examples/recursive_crawler.py +examples/webcrawler.py +examples/websocket.html +examples/websocket.py +examples/websocket_chat.html +examples/websocket_chat.py +examples/wsgi.py +examples/zmq_chat.py +examples/zmq_simple.py +tests/__init__.py +tests/api_test.py +tests/backdoor_test.py +tests/convenience_test.py +tests/dagpool_test.py +tests/db_pool_test.py +tests/debug_test.py +tests/env_test.py +tests/event_test.py +tests/green_http_test.py +tests/green_profile_test.py +tests/green_select_test.py +tests/greendns_test.py +tests/greenio_test.py +tests/greenpool_test.py +tests/greenthread_test.py +tests/hub_test.py +tests/mock.py +tests/mysqldb_test.py +tests/nosewrapper.py +tests/openssl_test.py +tests/parse_results.py +tests/patcher_psycopg_test.py +tests/patcher_test.py +tests/pools_test.py +tests/queue_test.py +tests/semaphore_test.py +tests/socket_test.py +tests/ssl_test.py +tests/subprocess_test.py +tests/test__event.py +tests/test__greenness.py +tests/test__refcount.py +tests/test__socket_errors.py +tests/test_server.crt +tests/test_server.key +tests/thread_test.py +tests/timeout_test.py +tests/timeout_test_with_statement.py +tests/timer_test.py +tests/tpool_test.py +tests/websocket_new_test.py +tests/websocket_test.py +tests/wsgi_test.py +tests/zmq_test.py +tests/isolated/__init__.py +tests/isolated/env_tpool_negative.py +tests/isolated/env_tpool_size.py +tests/isolated/env_tpool_zero.py +tests/isolated/green_http_doesnt_change_original_module.py +tests/isolated/green_httplib_doesnt_change_original_module.py +tests/isolated/green_ssl_py36_properties.py +tests/isolated/greendns_from_address_203.py +tests/isolated/greendns_import_rdtypes_then_eventlet.py +tests/isolated/greenio_double_close_219.py +tests/isolated/hub_fork.py +tests/isolated/hub_fork_simple.py +tests/isolated/mysqldb_monkey_patch.py +tests/isolated/patcher_blocking_select_methods_are_deleted.py +tests/isolated/patcher_existing_locks_early.py +tests/isolated/patcher_existing_locks_late.py +tests/isolated/patcher_existing_locks_locked.py +tests/isolated/patcher_existing_locks_unlocked.py +tests/isolated/patcher_import_patched_defaults.py +tests/isolated/patcher_importlib_lock.py +tests/isolated/patcher_socketserver_selectors.py +tests/isolated/patcher_threading_condition.py +tests/isolated/patcher_threading_current.py +tests/isolated/patcher_threading_join.py +tests/isolated/regular_file_readall.py +tests/isolated/socket_resolve_green.py +tests/isolated/subprocess_exception_identity.py +tests/isolated/subprocess_patched_communicate.py +tests/isolated/tpool_exception_leak.py +tests/isolated/tpool_isolate_socket_default_timeout.py +tests/isolated/wsgi_connection_timeout.py +tests/manual/__init__.py +tests/manual/greenio_memtest.py +tests/manual/regress-226-unpatched-ssl.py +tests/manual/websocket-gunicorn.py +tests/patcher/__init__.py +tests/patcher/shared1.py +tests/patcher/shared_import_socket.py +tests/stdlib/all.py +tests/stdlib/all_modules.py +tests/stdlib/all_monkey.py +tests/stdlib/test_SimpleHTTPServer.py +tests/stdlib/test_asynchat.py +tests/stdlib/test_asyncore.py +tests/stdlib/test_ftplib.py +tests/stdlib/test_httplib.py +tests/stdlib/test_httpservers.py +tests/stdlib/test_os.py +tests/stdlib/test_queue.py +tests/stdlib/test_select.py +tests/stdlib/test_socket.py +tests/stdlib/test_socket_ssl.py +tests/stdlib/test_socketserver.py +tests/stdlib/test_ssl.py +tests/stdlib/test_subprocess.py +tests/stdlib/test_thread.py +tests/stdlib/test_thread__boundedsem.py +tests/stdlib/test_threading.py +tests/stdlib/test_threading_local.py +tests/stdlib/test_timeout.py +tests/stdlib/test_urllib.py +tests/stdlib/test_urllib2.py +tests/stdlib/test_urllib2_localnet.py \ No newline at end of file diff -Nru python-eventlet-0.20.0/eventlet.egg-info/top_level.txt python-eventlet-0.24.1/eventlet.egg-info/top_level.txt --- python-eventlet-0.20.0/eventlet.egg-info/top_level.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/eventlet.egg-info/top_level.txt 2018-08-06 16:17:49.000000000 +0000 @@ -0,0 +1 @@ +eventlet diff -Nru python-eventlet-0.20.0/examples/producer_consumer.py python-eventlet-0.24.1/examples/producer_consumer.py --- python-eventlet-0.20.0/examples/producer_consumer.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/examples/producer_consumer.py 2018-08-06 16:17:47.000000000 +0000 @@ -9,8 +9,6 @@ number of "workers", so you don't have to write that tedious management code yourself. """ -from __future__ import with_statement - from eventlet.green import urllib2 import eventlet import re diff -Nru python-eventlet-0.20.0/examples/recursive_crawler.py python-eventlet-0.24.1/examples/recursive_crawler.py --- python-eventlet-0.20.0/examples/recursive_crawler.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/examples/recursive_crawler.py 2018-08-06 16:17:47.000000000 +0000 @@ -9,8 +9,6 @@ acts as sort of a job coordinator (and concurrency controller of course). """ -from __future__ import with_statement - from eventlet.green import urllib2 import eventlet import re diff -Nru python-eventlet-0.20.0/examples/websocket.py python-eventlet-0.24.1/examples/websocket.py --- python-eventlet-0.20.0/examples/websocket.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/examples/websocket.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,7 +1,7 @@ import eventlet from eventlet import wsgi from eventlet import websocket -from eventlet.support import six +import six # demo app import os diff -Nru python-eventlet-0.20.0/.gitignore python-eventlet-0.24.1/.gitignore --- python-eventlet-0.20.0/.gitignore 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -# please keep this file sorted -*.egg* -*.pyc -.* -build/ -dist/ -doc/changelog.rst -venv* -website-build/ diff -Nru python-eventlet-0.20.0/.hgignore python-eventlet-0.24.1/.hgignore --- python-eventlet-0.20.0/.hgignore 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/.hgignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -syntax: glob -*~ -*.pyc -*.orig -dist -*.egg-info -build -*.esproj -.DS_Store -.idea -doc/_build -annotated -cover -nosetests*.xml -.coverage -*,cover -lib* -bin -include -.noseids -pip-log.txt -.tox - -syntax: re -^.ropeproject/.*$ - diff -Nru python-eventlet-0.20.0/NEWS python-eventlet-0.24.1/NEWS --- python-eventlet-0.20.0/NEWS 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/NEWS 2018-08-06 16:17:47.000000000 +0000 @@ -1,3 +1,84 @@ +0.24.1 +====== +* greendns: don't contact nameservers if one entry is returned from hosts file; Thanks to Daniel Alvarez + +0.24.0 +====== +* greendns: Fix infinite loop when UDP source address mismatch; Thanks to Lon Hohberger +* greendns: Fix bad ipv6 comparison; Thanks to Lon Hohberger +* wsgi: Use byte strings on py2 and unicode strings on py3; Thanks to Tim Burke +* pools: put to empty pool would block sometimes; Thanks to Sam Merritt +* greendns: resolving over TCP produced ValueError; Thanks to Jaume Marhuenda +* support.greendns: ImportError when dns.rdtypes was imported before eventlet; Thanks to Jaume Marhuenda +* greendns: full comment lines were not skipped; Thanks to nat-goodspeed +* Drop support for Python3.3; Python2.6 and python-epoll package +* external dependencies for six, monotonic, dnspython; Thanks to nat-goodspeed +* wsgi: Don't strip all Unicode whitespace from headers on py3; Thanks to Tim Burke + +0.23.0 +====== +* green.threading: current_thread() did not see new monkey-patched threads; Thanks to Jake Tesler +* tpool: exception in tpool-ed call leaked memory via backtrace +* wsgi: latin-1 encoding dance for environ[PATH_INFO] + +0.22.1 +====== +* Fixed issue installing excess enum34 on Python3.4+ (rebuild with updated setuptools) +* event: Event.wait() timeout=None argument to be compatible with upstream CPython +* greendns: Treat /etc/hosts entries case-insensitive; Thanks to Ralf Haferkamp + + +0.22.0 +====== +* convenience: (SO_REUSEPORT) socket.error is not OSError on Python 2; Thanks to JacoFourie@github +* convenience: SO_REUSEPORT is not available on WSL platform (Linux on Windows) +* convenience: skip SO_REUSEPORT for bind on random port (0) +* dns: reading /etc/hosts raised DeprecationWarning for universal lines on Python 3.4+; Thanks to Chris Kerr +* green.openssl: Drop OpenSSL.rand support; Thanks to Haikel Guemar +* green.subprocess: keep CalledProcessError identity; Thanks to Linbing@github +* greendns: be explicit about expecting bytes from sock.recv; Thanks to Matt Bennett +* greendns: early socket.timeout was breaking IO retry loops +* GreenSocket.accept does not notify_open; Thanks to orishoshan +* patcher: set locked RLocks' owner only when patching existing locks; Thanks to Quan Tian +* patcher: workaround for monotonic "no suitable implementation"; Thanks to Geoffrey Thomas +* queue: empty except was catching too much +* socket: context manager support; Thanks to Miguel Grinberg +* support: update monotonic 1.3 (5c0322dc559bf) +* support: upgrade bundled dnspython to 1.16.0 (22e9de1d7957e) https://github.com/eventlet/eventlet/issues/427 +* websocket: fd leak when client did not close connection properly; Thanks to Konstantin Enchant +* websocket: support permessage-deflate extension; Thanks to Costas Christofi and Peter Kovary +* wsgi: close idle connections (also applies to websockets) +* wsgi: deprecated options are one step closer to removal +* wsgi: handle remote connection resets; Thanks to Stefan Nica + +0.21.0 +====== +* New timeout error API: .is_timeout=True on exception object + It's now easy to test if network error is transient and retry is appropriate. + Please spread the word and invite other libraries to support this interface. +* hubs: use monotonic clock by default (bundled package); Thanks to Roman Podoliaka and Victor Stinner +* dns: EVENTLET_NO_GREENDNS option is back, green is still default +* dns: hosts file was consulted after nameservers +* ssl: RecursionError on Python3.6+; Thanks to justdoit0823@github and Gevent developers +* wsgi: log_output=False was not disabling startup and accepted messages +* greenio: Fixed OSError: [WinError 10038] Socket operation on nonsocket +* dns: EAI_NODATA was removed from RFC3493 and FreeBSD +* green.select: fix mark_as_closed() wrong number of args +* green.zmq: socket.{recv,send}_* signatures did not match recent upstream pyzmq +* New feature: Add zipkin tracing to eventlet +* db_pool: proxy Connection.set_isolation_level() +* green.zmq: support RCVTIMEO (receive timeout) +* green.profile: Python3 compatibility; Thanks to Artur Stawiarski +* support: upgrade bundled six to 1.10 (dbfbfc818e3d) +* python3.6: http.client.request support chunked_encoding + +0.20.1 +====== +* dns: try unqualified queries as top level +* test_import_patched_defaults bended to play with pyopenssl>=16.1.0 +* Explicit environ flag for importing eventlet.__version__ without ignoring import errors +* Type check Semaphore, GreenPool arguments; Thanks to Matthew D. Pagel + 0.20.0 ====== * IMPORTANT: removed select.poll() function diff -Nru python-eventlet-0.20.0/PKG-INFO python-eventlet-0.24.1/PKG-INFO --- python-eventlet-0.20.0/PKG-INFO 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/PKG-INFO 2018-08-06 16:17:49.000000000 +0000 @@ -0,0 +1,99 @@ +Metadata-Version: 1.1 +Name: eventlet +Version: 0.24.1 +Summary: Highly concurrent networking library +Home-page: http://eventlet.net +Author: Linden Lab +Author-email: eventletdev@lists.secondlife.com +License: UNKNOWN +Description-Content-Type: UNKNOWN +Description: Eventlet is a concurrent networking library for Python that allows you to change how you run your code, not how you write it. + + It uses epoll or libevent for highly scalable non-blocking I/O. Coroutines ensure that the developer uses a blocking style of programming that is similar to threading, but provide the benefits of non-blocking I/O. The event dispatch is implicit, which means you can easily use Eventlet from the Python interpreter, or as a small part of a larger application. + + It's easy to get started using Eventlet, and easy to convert existing + applications to use it. Start off by looking at the `examples`_, + `common design patterns`_, and the list of `basic API primitives`_. + + .. _examples: http://eventlet.net/doc/examples.html + .. _common design patterns: http://eventlet.net/doc/design_patterns.html + .. _basic API primitives: http://eventlet.net/doc/basic_usage.html + + + Quick Example + =============== + + Here's something you can try right on the command line:: + + % python + >>> import eventlet + >>> from eventlet.green import urllib2 + >>> gt = eventlet.spawn(urllib2.urlopen, 'http://eventlet.net') + >>> gt2 = eventlet.spawn(urllib2.urlopen, 'http://secondlife.com') + >>> gt2.wait() + >>> gt.wait() + + + Getting Eventlet + ================== + + The easiest way to get Eventlet is to use pip:: + + pip install -U eventlet + + To install latest development version once:: + + pip install -U https://github.com/eventlet/eventlet/archive/master.zip + + + Building the Docs Locally + ========================= + + To build a complete set of HTML documentation, you must have Sphinx, which can be found at http://sphinx.pocoo.org/ (or installed with `pip install Sphinx`):: + + cd doc + make html + + The built html files can be found in doc/_build/html afterward. + + + Twisted + ======= + + Eventlet had Twisted hub in the past, but community interest to this integration has dropped over time, + now it is not supported, so with apologies for any inconvenience we discontinue Twisted integration. + + If you have a project that uses Eventlet with Twisted, your options are: + + * use last working release eventlet==0.14 + * start a new project with only Twisted hub code, identify and fix problems. As of eventlet 0.13, `EVENTLET_HUB` environment variable can point to external modules. + * fork Eventlet, revert Twisted removal, identify and fix problems. This work may be merged back into main project. + + Apologies for any inconvenience. + + + Flair + ===== + + .. image:: https://travis-ci.org/eventlet/eventlet.svg?branch=master + :target: https://travis-ci.org/eventlet/eventlet + + .. image:: https://codecov.io/gh/eventlet/eventlet/branch/master/graph/badge.svg + :target: https://codecov.io/gh/eventlet/eventlet + +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: POSIX +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python +Classifier: Topic :: Internet +Classifier: Topic :: Software Development :: Libraries :: Python Modules diff -Nru python-eventlet-0.20.0/README.rst python-eventlet-0.24.1/README.rst --- python-eventlet-0.20.0/README.rst 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/README.rst 2018-08-06 16:17:47.000000000 +0000 @@ -30,13 +30,11 @@ The easiest way to get Eventlet is to use pip:: - pip install eventlet + pip install -U eventlet -The development `tip`_ is available as well:: +To install latest development version once:: - pip install 'eventlet==dev' - -.. _tip: http://bitbucket.org/eventlet/eventlet/get/tip.zip#egg=eventlet-dev + pip install -U https://github.com/eventlet/eventlet/archive/master.zip Building the Docs Locally @@ -63,3 +61,13 @@ * fork Eventlet, revert Twisted removal, identify and fix problems. This work may be merged back into main project. Apologies for any inconvenience. + + +Flair +===== + +.. image:: https://travis-ci.org/eventlet/eventlet.svg?branch=master + :target: https://travis-ci.org/eventlet/eventlet + +.. image:: https://codecov.io/gh/eventlet/eventlet/branch/master/graph/badge.svg + :target: https://codecov.io/gh/eventlet/eventlet diff -Nru python-eventlet-0.20.0/setup.cfg python-eventlet-0.24.1/setup.cfg --- python-eventlet-0.20.0/setup.cfg 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/setup.cfg 2018-08-06 16:17:49.000000000 +0000 @@ -1,2 +1,10 @@ +[metadata] +description-file = README.rst + [wheel] universal = True + +[egg_info] +tag_build = +tag_date = 0 + diff -Nru python-eventlet-0.20.0/setup.py python-eventlet-0.24.1/setup.py --- python-eventlet-0.20.0/setup.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/setup.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,42 +1,49 @@ #!/usr/bin/env python -from setuptools import find_packages, setup -from eventlet import __version__ -from os import path +import os +import setuptools -setup( +os.environ.setdefault('EVENTLET_IMPORT_VERSION_ONLY', '1') +import eventlet + +setuptools.setup( name='eventlet', - version=__version__, + version=eventlet.__version__, description='Highly concurrent networking library', author='Linden Lab', author_email='eventletdev@lists.secondlife.com', url='http://eventlet.net', - packages=find_packages(exclude=['benchmarks', 'tests', 'tests.*']), + packages=setuptools.find_packages(exclude=['benchmarks', 'tests', 'tests.*']), install_requires=( - 'enum-compat', + 'dnspython >= 1.15.0', + 'enum34;python_version<"3.4"', 'greenlet >= 0.3', + 'monotonic >= 1.4', + 'six >= 1.10.0', ), zip_safe=False, long_description=open( - path.join( - path.dirname(__file__), + os.path.join( + os.path.dirname(__file__), 'README.rst' ) ).read(), test_suite='nose.collector', classifiers=[ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", - "Programming Language :: Python", "Operating System :: MacOS :: MacOS X", - "Operating System :: POSIX", "Operating System :: Microsoft :: Windows", - "Programming Language :: Python :: 2.6", + "Operating System :: POSIX", + "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python", "Topic :: Internet", "Topic :: Software Development :: Libraries :: Python Modules", - "Intended Audience :: Developers", - "Development Status :: 4 - Beta", ] ) diff -Nru python-eventlet-0.20.0/tests/api_test.py python-eventlet-0.24.1/tests/api_test.py --- python-eventlet-0.20.0/tests/api_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/api_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,12 +1,7 @@ -import os -from unittest import TestCase, main - -from nose.tools import eq_ - import eventlet -from eventlet import greenio, hubs, greenthread, spawn +from eventlet import greenio, hubs, greenthread from eventlet.green import ssl -from tests import skip_if_no_ssl +import tests def check_hub(): @@ -21,10 +16,7 @@ assert not hub.running -class TestApi(TestCase): - - certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt') - private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key') +class TestApi(tests.LimitedTestCase): def test_tcp_listener(self): socket = eventlet.listen(('0.0.0.0', 0)) @@ -50,13 +42,13 @@ client = eventlet.connect(('127.0.0.1', server.getsockname()[1])) fd = client.makefile('rb') client.close() - eq_(fd.readline(), b'hello\n') - eq_(fd.read(), b'') + assert fd.readline() == b'hello\n' + assert fd.read() == b'' fd.close() check_hub() - @skip_if_no_ssl + @tests.skip_if_no_ssl def test_connect_ssl(self): def accept_once(listenfd): try: @@ -70,8 +62,8 @@ server = eventlet.wrap_ssl( eventlet.listen(('0.0.0.0', 0)), - self.private_key_file, - self.certificate_file, + tests.private_key_file, + tests.certificate_file, server_side=True ) eventlet.spawn_n(accept_once, server) @@ -98,12 +90,12 @@ def server(sock): client, addr = sock.accept() eventlet.sleep(0.1) - server_evt = spawn(server, server_sock) + server_evt = eventlet.spawn(server, server_sock) eventlet.sleep(0) try: desc = eventlet.connect(('127.0.0.1', bound_port)) hubs.trampoline(desc, read=True, write=False, timeout=0.001) - except eventlet.TimeoutError: + except eventlet.Timeout: pass # test passed else: assert False, "Didn't timeout" @@ -126,7 +118,7 @@ desc = eventlet.connect(('127.0.0.1', bound_port)) try: hubs.trampoline(desc, read=True, timeout=0.1) - except eventlet.TimeoutError: + except eventlet.Timeout: assert False, "Timed out" server.close() @@ -174,14 +166,21 @@ try: eventlet.with_timeout(0.1, func) - self.fail(u'Expected TimeoutError') - except eventlet.TimeoutError: + self.fail(u'Expected Timeout') + except eventlet.Timeout: pass -class Foo(object): - pass +def test_wrap_is_timeout(): + class A(object): + pass + + obj = eventlet.wrap_is_timeout(A)() + tests.check_is_timeout(obj) -if __name__ == '__main__': - main() +def test_timeouterror_deprecated(): + # https://github.com/eventlet/eventlet/issues/378 + code = '''import eventlet; eventlet.Timeout(1).cancel(); print('pass')''' + args = ['-Werror:eventlet.Timeout:DeprecationWarning', '-c', code] + tests.run_python(path=None, args=args, expect_pass=True) diff -Nru python-eventlet-0.20.0/tests/backdoor_test.py python-eventlet-0.24.1/tests/backdoor_test.py --- python-eventlet-0.20.0/tests/backdoor_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/backdoor_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -6,10 +6,10 @@ from eventlet import backdoor from eventlet.green import socket -from tests import LimitedTestCase, main +import tests -class BackdoorTest(LimitedTestCase): +class BackdoorTest(tests.LimitedTestCase): def test_server(self): listener = socket.socket() listener.bind(('localhost', 0)) @@ -36,9 +36,10 @@ # wait for the console to discover that it's dead eventlet.sleep(0.1) + @tests.skip_if_no_ipv6 def test_server_on_ipv6_socket(self): listener = socket.socket(socket.AF_INET6) - listener.bind(('::1', 0)) + listener.bind(('::', 0)) listener.listen(5) serv = eventlet.spawn(backdoor.backdoor_server, listener) client = socket.socket(socket.AF_INET6) @@ -56,7 +57,3 @@ client = socket.socket(socket.AF_UNIX) client.connect(SOCKET_PATH) self._run_test_on_client_and_server(client, serv) - - -if __name__ == '__main__': - main() diff -Nru python-eventlet-0.20.0/tests/convenience_test.py python-eventlet-0.24.1/tests/convenience_test.py --- python-eventlet-0.20.0/tests/convenience_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/convenience_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,10 +1,12 @@ import os +import warnings import eventlet -from eventlet import debug, event +from eventlet import convenience, debug from eventlet.green import socket -from eventlet.support import six +import six import tests +import tests.mock certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt') @@ -90,7 +92,7 @@ gt.wait() def test_concurrency(self): - evt = event.Event() + evt = eventlet.Event() def waiter(sock, addr): sock.sendall(b'hi') @@ -128,18 +130,67 @@ client.sendall(b"echo") self.assertEqual(b"echo", client.recv(1024)) - def test_socket_reuse(self): + +def test_socket_reuse(): + # pick a free port with bind to 0 - without SO_REUSEPORT + # then close it and try to bind to same port with SO_REUSEPORT + # loop helps in case something else used the chosen port before second bind + addr = None + errors = [] + for _ in range(5): lsock1 = eventlet.listen(('localhost', 0)) - port = lsock1.getsockname()[1] + addr = lsock1.getsockname() + lsock1.close() + try: + lsock1 = eventlet.listen(addr) + except socket.error as e: + errors.append(e) + continue + break + else: + assert False, errors + + if hasattr(socket, 'SO_REUSEPORT'): + lsock2 = eventlet.listen(addr) + else: + try: + lsock2 = eventlet.listen(addr) + assert lsock2 + lsock2.close() + except socket.error: + pass - if hasattr(socket, 'SO_REUSEPORT'): - lsock2 = eventlet.listen(('localhost', port)) - else: - try: - lsock2 = eventlet.listen(('localhost', port)) - assert lsock2 - lsock2.close() - except socket.error: - pass + lsock1.close() - lsock1.close() + +def test_reuse_random_port_warning(): + with warnings.catch_warnings(record=True) as w: + eventlet.listen(('localhost', 0), reuse_port=True).close() + assert len(w) == 1 + assert issubclass(w[0].category, convenience.ReuseRandomPortWarning) + + +@tests.skip_unless(hasattr(socket, 'SO_REUSEPORT')) +def test_reuseport_oserror(): + # https://github.com/eventlet/eventlet/issues/380 + # https://github.com/eventlet/eventlet/issues/418 + err22 = OSError(22, 'Invalid argument') + + sock1 = eventlet.listen(('localhost', 0)) + addr = sock1.getsockname() + sock1.close() + + original_socket_init = socket.socket.__init__ + + def patched(self, *a, **kw): + original_socket_init(self, *a, **kw) + self.setsockopt = tests.mock.Mock(side_effect=err22) + + with warnings.catch_warnings(record=True) as w: + try: + socket.socket.__init__ = patched + eventlet.listen(addr, reuse_addr=False, reuse_port=True).close() + finally: + socket.socket.__init__ = original_socket_init + assert len(w) == 1 + assert issubclass(w[0].category, convenience.ReusePortUnavailableWarning) diff -Nru python-eventlet-0.20.0/tests/dagpool_test.py python-eventlet-0.24.1/tests/dagpool_test.py --- python-eventlet-0.20.0/tests/dagpool_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/dagpool_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -8,7 +8,7 @@ from nose.tools import * import eventlet from eventlet.dagpool import DAGPool, Collision, PropagateError -from eventlet.support import six +import six from contextlib import contextmanager import itertools diff -Nru python-eventlet-0.20.0/tests/db_pool_test.py python-eventlet-0.24.1/tests/db_pool_test.py --- python-eventlet-0.20.0/tests/db_pool_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/db_pool_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,17 +1,27 @@ -'''Test cases for db_pool -''' from __future__ import print_function - -import sys import os +import sys import traceback -from unittest import TestCase, main -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 +import six import eventlet +import eventlet.tpool +import tests +import tests.mock + +psycopg2 = None +try: + import psycopg2 + import psycopg2.extensions +except ImportError: + pass + +MySQLdb = None +try: + import MySQLdb +except ImportError: + pass class DBTester(object): @@ -141,7 +151,7 @@ curs = conn.cursor() results = [] SHORT_QUERY = "select * from test_table" - evt = event.Event() + evt = eventlet.Event() def a_query(): self.assert_cursor_works(curs) @@ -282,7 +292,7 @@ self.connection = self.pool.get() self.assertEqual(self.pool.free(), 0) self.assertEqual(self.pool.waiting(), 0) - e = event.Event() + e = eventlet.Event() def retrieve(pool, ev): c = pool.get() @@ -337,14 +347,13 @@ connect_timeout=connect_timeout, **self._auth) - @skip_with_pyevent + @tests.skip_with_pyevent def setUp(self): super(TpoolConnectionPool, self).setUp() def tearDown(self): super(TpoolConnectionPool, self).tearDown() - from eventlet import tpool - tpool.killall() + eventlet.tpool.killall() class RawConnectionPool(DBConnectionPool): @@ -373,7 +382,7 @@ def test_raw_pool_custom_cleanup_ok(): - cleanup_mock = mock.Mock() + cleanup_mock = tests.mock.Mock() pool = db_pool.RawConnectionPool(DummyDBModule(), cleanup=cleanup_mock) conn = pool.get() pool.put(conn) @@ -385,7 +394,7 @@ def test_raw_pool_custom_cleanup_arg_error(): - cleanup_mock = mock.Mock(side_effect=NotImplementedError) + cleanup_mock = tests.mock.Mock(side_effect=NotImplementedError) pool = db_pool.RawConnectionPool(DummyDBModule()) conn = pool.get() pool.put(conn, cleanup=cleanup_mock) @@ -427,27 +436,23 @@ assert len(pool.free_items) == 0 -get_auth = get_database_auth - - def mysql_requirement(_f): verbose = os.environ.get('eventlet_test_mysql_verbose') - try: - import MySQLdb - try: - auth = get_auth()['MySQLdb'].copy() - MySQLdb.connect(**auth) - return True - except MySQLdb.OperationalError: - if verbose: - print(">> Skipping mysql tests, error when connecting:", file=sys.stderr) - traceback.print_exc() - return False - except ImportError: + if MySQLdb is None: if verbose: print(">> Skipping mysql tests, MySQLdb not importable", file=sys.stderr) return False + try: + auth = tests.get_database_auth()['MySQLdb'].copy() + MySQLdb.connect(**auth) + return True + except MySQLdb.OperationalError: + if verbose: + print(">> Skipping mysql tests, error when connecting:", file=sys.stderr) + traceback.print_exc() + return False + class MysqlConnectionPool(object): dummy_table_sql = """CREATE TEMPORARY TABLE test_table @@ -463,11 +468,10 @@ created TIMESTAMP ) ENGINE=InnoDB;""" - @skip_unless(mysql_requirement) + @tests.skip_unless(mysql_requirement) def setUp(self): - import MySQLdb self._dbmodule = MySQLdb - self._auth = get_auth()['MySQLdb'] + self._auth = tests.get_database_auth()['MySQLdb'] super(MysqlConnectionPool, self).setUp() def tearDown(self): @@ -493,28 +497,27 @@ del db -class Test01MysqlTpool(MysqlConnectionPool, TpoolConnectionPool, TestCase): +class Test01MysqlTpool(MysqlConnectionPool, TpoolConnectionPool, tests.LimitedTestCase): __test__ = True -class Test02MysqlRaw(MysqlConnectionPool, RawConnectionPool, TestCase): +class Test02MysqlRaw(MysqlConnectionPool, RawConnectionPool, tests.LimitedTestCase): __test__ = True def postgres_requirement(_f): - try: - import psycopg2 - try: - auth = get_auth()['psycopg2'].copy() - psycopg2.connect(**auth) - return True - except psycopg2.OperationalError: - print("Skipping postgres tests, error when connecting") - return False - except ImportError: + if psycopg2 is None: print("Skipping postgres tests, psycopg2 not importable") return False + try: + auth = tests.get_database_auth()['psycopg2'].copy() + psycopg2.connect(**auth) + return True + except psycopg2.OperationalError: + print("Skipping postgres tests, error when connecting") + return False + class Psycopg2ConnectionPool(object): dummy_table_sql = """CREATE TEMPORARY TABLE test_table @@ -529,11 +532,10 @@ created TIMESTAMP );""" - @skip_unless(postgres_requirement) + @tests.skip_unless(postgres_requirement) def setUp(self): - import psycopg2 self._dbmodule = psycopg2 - self._auth = get_auth()['psycopg2'] + self._auth = tests.get_database_auth()['psycopg2'] super(Psycopg2ConnectionPool, self).setUp() def tearDown(self): @@ -566,7 +568,7 @@ conn.close() -class TestPsycopg2Base(TestCase): +class TestPsycopg2Base(tests.LimitedTestCase): __test__ = False def test_cursor_works_as_context_manager(self): @@ -575,6 +577,9 @@ row = c.fetchone() assert row == (1,) + def test_set_isolation_level(self): + self.connection.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT) + class Test01Psycopg2Tpool(Psycopg2ConnectionPool, TpoolConnectionPool, TestPsycopg2Base): __test__ = True @@ -582,7 +587,3 @@ class Test02Psycopg2Raw(Psycopg2ConnectionPool, RawConnectionPool, TestPsycopg2Base): __test__ = True - - -if __name__ == '__main__': - main() diff -Nru python-eventlet-0.20.0/tests/debug_test.py python-eventlet-0.24.1/tests/debug_test.py --- python-eventlet-0.20.0/tests/debug_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/debug_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,13 +1,12 @@ import sys -from unittest import TestCase from eventlet import debug -from eventlet.support import capture_stderr, six -from tests import LimitedTestCase, main +import six +import tests import eventlet -class TestSpew(TestCase): +class TestSpew(tests.LimitedTestCase): def setUp(self): self.orig_trace = sys.settrace sys.settrace = self._settrace @@ -84,7 +83,7 @@ assert output == "" -class TestDebug(LimitedTestCase): +class TestDebug(tests.LimitedTestCase): def test_everything(self): debug.hub_exceptions(True) debug.hub_exceptions(False) @@ -107,7 +106,7 @@ s.recv(1) {}[1] # keyerror - with capture_stderr() as fake: + with tests.capture_stderr() as fake: gt = eventlet.spawn(hurl, client_2) eventlet.sleep(0) client.send(b' ') @@ -119,6 +118,3 @@ debug.hub_exceptions(False) # look for the KeyError exception in the traceback assert 'KeyError: 1' in fake.getvalue(), "Traceback not in:\n" + fake.getvalue() - -if __name__ == "__main__": - main() diff -Nru python-eventlet-0.20.0/tests/env_test.py python-eventlet-0.24.1/tests/env_test.py --- python-eventlet-0.20.0/tests/env_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/env_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -19,12 +19,12 @@ socket.getaddrinfo('localhost', 80) print('pass') ''' - output = tests.run_python( + tests.run_python( path=None, env={'EVENTLET_TPOOL_DNS': 'yes'}, args=['-c', code], + expect_pass=True, ) - assert output.rstrip() == b'pass' @tests.skip_with_pyevent diff -Nru python-eventlet-0.20.0/tests/event_test.py python-eventlet-0.24.1/tests/event_test.py --- python-eventlet-0.20.0/tests/event_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/event_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,11 +1,11 @@ import eventlet -from eventlet import event +import eventlet.hubs from tests import LimitedTestCase class TestEvent(LimitedTestCase): def test_waiting_for_event(self): - evt = event.Event() + evt = eventlet.Event() value = 'some stuff' def send_to_event(): @@ -20,7 +20,7 @@ self._test_multiple_waiters(True) def _test_multiple_waiters(self, exception): - evt = event.Event() + evt = eventlet.Event() results = [] def wait_on_event(i_am_done): @@ -33,7 +33,7 @@ waiters = [] count = 5 for i in range(count): - waiters.append(event.Event()) + waiters.append(eventlet.Event()) eventlet.spawn_n(wait_on_event, waiters[-1]) eventlet.sleep() # allow spawns to start executing evt.send() @@ -44,7 +44,7 @@ self.assertEqual(len(results), count) def test_reset(self): - evt = event.Event() + evt = eventlet.Event() # calling reset before send should throw self.assertRaises(AssertionError, evt.reset) @@ -71,7 +71,7 @@ self.assertEqual(evt.wait(), value2) def test_double_exception(self): - evt = event.Event() + evt = eventlet.Event() # send an exception through the event evt.send(exc=RuntimeError('from test_double_exception')) self.assertRaises(RuntimeError, evt.wait) @@ -79,3 +79,27 @@ # shouldn't see the RuntimeError again eventlet.Timeout(0.001) self.assertRaises(eventlet.Timeout, evt.wait) + + +def test_wait_timeout_ok(): + evt = eventlet.Event() + delay = 0.1 + eventlet.spawn_after(delay, evt.send, True) + t1 = eventlet.hubs.get_hub().clock() + with eventlet.Timeout(delay * 3, False): + result = evt.wait(timeout=delay * 2) + td = eventlet.hubs.get_hub().clock() - t1 + assert result + assert td >= delay + + +def test_wait_timeout_exceed(): + evt = eventlet.Event() + delay = 0.1 + eventlet.spawn_after(delay * 2, evt.send, True) + t1 = eventlet.hubs.get_hub().clock() + with eventlet.Timeout(delay, False): + result = evt.wait(timeout=delay) + td = eventlet.hubs.get_hub().clock() - t1 + assert not result + assert td >= delay diff -Nru python-eventlet-0.20.0/tests/fork_test.py python-eventlet-0.24.1/tests/fork_test.py --- python-eventlet-0.20.0/tests/fork_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/fork_test.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -from tests.patcher_test import ProcessBase - - -class ForkTest(ProcessBase): - def test_simple(self): - newmod = ''' -import eventlet -import os -import sys -import signal -from eventlet.support import bytes_to_str, six -mydir = %r -signal_file = os.path.join(mydir, "output.txt") -pid = os.fork() -if (pid != 0): - eventlet.Timeout(10) - try: - port = None - while True: - try: - contents = open(signal_file, "rb").read() - port = int(contents.split()[0]) - break - except (IOError, IndexError, ValueError, TypeError): - eventlet.sleep(0.1) - eventlet.connect(('127.0.0.1', port)) - while True: - try: - contents = open(signal_file, "rb").read() - result = contents.split()[1] - break - except (IOError, IndexError): - eventlet.sleep(0.1) - print('result {0}'.format(bytes_to_str(result))) - finally: - os.kill(pid, signal.SIGTERM) -else: - try: - s = eventlet.listen(('', 0)) - fd = open(signal_file, "wb") - fd.write(six.b(str(s.getsockname()[1]))) - fd.write(b"\\n") - fd.flush() - s.accept() - fd.write(b"done") - fd.flush() - finally: - fd.close() -''' - self.write_to_tempfile("newmod", newmod % self.tempdir) - output, lines = self.launch_subprocess('newmod.py') - self.assertEqual(lines[0], "result done", output) diff -Nru python-eventlet-0.20.0/tests/greendns_test.py python-eventlet-0.24.1/tests/greendns_test.py --- python-eventlet-0.20.0/tests/greendns_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/greendns_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -5,59 +5,78 @@ import socket import tempfile import time +from dns.resolver import NoAnswer, Answer, Resolver -import tests -from tests import mock from eventlet.support import greendns from eventlet.support.greendns import dns +import tests +import tests.mock -class TestHostsResolver(tests.LimitedTestCase): +def _make_host_resolver(): + """Returns a HostResolver instance - def _make_host_resolver(self): - """Returns a HostResolver instance + The hosts file will be empty but accessible as a py.path.local + instance using the ``hosts`` attribute. + """ + hosts = tempfile.NamedTemporaryFile() + hr = greendns.HostsResolver(fname=hosts.name) + hr.hosts = hosts + hr._last_stat = 0 + return hr - The hosts file will be empty but accessible as a py.path.local - instance using the ``hosts`` attribute. - """ - hosts = tempfile.NamedTemporaryFile() - hr = greendns.HostsResolver(fname=hosts.name) - hr.hosts = hosts - hr._last_stat = 0 - return hr + +class TestHostsResolver(tests.LimitedTestCase): def test_default_fname(self): hr = greendns.HostsResolver() assert os.path.exists(hr.fname) def test_readlines_lines(self): - hr = self._make_host_resolver() + hr = _make_host_resolver() hr.hosts.write(b'line0\n') hr.hosts.flush() - assert hr._readlines() == ['line0'] + assert list(hr._readlines()) == ['line0'] hr._last_stat = 0 hr.hosts.write(b'line1\n') hr.hosts.flush() - assert hr._readlines() == ['line0', 'line1'] + assert list(hr._readlines()) == ['line0', 'line1'] + # Test reading of varied newline styles hr._last_stat = 0 - hr.hosts.write(b'#comment0\nline0\n #comment1\nline1') - assert hr._readlines() == ['line0', 'line1'] + hr.hosts.seek(0) + hr.hosts.truncate() + hr.hosts.write(b'\naa\r\nbb\r cc \n\n\tdd ee') + hr.hosts.flush() + assert list(hr._readlines()) == ['aa', 'bb', 'cc', 'dd ee'] + # Test comments, including inline comments + hr._last_stat = 0 + hr.hosts.seek(0) + hr.hosts.truncate() + hr.hosts.write(b'''\ +# First couple lines +# are comments. +line1 +#comment +line2 # inline comment +''') + hr.hosts.flush() + assert list(hr._readlines()) == ['line1', 'line2'] def test_readlines_missing_file(self): - hr = self._make_host_resolver() + hr = _make_host_resolver() hr.hosts.close() hr._last_stat = 0 - assert hr._readlines() == [] + assert list(hr._readlines()) == [] def test_load_no_contents(self): - hr = self._make_host_resolver() + hr = _make_host_resolver() hr._load() assert not hr._v4 assert not hr._v6 assert not hr._aliases def test_load_v4_v6_cname_aliases(self): - hr = self._make_host_resolver() + hr = _make_host_resolver() hr.hosts.write(b'1.2.3.4 v4.example.com v4\n' b'dead:beef::1 v6.example.com v6\n') hr.hosts.flush() @@ -69,7 +88,7 @@ 'v6': 'v6.example.com'} def test_load_v6_link_local(self): - hr = self._make_host_resolver() + hr = _make_host_resolver() hr.hosts.write(b'fe80:: foo\n' b'fe80:dead:beef::1 bar\n') hr.hosts.flush() @@ -78,14 +97,14 @@ assert not hr._v6 def test_query_A(self): - hr = self._make_host_resolver() + hr = _make_host_resolver() hr._v4 = {'v4.example.com': '1.2.3.4'} ans = hr.query('v4.example.com') assert ans[0].address == '1.2.3.4' def test_query_ans_types(self): # This assumes test_query_A above succeeds - hr = self._make_host_resolver() + hr = _make_host_resolver() hr._v4 = {'v4.example.com': '1.2.3.4'} hr._last_stat = time.time() ans = hr.query('v4.example.com') @@ -108,18 +127,18 @@ assert rr.address == '1.2.3.4' def test_query_AAAA(self): - hr = self._make_host_resolver() + hr = _make_host_resolver() hr._v6 = {'v6.example.com': 'dead:beef::1'} ans = hr.query('v6.example.com', dns.rdatatype.AAAA) assert ans[0].address == 'dead:beef::1' def test_query_unknown_raises(self): - hr = self._make_host_resolver() + hr = _make_host_resolver() with tests.assert_raises(greendns.dns.resolver.NoAnswer): hr.query('example.com') def test_query_unknown_no_raise(self): - hr = self._make_host_resolver() + hr = _make_host_resolver() ans = hr.query('example.com', raise_on_no_answer=False) assert isinstance(ans, greendns.dns.resolver.Answer) assert ans.response is None @@ -134,34 +153,48 @@ assert len(ans.rrset) == 0 def test_query_CNAME(self): - hr = self._make_host_resolver() + hr = _make_host_resolver() hr._aliases = {'host': 'host.example.com'} ans = hr.query('host', dns.rdatatype.CNAME) assert ans[0].target == dns.name.from_text('host.example.com') assert str(ans[0].target) == 'host.example.com.' def test_query_unknown_type(self): - hr = self._make_host_resolver() + hr = _make_host_resolver() with tests.assert_raises(greendns.dns.resolver.NoAnswer): hr.query('example.com', dns.rdatatype.MX) def test_getaliases(self): - hr = self._make_host_resolver() + hr = _make_host_resolver() hr._aliases = {'host': 'host.example.com', 'localhost': 'host.example.com'} res = set(hr.getaliases('host')) assert res == set(['host.example.com', 'localhost']) def test_getaliases_unknown(self): - hr = self._make_host_resolver() + hr = _make_host_resolver() assert hr.getaliases('host.example.com') == [] def test_getaliases_fqdn(self): - hr = self._make_host_resolver() + hr = _make_host_resolver() hr._aliases = {'host': 'host.example.com'} res = set(hr.getaliases('host.example.com')) assert res == set(['host']) + def test_hosts_case_insensitive(self): + name = 'example.com' + hr = _make_host_resolver() + hr.hosts.write(b'1.2.3.4 ExAmPlE.CoM\n') + hr.hosts.flush() + hr._load() + + ans = hr.query(name) + rr = ans.rrset[0] + assert isinstance(rr, greendns.dns.rdtypes.IN.A.A) + assert rr.rdtype == dns.rdatatype.A + assert rr.rdclass == dns.rdataclass.IN + assert rr.address == '1.2.3.4' + def _make_mock_base_resolver(): """A mocked base resolver class""" @@ -172,6 +205,7 @@ aliases = ['cname.example.com'] raises = None rr = RR() + rr6 = RR() def query(self, *args, **kwargs): self.args = args @@ -181,7 +215,10 @@ if hasattr(self, 'rrset'): rrset = self.rrset else: - rrset = [self.rr] + if self.rr6 and self.args[1] == dns.rdatatype.AAAA: + rrset = [self.rr6] + else: + rrset = [self.rr] return greendns.HostsAnswer('foo', 1, 1, rrset, False) def getaliases(self, *args, **kwargs): @@ -190,6 +227,47 @@ return Resolver +class TestUdp(tests.LimitedTestCase): + + def setUp(self): + # Store this so we can reuse it for each test + self.query = greendns.dns.message.Message() + self.query.flags = greendns.dns.flags.QR + self.query_wire = self.query.to_wire() + super(TestUdp, self).setUp() + + def test_udp_ipv6(self): + with tests.mock.patch('eventlet.support.greendns.socket.socket.recvfrom', + return_value=(self.query_wire, + ('::1', 53, 0, 0))): + greendns.udp(self.query, '::1') + + def test_udp_ipv6_timeout(self): + with tests.mock.patch('eventlet.support.greendns.socket.socket.recvfrom', + side_effect=socket.timeout): + with tests.assert_raises(dns.exception.Timeout): + greendns.udp(self.query, '::1', timeout=0.1) + + def test_udp_ipv6_addr_zeroes(self): + with tests.mock.patch('eventlet.support.greendns.socket.socket.recvfrom', + return_value=(self.query_wire, + ('0:00:0000::1', 53, 0, 0))): + greendns.udp(self.query, '::1') + + def test_udp_ipv6_wrong_addr_ignore(self): + with tests.mock.patch('eventlet.support.greendns.socket.socket.recvfrom', + side_effect=socket.timeout): + with tests.assert_raises(dns.exception.Timeout): + greendns.udp(self.query, '::1', timeout=0.1, ignore_unexpected=True) + + def test_udp_ipv6_wrong_addr(self): + with tests.mock.patch('eventlet.support.greendns.socket.socket.recvfrom', + return_value=(self.query_wire, + ('ffff:0000::1', 53, 0, 0))): + with tests.assert_raises(dns.query.UnexpectedSource): + greendns.udp(self.query, '::1') + + class TestProxyResolver(tests.LimitedTestCase): def test_clear(self): @@ -318,7 +396,7 @@ assert greendns.resolver.args == ('host.example.com', dns.rdatatype.A) def test_AAAA(self): - greendns.resolver.rr.address = 'dead:beef::1' + greendns.resolver.rr6.address = 'dead:beef::1' ans = greendns.resolve('host.example.com', socket.AF_INET6) assert ans[0].address == 'dead:beef::1' assert greendns.resolver.args == ('host.example.com', dns.rdatatype.AAAA) @@ -393,7 +471,8 @@ def __init__(self): self.answers = {} - def __call__(self, name, family=socket.AF_INET, raises=True): + def __call__(self, name, family=socket.AF_INET, raises=True, + _proxy=None, use_network=True): qname = dns.name.from_text(name) try: rrset = self.answers[name][family] @@ -458,11 +537,11 @@ greendns.resolve = _make_mock_resolve() greendns.resolve.add('example.com', '127.0.0.2') greendns.resolve.add('example.com', '::1') - res = greendns.getaddrinfo('example.com', 'ssh') - addr = ('127.0.0.2', 22) + res = greendns.getaddrinfo('example.com', 'domain') + addr = ('127.0.0.2', 53) tcp = (socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, addr) udp = (socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP, addr) - addr = ('::1', 22, 0, 0) + addr = ('::1', 53, 0, 0) tcp6 = (socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_TCP, addr) udp6 = (socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP, addr) filt_res = [ai[:3] + (ai[4],) for ai in res] @@ -475,8 +554,8 @@ greendns.resolve = _make_mock_resolve() idn_name = u'евентлет.com' greendns.resolve.add(idn_name.encode('idna').decode('ascii'), '127.0.0.2') - res = greendns.getaddrinfo(idn_name, 'ssh') - addr = ('127.0.0.2', 22) + res = greendns.getaddrinfo(idn_name, 'domain') + addr = ('127.0.0.2', 53) tcp = (socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, addr) udp = (socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP, addr) filt_res = [ai[:3] + (ai[4],) for ai in res] @@ -486,8 +565,8 @@ def test_getaddrinfo_inet(self): greendns.resolve = _make_mock_resolve() greendns.resolve.add('example.com', '127.0.0.2') - res = greendns.getaddrinfo('example.com', 'ssh', socket.AF_INET) - addr = ('127.0.0.2', 22) + res = greendns.getaddrinfo('example.com', 'domain', socket.AF_INET) + addr = ('127.0.0.2', 53) tcp = (socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, addr) udp = (socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP, addr) assert tcp in [ai[:3] + (ai[4],) for ai in res] @@ -496,8 +575,8 @@ def test_getaddrinfo_inet6(self): greendns.resolve = _make_mock_resolve() greendns.resolve.add('example.com', '::1') - res = greendns.getaddrinfo('example.com', 'ssh', socket.AF_INET6) - addr = ('::1', 22, 0, 0) + res = greendns.getaddrinfo('example.com', 'domain', socket.AF_INET6) + addr = ('::1', 53, 0, 0) tcp = (socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_TCP, addr) udp = (socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP, addr) assert tcp in [ai[:3] + (ai[4],) for ai in res] @@ -775,5 +854,127 @@ assert res == ('host.example.com', [], ['1.2.3.4', '1.2.3.5']) +class TinyDNSTests(tests.LimitedTestCase): + + def test_raise_dns_tcp(self): + # https://github.com/eventlet/eventlet/issues/499 + # None means we don't want the server to find the IP + with tests.dns_tcp_server(None) as dnsaddr: + resolver = Resolver() + resolver.nameservers = [dnsaddr[0]] + resolver.nameserver_ports[dnsaddr[0]] = dnsaddr[1] + + with self.assertRaises(NoAnswer): + resolver.query('host.example.com', 'a', tcp=True) + + def test_noraise_dns_tcp(self): + # https://github.com/eventlet/eventlet/issues/499 + expected_ip = "192.168.1.1" + with tests.dns_tcp_server(expected_ip) as dnsaddr: + resolver = Resolver() + resolver.nameservers = [dnsaddr[0]] + resolver.nameserver_ports[dnsaddr[0]] = dnsaddr[1] + response = resolver.query('host.example.com', 'a', tcp=True) + self.assertIsInstance(response, Answer) + self.assertEqual(response.rrset.items[0].address, expected_ip) + + def test_reverse_name(): tests.run_isolated('greendns_from_address_203.py') + + +def test_proxy_resolve_unqualified(): + # https://github.com/eventlet/eventlet/issues/363 + rp = greendns.ResolverProxy(filename=None) + rp._resolver.search.append(dns.name.from_text('example.com')) + with tests.mock.patch('dns.resolver.Resolver.query', side_effect=dns.resolver.NoAnswer) as m: + try: + rp.query('machine') + assert False, 'Expected NoAnswer exception' + except dns.resolver.NoAnswer: + pass + assert any(call[0][0] == dns.name.from_text('machine') for call in m.call_args_list) + assert any(call[0][0] == dns.name.from_text('machine.') for call in m.call_args_list) + + +def test_hosts_priority(): + name = 'example.com' + addr_from_ns = '1.0.2.0' + + hr = _make_host_resolver() + rp = greendns.ResolverProxy(hosts_resolver=hr, filename=None) + base = _make_mock_base_resolver() + base.rr.address = addr_from_ns + rp._resolver = base() + + # Default behavior + rrns = greendns.resolve(name, _proxy=rp).rrset[0] + assert rrns.address == addr_from_ns + + # Hosts result must shadow that from nameservers + hr.hosts.write(b'1.2.3.4 example.com\ndead:beef::1 example.com\n') + hr.hosts.flush() + hr._load() + rrs4 = greendns.resolve(name, family=socket.AF_INET, _proxy=rp).rrset + assert len(rrs4) == 1 + assert rrs4[0].address == '1.2.3.4', rrs4[0].address + rrs6 = greendns.resolve(name, family=socket.AF_INET6, _proxy=rp).rrset + assert len(rrs6) == 1 + assert rrs6[0].address == 'dead:beef::1', rrs6[0].address + + +def test_hosts_no_network(): + + name = 'example.com' + addr_from_ns = '1.0.2.0' + addr6_from_ns = 'dead:beef::1' + + hr = _make_host_resolver() + rp = greendns.ResolverProxy(hosts_resolver=hr, filename=None) + base = _make_mock_base_resolver() + base.rr.address = addr_from_ns + base.rr6.address = addr6_from_ns + rp._resolver = base() + + with tests.mock.patch.object(greendns, 'resolver', + new_callable=tests.mock.PropertyMock(return_value=rp)): + res = greendns.getaddrinfo('example.com', 'domain', socket.AF_UNSPEC) + # Default behavior + addr = (addr_from_ns, 53) + tcp = (socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, addr) + udp = (socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP, addr) + addr = (addr6_from_ns, 53, 0, 0) + tcp6 = (socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_TCP, addr) + udp6 = (socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP, addr) + filt_res = [ai[:3] + (ai[4],) for ai in res] + assert tcp in filt_res + assert udp in filt_res + assert tcp6 in filt_res + assert udp6 in filt_res + + # Hosts result must shadow that from nameservers + hr = _make_host_resolver() + hr.hosts.write(b'1.2.3.4 example.com') + hr.hosts.flush() + hr._load() + greendns.resolver._hosts = hr + + res = greendns.getaddrinfo('example.com', 'domain', socket.AF_UNSPEC) + filt_res = [ai[:3] + (ai[4],) for ai in res] + + # Make sure that only IPv4 entry from hosts is present. + assert tcp not in filt_res + assert udp not in filt_res + assert tcp6 not in filt_res + assert udp6 not in filt_res + + addr = ('1.2.3.4', 53) + tcp = (socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, addr) + udp = (socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP, addr) + assert tcp in filt_res + assert udp in filt_res + + +def test_import_rdtypes_then_eventlet(): + # https://github.com/eventlet/eventlet/issues/479 + tests.run_isolated('greendns_import_rdtypes_then_eventlet.py') diff -Nru python-eventlet-0.20.0/tests/green_http_test.py python-eventlet-0.24.1/tests/green_http_test.py --- python-eventlet-0.20.0/tests/green_http_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/green_http_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,4 +1,5 @@ -from eventlet.support import six +import eventlet +import six import tests __test__ = six.PY3 @@ -10,3 +11,14 @@ def test_green_httplib_doesnt_change_original_module(): tests.run_isolated('green_httplib_doesnt_change_original_module.py') + + +def test_http_request_encode_chunked_kwarg(): + # https://bugs.python.org/issue12319 + # As of 2017-01 this test only verifies encode_chunked kwarg is properly accepted. + # Stdlib http.client code was copied partially, chunked encoding may not work. + from eventlet.green.http import client + server_sock = eventlet.listen(('127.0.0.1', 0)) + addr = server_sock.getsockname() + h = client.HTTPConnection(host=addr[0], port=addr[1]) + h.request('GET', '/', encode_chunked=True) diff -Nru python-eventlet-0.20.0/tests/greenio_test.py python-eventlet-0.24.1/tests/greenio_test.py --- python-eventlet-0.20.0/tests/greenio_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/greenio_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,6 +1,5 @@ import array import errno -import eventlet import fcntl import gc from io import DEFAULT_BUFFER_SIZE @@ -16,8 +15,10 @@ from eventlet import event, greenio, debug from eventlet.hubs import get_hub from eventlet.green import select, socket, time, ssl -from eventlet.support import capture_stderr, get_errno, six +from eventlet.support import get_errno +import six import tests +import tests.mock as mock def bufsized(sock, size=1): @@ -321,6 +322,70 @@ killer.wait() + def test_blocking_accept_mark_as_reopened(self): + evt_hub = get_hub() + with mock.patch.object(evt_hub, "mark_as_reopened") as patched_mark_as_reopened: + def connect_once(listener): + # delete/overwrite the original conn + # object, only keeping the file object around + # closing the file object should close everything + client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + client.connect(('127.0.0.1', listener.getsockname()[1])) + client.close() + + server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server.bind(('127.0.0.1', 0)) + server.listen(50) + acceptlet = eventlet.spawn(connect_once, server) + conn, addr = server.accept() + conn.sendall(b'hello\n') + connfileno = conn.fileno() + conn.close() + assert patched_mark_as_reopened.called + assert patched_mark_as_reopened.call_count == 3, "3 fds were opened, but the hub was " \ + "only notified {call_count} times" \ + .format(call_count=patched_mark_as_reopened.call_count) + args, kwargs = patched_mark_as_reopened.call_args + assert args == (connfileno,), "Expected mark_as_reopened to be called " \ + "with {expected_fileno}, but it was called " \ + "with {fileno}".format(expected_fileno=connfileno, + fileno=args[0]) + server.close() + + def test_nonblocking_accept_mark_as_reopened(self): + evt_hub = get_hub() + with mock.patch.object(evt_hub, "mark_as_reopened") as patched_mark_as_reopened: + def connect_once(listener): + # delete/overwrite the original conn + # object, only keeping the file object around + # closing the file object should close everything + client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + client.connect(('127.0.0.1', listener.getsockname()[1])) + client.close() + + server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server.bind(('127.0.0.1', 0)) + server.listen(50) + server.setblocking(False) + acceptlet = eventlet.spawn(connect_once, server) + out = select.select([server], [], []) + conn, addr = server.accept() + conn.sendall(b'hello\n') + connfileno = conn.fileno() + conn.close() + assert patched_mark_as_reopened.called + assert patched_mark_as_reopened.call_count == 3, "3 fds were opened, but the hub was " \ + "only notified {call_count} times" \ + .format(call_count=patched_mark_as_reopened.call_count) + args, kwargs = patched_mark_as_reopened.call_args + assert args == (connfileno,), "Expected mark_as_reopened to be called " \ + "with {expected_fileno}, but it was called " \ + "with {fileno}".format(expected_fileno=connfileno, + fileno=args[0]) + server.close() + def test_full_duplex(self): large_data = b'*' * 10 * min_buf_size() listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -443,7 +508,7 @@ wrap_rfile = client.makefile() wrap_rfile.read(1) self.fail() - except eventlet.TimeoutError: + except eventlet.Timeout: pass result = evt.wait() @@ -870,7 +935,7 @@ def __init__(self): pass - with capture_stderr() as err: + with tests.capture_stderr() as err: SocketSubclass() assert err.getvalue() == '' diff -Nru python-eventlet-0.20.0/tests/greenpool_test.py python-eventlet-0.24.1/tests/greenpool_test.py --- python-eventlet-0.20.0/tests/greenpool_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/greenpool_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,10 +1,10 @@ import gc -import os import random import eventlet -from eventlet import hubs, greenpool, event, pools -from eventlet.support import greenlets as greenlet, six +from eventlet import hubs, pools +from eventlet.support import greenlets as greenlet +import six import tests @@ -24,7 +24,7 @@ class GreenPool(tests.LimitedTestCase): def test_spawn(self): - p = greenpool.GreenPool(4) + p = eventlet.GreenPool(4) waiters = [] for i in range(10): waiters.append(p.spawn(passthru, i)) @@ -32,7 +32,7 @@ self.assertEqual(results, list(range(10))) def test_spawn_n(self): - p = greenpool.GreenPool(4) + p = eventlet.GreenPool(4) results_closure = [] def do_something(a): @@ -45,8 +45,8 @@ self.assertEqual(results_closure, list(range(10))) def test_waiting(self): - pool = greenpool.GreenPool(1) - done = event.Event() + pool = eventlet.GreenPool(1) + done = eventlet.Event() def consume(): done.wait() @@ -74,7 +74,7 @@ self.assertEqual(pool.running(), 0) def test_multiple_coros(self): - evt = event.Event() + evt = eventlet.Event() results = [] def producer(): @@ -86,7 +86,7 @@ evt.wait() results.append('cons2') - pool = greenpool.GreenPool(2) + pool = eventlet.GreenPool(2) done = pool.spawn(consumer) pool.spawn_n(producer) done.wait() @@ -103,7 +103,7 @@ def some_work(): hubs.get_hub().schedule_call_local(0, fire_timer) - pool = greenpool.GreenPool(2) + pool = eventlet.GreenPool(2) worker = pool.spawn(some_work) worker.wait() eventlet.sleep(0) @@ -111,7 +111,7 @@ self.assertEqual(timer_fired, []) def test_reentrant(self): - pool = greenpool.GreenPool(1) + pool = eventlet.GreenPool(1) def reenter(): waiter = pool.spawn(lambda a: a, 'reenter') @@ -120,7 +120,7 @@ outer_waiter = pool.spawn(reenter) outer_waiter.wait() - evt = event.Event() + evt = eventlet.Event() def reenter_async(): pool.spawn_n(lambda a: a, 'reenter') @@ -137,7 +137,7 @@ timer = eventlet.Timeout(1) try: - evt = event.Event() + evt = eventlet.Event() for x in six.moves.range(num_free): pool.spawn(wait_long_time, evt) # if the pool has fewer free than we expect, @@ -159,8 +159,8 @@ eventlet.sleep(0) def test_resize(self): - pool = greenpool.GreenPool(2) - evt = event.Event() + pool = eventlet.GreenPool(2) + evt = eventlet.Event() def wait_long_time(e): e.wait() @@ -194,7 +194,7 @@ # The premise is that a coroutine in a Pool tries to get a token out # of a token pool but times out before getting the token. We verify # that neither pool is adversely affected by this situation. - pool = greenpool.GreenPool(1) + pool = eventlet.GreenPool(1) tp = pools.TokenPool(max_size=1) tp.get() # empty out the pool @@ -230,7 +230,7 @@ gt.wait() def test_spawn_n_2(self): - p = greenpool.GreenPool(2) + p = eventlet.GreenPool(2) self.assertEqual(p.free(), 2) r = [] @@ -259,7 +259,7 @@ self.assertEqual(set(r), set([1, 2, 3, 4])) def test_exceptions(self): - p = greenpool.GreenPool(2) + p = eventlet.GreenPool(2) for m in (p.spawn, p.spawn_n): self.assert_pool_has_free(p, 2) m(raiser, RuntimeError()) @@ -272,22 +272,22 @@ self.assert_pool_has_free(p, 2) def test_imap(self): - p = greenpool.GreenPool(4) + p = eventlet.GreenPool(4) result_list = list(p.imap(passthru, range(10))) self.assertEqual(result_list, list(range(10))) def test_empty_imap(self): - p = greenpool.GreenPool(4) + p = eventlet.GreenPool(4) result_iter = p.imap(passthru, []) self.assertRaises(StopIteration, result_iter.next) def test_imap_nonefunc(self): - p = greenpool.GreenPool(4) + p = eventlet.GreenPool(4) result_list = list(p.imap(None, range(10))) self.assertEqual(result_list, [(x,) for x in range(10)]) def test_imap_multi_args(self): - p = greenpool.GreenPool(4) + p = eventlet.GreenPool(4) result_list = list(p.imap(passthru2, range(10), range(10, 20))) self.assertEqual(result_list, list(zip(range(10), range(10, 20)))) @@ -295,7 +295,7 @@ # testing the case where the function raises an exception; # both that the caller sees that exception, and that the iterator # continues to be usable to get the rest of the items - p = greenpool.GreenPool(4) + p = eventlet.GreenPool(4) def raiser(item): if item == 1 or item == 7: @@ -315,30 +315,30 @@ self.assertEqual(results, [0, 'r', 2, 3, 4, 5, 6, 'r', 8, 9]) def test_starmap(self): - p = greenpool.GreenPool(4) + p = eventlet.GreenPool(4) result_list = list(p.starmap(passthru, [(x,) for x in range(10)])) self.assertEqual(result_list, list(range(10))) def test_waitall_on_nothing(self): - p = greenpool.GreenPool() + p = eventlet.GreenPool() p.waitall() def test_recursive_waitall(self): - p = greenpool.GreenPool() + p = eventlet.GreenPool() gt = p.spawn(p.waitall) self.assertRaises(AssertionError, gt.wait) class GreenPile(tests.LimitedTestCase): def test_pile(self): - p = greenpool.GreenPile(4) + p = eventlet.GreenPile(4) for i in range(10): p.spawn(passthru, i) result_list = list(p) self.assertEqual(result_list, list(range(10))) def test_pile_spawn_times_out(self): - p = greenpool.GreenPile(4) + p = eventlet.GreenPile(4) for i in range(4): p.spawn(passthru, i) # now it should be full and this should time out @@ -351,9 +351,9 @@ self.assertEqual(list(p), list(range(10))) def test_constructing_from_pool(self): - pool = greenpool.GreenPool(2) - pile1 = greenpool.GreenPile(pool) - pile2 = greenpool.GreenPile(pool) + pool = eventlet.GreenPool(2) + pile1 = eventlet.GreenPile(pool) + pile2 = eventlet.GreenPile(pool) def bunch_of_work(pile, unique): for i in range(10): @@ -366,6 +366,17 @@ self.assertEqual(list(pile1), list(range(10))) +def test_greenpool_type_check(): + eventlet.GreenPool(0) + eventlet.GreenPool(1) + eventlet.GreenPool(1e3) + + with tests.assert_raises(TypeError): + eventlet.GreenPool('foo') + with tests.assert_raises(ValueError): + eventlet.GreenPool(-1) + + class StressException(Exception): pass @@ -391,10 +402,9 @@ # tests will take extra-long TEST_TIMEOUT = 60 - @tests.skip_unless(os.environ.get('RUN_STRESS_TESTS') == 'YES') def spawn_order_check(self, concurrency): # checks that piles are strictly ordered - p = greenpool.GreenPile(concurrency) + p = eventlet.GreenPile(concurrency) def makework(count, unique): for i in six.moves.range(count): @@ -425,18 +435,16 @@ for l in latest[1:]: self.assertEqual(l, iters - 1) - @tests.skip_unless(os.environ.get('RUN_STRESS_TESTS') == 'YES') def test_ordering_5(self): self.spawn_order_check(5) - @tests.skip_unless(os.environ.get('RUN_STRESS_TESTS') == 'YES') def test_ordering_50(self): self.spawn_order_check(50) def imap_memory_check(self, concurrency): # checks that imap is strictly # ordered and consumes a constant amount of memory - p = greenpool.GreenPool(concurrency) + p = eventlet.GreenPool(concurrency) count = 1000 it = p.imap(passthru, six.moves.range(count)) latest = -1 @@ -460,15 +468,12 @@ # make sure we got to the end self.assertEqual(latest, count - 1) - @tests.skip_unless(os.environ.get('RUN_STRESS_TESTS') == 'YES') def test_imap_50(self): self.imap_memory_check(50) - @tests.skip_unless(os.environ.get('RUN_STRESS_TESTS') == 'YES') def test_imap_500(self): self.imap_memory_check(500) - @tests.skip_unless(os.environ.get('RUN_STRESS_TESTS') == 'YES') def test_with_intpool(self): class IntPool(pools.Pool): def create(self): @@ -483,7 +488,7 @@ return token int_pool = IntPool(max_size=intpool_size) - pool = greenpool.GreenPool(pool_size) + pool = eventlet.GreenPool(pool_size) for ix in six.moves.range(num_executes): pool.spawn(run, int_pool) pool.waitall() diff -Nru python-eventlet-0.20.0/tests/green_profile_test.py python-eventlet-0.24.1/tests/green_profile_test.py --- python-eventlet-0.20.0/tests/green_profile_test.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/tests/green_profile_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,9 @@ +import eventlet +from eventlet.green import profile +import tests + + +def test_green_profile_basic(): + statement = 'eventlet.sleep()' + result = profile.Profile().runctx(statement, {'eventlet': eventlet}, {}) + assert ('profile', 0, statement) in result.timings diff -Nru python-eventlet-0.20.0/tests/green_select_test.py python-eventlet-0.24.1/tests/green_select_test.py --- python-eventlet-0.20.0/tests/green_select_test.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/tests/green_select_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,25 @@ +import eventlet +from eventlet import hubs +from eventlet.green import select +import tests +original_socket = eventlet.patcher.original('socket') + + +def test_select_mark_file_as_reopened(): + # https://github.com/eventlet/eventlet/pull/294 + # Fix API inconsistency in select and Hub. + # mark_as_closed takes one argument, but called without arguments. + # on_error takes file descriptor, but called with an exception object. + s = original_socket.socket() + s.setblocking(0) + s.bind(('127.0.0.1', 0)) + s.listen(5) + + gt = eventlet.spawn(select.select, [s], [s], [s]) + eventlet.sleep(0.01) + + with eventlet.Timeout(0.5) as t: + with tests.assert_raises(hubs.IOClosed): + hubs.get_hub().mark_as_reopened(s.fileno()) + gt.wait() + t.cancel() diff -Nru python-eventlet-0.20.0/tests/hub_test_fork.py python-eventlet-0.24.1/tests/hub_test_fork.py --- python-eventlet-0.20.0/tests/hub_test_fork.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/hub_test_fork.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -# no standard tests in this file, ignore -__test__ = False - -if __name__ == '__main__': - import os - import eventlet - server = eventlet.listen(('localhost', 12345)) - t = eventlet.Timeout(0.01) - try: - new_sock, address = server.accept() - except eventlet.Timeout as t: - pass - - pid = os.fork() - if not pid: - t = eventlet.Timeout(0.1) - try: - new_sock, address = server.accept() - except eventlet.Timeout as t: - print("accept blocked") - else: - kpid, status = os.wait() - assert kpid == pid - assert status == 0 - print("child died ok") diff -Nru python-eventlet-0.20.0/tests/hub_test.py python-eventlet-0.24.1/tests/hub_test.py --- python-eventlet-0.20.0/tests/hub_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/hub_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,15 +1,14 @@ from __future__ import with_statement import sys +import time import tests -from tests import LimitedTestCase, main, skip_with_pyevent, skip_if_no_itimer, skip_unless +from tests import skip_with_pyevent, skip_if_no_itimer, skip_unless from tests.patcher_test import ProcessBase -import time import eventlet from eventlet import hubs -from eventlet.event import Event -from eventlet.semaphore import Semaphore -from eventlet.support import greenlets, six +from eventlet.support import greenlets +import six DELAY = 0.001 @@ -19,7 +18,7 @@ pass -class TestTimerCleanup(LimitedTestCase): +class TestTimerCleanup(tests.LimitedTestCase): TEST_TIMEOUT = 2 @skip_with_pyevent @@ -85,7 +84,7 @@ eventlet.sleep() -class TestScheduleCall(LimitedTestCase): +class TestScheduleCall(tests.LimitedTestCase): def test_local(self): lst = [1] @@ -111,7 +110,7 @@ self.assertEqual(lst, [1, 2, 3]) -class TestDebug(LimitedTestCase): +class TestDebug(tests.LimitedTestCase): def test_debug_listeners(self): hubs.get_hub().set_debug_listeners(True) @@ -122,7 +121,7 @@ hubs.get_hub().set_timer_exceptions(False) -class TestExceptionInMainloop(LimitedTestCase): +class TestExceptionInMainloop(tests.LimitedTestCase): def test_sleep(self): # even if there was an error in the mainloop, the hub should continue @@ -149,13 +148,13 @@ delay, DELAY) -class TestExceptionInGreenthread(LimitedTestCase): +class TestExceptionInGreenthread(tests.LimitedTestCase): @skip_unless(greenlets.preserves_excinfo) def test_exceptionpreservation(self): # events for controlling execution order - gt1event = Event() - gt2event = Event() + gt1event = eventlet.Event() + gt2event = eventlet.Event() def test_gt1(): try: @@ -196,7 +195,7 @@ hubs.get_hub().switch() # semaphores for controlling execution order - sem = Semaphore() + sem = eventlet.Semaphore() sem.acquire() g = eventlet.spawn(test_gt, sem) try: @@ -206,7 +205,7 @@ g.kill() -class TestHubSelection(LimitedTestCase): +class TestHubSelection(tests.LimitedTestCase): def test_explicit_hub(self): oldhub = hubs.get_hub() @@ -217,7 +216,7 @@ hubs._threadlocal.hub = oldhub -class TestHubBlockingDetector(LimitedTestCase): +class TestHubBlockingDetector(tests.LimitedTestCase): TEST_TIMEOUT = 10 @skip_with_pyevent @@ -245,7 +244,7 @@ debug.hub_blocking_detection(False) -class TestSuspend(LimitedTestCase): +class TestSuspend(tests.LimitedTestCase): TEST_TIMEOUT = 4 longMessage = True maxDiff = None @@ -283,25 +282,30 @@ shutil.rmtree(self.tempdir) -class TestBadFilenos(LimitedTestCase): +def test_repeated_select_bad_fd(): + from eventlet.green import select - @skip_with_pyevent - def test_repeated_selects(self): - from eventlet.green import select - self.assertRaises(ValueError, select.select, [-1], [], []) - self.assertRaises(ValueError, select.select, [-1], [], []) + def once(): + try: + select.select([-1], [], []) + assert False, 'Expected ValueError' + except ValueError: + pass + once() + once() -class TestFork(LimitedTestCase): - @skip_with_pyevent - def test_fork(self): - output = tests.run_python('tests/hub_test_fork.py') - lines = output.splitlines() - self.assertEqual(lines, [b"accept blocked", b"child died ok"], output) +@skip_with_pyevent +def test_fork(): + tests.run_isolated('hub_fork.py') + + +def test_fork_simple(): + tests.run_isolated('hub_fork_simple.py') -class TestDeadRunLoop(LimitedTestCase): +class TestDeadRunLoop(tests.LimitedTestCase): TEST_TIMEOUT = 2 class CustomException(Exception): @@ -376,7 +380,7 @@ except AttributeError: pass -from eventlet.support.six.moves import builtins +from six.moves import builtins original_import = builtins.__import__ @@ -397,7 +401,3 @@ self.write_to_tempfile('newmod', module_source) output, _ = self.launch_subprocess('newmod.py') self.assertEqual(output, 'kqueue tried\nok\n') - - -if __name__ == '__main__': - main() diff -Nru python-eventlet-0.20.0/tests/__init__.py python-eventlet-0.24.1/tests/__init__.py --- python-eventlet-0.20.0/tests/__init__.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/__init__.py 2018-08-06 16:17:47.000000000 +0000 @@ -24,6 +24,10 @@ import eventlet from eventlet import tpool +import six +import socket +from threading import Thread +import struct # convenience for importers @@ -123,6 +127,15 @@ return skip_unless(has_itimer)(func) +def skip_if_CRLock_exist(func): + """ Decorator that skips a test if the `_thread.RLock` class exists """ + try: + from _thread import RLock + return skipped(func) + except ImportError: + return func + + def skip_if_no_ssl(func): """ Decorator that skips a test if SSL is not available.""" try: @@ -136,6 +149,12 @@ return skipped(func) +def skip_if_no_ipv6(func): + if os.environ.get('eventlet_test_ipv6') != '1': + return skipped(func) + return func + + class TestIsTakingTooLong(Exception): """ Custom exception class to be raised when a test's runtime exceeds a limit. """ pass @@ -302,16 +321,25 @@ return retval -def run_python(path, env=None, args=None, timeout=None): +def run_python(path, env=None, args=None, timeout=None, pythonpath_extend=None, expect_pass=False): new_argv = [sys.executable] + if sys.version_info[:2] <= (2, 6): + new_argv += ['-W', 'ignore::DeprecationWarning'] new_env = os.environ.copy() + new_env.setdefault('eventlet_test_in_progress', 'yes') + src_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if path: 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 pythonpath_extend: + new_path = [p for p in new_env.get('PYTHONPATH', '').split(os.pathsep) if p] + new_path.extend( + p if os.path.isabs(p) else os.path.join(src_dir, p) for p in pythonpath_extend + ) + new_env['PYTHONPATH'] = os.pathsep.join(new_path) if args: new_argv.extend(args) p = subprocess.Popen( @@ -329,21 +357,42 @@ p.kill() output, _ = p.communicate(timeout=timeout) return '{0}\nFAIL - timed out'.format(output).encode() + + if expect_pass: + if output.startswith(b'skip'): + parts = output.rstrip().split(b':', 1) + skip_args = [] + if len(parts) > 1: + skip_args.append(parts[1]) + raise SkipTest(*skip_args) + ok = output.rstrip() == b'pass' + if not ok: + sys.stderr.write('Program {0} output:\n---\n{1}\n---\n'.format(path, output.decode())) + assert ok, 'Expected single line "pass" in stdout' + return output -def run_isolated(path, prefix='tests/isolated/', env=None, args=None, timeout=None): - output = run_python(prefix + path, env=env, args=args, timeout=timeout).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) - 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' +def run_isolated(path, prefix='tests/isolated/', **kwargs): + kwargs.setdefault('expect_pass', True) + run_python(prefix + path, **kwargs) + + +def check_is_timeout(obj): + value_text = getattr(obj, 'is_timeout', '(missing)') + assert obj.is_timeout, 'type={0} str={1} .is_timeout={2}'.format(type(obj), str(obj), value_text) + + +@contextlib.contextmanager +def capture_stderr(): + stream = six.StringIO() + original = sys.stderr + try: + sys.stderr = stream + yield stream + finally: + sys.stderr = original + stream.seek(0) certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt') @@ -353,3 +402,86 @@ def test_run_python_timeout(): output = run_python('', args=('-c', 'import time; time.sleep(0.5)'), timeout=0.1) assert output.endswith(b'FAIL - timed out') + + +def test_run_python_pythonpath_extend(): + code = '''import os, sys ; print('\\n'.join(sys.path))''' + output = run_python('', args=('-c', code), pythonpath_extend=('dira', 'dirb')) + assert b'/dira\n' in output + assert b'/dirb\n' in output + + +@contextlib.contextmanager +def dns_tcp_server(ip_to_give, request_count=1): + state = [0] # request count storage writable by thread + host = "localhost" + death_pill = b"DEATH_PILL" + + def extract_domain(data): + domain = b'' + kind = (data[4] >> 3) & 15 # Opcode bits + if kind == 0: # Standard query + ini = 14 + length = data[ini] + while length != 0: + domain += data[ini + 1:ini + length + 1] + b'.' + ini += length + 1 + length = data[ini] + return domain + + def answer(data, domain): + domain_length = len(domain) + packet = b'' + if domain: + # If an ip was given we return it in the answer + if ip_to_give: + packet += data[2:4] + b'\x81\x80' + packet += data[6:8] + data[6:8] + b'\x00\x00\x00\x00' # Questions and answers counts + packet += data[14: 14 + domain_length + 1] # Original domain name question + packet += b'\x00\x01\x00\x01' # Type and class + packet += b'\xc0\x0c\x00\x01' # TTL + packet += b'\x00\x01' + packet += b'\x00\x00\x00\x08' + packet += b'\x00\x04' # Resource data length -> 4 bytes + packet += bytearray(int(x) for x in ip_to_give.split(".")) + else: + packet += data[2:4] + b'\x85\x80' + packet += data[6:8] + b'\x00\x00' + b'\x00\x00\x00\x00' # Questions and answers counts + packet += data[14: 14 + domain_length + 1] # Original domain name question + packet += b'\x00\x01\x00\x01' # Type and class + + sz = struct.pack('>H', len(packet)) + return sz + packet + + def serve(server_socket): # thread target + client_sock, address = server_socket.accept() + state[0] += 1 + if state[0] <= request_count: + data = bytearray(client_sock.recv(1024)) + if data == death_pill: + client_sock.close() + return + + domain = extract_domain(data) + client_sock.sendall(answer(data, domain)) + client_sock.close() + + # Server starts + server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server_socket.bind((host, 0)) + server_socket.listen(5) + server_addr = server_socket.getsockname() + + thread = Thread(target=serve, args=(server_socket, )) + thread.start() + + yield server_addr + + # Stop the server + client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + client.connect(server_addr) + client.send(death_pill) + client.close() + thread.join() + server_socket.close() diff -Nru python-eventlet-0.20.0/tests/isolated/greendns_from_address_203.py python-eventlet-0.24.1/tests/isolated/greendns_from_address_203.py --- python-eventlet-0.20.0/tests/isolated/greendns_from_address_203.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/isolated/greendns_from_address_203.py 2018-08-06 16:17:47.000000000 +0000 @@ -2,7 +2,7 @@ if __name__ == '__main__': import eventlet - from eventlet.support.dns import reversename + from dns import reversename eventlet.monkey_patch(all=True) reversename.from_address('127.0.0.1') print('pass') diff -Nru python-eventlet-0.20.0/tests/isolated/greendns_import_rdtypes_then_eventlet.py python-eventlet-0.24.1/tests/isolated/greendns_import_rdtypes_then_eventlet.py --- python-eventlet-0.20.0/tests/isolated/greendns_import_rdtypes_then_eventlet.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/tests/isolated/greendns_import_rdtypes_then_eventlet.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,8 @@ +__test__ = False + +if __name__ == '__main__': + import dns.rdtypes + import eventlet.support.greendns + # AttributeError: 'module' object has no attribute 'dnskeybase' + # https://github.com/eventlet/eventlet/issues/479 + print('pass') diff -Nru python-eventlet-0.20.0/tests/isolated/green_ssl_py36_properties.py python-eventlet-0.24.1/tests/isolated/green_ssl_py36_properties.py --- python-eventlet-0.20.0/tests/isolated/green_ssl_py36_properties.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/tests/isolated/green_ssl_py36_properties.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,16 @@ +__test__ = False + + +if __name__ == '__main__': + import eventlet + eventlet.monkey_patch() + + try: + eventlet.wrap_ssl( + eventlet.listen(('localhost', 0)), + certfile='does-not-exist', + keyfile='does-not-exist', + server_side=True) + except IOError as ex: + assert ex.errno == 2 + print('pass') diff -Nru python-eventlet-0.20.0/tests/isolated/hub_fork.py python-eventlet-0.24.1/tests/isolated/hub_fork.py --- python-eventlet-0.20.0/tests/isolated/hub_fork.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/tests/isolated/hub_fork.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,33 @@ +# verify eventlet.listen() accepts in forked children +__test__ = False + +if __name__ == '__main__': + import os + import sys + import eventlet + + server = eventlet.listen(('127.0.0.1', 0)) + result = eventlet.with_timeout(0.01, server.accept, timeout_value=True) + assert result is True, 'Expected timeout' + + pid = os.fork() + if pid < 0: + print('fork error') + sys.exit(1) + elif pid == 0: + with eventlet.Timeout(1): + sock, _ = server.accept() + sock.sendall('ok {0}'.format(os.getpid()).encode()) + sock.close() + sys.exit(0) + elif pid > 0: + with eventlet.Timeout(1): + sock = eventlet.connect(server.getsockname()) + data = sock.recv(20).decode() + assert data.startswith('ok ') + spid = int(data[3:].strip()) + assert spid == pid + kpid, status = os.wait() + assert kpid == pid + assert status == 0 + print('pass') diff -Nru python-eventlet-0.20.0/tests/isolated/hub_fork_simple.py python-eventlet-0.24.1/tests/isolated/hub_fork_simple.py --- python-eventlet-0.20.0/tests/isolated/hub_fork_simple.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/tests/isolated/hub_fork_simple.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,58 @@ +import os +import signal +import sys +import tempfile +__test__ = False + + +def parent(signal_path, pid): + eventlet.Timeout(5) + port = None + while True: + try: + contents = open(signal_path, 'rb').read() + port = int(contents.strip()) + break + except Exception: + eventlet.sleep(0.1) + eventlet.connect(('127.0.0.1', port)) + while True: + try: + contents = open(signal_path, 'rb').read() + result = contents.split()[1] + break + except Exception: + eventlet.sleep(0.1) + assert result == b'done', repr(result) + print('pass') + + +def child(signal_path): + eventlet.Timeout(5) + s = eventlet.listen(('127.0.0.1', 0)) + with open(signal_path, 'wb') as f: + f.write(str(s.getsockname()[1]).encode() + b'\n') + f.flush() + s.accept() + f.write(b'done\n') + f.flush() + + +if __name__ == '__main__': + import eventlet + + with tempfile.NamedTemporaryFile() as signal_file: + signal_path = signal_file.name + + pid = os.fork() + if pid < 0: + sys.stderr.write('fork error\n') + sys.exit(1) + elif pid == 0: + child(signal_path) + sys.exit(0) + elif pid > 0: + try: + parent(signal_path, pid) + except Exception: + os.kill(pid, signal.SIGTERM) diff -Nru python-eventlet-0.20.0/tests/isolated/patcher_existing_locks_unlocked.py python-eventlet-0.24.1/tests/isolated/patcher_existing_locks_unlocked.py --- python-eventlet-0.20.0/tests/isolated/patcher_existing_locks_unlocked.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/tests/isolated/patcher_existing_locks_unlocked.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,25 @@ +__test__ = False + + +def take(lock, e1, e2): + with lock: + e1.set() + e2.wait() + + +if __name__ == '__main__': + import sys + import threading + lock = threading.RLock() + import eventlet + eventlet.monkey_patch() + + lock.acquire() + lock.release() + + e1, e2 = threading.Event(), threading.Event() + eventlet.spawn(take, lock, e1, e2) + e1.wait() + assert not lock.acquire(blocking=0) + e2.set() + print('pass') diff -Nru python-eventlet-0.20.0/tests/isolated/patcher_import_patched_defaults.py python-eventlet-0.24.1/tests/isolated/patcher_import_patched_defaults.py --- python-eventlet-0.20.0/tests/isolated/patcher_import_patched_defaults.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/tests/isolated/patcher_import_patched_defaults.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,18 @@ +__test__ = False + +if __name__ == '__main__': + import sys + # On eventlet<=0.20.0 uncommenting this unpatched import fails test + # because import_patched did not agressively repatch sub-imported modules cached in sys.modules + # to be fixed in https://github.com/eventlet/eventlet/issues/368 + # import tests.patcher.shared_import_socket + + import eventlet + target = eventlet.import_patched('tests.patcher.shared1').shared + t = target.socket.socket + import eventlet.green.socket as g + if not issubclass(t, g.socket): + print('Fail. Target socket not green: {0} bases {1}'.format(t, t.__bases__)) + sys.exit(1) + + print('pass') diff -Nru python-eventlet-0.20.0/tests/isolated/patcher_socketserver_selectors.py python-eventlet-0.24.1/tests/isolated/patcher_socketserver_selectors.py --- python-eventlet-0.20.0/tests/isolated/patcher_socketserver_selectors.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/isolated/patcher_socketserver_selectors.py 2018-08-06 16:17:47.000000000 +0000 @@ -4,7 +4,7 @@ import eventlet eventlet.monkey_patch() - from eventlet.support.six.moves.BaseHTTPServer import ( + from six.moves.BaseHTTPServer import ( HTTPServer, BaseHTTPRequestHandler, ) diff -Nru python-eventlet-0.20.0/tests/isolated/patcher_threading_current.py python-eventlet-0.24.1/tests/isolated/patcher_threading_current.py --- python-eventlet-0.20.0/tests/isolated/patcher_threading_current.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/tests/isolated/patcher_threading_current.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,25 @@ +# Threading.current_thread does not change when using greenthreads? +# https://github.com/eventlet/eventlet/issues/172 +__test__ = False + +if __name__ == '__main__': + import eventlet + eventlet.monkey_patch() + + import threading + + g = set() + + def fun(): + ct = threading.current_thread() + g.add(ct.name) + + ts = tuple(threading.Thread(target=fun, name='t{}'.format(i)) for i in range(3)) + for t in ts: + t.start() + for t in ts: + t.join() + + assert g == set(('t0', 't1', 't2')), repr(g) + + print('pass') diff -Nru python-eventlet-0.20.0/tests/isolated/regular_file_readall.py python-eventlet-0.24.1/tests/isolated/regular_file_readall.py --- python-eventlet-0.20.0/tests/isolated/regular_file_readall.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/isolated/regular_file_readall.py 2018-08-06 16:17:47.000000000 +0000 @@ -4,7 +4,7 @@ import eventlet eventlet.monkey_patch() - from eventlet.support import six + import six import io import os import tempfile diff -Nru python-eventlet-0.20.0/tests/isolated/socket_resolve_green.py python-eventlet-0.24.1/tests/isolated/socket_resolve_green.py --- python-eventlet-0.20.0/tests/isolated/socket_resolve_green.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/isolated/socket_resolve_green.py 2018-08-06 16:17:47.000000000 +0000 @@ -8,20 +8,22 @@ import dns.message import dns.query + n = 10 + delay = 0.01 + addr_map = {'test-host{0}.'.format(i): '0.0.1.{0}'.format(i) for i in range(n)} + def slow_udp(q, *a, **kw): - addr = '0.0.0.1' - if 'host2' in str(q.question): - addr = '0.0.0.2' - if 'host3' in str(q.question): - addr = '0.0.0.3' + qname = q.question[0].name + addr = addr_map[qname.to_text()] r = dns.message.make_response(q) r.index = None r.flags = 256 - r.answer.append(dns.rrset.from_text(str(q.question[0].name), 60, 'IN', 'A', addr)) + r.answer.append(dns.rrset.from_text(str(qname), 60, 'IN', 'A', addr)) r.time = 0.001 - eventlet.sleep(0.1) + eventlet.sleep(delay) return r + dns.query.tcp = lambda: eventlet.Timeout(0) dns.query.udp = slow_udp results = {} @@ -31,15 +33,18 @@ except socket.error as e: print('name: {0} error: {1}'.format(name, e)) - pool = eventlet.GreenPool() + pool = eventlet.GreenPool(size=n + 1) + + # FIXME: For unknown reason, first GreenPool.spawn() takes ~250ms on some platforms. + # Spawned function executes for normal expected time, it's the GreenPool who needs warmup. + pool.spawn(eventlet.sleep) + t1 = time.time() - pool.spawn(fun, 'eventlet-test-host1.') - pool.spawn(fun, 'eventlet-test-host2.') - pool.spawn(fun, 'eventlet-test-host3.') + for name in addr_map: + pool.spawn(fun, name) pool.waitall() td = time.time() - t1 - assert 0.1 <= td < 0.3, 'Resolve time expected: ~0.1s, real: {0:.3f}'.format(td) - assert results.get('eventlet-test-host1.') == '0.0.0.1' - assert results.get('eventlet-test-host2.') == '0.0.0.2' - assert results.get('eventlet-test-host3.') == '0.0.0.3' + fail_msg = 'Resolve time expected: ~{0:.3f}s, real: {1:.3f}'.format(delay, td) + assert delay <= td < delay * n, fail_msg + assert addr_map == results print('pass') diff -Nru python-eventlet-0.20.0/tests/isolated/subprocess_exception_identity.py python-eventlet-0.24.1/tests/isolated/subprocess_exception_identity.py --- python-eventlet-0.20.0/tests/isolated/subprocess_exception_identity.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/tests/isolated/subprocess_exception_identity.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,14 @@ +__test__ = False + +if __name__ == '__main__': + import subprocess as original + from eventlet.green import subprocess as green + + cases = ( + 'CalledProcessError', + 'TimeoutExpired', + ) + for c in cases: + if hasattr(original, c): + assert getattr(green, c) is getattr(original, c), c + print('pass') diff -Nru python-eventlet-0.20.0/tests/isolated/tpool_exception_leak.py python-eventlet-0.24.1/tests/isolated/tpool_exception_leak.py --- python-eventlet-0.20.0/tests/isolated/tpool_exception_leak.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/tests/isolated/tpool_exception_leak.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,43 @@ +__test__ = False + +if __name__ == '__main__': + import eventlet + import eventlet.tpool + import gc + import pprint + + class RequiredException(Exception): + pass + + class A(object): + def ok(self): + return 'ok' + + def err(self): + raise RequiredException + + a = A() + + # case 1 no exception + assert eventlet.tpool.Proxy(a).ok() == 'ok' + # yield to tpool_trampoline(), otherwise e.send(rv) have a reference + eventlet.sleep(0.1) + gc.collect() + refs = gc.get_referrers(a) + assert len(refs) == 1, 'tpool.Proxy-ied object leaked: {}'.format(pprint.pformat(refs)) + + # case 2 with exception + def test_exception(): + try: + eventlet.tpool.Proxy(a).err() + assert False, 'expected exception' + except RequiredException: + pass + test_exception() + # yield to tpool_trampoline(), otherwise e.send(rv) have a reference + eventlet.sleep(0.1) + gc.collect() + refs = gc.get_referrers(a) + assert len(refs) == 1, 'tpool.Proxy-ied object leaked: {}'.format(pprint.pformat(refs)) + + print('pass') diff -Nru python-eventlet-0.20.0/tests/isolated/wsgi_connection_timeout.py python-eventlet-0.24.1/tests/isolated/wsgi_connection_timeout.py --- python-eventlet-0.20.0/tests/isolated/wsgi_connection_timeout.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/isolated/wsgi_connection_timeout.py 2018-08-06 16:17:47.000000000 +0000 @@ -25,7 +25,7 @@ import socket import eventlet -from eventlet.support import six +import six import tests.wsgi_test diff -Nru python-eventlet-0.20.0/tests/openssl_test.py python-eventlet-0.24.1/tests/openssl_test.py --- python-eventlet-0.20.0/tests/openssl_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/openssl_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -12,6 +12,5 @@ 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 diff -Nru python-eventlet-0.20.0/tests/patcher/shared1.py python-eventlet-0.24.1/tests/patcher/shared1.py --- python-eventlet-0.20.0/tests/patcher/shared1.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/tests/patcher/shared1.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,11 @@ +import os +__test__ = False +shared = None + + +if os.environ.get('eventlet_test_in_progress') == 'yes': + # pyopenssl imported urllib before we could patch it + # we can ensure this shared module was not imported + # https://github.com/eventlet/eventlet/issues/362 + import tests.patcher.shared_import_socket as shared + _ = shared # mask unused import error diff -Nru python-eventlet-0.20.0/tests/patcher/shared_import_socket.py python-eventlet-0.24.1/tests/patcher/shared_import_socket.py --- python-eventlet-0.20.0/tests/patcher/shared_import_socket.py 1970-01-01 00:00:00.000000000 +0000 +++ python-eventlet-0.24.1/tests/patcher/shared_import_socket.py 2018-08-06 16:17:47.000000000 +0000 @@ -0,0 +1,7 @@ +import os +import socket +__test__ = False +_ = socket # mask unused import error + +# prevent accidental imports +assert os.environ.get('eventlet_test_in_progress') == 'yes' diff -Nru python-eventlet-0.20.0/tests/patcher_psycopg_test.py python-eventlet-0.24.1/tests/patcher_psycopg_test.py --- python-eventlet-0.20.0/tests/patcher_psycopg_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/patcher_psycopg_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,6 +1,6 @@ import os -from eventlet.support import six +import six from tests import patcher_test, skip_unless from tests import get_database_auth diff -Nru python-eventlet-0.20.0/tests/patcher_test.py python-eventlet-0.24.1/tests/patcher_test.py --- python-eventlet-0.20.0/tests/patcher_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/patcher_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -3,7 +3,7 @@ import sys import tempfile -from eventlet.support import six +import six import tests @@ -82,26 +82,9 @@ assert 'eventlet.green.urllib' in lines[2], repr(output) assert 'eventlet.green.httplib' not in lines[2], repr(output) - def test_import_patched_defaults(self): - self.write_to_tempfile("base", """ -import socket -try: - import urllib.request as urllib -except ImportError: - import urllib -print("base {0} {1}".format(socket, urllib))""") - new_mod = """ -from eventlet import patcher -base = patcher.import_patched('base') -print("newmod {0} {1} {2}".format(base, base.socket, base.urllib.socket.socket)) -""" - self.write_to_tempfile("newmod", new_mod) - output, lines = self.launch_subprocess('newmod.py') - assert lines[0].startswith('base'), repr(output) - assert lines[1].startswith('newmod'), repr(output) - assert 'eventlet.green.socket' in lines[1], repr(output) - assert 'GreenSocket' in lines[1], repr(output) +def test_import_patched_defaults(): + tests.run_isolated('patcher_import_patched_defaults.py') class MonkeyPatch(ProcessBase): @@ -226,7 +209,7 @@ tickcount = [0] def tick(): - from eventlet.support import six + import six for i in six.moves.range(1000): tickcount[0] += 1 eventlet.sleep() @@ -329,23 +312,6 @@ assert lines[1] == '1', lines assert lines[2] == '1', lines - def test_threading(self): - new_mod = """import eventlet -eventlet.monkey_patch() -import threading -def test(): - print(repr(threading.currentThread())) -t = threading.Thread(target=test) -t.start() -t.join() -print(len(threading._active)) -""" - self.write_to_tempfile("newmod", new_mod) - output, lines = self.launch_subprocess('newmod.py') - self.assertEqual(len(lines), 3, "\n".join(lines)) - assert lines[0].startswith('<_MainThread'), lines[0] - self.assertEqual(lines[1], "1", lines[1]) - def test_tpool(self): new_mod = """import eventlet eventlet.monkey_patch() @@ -510,6 +476,11 @@ tests.run_isolated('patcher_existing_locks_locked.py') +@tests.skip_if_CRLock_exist +def test_patcher_existing_locks_unlocked(): + tests.run_isolated('patcher_existing_locks_unlocked.py') + + def test_importlib_lock(): tests.run_isolated('patcher_importlib_lock.py') @@ -532,3 +503,7 @@ def test_regular_file_readall(): tests.run_isolated('regular_file_readall.py') + + +def test_threading_current(): + tests.run_isolated('patcher_threading_current.py') diff -Nru python-eventlet-0.20.0/tests/pools_test.py python-eventlet-0.24.1/tests/pools_test.py --- python-eventlet-0.20.0/tests/pools_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/pools_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -2,8 +2,9 @@ import eventlet from eventlet import Queue +from eventlet import hubs from eventlet import pools -from eventlet.support import six +import six class IntPool(pools.Pool): @@ -164,6 +165,25 @@ gp.waitall() self.assertEqual(creates[0], 4) + def test_put_with_timed_out_getters(self): + p = IntPool(max_size=2) + hub = hubs.get_hub() + # check out all the items + p.get() + p.get() + + # all getting greenthreads are blocked and have Timeouts that are + # ready to fire, but have not fired yet + getters = [eventlet.spawn(p.get) for _ in range(5)] + eventlet.sleep() + for getter in getters: + hub.schedule_call_global(0, getter.throw, eventlet.Timeout(None)) + + # put one item back; this should not block since the pool is empty + with eventlet.Timeout(10): # don't hang if unblocking fails + p.put(0) + self.assertEqual(len(p.free_items), 1) + class TestAbstract(TestCase): mode = 'static' diff -Nru python-eventlet-0.20.0/tests/queue_test.py python-eventlet-0.24.1/tests/queue_test.py --- python-eventlet-0.20.0/tests/queue_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/queue_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,6 +1,6 @@ import eventlet from eventlet import event, hubs, queue -from tests import LimitedTestCase, main +import tests def do_bail(q): @@ -12,7 +12,7 @@ return 'timed out' -class TestQueue(LimitedTestCase): +class TestQueue(tests.LimitedTestCase): def test_send_first(self): q = eventlet.Queue() q.put('hi') @@ -246,7 +246,7 @@ self.assertRaises(queue.Empty, c.get_nowait) def test_task_done(self): - channel = queue.Queue(0) + channel = eventlet.Queue(0) X = object() gt = eventlet.spawn(channel.put, X) result = channel.get() @@ -260,6 +260,25 @@ queue = eventlet.Queue() queue.join() + def test_zero_length_queue_nonblocking_put(self): + hub = hubs.get_hub() + queue = eventlet.Queue(0) + got = [] + + def fetch_item(): + got.append(queue.get()) + + for _ in range(10): + good_getter = eventlet.spawn(fetch_item) + bad_getter = eventlet.spawn(fetch_item) + hub.schedule_call_global(0, bad_getter.throw, Exception("kaboom")) + eventlet.sleep(0) + + for i in range(10): + queue.put(i) + + self.assertEqual(got, list(range(10))) + def store_result(result, func, *args): try: @@ -268,7 +287,7 @@ result.append(exc) -class TestNoWait(LimitedTestCase): +class TestNoWait(tests.LimitedTestCase): def test_put_nowait_simple(self): hub = hubs.get_hub() result = [] @@ -284,7 +303,7 @@ def test_get_nowait_simple(self): hub = hubs.get_hub() result = [] - q = queue.Queue(1) + q = eventlet.Queue(1) q.put(4) hub.schedule_call_global(0, store_result, result, q.get_nowait) hub.schedule_call_global(0, store_result, result, q.get_nowait) @@ -297,7 +316,7 @@ def test_get_nowait_unlock(self): hub = hubs.get_hub() result = [] - q = queue.Queue(0) + q = eventlet.Queue(0) p = eventlet.spawn(q.put, 5) assert q.empty(), q assert q.full(), q @@ -318,7 +337,7 @@ def test_put_nowait_unlock(self): hub = hubs.get_hub() result = [] - q = queue.Queue(0) + q = eventlet.Queue(0) eventlet.spawn(q.get) assert q.empty(), q assert q.full(), q @@ -335,6 +354,17 @@ assert q.full(), q assert q.empty(), q + def test_wait_except(self): + # https://github.com/eventlet/eventlet/issues/407 + q = eventlet.Queue() + + def get(): + q.get() + raise KeyboardInterrupt + + eventlet.spawn(get) + eventlet.sleep() -if __name__ == '__main__': - main() + with tests.assert_raises(KeyboardInterrupt): + q.put(None) + eventlet.sleep() diff -Nru python-eventlet-0.20.0/tests/README python-eventlet-0.24.1/tests/README --- python-eventlet-0.20.0/tests/README 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -The tests are intended to be run using Nose. -http://somethingaboutorange.com/mrl/projects/nose/ - -To run tests, simply install nose, and then, in the eventlet tree, do: - $ nosetests - -That's it! Its output is the same as unittest's output. It tends to emit a lot of tracebacks from various poorly-behaving tests, but they still (generally) pass. \ No newline at end of file diff -Nru python-eventlet-0.20.0/tests/semaphore_test.py python-eventlet-0.24.1/tests/semaphore_test.py --- python-eventlet-0.20.0/tests/semaphore_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/semaphore_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,14 +1,13 @@ import time import eventlet -from eventlet import semaphore -from tests import LimitedTestCase +import tests -class TestSemaphore(LimitedTestCase): +class TestSemaphore(tests.LimitedTestCase): def test_bounded(self): - sem = semaphore.CappedSemaphore(2, limit=3) + sem = eventlet.CappedSemaphore(2, limit=3) self.assertEqual(sem.acquire(), True) self.assertEqual(sem.acquire(), True) gt1 = eventlet.spawn(sem.release) @@ -24,28 +23,28 @@ gt2.wait() def test_bounded_with_zero_limit(self): - sem = semaphore.CappedSemaphore(0, 0) + sem = eventlet.CappedSemaphore(0, 0) gt = eventlet.spawn(sem.acquire) sem.release() gt.wait() def test_non_blocking(self): - sem = semaphore.Semaphore(0) + sem = eventlet.Semaphore(0) self.assertEqual(sem.acquire(blocking=False), False) def test_timeout(self): - sem = semaphore.Semaphore(0) + sem = eventlet.Semaphore(0) start = time.time() self.assertEqual(sem.acquire(timeout=0.1), False) self.assertTrue(time.time() - start >= 0.1) def test_timeout_non_blocking(self): - sem = semaphore.Semaphore() + sem = eventlet.Semaphore() self.assertRaises(ValueError, sem.acquire, blocking=False, timeout=1) def test_semaphore_contention(): - g_mutex = semaphore.Semaphore() + g_mutex = eventlet.Semaphore() counts = [0, 0] def worker(no): @@ -61,3 +60,14 @@ t2.kill() assert abs(counts[0] - counts[1]) < int(min(counts) * 0.1), counts + + +def test_semaphore_type_check(): + eventlet.Semaphore(0) + eventlet.Semaphore(1) + eventlet.Semaphore(1e2) + + with tests.assert_raises(TypeError): + eventlet.Semaphore('foo') + with tests.assert_raises(ValueError): + eventlet.Semaphore(-1) diff -Nru python-eventlet-0.20.0/tests/socket_test.py python-eventlet-0.24.1/tests/socket_test.py --- python-eventlet-0.20.0/tests/socket_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/socket_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -72,10 +72,7 @@ with open(mock_sys_pkg_dir + '/dns.py', 'wb') as f: f.write(b'raise Exception("Your IP address string is so illegal ' + b'it prevents installing packages.")\n') - tests.run_isolated( - 'socket_resolve_green.py', - env={'PYTHONPATH': os.pathsep.join(sys.path + [mock_sys_pkg_dir])}, - ) + tests.run_isolated('socket_resolve_green.py', pythonpath_extend=[mock_sys_pkg_dir]) finally: shutil.rmtree(mock_sys_pkg_dir) @@ -91,3 +88,14 @@ if not socket.has_ipv6: return socket.getaddrinfo('::1%2', 80, socket.AF_INET6) + + +def test_error_is_timeout(): + s1, _ = socket.socketpair() + s1.settimeout(0.01) + try: + s1.recv(1) + except socket.error as e: + tests.check_is_timeout(e) + else: + assert False, 'No timeout, socket.error was not raised' diff -Nru python-eventlet-0.20.0/tests/ssl_test.py python-eventlet-0.24.1/tests/ssl_test.py --- python-eventlet-0.20.0/tests/ssl_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/ssl_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -9,7 +9,7 @@ from eventlet.green import ssl except ImportError: __test__ = False -from eventlet.support import six +import six import tests diff -Nru python-eventlet-0.20.0/tests/subprocess_test.py python-eventlet-0.24.1/tests/subprocess_test.py --- python-eventlet-0.20.0/tests/subprocess_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/subprocess_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -93,3 +93,9 @@ stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) + + +def test_exception_identity(): + # https://github.com/eventlet/eventlet/issues/413 + # green module must keep exceptions classes as stdlib version + tests.run_isolated('subprocess_exception_identity.py') diff -Nru python-eventlet-0.20.0/tests/test__greenness.py python-eventlet-0.24.1/tests/test__greenness.py --- python-eventlet-0.20.0/tests/test__greenness.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/test__greenness.py 2018-08-06 16:17:47.000000000 +0000 @@ -4,7 +4,7 @@ """ import eventlet from eventlet.green import BaseHTTPServer -from eventlet.support import six +import six if six.PY2: from eventlet.green.urllib2 import HTTPError, urlopen diff -Nru python-eventlet-0.20.0/tests/test__refcount.py python-eventlet-0.24.1/tests/test__refcount.py --- python-eventlet-0.20.0/tests/test__refcount.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/test__refcount.py 2018-08-06 16:17:47.000000000 +0000 @@ -2,78 +2,71 @@ are not leaked by the hub. """ import gc -from pprint import pformat +import pprint +import sys import weakref -from eventlet.support import clear_sys_exc_info +import eventlet from eventlet.green import socket -from eventlet.green.thread import start_new_thread -from eventlet.green.time import sleep - -SOCKET_TIMEOUT = 0.1 -def init_server(): - s = socket.socket() - s.settimeout(SOCKET_TIMEOUT) - s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - s.bind(('localhost', 0)) - s.listen(5) - return s, s.getsockname()[1] +SOCKET_TIMEOUT = 0.1 def handle_request(s, raise_on_timeout): try: conn, address = s.accept() except socket.timeout: + print('handle_request: server accept timeout') if raise_on_timeout: raise else: return - # print('handle_request - accepted') + print('handle_request: accepted') res = conn.recv(100) assert res == b'hello', repr(res) - # print('handle_request - recvd %r' % res) - res = conn.send(b'bye') - # print('handle_request - sent %r' % res) - # print('handle_request - conn refcount: %s' % sys.getrefcount(conn)) - # conn.close() + # print('handle_request: recvd %r' % res) + res = conn.sendall(b'bye') + # print('handle_request: sent %r' % res) + # print('handle_request: conn refcount: %s' % sys.getrefcount(conn)) -def make_request(port): +def make_request(addr): # print('make_request') - s = socket.socket() - s.connect(('localhost', port)) + s = eventlet.connect(addr) # print('make_request - connected') - res = s.send(b'hello') + res = s.sendall(b'hello') # print('make_request - sent %s' % res) res = s.recv(100) assert res == b'bye', repr(res) # print('make_request - recvd %r' % res) - # s.close() def run_interaction(run_client): - s, port = init_server() - start_new_thread(handle_request, (s, run_client)) + s = eventlet.listen(('127.0.0.1', 0)) + s.settimeout(SOCKET_TIMEOUT) + addr = s.getsockname() + print('run_interaction: addr:', addr) + eventlet.spawn(handle_request, s, run_client) if run_client: - start_new_thread(make_request, (port,)) - sleep(0.1 + SOCKET_TIMEOUT) - # print(sys.getrefcount(s.fd)) - # s.close() + eventlet.spawn(make_request, addr) + eventlet.sleep(0.1 + SOCKET_TIMEOUT) + print('run_interaction: refcount(s.fd)', sys.getrefcount(s.fd)) return weakref.ref(s.fd) def run_and_check(run_client): w = run_interaction(run_client=run_client) - clear_sys_exc_info() + # clear_sys_exc_info() gc.collect() - if w(): - print(pformat(gc.get_referrers(w()))) - for x in gc.get_referrers(w()): - print(pformat(x)) + fd = w() + print('run_and_check: weakref fd:', fd) + if fd: + print(pprint.pformat(gc.get_referrers(fd))) + for x in gc.get_referrers(fd): + print(pprint.pformat(x)) for y in gc.get_referrers(x): - print('- {0}'.format(pformat(y))) + print('- {0}'.format(pprint.pformat(y))) raise AssertionError('server should be dead by now') diff -Nru python-eventlet-0.20.0/tests/test__socket_errors.py python-eventlet-0.24.1/tests/test__socket_errors.py --- python-eventlet-0.20.0/tests/test__socket_errors.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/test__socket_errors.py 2018-08-06 16:17:47.000000000 +0000 @@ -56,7 +56,7 @@ def test_create_connection_refused(): errno = None try: - socket.create_connection(('127.0.0.1', 0)) + socket.create_connection(('127.0.0.1', 1)) except socket.error as ex: errno = ex.errno assert errno in [111, 61, 10061], 'Expected socket.error ECONNREFUSED, got {0}'.format(errno) diff -Nru python-eventlet-0.20.0/tests/thread_test.py python-eventlet-0.24.1/tests/thread_test.py --- python-eventlet-0.20.0/tests/thread_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/thread_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -6,7 +6,7 @@ from eventlet import event from eventlet import greenthread from eventlet.green import thread -from eventlet.support import six +import six from tests import LimitedTestCase diff -Nru python-eventlet-0.20.0/tests/timeout_test.py python-eventlet-0.24.1/tests/timeout_test.py --- python-eventlet-0.20.0/tests/timeout_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/timeout_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,12 +1,12 @@ import eventlet -from tests import LimitedTestCase +import tests DELAY = 0.01 -class TestDirectRaise(LimitedTestCase): +class TestDirectRaise(tests.LimitedTestCase): def test_direct_raise_class(self): try: raise eventlet.Timeout @@ -36,7 +36,7 @@ str(tm) -class TestWithTimeout(LimitedTestCase): +class TestWithTimeout(tests.LimitedTestCase): def test_with_timeout(self): self.assertRaises(eventlet.Timeout, eventlet.with_timeout, DELAY, eventlet.sleep, DELAY * 10) X = object() @@ -53,3 +53,7 @@ eventlet.Timeout, eventlet.with_timeout, DELAY, longer_timeout) + + +def test_is_timeout_attribute(): + tests.check_is_timeout(eventlet.Timeout()) diff -Nru python-eventlet-0.20.0/tests/tpool_test.py python-eventlet-0.24.1/tests/tpool_test.py --- python-eventlet-0.20.0/tests/tpool_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/tpool_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -20,8 +20,8 @@ import time import eventlet -from eventlet import tpool, debug, event -from eventlet.support import six +from eventlet import tpool +import six import tests @@ -218,10 +218,13 @@ @tests.skip_with_pyevent def test_timeout(self): - import time - eventlet.Timeout(0.1, eventlet.TimeoutError()) - self.assertRaises(eventlet.TimeoutError, - tpool.execute, time.sleep, 0.3) + blocking = eventlet.patcher.original('time') + eventlet.Timeout(0.1, eventlet.Timeout()) + try: + tpool.execute(blocking.sleep, 0.3) + assert False, 'Expected Timeout' + except eventlet.Timeout: + pass @tests.skip_with_pyevent def test_killall(self): @@ -230,7 +233,7 @@ @tests.skip_with_pyevent def test_killall_remaining_results(self): - semaphore = event.Event() + semaphore = eventlet.Event() def native_fun(): time.sleep(.5) @@ -364,3 +367,7 @@ def test_isolate_from_socket_default_timeout(): tests.run_isolated('tpool_isolate_socket_default_timeout.py', timeout=1) + + +def test_exception_leak(): + tests.run_isolated('tpool_exception_leak.py') diff -Nru python-eventlet-0.20.0/tests/websocket_new_test.py python-eventlet-0.24.1/tests/websocket_new_test.py --- python-eventlet-0.20.0/tests/websocket_new_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/websocket_new_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,12 +1,13 @@ import errno import struct +import re import eventlet from eventlet import event from eventlet import websocket from eventlet.green import httplib from eventlet.green import socket -from eventlet.support import six +import six import tests.wsgi_test @@ -228,3 +229,308 @@ sock.sendall(b'\x07\xff') # Weird packet. done_with_request.wait() assert not error_detected[0] + + +class TestWebSocketWithCompression(tests.wsgi_test._TestBase): + TEST_TIMEOUT = 5 + + def set_site(self): + self.site = wsapp + + def setUp(self): + super(TestWebSocketWithCompression, self).setUp() + self.connect = '\r\n'.join([ + "GET /echo HTTP/1.1", + "Upgrade: websocket", + "Connection: upgrade", + "Host: %s:%s" % self.server_addr, + "Origin: http://%s:%s" % self.server_addr, + "Sec-WebSocket-Version: 13", + "Sec-WebSocket-Key: d9MXuOzlVQ0h+qRllvSCIg==", + "Sec-WebSocket-Extensions: %s", + '\r\n' + ]) + self.handshake_re = re.compile(six.b('\r\n'.join([ + 'HTTP/1.1 101 Switching Protocols', + 'Upgrade: websocket', + 'Connection: Upgrade', + 'Sec-WebSocket-Accept: ywSyWXCPNsDxLrQdQrn5RFNRfBU=', + 'Sec-WebSocket-Extensions: (.+)' + '\r\n', + ]))) + + @staticmethod + def get_deflated_reply(ws): + msg = ws._recv_frame(None) + msg.decompressor = None + return msg.getvalue() + + def test_accept_basic_deflate_ext_13(self): + for extension in [ + 'permessage-deflate', + 'PeRMessAGe-dEFlaTe', + ]: + sock = eventlet.connect(self.server_addr) + + sock.sendall(six.b(self.connect % extension)) + result = sock.recv(1024) + + # The server responds the correct Websocket handshake + # print('Extension offer: %r' % extension) + match = re.match(self.handshake_re, result) + assert match is not None + assert len(match.groups()) == 1 + + def test_accept_deflate_ext_context_takeover_13(self): + for extension in [ + 'permessage-deflate;CLient_No_conteXT_TAkeOver', + 'permessage-deflate; SerVER_No_conteXT_TAkeOver', + 'permessage-deflate; server_no_context_takeover; client_no_context_takeover', + ]: + sock = eventlet.connect(self.server_addr) + + sock.sendall(six.b(self.connect % extension)) + result = sock.recv(1024) + + # The server responds the correct Websocket handshake + # print('Extension offer: %r' % extension) + match = re.match(self.handshake_re, result) + assert match is not None + assert len(match.groups()) == 1 + offered_ext_parts = (ex.strip().lower() for ex in extension.split(';')) + accepted_ext_parts = match.groups()[0].decode().split('; ') + assert all(oep in accepted_ext_parts for oep in offered_ext_parts) + + def test_accept_deflate_ext_window_max_bits_13(self): + for extension_string, vals in [ + ('permessage-deflate; client_max_window_bits', [15]), + ('permessage-deflate; Server_Max_Window_Bits = 11', [11]), + ('permessage-deflate; server_max_window_bits; ' + 'client_max_window_bits=9', [15, 9]) + ]: + sock = eventlet.connect(self.server_addr) + + sock.sendall(six.b(self.connect % extension_string)) + result = sock.recv(1024) + + # The server responds the correct Websocket handshake + # print('Extension offer: %r' % extension_string) + match = re.match(self.handshake_re, result) + assert match is not None + assert len(match.groups()) == 1 + + offered_parts = [part.strip().lower() for part in extension_string.split(';')] + offered_parts_names = [part.split('=')[0].strip() for part in offered_parts] + offered_parts_dict = dict(zip(offered_parts_names[1:], vals)) + + accepted_ext_parts = match.groups()[0].decode().split('; ') + assert accepted_ext_parts[0] == 'permessage-deflate' + for param, val in (part.split('=') for part in accepted_ext_parts[1:]): + assert int(val) == offered_parts_dict[param] + + def test_reject_max_window_bits_out_of_range_13(self): + extension_string = ('permessage-deflate; client_max_window_bits=7,' + 'permessage-deflate; server_max_window_bits=16, ' + 'permessage-deflate; client_max_window_bits=16; ' + 'server_max_window_bits=7, ' + 'permessage-deflate') + sock = eventlet.connect(self.server_addr) + + sock.sendall(six.b(self.connect % extension_string)) + result = sock.recv(1024) + + # The server responds the correct Websocket handshake + # print('Extension offer: %r' % extension_string) + match = re.match(self.handshake_re, result) + assert match.groups()[0] == b'permessage-deflate' + + def test_server_compress_with_context_takeover_13(self): + extensions_string = 'permessage-deflate; client_no_context_takeover;' + extensions = {'permessage-deflate': { + 'client_no_context_takeover': True, + 'server_no_context_takeover': False}} + + sock = eventlet.connect(self.server_addr) + sock.sendall(six.b(self.connect % extensions_string)) + sock.recv(1024) + ws = websocket.RFC6455WebSocket(sock, {}, client=True, + extensions=extensions) + + # Deflated values taken from Section 7.2.3 of RFC 7692 + # https://tools.ietf.org/html/rfc7692#section-7.2.3 + ws.send(b'Hello') + msg1 = self.get_deflated_reply(ws) + assert msg1 == b'\xf2\x48\xcd\xc9\xc9\x07\x00' + + ws.send(b'Hello') + msg2 = self.get_deflated_reply(ws) + assert msg2 == b'\xf2\x00\x11\x00\x00' + + ws.close() + eventlet.sleep(0.01) + + def test_server_compress_no_context_takeover_13(self): + extensions_string = 'permessage-deflate; server_no_context_takeover;' + extensions = {'permessage-deflate': { + 'client_no_context_takeover': False, + 'server_no_context_takeover': True}} + + sock = eventlet.connect(self.server_addr) + sock.sendall(six.b(self.connect % extensions_string)) + sock.recv(1024) + ws = websocket.RFC6455WebSocket(sock, {}, client=True, + extensions=extensions) + + masked_msg1 = ws._pack_message(b'Hello', masked=True) + ws._send(masked_msg1) + masked_msg2 = ws._pack_message(b'Hello', masked=True) + ws._send(masked_msg2) + # Verify that client uses context takeover by checking + # that the second message + assert len(masked_msg2) < len(masked_msg1) + + # Verify that server drops context between messages + # Deflated values taken from Section 7.2.3 of RFC 7692 + # https://tools.ietf.org/html/rfc7692#section-7.2.3 + reply_msg1 = self.get_deflated_reply(ws) + assert reply_msg1 == b'\xf2\x48\xcd\xc9\xc9\x07\x00' + reply_msg2 = self.get_deflated_reply(ws) + assert reply_msg2 == b'\xf2\x48\xcd\xc9\xc9\x07\x00' + + def test_client_compress_with_context_takeover_13(self): + extensions = {'permessage-deflate': { + 'client_no_context_takeover': False, + 'server_no_context_takeover': True}} + ws = websocket.RFC6455WebSocket(None, {}, client=True, + extensions=extensions) + + # Deflated values taken from Section 7.2.3 of RFC 7692 + # modified opcode to Binary instead of Text + # https://tools.ietf.org/html/rfc7692#section-7.2.3 + packed_msg_1 = ws._pack_message(b'Hello', masked=False) + assert packed_msg_1 == b'\xc2\x07\xf2\x48\xcd\xc9\xc9\x07\x00' + packed_msg_2 = ws._pack_message(b'Hello', masked=False) + assert packed_msg_2 == b'\xc2\x05\xf2\x00\x11\x00\x00' + + eventlet.sleep(0.01) + + def test_client_compress_no_context_takeover_13(self): + extensions = {'permessage-deflate': { + 'client_no_context_takeover': True, + 'server_no_context_takeover': False}} + ws = websocket.RFC6455WebSocket(None, {}, client=True, + extensions=extensions) + + # Deflated values taken from Section 7.2.3 of RFC 7692 + # modified opcode to Binary instead of Text + # https://tools.ietf.org/html/rfc7692#section-7.2.3 + packed_msg_1 = ws._pack_message(b'Hello', masked=False) + assert packed_msg_1 == b'\xc2\x07\xf2\x48\xcd\xc9\xc9\x07\x00' + packed_msg_2 = ws._pack_message(b'Hello', masked=False) + assert packed_msg_2 == b'\xc2\x07\xf2\x48\xcd\xc9\xc9\x07\x00' + + def test_compressed_send_recv_13(self): + extensions_string = 'permessage-deflate' + extensions = {'permessage-deflate': { + 'client_no_context_takeover': False, + 'server_no_context_takeover': False}} + + sock = eventlet.connect(self.server_addr) + sock.sendall(six.b(self.connect % extensions_string)) + sock.recv(1024) + ws = websocket.RFC6455WebSocket(sock, {}, client=True, extensions=extensions) + + ws.send(b'hello') + assert ws.wait() == b'hello' + ws.send(b'hello world!') + ws.send(u'hello world again!') + assert ws.wait() == b'hello world!' + assert ws.wait() == u'hello world again!' + + ws.close() + eventlet.sleep(0.01) + + def test_send_uncompressed_msg_13(self): + extensions_string = 'permessage-deflate' + extensions = {'permessage-deflate': { + 'client_no_context_takeover': False, + 'server_no_context_takeover': False}} + + sock = eventlet.connect(self.server_addr) + sock.sendall(six.b(self.connect % extensions_string)) + sock.recv(1024) + + # Send without using deflate, having rsv1 unset + ws = websocket.RFC6455WebSocket(sock, {}, client=True) + ws.send(b'Hello') + + # Adding extensions to recognise deflated response + ws.extensions = extensions + assert ws.wait() == b'Hello' + + ws.close() + eventlet.sleep(0.01) + + def test_compressed_send_recv_client_no_context_13(self): + extensions_string = 'permessage-deflate; client_no_context_takeover' + extensions = {'permessage-deflate': { + 'client_no_context_takeover': True, + 'server_no_context_takeover': False}} + + sock = eventlet.connect(self.server_addr) + sock.sendall(six.b(self.connect % extensions_string)) + sock.recv(1024) + ws = websocket.RFC6455WebSocket(sock, {}, client=True, extensions=extensions) + + ws.send(b'hello') + assert ws.wait() == b'hello' + ws.send(b'hello world!') + ws.send(u'hello world again!') + assert ws.wait() == b'hello world!' + assert ws.wait() == u'hello world again!' + + ws.close() + eventlet.sleep(0.01) + + def test_compressed_send_recv_server_no_context_13(self): + extensions_string = 'permessage-deflate; server_no_context_takeover' + extensions = {'permessage-deflate': { + 'client_no_context_takeover': False, + 'server_no_context_takeover': False}} + + sock = eventlet.connect(self.server_addr) + sock.sendall(six.b(self.connect % extensions_string)) + sock.recv(1024) + ws = websocket.RFC6455WebSocket(sock, {}, client=True, extensions=extensions) + + ws.send(b'hello') + assert ws.wait() == b'hello' + ws.send(b'hello world!') + ws.send(u'hello world again!') + assert ws.wait() == b'hello world!' + assert ws.wait() == u'hello world again!' + + ws.close() + eventlet.sleep(0.01) + + def test_compressed_send_recv_both_no_context_13(self): + extensions_string = ('permessage-deflate;' + ' server_no_context_takeover; client_no_context_takeover') + extensions = {'permessage-deflate': { + 'client_no_context_takeover': True, + 'server_no_context_takeover': True}} + + sock = eventlet.connect(self.server_addr) + sock.sendall(six.b(self.connect % extensions_string)) + sock.recv(1024) + ws = websocket.RFC6455WebSocket(sock, {}, client=True, extensions=extensions) + + ws.send(b'hello') + assert ws.wait() == b'hello' + ws.send(b'hello world!') + ws.send(u'hello world again!') + assert ws.wait() == b'hello world!' + assert ws.wait() == u'hello world again!' + + ws.close() + eventlet.sleep(0.01) diff -Nru python-eventlet-0.20.0/tests/websocket_test.py python-eventlet-0.24.1/tests/websocket_test.py --- python-eventlet-0.20.0/tests/websocket_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/websocket_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,11 +1,12 @@ import errno import socket +import sys import eventlet from eventlet import event from eventlet import greenio from eventlet.green import httplib -from eventlet.support import six +import six from eventlet.websocket import WebSocket, WebSocketWSGI import tests @@ -503,6 +504,30 @@ done_with_request.wait() assert error_detected[0] + def test_close_idle(self): + pool = eventlet.GreenPool() + # use log=stderr when test runner can capture it + self.spawn_server(custom_pool=pool, log=sys.stdout) + connect = ( + 'GET /echo HTTP/1.1', + 'Upgrade: WebSocket', + 'Connection: Upgrade', + '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(self.server_addr) + sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n^n:ds[4U')) + sock.recv(1024) + sock.sendall(b'\x00hello\xff') + result = sock.recv(1024) + assert result, b'\x00hello\xff' + self.killer.kill(KeyboardInterrupt) + with eventlet.Timeout(1): + pool.waitall() + class TestWebSocketSSL(tests.wsgi_test._TestBase): def set_site(self): diff -Nru python-eventlet-0.20.0/tests/wsgi_test.py python-eventlet-0.24.1/tests/wsgi_test.py --- python-eventlet-0.20.0/tests/wsgi_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/wsgi_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,3 +1,4 @@ +# coding: utf-8 import cgi import collections import errno @@ -19,7 +20,8 @@ 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 +from eventlet.support import bytes_to_str +import six import tests @@ -217,7 +219,6 @@ class _TestBase(tests.LimitedTestCase): def setUp(self): super(_TestBase, self).setUp() - self.logfile = six.StringIO() self.site = Site() self.killer = None self.set_site() @@ -234,6 +235,7 @@ Sets `self.server_addr` to (host, port) tuple suitable for `socket.connect`. """ + self.logfile = six.StringIO() new_kwargs = dict(max_size=128, log=self.logfile, site=self.site) @@ -255,7 +257,7 @@ if self.killer: greenthread.kill(self.killer) - self.killer = eventlet.spawn_n(target, **kwargs) + self.killer = eventlet.spawn(target, **kwargs) def set_site(self): raise NotImplementedError @@ -557,8 +559,8 @@ def server(sock, site, log): try: serv = wsgi.Server(sock, sock.getsockname(), site, log) - client_socket = sock.accept() - serv.process_request(client_socket) + client_socket, addr = sock.accept() + serv.process_request([addr, client_socket, wsgi.STATE_IDLE]) return True except Exception: traceback.print_exc() @@ -982,7 +984,7 @@ listener = greensocket.socket() listener.bind(('localhost', 0)) # NOT calling listen, to trigger the error - with capture_stderr() as log: + with tests.capture_stderr() as log: self.spawn_server(sock=listener) eventlet.sleep(0) # need to enter server loop try: @@ -1398,10 +1400,38 @@ 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 result.status == 'HTTP/1.1 200 OK' assert b'decoded: /a*b@@#3' in result.body assert b'raw: /a*b@%40%233' in result.body + def test_path_info_latin1(self): + # https://github.com/eventlet/eventlet/issues/468 + g = [] + + def wsgi_app(environ, start_response): + g.append(environ['PATH_INFO']) + start_response("200 OK", []) + return b'' + + self.site.application = wsgi_app + sock = eventlet.connect(self.server_addr) + sock.sendall(b'GET /%E4%BD%A0%E5%A5%BD HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') + result = read_http(sock) + assert result.status == 'HTTP/1.1 200 OK' + # that was only preparation, actual test below + # Per PEP-0333 https://www.python.org/dev/peps/pep-0333/#unicode-issues + # in all WSGI environment strings application must observe either bytes in latin-1 (ISO-8859-1) + # or unicode code points \u0000..\u00ff + # wsgi_decoding_dance from Werkzeug to emulate concerned application + msg = 'Expected PATH_INFO to be a native string, not {0}'.format(type(g[0])) + assert isinstance(g[0], str), msg + if six.PY2: + assert g[0] == u'/你好'.encode('utf-8') + else: + decoded = g[0].encode('latin1').decode('utf-8', 'replace') + assert decoded == u'/你好' + + @tests.skip_if_no_ipv6 def test_ipv6(self): try: sock = eventlet.listen(('::1', 0), family=socket.AF_INET6) @@ -1471,13 +1501,14 @@ sock.close() request_thread = eventlet.spawn(make_request) - server_conn = server_sock.accept() + client_sock, addr = server_sock.accept() # Next line must not raise IOError -32 Broken pipe - server.process_request(server_conn) + server.process_request([addr, client_sock, wsgi.STATE_IDLE]) request_thread.wait() server_sock.close() def test_server_connection_timeout_exception(self): + self.reset_timeout(5) # Handle connection socket timeouts # https://bitbucket.org/eventlet/eventlet/issue/143/ # Runs tests.wsgi_test_conntimeout in a separate process. @@ -1572,6 +1603,61 @@ assert result.body == (b'HTTP_HOST: localhost\nHTTP_HTTP_X_ANY_K: two\n' b'HTTP_PATH_INFO: foo\nHTTP_X_ANY_K: one\n') + def test_env_header_stripping(self): + def app(environ, start_response): + start_response('200 OK', []) + # On py3, headers get parsed as Latin-1, so send them back out as Latin-1, too + return [line if isinstance(line, bytes) else line.encode('latin1') + for kv in sorted(environ.items()) + if kv[0].startswith('HTTP_') + for line in ('{0}: {1}\n'.format(*kv),)] + + self.spawn_server(site=app) + sock = eventlet.connect(self.server_addr) + sock.sendall( + b'GET / HTTP/1.1\r\n' + b'Host: localhost\r\n' + b'spaced: o u t \r\n' + b'trailing: tab\t\r\n' + b'trailing-nbsp: \xc2\xa0\r\n' + b'null-set: \xe2\x88\x85\r\n\r\n') + result = read_http(sock) + sock.close() + assert result.status == 'HTTP/1.1 200 OK', 'Received status {0!r}'.format(result.status) + assert result.body == ( + b'HTTP_HOST: localhost\n' + b'HTTP_NULL_SET: \xe2\x88\x85\n' + b'HTTP_SPACED: o u t\n' + b'HTTP_TRAILING: tab\n' + b'HTTP_TRAILING_NBSP: \xc2\xa0\n') + + def test_log_disable(self): + self.spawn_server(log_output=False) + sock = eventlet.connect(self.server_addr) + sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\npath-info: foo\r\n' + b'x-ANY_k: one\r\nhttp-x-ANY_k: two\r\n\r\n') + read_http(sock) + sock.close() + log_content = self.logfile.getvalue() + assert log_content == '' + + def test_close_idle_connections(self): + self.reset_timeout(2) + pool = eventlet.GreenPool() + self.spawn_server(custom_pool=pool) + # https://github.com/eventlet/eventlet/issues/188 + sock = eventlet.connect(self.server_addr) + + sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') + result = read_http(sock) + assert result.status == 'HTTP/1.1 200 OK', 'Received status {0!r}'.format(result.status) + self.killer.kill(KeyboardInterrupt) + try: + with eventlet.Timeout(1): + pool.waitall() + except Exception: + assert False, self.logfile.getvalue() + def read_headers(sock): fd = sock.makefile('rb') diff -Nru python-eventlet-0.20.0/tests/zmq_test.py python-eventlet-0.24.1/tests/zmq_test.py --- python-eventlet-0.20.0/tests/zmq_test.py 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tests/zmq_test.py 2018-08-06 16:17:47.000000000 +0000 @@ -1,3 +1,5 @@ +import contextlib + try: from eventlet.green import zmq except ImportError: @@ -6,7 +8,6 @@ RECV_ON_CLOSED_SOCKET_ERRNOS = (zmq.ENOTSUP, zmq.ENOTSOCK) import eventlet -from eventlet import event, spawn, sleep, semaphore import tests @@ -80,15 +81,15 @@ req, rep, port = self.create_bound_pair(zmq.PAIR, zmq.PAIR) # req.connect(ipc) # rep.bind(ipc) - sleep() + eventlet.sleep() msg = dict(res=None) - done = event.Event() + done = eventlet.Event() def rx(): msg['res'] = rep.recv() done.send('done') - spawn(rx) + eventlet.spawn(rx) req.send(b'test') done.wait() self.assertEqual(msg['res'], b'test') @@ -114,8 +115,8 @@ @tests.skip_unless(zmq_supported) def test_send_1k_req_rep(self): req, rep, port = self.create_bound_pair(zmq.REQ, zmq.REP) - sleep() - done = event.Event() + eventlet.sleep() + done = eventlet.Event() def tx(): tx_i = 0 @@ -132,17 +133,17 @@ rep.send(b'done') break rep.send(b'i') - spawn(tx) - spawn(rx) + eventlet.spawn(tx) + eventlet.spawn(rx) final_i = done.wait() self.assertEqual(final_i, 0) @tests.skip_unless(zmq_supported) def test_send_1k_push_pull(self): down, up, port = self.create_bound_pair(zmq.PUSH, zmq.PULL) - sleep() + eventlet.sleep() - done = event.Event() + done = eventlet.Event() def tx(): tx_i = 0 @@ -156,8 +157,8 @@ if rx_i == b"1000": done.send(0) break - spawn(tx) - spawn(rx) + eventlet.spawn(tx) + eventlet.spawn(rx) final_i = done.wait() self.assertEqual(final_i, 0) @@ -174,17 +175,17 @@ sub1.setsockopt(zmq.SUBSCRIBE, b'sub1') sub2.setsockopt(zmq.SUBSCRIBE, b'sub2') - sub_all_done = event.Event() - sub1_done = event.Event() - sub2_done = event.Event() + sub_all_done = eventlet.Event() + sub1_done = eventlet.Event() + sub2_done = eventlet.Event() - sleep(0.2) + eventlet.sleep(0.2) def rx(sock, done_evt, msg_count=10000): count = 0 while count < msg_count: msg = sock.recv() - sleep() + eventlet.sleep() if b'LAST' in msg: break count += 1 @@ -195,14 +196,14 @@ for i in range(1, 1001): msg = ("sub%s %s" % ([2, 1][i % 2], i)).encode() sock.send(msg) - sleep() + eventlet.sleep() sock.send(b'sub1 LAST') sock.send(b'sub2 LAST') - spawn(rx, sub_all, sub_all_done) - spawn(rx, sub1, sub1_done) - spawn(rx, sub2, sub2_done) - spawn(tx, pub) + eventlet.spawn(rx, sub_all, sub_all_done) + eventlet.spawn(rx, sub1, sub1_done) + eventlet.spawn(rx, sub2, sub2_done) + eventlet.spawn(tx, pub) sub1_count = sub1_done.wait() sub2_count = sub2_done.wait() sub_all_count = sub_all_done.wait() @@ -216,14 +217,14 @@ # of sporadic failures on Travis. pub, sub, port = self.create_bound_pair(zmq.PUB, zmq.SUB) sub.setsockopt(zmq.SUBSCRIBE, b'test') - sleep(0) - sub_ready = event.Event() - sub_last = event.Event() - sub_done = event.Event() + eventlet.sleep(0) + sub_ready = eventlet.Event() + sub_last = eventlet.Event() + sub_done = eventlet.Event() def rx(): while sub.recv() != b'test BEGIN': - sleep(0) + eventlet.sleep(0) sub_ready.send() count = 0 while True: @@ -234,7 +235,7 @@ if msg == b'test LAST': sub.setsockopt(zmq.SUBSCRIBE, b'done') sub.setsockopt(zmq.UNSUBSCRIBE, b'test') - sleep(0) + eventlet.sleep(0) # In real application you should either sync # or tolerate loss of messages. sub_last.send() @@ -247,7 +248,7 @@ # Sync receiver ready to avoid loss of first packets while not sub_ready.ready(): pub.send(b'test BEGIN') - sleep(0.005) + eventlet.sleep(0.005) for i in range(1, 101): msg = 'test {0}'.format(i).encode() if i != 50: @@ -256,8 +257,8 @@ pub.send(b'test LAST') sub_last.wait() # XXX: putting a real delay of 1ms here fixes sporadic failures on Travis - # just yield sleep(0) doesn't cut it - sleep(0.001) + # just yield eventlet.sleep(0) doesn't cut it + eventlet.sleep(0.001) pub.send(b'done DONE') eventlet.spawn(rx) @@ -292,10 +293,10 @@ @tests.skip_unless(zmq_supported) def test_send_during_recv(self): sender, receiver, port = self.create_bound_pair(zmq.XREQ, zmq.XREQ) - sleep() + eventlet.sleep() num_recvs = 30 - done_evts = [event.Event() for _ in range(num_recvs)] + done_evts = [eventlet.Event() for _ in range(num_recvs)] def slow_rx(done, msg): self.assertEqual(sender.recv(), msg) @@ -313,24 +314,24 @@ if rx_i == b"1000": for i in range(num_recvs): receiver.send(('done%d' % i).encode()) - sleep() + eventlet.sleep() return for i in range(num_recvs): - spawn(slow_rx, done_evts[i], ("done%d" % i).encode()) + eventlet.spawn(slow_rx, done_evts[i], ("done%d" % i).encode()) - spawn(tx) - spawn(rx) + eventlet.spawn(tx) + eventlet.spawn(rx) for evt in done_evts: self.assertEqual(evt.wait(), 0) @tests.skip_unless(zmq_supported) def test_send_during_recv_multipart(self): sender, receiver, port = self.create_bound_pair(zmq.XREQ, zmq.XREQ) - sleep() + eventlet.sleep() num_recvs = 30 - done_evts = [event.Event() for _ in range(num_recvs)] + done_evts = [eventlet.Event() for _ in range(num_recvs)] def slow_rx(done, msg): self.assertEqual(sender.recv_multipart(), msg) @@ -349,15 +350,15 @@ for i in range(num_recvs): receiver.send_multipart([ ('done%d' % i).encode(), b'a', b'b', b'c']) - sleep() + eventlet.sleep() return for i in range(num_recvs): - spawn(slow_rx, done_evts[i], [ + eventlet.spawn(slow_rx, done_evts[i], [ ("done%d" % i).encode(), b'a', b'b', b'c']) - spawn(tx) - spawn(rx) + eventlet.spawn(tx) + eventlet.spawn(rx) for i in range(num_recvs): final_i = done_evts[i].wait() self.assertEqual(final_i, 0) @@ -366,9 +367,9 @@ @tests.skip_unless(zmq_supported) def test_recv_during_send(self): sender, receiver, port = self.create_bound_pair(zmq.XREQ, zmq.XREQ) - sleep() + eventlet.sleep() - done = event.Event() + done = eventlet.Event() try: SNDHWM = zmq.SNDHWM @@ -388,25 +389,25 @@ tx_i += 1 done.send(0) - spawn(tx) + eventlet.spawn(tx) final_i = done.wait() self.assertEqual(final_i, 0) @tests.skip_unless(zmq_supported) def test_close_during_recv(self): sender, receiver, port = self.create_bound_pair(zmq.XREQ, zmq.XREQ) - sleep() - done1 = event.Event() - done2 = event.Event() + eventlet.sleep() + done1 = eventlet.Event() + done2 = eventlet.Event() def rx(e): self.assertRaisesErrno(RECV_ON_CLOSED_SOCKET_ERRNOS, receiver.recv) e.send() - spawn(rx, done1) - spawn(rx, done2) + eventlet.spawn(rx, done1) + eventlet.spawn(rx, done2) - sleep() + eventlet.sleep() receiver.close() done1.wait() @@ -415,7 +416,7 @@ @tests.skip_unless(zmq_supported) def test_getsockopt_events(self): sock1, sock2, _port = self.create_bound_pair(zmq.DEALER, zmq.DEALER) - sleep() + eventlet.sleep() poll_out = zmq.Poller() poll_out.register(sock1, zmq.POLLOUT) sock_map = poll_out.poll(100) @@ -447,7 +448,7 @@ sock = self.context.socket(zmq.PUB) self.sockets.append(sock) sock.bind_to_random_port("tcp://127.0.0.1") - sleep() + eventlet.sleep() tests.check_idle_cpu_usage(0.2, 0.1) @tests.skip_unless(zmq_supported) @@ -458,12 +459,12 @@ """ pub, sub, _port = self.create_bound_pair(zmq.PUB, zmq.SUB) sub.setsockopt(zmq.SUBSCRIBE, b"") - sleep() + eventlet.sleep() pub.send(b'test_send') tests.check_idle_cpu_usage(0.2, 0.1) sender, receiver, _port = self.create_bound_pair(zmq.DEALER, zmq.DEALER) - sleep() + eventlet.sleep() sender.send(b'test_recv') msg = receiver.recv() self.assertEqual(msg, b'test_recv') @@ -474,7 +475,7 @@ @tests.skip_unless(zmq_supported) def test_queue_lock_order(self): q = zmq._QueueLock() - s = semaphore.Semaphore(0) + s = eventlet.Semaphore(0) results = [] def lock(x): @@ -484,12 +485,12 @@ q.acquire() - spawn(lock, 1) - sleep() - spawn(lock, 2) - sleep() - spawn(lock, 3) - sleep() + eventlet.spawn(lock, 1) + eventlet.sleep() + eventlet.spawn(lock, 2) + eventlet.sleep() + eventlet.spawn(lock, 3) + eventlet.sleep() self.assertEqual(results, []) q.release() @@ -529,7 +530,7 @@ q.acquire() q.acquire() - s = semaphore.Semaphore(0) + s = eventlet.Semaphore(0) results = [] def lock(x): @@ -537,11 +538,11 @@ results.append(x) s.release() - spawn(lock, 1) - sleep() + eventlet.spawn(lock, 1) + eventlet.sleep() self.assertEqual(results, []) q.release() - sleep() + eventlet.sleep() self.assertEqual(results, []) self.assertTrue(q) q.release() @@ -554,16 +555,58 @@ @tests.skip_unless(zmq_supported) def test_block(self): e = zmq._BlockedThread() - done = event.Event() + done = eventlet.Event() self.assertFalse(e) def block(): e.block() done.send(1) - spawn(block) - sleep() + eventlet.spawn(block) + eventlet.sleep() self.assertFalse(done.has_result()) e.wake() done.wait() + + +@contextlib.contextmanager +def clean_context(): + ctx = zmq.Context() + eventlet.sleep() + yield ctx + ctx.destroy() + + +@contextlib.contextmanager +def clean_pair(type1, type2, interface='tcp://127.0.0.1'): + with clean_context() as ctx: + s1 = ctx.socket(type1) + port = s1.bind_to_random_port(interface) + s2 = ctx.socket(type2) + s2.connect('{0}:{1}'.format(interface, port)) + eventlet.sleep() + yield (s1, s2, port) + s1.close() + s2.close() + + +@tests.skip_unless(zmq_supported) +def test_recv_json_no_args(): + # https://github.com/eventlet/eventlet/issues/376 + with clean_pair(zmq.REQ, zmq.REP) as (s1, s2, _): + eventlet.spawn(s1.send_json, {}) + s2.recv_json() + + +@tests.skip_unless(zmq_supported) +def test_recv_timeout(): + # https://github.com/eventlet/eventlet/issues/282 + with clean_pair(zmq.PUB, zmq.SUB) as (_, sub, _): + sub.setsockopt(zmq.RCVTIMEO, 100) + try: + with eventlet.Timeout(1, False): + sub.recv() + assert False + except zmq.ZMQError as e: + assert eventlet.is_timeout(e) diff -Nru python-eventlet-0.20.0/tox.ini python-eventlet-0.24.1/tox.ini --- python-eventlet-0.20.0/tox.ini 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/tox.ini 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -# The flake8 and pep8 sections just contain configuration for corresponding tools. -# Checkers are not run implicitly. -[flake8] -exclude = *.egg*,.env,.git,.hg,.tox,_*,build*,dist*,venv*,six.py,mock.py,eventlet/green/http/*,eventlet/support/dns/* -ignore = E261 -max-line-length = 101 - -[pep8] -count = 1 -exclude = *.egg*,.env,.git,.hg,.tox,_*,build*,dist*,venv*,six.py,mock.py,eventlet/green/http/*,eventlet/support/dns/* -ignore = E261 -max-line-length = 101 -show-source = 1 -statistics = 1 - -[tox] -minversion=1.8 -envlist = - pep8, py{26,27,33,34,35,py}-{selects,poll,epolls} - -[testenv:pep8] -basepython = python2.7 -setenv = - {[testenv]setenv} -deps = - pep8==1.5.6 -commands = - pep8 benchmarks/ eventlet/ tests/ - -[testenv] -passenv = TRAVIS* -setenv = - PYTHONDONTWRITEBYTECODE = 1 - selects: EVENTLET_HUB = selects - poll: EVENTLET_HUB = poll - epolls: EVENTLET_HUB = epolls -basepython = - py26: python2.6 - py27: python2.7 - py33: python3.3 - py34: python3.4 - py35: python3.5 - pypy: pypy -deps = - nose==1.3.1 - setuptools==5.4.1 - py{26,27}: subprocess32==3.2.7 - py{26,27}-{selects,poll,epolls}: MySQL-python==1.2.5 - py26-{selects,poll,epolls}: pyopenssl==0.13 - py{27,33,34}-{selects,poll,epolls}: pyopenssl==16.0.0 - {selects,poll,epolls}: psycopg2cffi-compat==1.1 - {selects,poll,epolls}: pyzmq==13.1.0 -commands = - nosetests --verbose {posargs:tests/} - nosetests --verbose --with-doctest eventlet/coros.py eventlet/event.py \ - eventlet/pools.py eventlet/queue.py eventlet/timeout.py diff -Nru python-eventlet-0.20.0/.travis.yml python-eventlet-0.24.1/.travis.yml --- python-eventlet-0.20.0/.travis.yml 2016-12-11 21:09:40.000000000 +0000 +++ python-eventlet-0.24.1/.travis.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -language: python -python: 3.5 -env: - matrix: - - TOX_ENV=pep8 - - TOX_ENV=py26-epolls - - TOX_ENV=py26-poll - - TOX_ENV=py26-selects - - TOX_ENV=py27-epolls - - TOX_ENV=py27-poll - - TOX_ENV=py27-selects - - TOX_ENV=py33-epolls - - TOX_ENV=py33-poll - - TOX_ENV=py33-selects - - TOX_ENV=py34-epolls - - TOX_ENV=py34-poll - - TOX_ENV=py34-selects - - TOX_ENV=py35-epolls - - TOX_ENV=py35-poll - - TOX_ENV=py35-selects - - TOX_ENV=pypy-epolls - - TOX_ENV=pypy-poll - - TOX_ENV=pypy-selects -matrix: - fast_finish: true - allow_failures: - - env: TOX_ENV=pypy-epolls - - env: TOX_ENV=pypy-poll - - env: TOX_ENV=pypy-selects -cache: - apt: true - ccache: true - pip: true - directories: - - $HOME/.cache -addons: - apt_packages: - - ccache - - libmysqlclient-dev - - libpq-dev - - libssl-dev - - libzmq3-dev -install: - - pip install --upgrade pip setuptools tox virtualenv -before_script: - - "export EVENTLET_DB_TEST_AUTH='{\"psycopg2\": {\"user\": \"postgres\"}, \"MySQLdb\": {\"passwd\": \"\", \"host\": \"localhost\", \"user\": \"root\"}}'" - - "export PATH=/usr/lib/ccache:$PATH" -script: - - tox -v -v -e $TOX_ENV -after_failure: - - for X in .tox/$TOX_ENV/log/*; do echo "$X\n"; cat "$X"; echo "\n\n"; done - - echo "pip.log\n"; cat $HOME/.pip/pip.log -notifications: - slack: eventlet-net:OYrQ1JE3hdTD78yQY1yZJnnc -sudo: false