Hello community, here is the log from the commit of package python-ws4py for openSUSE:Leap:15.2 checked in at 2020-02-25 12:18:26 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Leap:15.2/python-ws4py (Old) and /work/SRC/openSUSE:Leap:15.2/.python-ws4py.new.26092 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-ws4py" Tue Feb 25 12:18:26 2020 rev:11 rq:778886 version:0.5.1 Changes: -------- --- /work/SRC/openSUSE:Leap:15.2/python-ws4py/python-ws4py.changes 2020-01-15 15:54:15.367625855 +0100 +++ /work/SRC/openSUSE:Leap:15.2/.python-ws4py.new.26092/python-ws4py.changes 2020-02-25 12:18:26.820589618 +0100 @@ -1,0 +2,21 @@ +Mon Feb 17 22:28:45 UTC 2020 - Julio González Gil <[email protected]> + +- Fix license. Correct one is BSD-3-Clause. + +------------------------------------------------------------------- +Thu Apr 11 12:09:24 UTC 2019 - Marketa Calabkova <[email protected]> + +- update to version 0.5.1 + * fixed runtime error: Set changed size during iteration + * on secure, only pass the requested number of bytes to the parsers + * Change threaded client test to test ssl socket + * exclude certain headers when requested + * Disable build for Python 3.4 +- launch tests using multibuild + +------------------------------------------------------------------- +Tue Dec 4 12:56:13 UTC 2018 - Matej Cepl <[email protected]> + +- Remove superfluous devel dependency for noarch package + +------------------------------------------------------------------- Old: ---- ws4py-0.4.2.tar.gz New: ---- _multibuild ws4py-0.5.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-ws4py.spec ++++++ --- /var/tmp/diff_new_pack.sXdFtx/_old 2020-02-25 12:18:27.112590223 +0100 +++ /var/tmp/diff_new_pack.sXdFtx/_new 2020-02-25 12:18:27.112590223 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-ws4py # -# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2020 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,31 +12,39 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ +# %{?!python_module:%define python_module() python-%{**} python3-%{**}} +%global flavor @BUILD_FLAVOR@%{nil} +%if "%{flavor}" == "test" +%define psuffix -test %bcond_without test -Name: python-ws4py -Version: 0.4.2 +%else +%define psuffix %{nil} +%bcond_with test +%endif +Name: python-ws4py%{psuffix} +Version: 0.5.1 Release: 0 -License: BSD-2-Clause Summary: WebSocket client and server library for Python -Url: https://github.com/Lawouach/WebSocket-for-Python +License: BSD-3-Clause Group: Development/Languages/Python +URL: https://github.com/Lawouach/WebSocket-for-Python Source: https://files.pythonhosted.org/packages/source/w/ws4py/ws4py-%{version}.tar.gz +BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: python-rpm-macros -BuildRequires: %{python_module devel} -BuildRequires: %{python_module setuptools} +BuildArch: noarch %if %{with test} -BuildRequires: %{python_module CherryPy} BuildRequires: %{python_module gevent} BuildRequires: %{python_module greenlet} +BuildRequires: %{python_module mock} +BuildRequires: %{python_module pytest} BuildRequires: %{python_module tornado} +BuildRequires: %{python_module ws4py = %{version}} %endif -BuildArch: noarch - %python_subpackages %description @@ -45,21 +53,28 @@ %prep %setup -q -n ws4py-%{version} +# CherryPy is python3 only to ease the testing just skip it here +rm test/test_cherrypy.py %build %python_build %install +%if !%{with test} %python_install %python_expand %fdupes %{buildroot}%{$python_sitelib} +%endif %if %{with test} %check -%python_exec setup.py test +%pytest %endif +%if !%{with test} %files %{python_files} -%defattr(-,root,root,-) +%license LICENSE +%doc README.md %{python_sitelib}/* +%endif %changelog ++++++ _multibuild ++++++ <multibuild> <package>test</package> </multibuild> ++++++ ws4py-0.4.2.tar.gz -> ws4py-0.5.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/CHANGELOG.md new/ws4py-0.5.1/CHANGELOG.md --- old/ws4py-0.4.2/CHANGELOG.md 1970-01-01 01:00:00.000000000 +0100 +++ new/ws4py-0.5.1/CHANGELOG.md 2018-02-28 17:24:13.000000000 +0100 @@ -0,0 +1,348 @@ +# Change Log + +## Unreleased +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/0.5.1...master) + +## [0.5.1](https://github.com/Lawouach/WebSocket-for-Python/tree/0.5.1) (2018-02-28) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/0.5.0...0.5.1) +**Merged pull requests:** + +- Rudimentary fix and testcase for Issue #179 [\#219](https://github.com/Lawouach/WebSocket-for-Python/pull/219) ([medington](https://github.com/medington)) + +## [0.5.0](https://github.com/Lawouach/WebSocket-for-Python/tree/0.5.0) (2018-02-27) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/0.4.3...0.5.0) +**Merged pull requests:** + +- proper fix for #230: on secure, only pass the requested number of bytes to the parsers [\#239](https://github.com/Lawouach/WebSocket-for-Python/pull/239) ([jmichiel](https://github.com/jmichiel)) +- fixed runtime error: Set changed size during iteration [\#233](https://github.com/Lawouach/WebSocket-for-Python/pull/233) ([kamwoh](https://github.com/kamwoh)) +- Adds argument to set block value on gevent get command in WebSocketClient.receive() [\#221](https://github.com/Lawouach/WebSocket-for-Python/pull/221) ([thaffenden](https://github.com/thaffenden)) + +**Changes:** + +- Clarifies this project is on hiatus in README + +## [0.4.3](https://github.com/Lawouach/WebSocket-for-Python/tree/0.4.3) (2017-12-19) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/0.4.3...0.4.3) +**Merged pull requests:** + +- Change threaded client test to test ssl socket [\#213](https://github.com/Lawouach/WebSocket-for-Python/pull/213) ([awelkie](https://github.com/awelkie)) +- Create MANIFEST.in with LICENSE [\#215](https://github.com/Lawouach/WebSocket-for-Python/pull/215) ([pmlandwehr](https://github.com/pmlandwehr)) +- exclude certain headers when requested [\#217](https://github.com/Lawouach/WebSocket-for-Python/pull/217) ([klattimer](https://github.com/klattimer)) +- change from type() to isinstance() [\#236](https://github.com/Lawouach/WebSocket-for-Python/pull/236) ([noam-graetz](https://github.com/noam-graetz)) + +**Changes:** + +- Various test cleanups +- Disable build for Python 3.4 as running into https://github.com/pypa/setuptools/issues/951 (Thinking of dropping official support for it too) + +## [0.4.2](https://github.com/Lawouach/WebSocket-for-Python/tree/0.4.2) (2017-03-29) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/0.4.1...0.4.2) + +**Merged pull requests:** + +- Block on receiving from SSL socket [\#212](https://github.com/Lawouach/WebSocket-for-Python/pull/212) ([awelkie](https://github.com/awelkie)) + +## [0.4.1](https://github.com/Lawouach/WebSocket-for-Python/tree/0.4.1) (2017-03-26) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/0.4.0...0.4.1) + +**Merged pull requests:** + +- fixes parsed hostname [\#210](https://github.com/Lawouach/WebSocket-for-Python/pull/210) ([isubas](https://github.com/isubas)) + +## [0.4.0](https://github.com/Lawouach/WebSocket-for-Python/tree/0.4.0) (2017-03-24) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/0.3.5...0.4.0) + +**Implemented enhancements:** + +- exception not catch in websocket.py always [\#70](https://github.com/Lawouach/WebSocket-for-Python/issues/70) + +**Fixed bugs:** + +- Last send never happens [\#167](https://github.com/Lawouach/WebSocket-for-Python/issues/167) + +**Closed issues:** + +- PyPI latest release 0.3.5 does not include \#205 and therefore breaks with cherrypy [\#209](https://github.com/Lawouach/WebSocket-for-Python/issues/209) +- Unable to reconnect [\#207](https://github.com/Lawouach/WebSocket-for-Python/issues/207) +- CherryPy does not use its own wsgiserver anymore, which ws4py depended on [\#205](https://github.com/Lawouach/WebSocket-for-Python/issues/205) +- py2exe / python2.7 / syntax error in "yield from" lines [\#202](https://github.com/Lawouach/WebSocket-for-Python/issues/202) +- Missing 0.3.5 changelog and tag [\#192](https://github.com/Lawouach/WebSocket-for-Python/issues/192) +- ws4py 0.3.5 doesn't receive all messages over wss [\#191](https://github.com/Lawouach/WebSocket-for-Python/issues/191) +- SSL: received\_message not getting called [\#183](https://github.com/Lawouach/WebSocket-for-Python/issues/183) +- Python 2.6 support [\#182](https://github.com/Lawouach/WebSocket-for-Python/issues/182) +- Overridden close\(\) not called under windows [\#178](https://github.com/Lawouach/WebSocket-for-Python/issues/178) +- Enabling cpstats causes ws4py to crash [\#177](https://github.com/Lawouach/WebSocket-for-Python/issues/177) +- Only support Python 3.0+ ? [\#175](https://github.com/Lawouach/WebSocket-for-Python/issues/175) +- IOError\(interrupted system call\) on dropping privilages [\#172](https://github.com/Lawouach/WebSocket-for-Python/issues/172) +- error: configure\_logger\(stdout=False, filepath="ws4py.log"\) [\#171](https://github.com/Lawouach/WebSocket-for-Python/issues/171) +- Python 3.4 and gevent 1.1 [\#170](https://github.com/Lawouach/WebSocket-for-Python/issues/170) +- Is it possible to extract headers from WebSocketProtocol using asyncio [\#169](https://github.com/Lawouach/WebSocket-for-Python/issues/169) +- server, opened\(\) is called each time a message is send [\#162](https://github.com/Lawouach/WebSocket-for-Python/issues/162) +- tlm [\#160](https://github.com/Lawouach/WebSocket-for-Python/issues/160) +- In opened\(\), closing connection would crash the server [\#159](https://github.com/Lawouach/WebSocket-for-Python/issues/159) +- Server crashes with broken pipe if client disconnects ungracefully? [\#150](https://github.com/Lawouach/WebSocket-for-Python/issues/150) +- Client connection hangs when using Cherrypy [\#146](https://github.com/Lawouach/WebSocket-for-Python/issues/146) +- low priority: wsgiref example doesn't work [\#145](https://github.com/Lawouach/WebSocket-for-Python/issues/145) +- CherryPy: simple example of an echo server [\#140](https://github.com/Lawouach/WebSocket-for-Python/issues/140) +- WebSocketClient.closed\(\) always returns code 1006 if reason string empty. [\#137](https://github.com/Lawouach/WebSocket-for-Python/issues/137) +- Server Side Connection Drops Immediately [\#134](https://github.com/Lawouach/WebSocket-for-Python/issues/134) +- Calling WebSocketClient.terminate\(\) results in AttributeError [\#131](https://github.com/Lawouach/WebSocket-for-Python/issues/131) +- ConnectionRefusedError: \[WinError 10061\] No connection could be made because the target machine actively refused it [\#130](https://github.com/Lawouach/WebSocket-for-Python/issues/130) +- AttributeError: 'NoneType' object has no attribute 'fileno' [\#129](https://github.com/Lawouach/WebSocket-for-Python/issues/129) +- wss is always one message behind [\#128](https://github.com/Lawouach/WebSocket-for-Python/issues/128) +- Asyncio Issues [\#125](https://github.com/Lawouach/WebSocket-for-Python/issues/125) + +**Merged pull requests:** + +- change cherrypy.wsgiserver to cheroot.server [\#206](https://github.com/Lawouach/WebSocket-for-Python/pull/206) ([raven38](https://github.com/raven38)) +- This change is to address the issue with run\_forever\(\) terminating too early. [\#201](https://github.com/Lawouach/WebSocket-for-Python/pull/201) ([steowens](https://github.com/steowens)) +- Don't crash with broken pipe when trying to close a connection [\#198](https://github.com/Lawouach/WebSocket-for-Python/pull/198) ([cristi8](https://github.com/cristi8)) +- adding heartbeat for gevent\_client [\#195](https://github.com/Lawouach/WebSocket-for-Python/pull/195) ([alexmnt](https://github.com/alexmnt)) +- minor - typo [\#193](https://github.com/Lawouach/WebSocket-for-Python/pull/193) ([johnwheeler](https://github.com/johnwheeler)) +- Eliminate a protocol error when first chunk is last too. [\#186](https://github.com/Lawouach/WebSocket-for-Python/pull/186) ([plu9in](https://github.com/plu9in)) +- Allow WebSocketWSGIHandler to work even in presence of a middleware [\#185](https://github.com/Lawouach/WebSocket-for-Python/pull/185) ([bozzzzo](https://github.com/bozzzzo)) +- Give application status code 1005 when no good status code is parsed/received [\#181](https://github.com/Lawouach/WebSocket-for-Python/pull/181) ([isonmad](https://github.com/isonmad)) +- Fix server "Bad file descriptor" error under gevent 1.1, \#170 [\#180](https://github.com/Lawouach/WebSocket-for-Python/pull/180) ([hyt-hz](https://github.com/hyt-hz)) +- Version of example that doesn't need jquery, fix IOError on resume, f… [\#173](https://github.com/Lawouach/WebSocket-for-Python/pull/173) ([EternityForest](https://github.com/EternityForest)) +- Fix typo [\#161](https://github.com/Lawouach/WebSocket-for-Python/pull/161) ([hexchain](https://github.com/hexchain)) +- added a word [\#157](https://github.com/Lawouach/WebSocket-for-Python/pull/157) ([Mrmaxmeier](https://github.com/Mrmaxmeier)) +- Removed unnecessary try/except and cleaned for some PEP8 [\#155](https://github.com/Lawouach/WebSocket-for-Python/pull/155) ([warvariuc](https://github.com/warvariuc)) +- Improve Origin handling in Client [\#154](https://github.com/Lawouach/WebSocket-for-Python/pull/154) ([rdbhost](https://github.com/rdbhost)) +- Fix: closing handshake does not work correctly when reason is empty [\#149](https://github.com/Lawouach/WebSocket-for-Python/pull/149) ([schiermike](https://github.com/schiermike)) +- pass ssl\_options to SSLIOStream\(\) to ensure certificate validation works [\#147](https://github.com/Lawouach/WebSocket-for-Python/pull/147) ([szweep](https://github.com/szweep)) +- Explained why wsgiref not for produciton [\#144](https://github.com/Lawouach/WebSocket-for-Python/pull/144) ([Seanny123](https://github.com/Seanny123)) +- Added Port to Host in handshake header. [\#139](https://github.com/Lawouach/WebSocket-for-Python/pull/139) ([thiagorcdl](https://github.com/thiagorcdl)) +- Don't fail when websocket was not inited. [\#135](https://github.com/Lawouach/WebSocket-for-Python/pull/135) ([eraviart](https://github.com/eraviart)) +- ws4py/\_\_init\_\_.py: fix configure\_logger by importing loging.handlers as handlers [\#133](https://github.com/Lawouach/WebSocket-for-Python/pull/133) ([andrew-canaday](https://github.com/andrew-canaday)) + +## [0.3.5](https://github.com/Lawouach/WebSocket-for-Python/tree/0.3.5) (2014-04-01) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/v0.3.4...0.3.5) + +**Closed issues:** + +- No longer working on Chome 34.0.1847.76 [\#124](https://github.com/Lawouach/WebSocket-for-Python/issues/124) + +## [v0.3.4](https://github.com/Lawouach/WebSocket-for-Python/tree/v0.3.4) (2014-03-30) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/v0.3.3...v0.3.4) + +**Fixed bugs:** + +- ws4py 0.3.3 installation broken [\#123](https://github.com/Lawouach/WebSocket-for-Python/issues/123) + +## [v0.3.3](https://github.com/Lawouach/WebSocket-for-Python/tree/v0.3.3) (2014-03-29) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/v0.3.2...v0.3.3) + +**Implemented enhancements:** + +- Upload releases to PyPI for compatibility with new pip versions [\#99](https://github.com/Lawouach/WebSocket-for-Python/issues/99) +- Gradually drop support for Python \<2.7 and \<3.3.2 [\#91](https://github.com/Lawouach/WebSocket-for-Python/issues/91) + +**Fixed bugs:** + +- Catch MemoryError when uploading a music file\(size: 16M\) [\#113](https://github.com/Lawouach/WebSocket-for-Python/issues/113) +- ws4py 0.2.2 no longer working on Chrome version 30 [\#108](https://github.com/Lawouach/WebSocket-for-Python/issues/108) + +**Closed issues:** + +- Exception in thread WebSocketClient during unit testing [\#122](https://github.com/Lawouach/WebSocket-for-Python/issues/122) +- TypeError: \_\_str\_\_ returned non-string \(type bytes\) [\#121](https://github.com/Lawouach/WebSocket-for-Python/issues/121) +- While using the Gevent WebSocket client an os error, OSError: \[Errno 24\] Too many open files, occurs [\#120](https://github.com/Lawouach/WebSocket-for-Python/issues/120) +- AttributeError: 'MyClient' object has no attribute '\_cleanup' [\#119](https://github.com/Lawouach/WebSocket-for-Python/issues/119) +- Message string representation does not work in Python 3 [\#117](https://github.com/Lawouach/WebSocket-for-Python/issues/117) +- Not able to install a specific version of an unsecure package [\#115](https://github.com/Lawouach/WebSocket-for-Python/issues/115) +- How to use WebSocketManager with server? [\#111](https://github.com/Lawouach/WebSocket-for-Python/issues/111) +- client: KeyboardInterrupt silently catched [\#109](https://github.com/Lawouach/WebSocket-for-Python/issues/109) +- unittests2 shouldn't be needed with python \>= 2.7 and \>= 3.2 [\#106](https://github.com/Lawouach/WebSocket-for-Python/issues/106) + +**Merged pull requests:** + +- base example documentation fix [\#118](https://github.com/Lawouach/WebSocket-for-Python/pull/118) ([husio](https://github.com/husio)) +- fix: changed gevent server to use a real gevent.pool.Pool [\#114](https://github.com/Lawouach/WebSocket-for-Python/pull/114) ([fischerq](https://github.com/fischerq)) +- Tutorial should import TornadoWebSocketClient. [\#112](https://github.com/Lawouach/WebSocket-for-Python/pull/112) ([ajdavis](https://github.com/ajdavis)) +- Fix cherrypy logging [\#107](https://github.com/Lawouach/WebSocket-for-Python/pull/107) ([UncleRus](https://github.com/UncleRus)) + +## [v0.3.2](https://github.com/Lawouach/WebSocket-for-Python/tree/v0.3.2) (2013-09-12) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/v0.3.0-beta...v0.3.2) + +**Implemented enhancements:** + +- Move back to unicode and byte litterals [\#100](https://github.com/Lawouach/WebSocket-for-Python/issues/100) +- remove implicit gevent monkey patching in the gevent client [\#90](https://github.com/Lawouach/WebSocket-for-Python/issues/90) +- Busy loop in SelectPoller that is consuming a lot of CPU [\#87](https://github.com/Lawouach/WebSocket-for-Python/issues/87) +- tornado expects bytes but TornadoWebSocketClient gives strings [\#71](https://github.com/Lawouach/WebSocket-for-Python/issues/71) + +**Fixed bugs:** + +- AssertionError: Header values must be strings [\#103](https://github.com/Lawouach/WebSocket-for-Python/issues/103) +- remove implicit gevent monkey patching in the gevent client [\#90](https://github.com/Lawouach/WebSocket-for-Python/issues/90) +- ws4py.server.wsgiutils.py got some error in python 3.3 [\#88](https://github.com/Lawouach/WebSocket-for-Python/issues/88) +- Busy loop in SelectPoller that is consuming a lot of CPU [\#87](https://github.com/Lawouach/WebSocket-for-Python/issues/87) +- Socket not properly closed in Win7 [\#69](https://github.com/Lawouach/WebSocket-for-Python/issues/69) + +**Closed issues:** + +- NameError: global name 'dec' is not defined \(in Python 2.7.5\) [\#102](https://github.com/Lawouach/WebSocket-for-Python/issues/102) +- Allow cherrypy users to pass in a custom poller to the manager [\#95](https://github.com/Lawouach/WebSocket-for-Python/issues/95) +- IPv6 sockets not supported [\#86](https://github.com/Lawouach/WebSocket-for-Python/issues/86) +- Support `ws+unix` scheme [\#76](https://github.com/Lawouach/WebSocket-for-Python/issues/76) +- Strange traceback with WebSocket.send [\#73](https://github.com/Lawouach/WebSocket-for-Python/issues/73) + +**Merged pull requests:** + +- fixed some old references to removed functions enc\(\) and dec\(\) [\#101](https://github.com/Lawouach/WebSocket-for-Python/pull/101) ([flaviogrossi](https://github.com/flaviogrossi)) +- ws4py.client classes should support client certificates [\#98](https://github.com/Lawouach/WebSocket-for-Python/pull/98) ([EliAndrewC](https://github.com/EliAndrewC)) +- Code correction in built-in client tutorial [\#96](https://github.com/Lawouach/WebSocket-for-Python/pull/96) ([elmiko](https://github.com/elmiko)) +- Fixed a couple of typos in the docs [\#92](https://github.com/Lawouach/WebSocket-for-Python/pull/92) ([rakiru](https://github.com/rakiru)) +- Fix typo in 'ws4y.websocket' [\#89](https://github.com/Lawouach/WebSocket-for-Python/pull/89) ([jodal](https://github.com/jodal)) +- Fix for bytestrings in Tornado client. [\#85](https://github.com/Lawouach/WebSocket-for-Python/pull/85) ([lbolla](https://github.com/lbolla)) + +## [v0.3.0-beta](https://github.com/Lawouach/WebSocket-for-Python/tree/v0.3.0-beta) (2013-03-16) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/v0.2.4...v0.3.0-beta) + +**Closed issues:** + +- Threaded WebSocket client always exits randomly [\#78](https://github.com/Lawouach/WebSocket-for-Python/issues/78) +- test\_cherrypy.py fails with py3 [\#72](https://github.com/Lawouach/WebSocket-for-Python/issues/72) +- A simpler gevent server example? [\#66](https://github.com/Lawouach/WebSocket-for-Python/issues/66) + +**Merged pull requests:** + +- select.select\(\) on Windows does not allow empty rlist. [\#83](https://github.com/Lawouach/WebSocket-for-Python/pull/83) ([Who8MyLunch](https://github.com/Who8MyLunch)) +- DOC: add omitted default value for closed\(\) in Client example [\#80](https://github.com/Lawouach/WebSocket-for-Python/pull/80) ([y-p](https://github.com/y-p)) +- README: Mention to wsaccel [\#79](https://github.com/Lawouach/WebSocket-for-Python/pull/79) ([methane](https://github.com/methane)) +- Faster utf8validate. [\#75](https://github.com/Lawouach/WebSocket-for-Python/pull/75) ([methane](https://github.com/methane)) +- Cleanup indent and trailing spaces. [\#74](https://github.com/Lawouach/WebSocket-for-Python/pull/74) ([methane](https://github.com/methane)) + +## [v0.2.4](https://github.com/Lawouach/WebSocket-for-Python/tree/v0.2.4) (2012-12-13) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/v0.2.3...v0.2.4) + +**Closed issues:** + +- echo\_cherrypy\_server with Python 3.2 fails on client connection [\#62](https://github.com/Lawouach/WebSocket-for-Python/issues/62) + +**Merged pull requests:** + +- Doc build improvements [\#65](https://github.com/Lawouach/WebSocket-for-Python/pull/65) ([jodal](https://github.com/jodal)) +- Don't broadcast messages to terminated WebSockets [\#64](https://github.com/Lawouach/WebSocket-for-Python/pull/64) ([jodal](https://github.com/jodal)) +- Fixup/readme [\#63](https://github.com/Lawouach/WebSocket-for-Python/pull/63) ([richo](https://github.com/richo)) + +## [v0.2.3](https://github.com/Lawouach/WebSocket-for-Python/tree/v0.2.3) (2012-10-27) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/v0.2.2...v0.2.3) + +**Closed issues:** + +- urlsplit in Python 2.6.1 and earlier doesn't parse ws or wss properly. [\#59](https://github.com/Lawouach/WebSocket-for-Python/issues/59) +- Inconsistent tabs/spaces [\#58](https://github.com/Lawouach/WebSocket-for-Python/issues/58) +- Bug in documentation [\#55](https://github.com/Lawouach/WebSocket-for-Python/issues/55) +- wss server support [\#40](https://github.com/Lawouach/WebSocket-for-Python/issues/40) +- Port to Python 3 [\#29](https://github.com/Lawouach/WebSocket-for-Python/issues/29) + +**Merged pull requests:** + +- Work around Python 2.6.X bug in urlparse.urlsplit\(\) [\#60](https://github.com/Lawouach/WebSocket-for-Python/pull/60) ([dsully](https://github.com/dsully)) +- Bug fix in WebSocketPlugin.broadcast\(\) [\#54](https://github.com/Lawouach/WebSocket-for-Python/pull/54) ([ralhei](https://github.com/ralhei)) +- Minor fix which turns an unintentional and confusing error message into the intended error message [\#53](https://github.com/Lawouach/WebSocket-for-Python/pull/53) ([EliAndrewC](https://github.com/EliAndrewC)) + +## [v0.2.2](https://github.com/Lawouach/WebSocket-for-Python/tree/v0.2.2) (2012-06-21) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/v0.2.1...v0.2.2) + +**Closed issues:** + +- memory leak in streaming.Stream [\#51](https://github.com/Lawouach/WebSocket-for-Python/issues/51) +- ws4py shouldn't send a masked message to the client [\#50](https://github.com/Lawouach/WebSocket-for-Python/issues/50) +- In client/\_\_init\_\_.py: remaining 'body' bytes ignored [\#46](https://github.com/Lawouach/WebSocket-for-Python/issues/46) +- ws4py.client.threadedclient is not compatible with ws4py.server.cherrypyserver [\#44](https://github.com/Lawouach/WebSocket-for-Python/issues/44) +- infinite loop in threadedclient.py when server closes websocket [\#23](https://github.com/Lawouach/WebSocket-for-Python/issues/23) + +**Merged pull requests:** + +- Change Sec-WebSocket-Origin header to Origin as per RFC [\#49](https://github.com/Lawouach/WebSocket-for-Python/pull/49) ([jtakkala](https://github.com/jtakkala)) +- Testing: Add support for `python setup.py test`, tox, and Travis CI [\#47](https://github.com/Lawouach/WebSocket-for-Python/pull/47) ([msabramo](https://github.com/msabramo)) +- Fixed geventclient.WebSocketClient.receive\(\) blocking forever [\#45](https://github.com/Lawouach/WebSocket-for-Python/pull/45) ([aluzzardi](https://github.com/aluzzardi)) +- Doctest fixed at ws4py.framing in Frame [\#43](https://github.com/Lawouach/WebSocket-for-Python/pull/43) ([stuntgoat](https://github.com/stuntgoat)) +- Delete greenlet start\(\) [\#42](https://github.com/Lawouach/WebSocket-for-Python/pull/42) ([yrttyr](https://github.com/yrttyr)) + +## [v0.2.1](https://github.com/Lawouach/WebSocket-for-Python/tree/v0.2.1) (2012-03-28) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/v0.2.0...v0.2.1) + +**Closed issues:** + +- wsgi.input \_sock not working [\#41](https://github.com/Lawouach/WebSocket-for-Python/issues/41) +- ImportError: No module named gevent [\#39](https://github.com/Lawouach/WebSocket-for-Python/issues/39) +- HandshakeError: WebSocket version required [\#36](https://github.com/Lawouach/WebSocket-for-Python/issues/36) +- tools.websocket.version should allow more than one version [\#34](https://github.com/Lawouach/WebSocket-for-Python/issues/34) +- TornadoWebSocketClient doesn't support SSL [\#32](https://github.com/Lawouach/WebSocket-for-Python/issues/32) +- Problem creating a websocket [\#31](https://github.com/Lawouach/WebSocket-for-Python/issues/31) +- KeyboardInterrupt ignored in WebSocketClient [\#30](https://github.com/Lawouach/WebSocket-for-Python/issues/30) + +**Merged pull requests:** + +- Delete start\(\) [\#38](https://github.com/Lawouach/WebSocket-for-Python/pull/38) ([yrttyr](https://github.com/yrttyr)) +- Tornado implementation fix [\#37](https://github.com/Lawouach/WebSocket-for-Python/pull/37) ([protoss-player](https://github.com/protoss-player)) +- Fix SSL support in TornadoWebSocketClient and add missing import [\#33](https://github.com/Lawouach/WebSocket-for-Python/pull/33) ([patrickod](https://github.com/patrickod)) +- Fix SSL Clients [\#27](https://github.com/Lawouach/WebSocket-for-Python/pull/27) ([chadselph](https://github.com/chadselph)) +- send\(\) really shouldn't fail silently when getting an unknown data type [\#26](https://github.com/Lawouach/WebSocket-for-Python/pull/26) ([chadselph](https://github.com/chadselph)) + +## [v0.2.0](https://github.com/Lawouach/WebSocket-for-Python/tree/v0.2.0) (2012-02-23) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/v0.1.5...v0.2.0) + +**Closed issues:** + +- Incorrect args in TornadoWebSocketClient constructor [\#25](https://github.com/Lawouach/WebSocket-for-Python/issues/25) +- Typo in echo\_client example [\#24](https://github.com/Lawouach/WebSocket-for-Python/issues/24) +- Typos following recent code changes... [\#22](https://github.com/Lawouach/WebSocket-for-Python/issues/22) +- ThreadedHandler still referenced [\#21](https://github.com/Lawouach/WebSocket-for-Python/issues/21) +- memory leak [\#20](https://github.com/Lawouach/WebSocket-for-Python/issues/20) +- Please store the close code and reason in WebSocketBaseClient [\#19](https://github.com/Lawouach/WebSocket-for-Python/issues/19) +- Exception when running with gevent 1.0 [\#18](https://github.com/Lawouach/WebSocket-for-Python/issues/18) +- Version 0.1.5 is not installable [\#17](https://github.com/Lawouach/WebSocket-for-Python/issues/17) +- TypeError: list indices must be integers, not str [\#16](https://github.com/Lawouach/WebSocket-for-Python/issues/16) +- All frames from the client should be masked [\#15](https://github.com/Lawouach/WebSocket-for-Python/issues/15) +- chrome 16.0.912.41 beta return code 400 [\#11](https://github.com/Lawouach/WebSocket-for-Python/issues/11) + +## [v0.1.5](https://github.com/Lawouach/WebSocket-for-Python/tree/v0.1.5) (2011-12-15) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/v0.1.4...v0.1.5) + +**Closed issues:** + +- Bad code for binary send in client/\_\_init\_\_.py ?? [\#14](https://github.com/Lawouach/WebSocket-for-Python/issues/14) +- Server not handling "Upgrade" header case-insensitively, as it should [\#13](https://github.com/Lawouach/WebSocket-for-Python/issues/13) + +**Merged pull requests:** + +- support for wss:// connections using ssl.wrap\_socket [\#12](https://github.com/Lawouach/WebSocket-for-Python/pull/12) ([EliAndrewC](https://github.com/EliAndrewC)) + +## [v0.1.4](https://github.com/Lawouach/WebSocket-for-Python/tree/v0.1.4) (2011-11-12) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/v0.1.3...v0.1.4) + +**Closed issues:** + +- Handle Connection: keep-alive, Upgrade header from Firefox 7.0 [\#3](https://github.com/Lawouach/WebSocket-for-Python/issues/3) + +**Merged pull requests:** + +- Hello, I had to make some minor changes to get the echo server to work for me. Thank for the excellent work. I am looking forward to incorporating it into my site :\). Regards, Derrick [\#10](https://github.com/Lawouach/WebSocket-for-Python/pull/10) ([dpetzold](https://github.com/dpetzold)) +- Added io\_loop parameter to TornadoWebSocketClient constructor [\#9](https://github.com/Lawouach/WebSocket-for-Python/pull/9) ([swax](https://github.com/swax)) +- Websocket threading client ignores initial data send by the server [\#7](https://github.com/Lawouach/WebSocket-for-Python/pull/7) ([majek](https://github.com/majek)) +- Fixed hangup in Tornado implementation [\#6](https://github.com/Lawouach/WebSocket-for-Python/pull/6) ([protoss-player](https://github.com/protoss-player)) +- Added a gevent client and fixed a major flaw in the gevent/"wsgi" server handler [\#5](https://github.com/Lawouach/WebSocket-for-Python/pull/5) ([progrium](https://github.com/progrium)) +- Some JSON functionality [\#4](https://github.com/Lawouach/WebSocket-for-Python/pull/4) ([protoss-player](https://github.com/protoss-player)) + +## [v0.1.3](https://github.com/Lawouach/WebSocket-for-Python/tree/v0.1.3) (2011-09-07) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/v0.1.2...v0.1.3) + +**Merged pull requests:** + +- Made it more generic, fixed some bugs, cleaned things up [\#2](https://github.com/Lawouach/WebSocket-for-Python/pull/2) ([progrium](https://github.com/progrium)) + +## [v0.1.2](https://github.com/Lawouach/WebSocket-for-Python/tree/v0.1.2) (2011-08-23) +[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/v0.1.1...v0.1.2) + +**Merged pull requests:** + +- gevent server implementation [\#1](https://github.com/Lawouach/WebSocket-for-Python/pull/1) ([progrium](https://github.com/progrium)) + +## [v0.1.1](https://github.com/Lawouach/WebSocket-for-Python/tree/v0.1.1) (2011-08-21) + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/LICENSE new/ws4py-0.5.1/LICENSE --- old/ws4py-0.4.2/LICENSE 1970-01-01 01:00:00.000000000 +0100 +++ new/ws4py-0.5.1/LICENSE 2017-05-09 12:35:59.000000000 +0200 @@ -0,0 +1,26 @@ +Copyright (c) 2011-2016, Sylvain Hellegouarch +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of ws4py nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY 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. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/MANIFEST.in new/ws4py-0.5.1/MANIFEST.in --- old/ws4py-0.4.2/MANIFEST.in 1970-01-01 01:00:00.000000000 +0100 +++ new/ws4py-0.5.1/MANIFEST.in 2017-10-17 12:52:58.000000000 +0200 @@ -0,0 +1,3 @@ +include LICENSE +include README.md +include CHANGELOG.md diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/PKG-INFO new/ws4py-0.5.1/PKG-INFO --- old/ws4py-0.4.2/PKG-INFO 2017-03-29 19:57:06.000000000 +0200 +++ new/ws4py-0.5.1/PKG-INFO 2018-02-28 18:40:21.000000000 +0100 @@ -1,12 +1,13 @@ Metadata-Version: 1.1 Name: ws4py -Version: 0.4.2 +Version: 0.5.1 Summary: WebSocket client and server library for Python 2 and 3 as well as PyPy Home-page: https://github.com/Lawouach/WebSocket-for-Python Author: Sylvain Hellegouarch Author-email: [email protected] License: BSD Download-URL: https://pypi.python.org/pypi/ws4py +Description-Content-Type: UNKNOWN Description: WebSocket client and server library for Python 2 and 3 as well as PyPy Platform: any Classifier: Development Status :: 5 - Production/Stable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/README.md new/ws4py-0.5.1/README.md --- old/ws4py-0.4.2/README.md 1970-01-01 01:00:00.000000000 +0100 +++ new/ws4py-0.5.1/README.md 2018-02-27 11:04:53.000000000 +0100 @@ -0,0 +1,24 @@ +# WebSocket for Python (ws4py) + +[](https://gitter.im/Lawouach/WebSocket-for-Python?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +[](https://travis-ci.org/Lawouach/WebSocket-for-Python) +[](https://pypi.org/project/ws4py/) + +Python library providing an implementation of the WebSocket protocol defined in [RFC 6455](http://tools.ietf.org/html/rfc6455). + +Read the [documentation](https://ws4py.readthedocs.org/en/latest/) for more information. + +You can also join the [ws4py mailing-list](http://groups.google.com/group/ws4py) to discuss the library. + +**WARNING**: This project is [on hiatus](https://opensource.guide/best-practices/#share-the-workload) +and [does not receive active maintainance](http://www.defuze.org/archives/409-ws4py-is-eager-for-a-new-maintainer.html). +Please be aware of this when deciding to rely on it as contributions may be slow +to make their way to a new release. If you feel like offering help in +maintaining it, [please let us know](https://groups.google.com/forum/#!forum/ws4py). + +## Installation + +``` +pip install ws4py +``` + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/setup.cfg new/ws4py-0.5.1/setup.cfg --- old/ws4py-0.4.2/setup.cfg 2017-03-29 19:57:06.000000000 +0200 +++ new/ws4py-0.5.1/setup.cfg 2018-02-28 18:40:21.000000000 +0100 @@ -1,5 +1,4 @@ [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/test/test_client.py new/ws4py-0.5.1/test/test_client.py --- old/ws4py-0.4.2/test/test_client.py 2017-03-24 16:25:29.000000000 +0100 +++ new/ws4py-0.5.1/test/test_client.py 2018-02-28 17:21:12.000000000 +0100 @@ -1,32 +1,28 @@ # -*- coding: utf-8 -*- from base64 import b64encode from hashlib import sha1 -import os import socket import time import unittest -from mock import MagicMock, call, patch +from mock import MagicMock, patch -from ws4py.manager import WebSocketManager -from ws4py.websocket import WebSocket from ws4py import WS_KEY from ws4py.exc import HandshakeError from ws4py.framing import Frame, OPCODE_TEXT, OPCODE_CLOSE -from ws4py.messaging import CloseControlMessage from ws4py.client import WebSocketBaseClient from ws4py.client.threadedclient import WebSocketClient class BasicClientTest(unittest.TestCase): def test_invalid_hostname_in_url(self): self.assertRaises(ValueError, WebSocketBaseClient, url="qsdfqsd65qsd354") - + def test_invalid_scheme_in_url(self): self.assertRaises(ValueError, WebSocketBaseClient, url="ftp://localhost") - + def test_invalid_hostname_in_url(self): self.assertRaises(ValueError, WebSocketBaseClient, url="ftp://?/") - + def test_parse_unix_schemes(self): c = WebSocketBaseClient(url="ws+unix:///my.socket") self.assertEqual(c.scheme, "ws+unix") @@ -35,7 +31,7 @@ self.assertEqual(c.unix_socket_path, "/my.socket") self.assertEqual(c.resource, "/") self.assertEqual(c.bind_addr, "/my.socket") - + c = WebSocketBaseClient(url="wss+unix:///my.socket") self.assertEqual(c.scheme, "wss+unix") self.assertEqual(c.host, "localhost") @@ -43,7 +39,7 @@ self.assertEqual(c.unix_socket_path, "/my.socket") self.assertEqual(c.resource, "/") self.assertEqual(c.bind_addr, "/my.socket") - + def test_parse_ws_scheme(self): c = WebSocketBaseClient(url="ws://127.0.0.1/") self.assertEqual(c.scheme, "ws") @@ -51,7 +47,7 @@ self.assertEqual(c.port, 80) self.assertEqual(c.resource, "/") self.assertEqual(c.bind_addr, ("127.0.0.1", 80)) - + def test_parse_ws_scheme_when_missing_resource(self): c = WebSocketBaseClient(url="ws://127.0.0.1") self.assertEqual(c.scheme, "ws") @@ -59,7 +55,7 @@ self.assertEqual(c.port, 80) self.assertEqual(c.resource, "/") self.assertEqual(c.bind_addr, ("127.0.0.1", 80)) - + def test_parse_ws_scheme_with_port(self): c = WebSocketBaseClient(url="ws://127.0.0.1:9090") self.assertEqual(c.scheme, "ws") @@ -67,7 +63,7 @@ self.assertEqual(c.port, 9090) self.assertEqual(c.resource, "/") self.assertEqual(c.bind_addr, ("127.0.0.1", 9090)) - + def test_parse_ws_scheme_with_query_string(self): c = WebSocketBaseClient(url="ws://127.0.0.1/?token=value") self.assertEqual(c.scheme, "ws") @@ -75,7 +71,7 @@ self.assertEqual(c.port, 80) self.assertEqual(c.resource, "/?token=value") self.assertEqual(c.bind_addr, ("127.0.0.1", 80)) - + def test_parse_wss_scheme(self): c = WebSocketBaseClient(url="wss://127.0.0.1/") self.assertEqual(c.scheme, "wss") @@ -83,7 +79,7 @@ self.assertEqual(c.port, 443) self.assertEqual(c.resource, "/") self.assertEqual(c.bind_addr, ("127.0.0.1", 443)) - + def test_parse_wss_scheme_when_missing_resource(self): c = WebSocketBaseClient(url="wss://127.0.0.1") self.assertEqual(c.scheme, "wss") @@ -91,7 +87,7 @@ self.assertEqual(c.port, 443) self.assertEqual(c.resource, "/") self.assertEqual(c.bind_addr, ("127.0.0.1", 443)) - + def test_parse_wss_scheme_with_port(self): c = WebSocketBaseClient(url="wss://127.0.0.1:9090") self.assertEqual(c.scheme, "wss") @@ -99,7 +95,7 @@ self.assertEqual(c.port, 9090) self.assertEqual(c.resource, "/") self.assertEqual(c.bind_addr, ("127.0.0.1", 9090)) - + def test_parse_wss_scheme_with_query_string(self): c = WebSocketBaseClient(url="wss://127.0.0.1/?token=value") self.assertEqual(c.scheme, "wss") @@ -107,23 +103,26 @@ self.assertEqual(c.port, 443) self.assertEqual(c.resource, "/?token=value") self.assertEqual(c.bind_addr, ("127.0.0.1", 443)) - + @patch('ws4py.client.socket') def test_connect_and_close(self, sock): - + s = MagicMock() sock.socket.return_value = s sock.getaddrinfo.return_value = [(socket.AF_INET, socket.SOCK_STREAM, 0, "", ("127.0.0.1", 80, 0, 0))] c = WebSocketBaseClient(url="ws://127.0.0.1/?token=value") - + s.recv.return_value = b"\r\n".join([ b"HTTP/1.1 101 Switching Protocols", b"Connection: Upgrade", b"Sec-Websocket-Version: 13", b"Content-Type: text/plain;charset=utf-8", b"Sec-Websocket-Accept: " + b64encode(sha1(c.key + WS_KEY).digest()), + b"Sec-WebSocket-Protocol: proto1, proto2", + b"Sec-WebSocket-Extensions: ext1, ext2", + b"Sec-WebSocket-Extensions: ext3", b"Upgrade: websocket", b"Date: Sun, 26 Jul 2015 12:32:55 GMT", b"Server: ws4py/test", @@ -132,6 +131,8 @@ c.connect() s.connect.assert_called_once_with(("127.0.0.1", 80)) + self.assertEqual(c.protocols, [b'proto1', b'proto2']) + self.assertEqual(c.extensions, [b'ext1', b'ext2', b'ext3']) s.reset_mock() c.close(code=1006, reason="boom") @@ -140,32 +141,32 @@ f.parser.send(args[0][0]) f.parser.close() self.assertIn(b'boom', f.unmask(f.body)) - + @patch('ws4py.client.socket') def test_empty_response(self, sock): - + s = MagicMock() sock.socket.return_value = s sock.getaddrinfo.return_value = [(socket.AF_INET, socket.SOCK_STREAM, 0, "", ("127.0.0.1", 80, 0, 0))] c = WebSocketBaseClient(url="ws://127.0.0.1/?token=value") - + s.recv.return_value = b"" self.assertRaises(HandshakeError, c.connect) s.shutdown.assert_called_once_with(socket.SHUT_RDWR) s.close.assert_called_once_with() - + @patch('ws4py.client.socket') - def test_invdalid_response_code(self, sock): - + def test_invalid_response_code(self, sock): + s = MagicMock() sock.socket.return_value = s sock.getaddrinfo.return_value = [(socket.AF_INET, socket.SOCK_STREAM, 0, "", ("127.0.0.1", 80, 0, 0))] c = WebSocketBaseClient(url="ws://127.0.0.1/?token=value") - + s.recv.return_value = b"\r\n".join([ b"HTTP/1.1 200 Switching Protocols", b"Connection: Upgrade", @@ -181,10 +182,10 @@ self.assertRaises(HandshakeError, c.connect) s.shutdown.assert_called_once_with(socket.SHUT_RDWR) s.close.assert_called_once_with() - + @patch('ws4py.client.socket') def test_invalid_response_headers(self, sock): - + for key_header, invalid_value in ((b'upgrade', b'boom'), (b'connection', b'bim')): s = MagicMock() @@ -192,7 +193,7 @@ sock.getaddrinfo.return_value = [(socket.AF_INET, socket.SOCK_STREAM, 0, "", ("127.0.0.1", 80, 0, 0))] c = WebSocketBaseClient(url="ws://127.0.0.1/?token=value") - + status_line = b"HTTP/1.1 101 Switching Protocols" headers = { b"connection": b"Upgrade", @@ -205,7 +206,7 @@ } headers[key_header] = invalid_value - + request = [status_line] + [k + b" : " + v for (k, v) in headers.items()] + [b'\r\n'] s.recv.return_value = b"\r\n".join(request) @@ -213,50 +214,70 @@ s.shutdown.assert_called_once_with(socket.SHUT_RDWR) s.close.assert_called_once_with() sock.reset_mock() - + class ThreadedClientTest(unittest.TestCase): + @patch('ws4py.client.socket') - def test_thread_is_started_once_connected(self, sock): - s = MagicMock(spec=socket.socket) - sock.socket.return_value = s + def setUp(self, sock): + self.sock = MagicMock(spec=socket.socket) + sock.socket.return_value = self.sock sock.getaddrinfo.return_value = [(socket.AF_INET, socket.SOCK_STREAM, 0, "", ("127.0.0.1", 80, 0, 0))] - - c = WebSocketClient(url="ws://127.0.0.1/") - def exchange1(*args, **kwargs): - yield b"\r\n".join([ - b"HTTP/1.1 101 Switching Protocols", - b"Connection: Upgrade", - b"Sec-Websocket-Version: 13", - b"Content-Type: text/plain;charset=utf-8", - b"Sec-Websocket-Accept: " + b64encode(sha1(c.key + WS_KEY).digest()), - b"Upgrade: websocket", - b"Date: Sun, 26 Jul 2015 12:32:55 GMT", - b"Server: ws4py/test", - b"\r\n" - ]) - - for i in range(100): - time.sleep(0.1) - yield Frame(opcode=OPCODE_TEXT, body=b'hello', - fin=1).build() - - s.recv.side_effect = exchange1() - self.assertFalse(c._th.is_alive()) - - c.connect() - time.sleep(0.5) - self.assertTrue(c._th.is_alive()) + self.client = WebSocketClient(url="ws://127.0.0.1/") + + def _exchange1(self, *args, **kwargs): + yield b"\r\n".join([ + b"HTTP/1.1 101 Switching Protocols", + b"Connection: Upgrade", + b"Sec-Websocket-Version: 13", + b"Content-Type: text/plain;charset=utf-8", + b"Sec-Websocket-Accept: " + b64encode(sha1(self.client.key + WS_KEY).digest()), + b"Upgrade: websocket", + b"Date: Sun, 26 Jul 2015 12:32:55 GMT", + b"Server: ws4py/test", + b"\r\n" + ]) - def exchange2(*args, **kwargs): - yield Frame(opcode=OPCODE_CLOSE, body=b'', + for i in range(100): + time.sleep(0.1) + yield Frame(opcode=OPCODE_TEXT, body=b'hello', fin=1).build() - s.recv.side_effect = exchange2() + + def _exchange2(self, *args, **kwargs): + yield Frame(opcode=OPCODE_CLOSE, body=b'', + fin=1).build() + + def test_thread_is_started_once_connected(self): + self.sock.recv.side_effect = self._exchange1() + self.assertFalse(self.client._th.is_alive()) + + self.client.connect() time.sleep(0.5) - self.assertFalse(c._th.is_alive()) - - + self.assertTrue(self.client._th.is_alive()) + + self.sock.recv.side_effect = self._exchange2() + time.sleep(0.5) + self.assertFalse(self.client._th.is_alive()) + + def test_thread_is_started_once_connected_secure(self): + """ Same as the above test, but with SSL socket """ + # pretend the socket is an SSL socket + self.sock.pending = lambda: False + self.client._is_secure = True + + self.sock.recv.side_effect = self._exchange1() + self.assertFalse(self.client._th.is_alive()) + + self.client.connect() + time.sleep(0.5) + self.assertTrue(self.client._th.is_alive()) + + self.sock.recv.side_effect = self._exchange2() + time.sleep(0.5) + self.assertFalse(self.client._th.is_alive()) + + if __name__ == '__main__': suite = unittest.TestSuite() loader = unittest.TestLoader() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/ws4py/__init__.py new/ws4py-0.5.1/ws4py/__init__.py --- old/ws4py-0.4.2/ws4py/__init__.py 2017-03-29 19:57:05.000000000 +0200 +++ new/ws4py-0.5.1/ws4py/__init__.py 2018-02-28 17:23:16.000000000 +0100 @@ -30,7 +30,7 @@ import logging.handlers as handlers __author__ = "Sylvain Hellegouarch" -__version__ = "0.4.2" +__version__ = "0.5.1" __all__ = ['WS_KEY', 'WS_VERSION', 'configure_logger', 'format_addresses'] WS_KEY = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/ws4py/async_websocket.py new/ws4py-0.5.1/ws4py/async_websocket.py --- old/ws4py-0.4.2/ws4py/async_websocket.py 1970-01-01 01:00:00.000000000 +0100 +++ new/ws4py-0.5.1/ws4py/async_websocket.py 2017-05-09 12:35:59.000000000 +0200 @@ -0,0 +1,126 @@ +# -*- coding: utf-8 -*- +__doc__ = """ +WebSocket implementation that relies on two new Python +features: + +* asyncio to provide the high-level interface above transports +* yield from to delegate to the reading stream whenever more + bytes are required + +You can use these implementations in that context +and benefit from those features whilst using ws4py. + +Strictly speaking this module probably doesn't have to +be called async_websocket but it feels this will be its typical +usage and is probably more readable than +delegated_generator_websocket_on_top_of_asyncio.py +""" +import asyncio +import types + +from ws4py.websocket import WebSocket as _WebSocket +from ws4py.messaging import Message + +__all__ = ['WebSocket', 'EchoWebSocket'] + +class WebSocket(_WebSocket): + def __init__(self, proto): + """ + A :pep:`3156` ready websocket handler that works + well in a coroutine-aware loop such as the one provided + by the asyncio module. + + The provided `proto` instance is a + :class:`asyncio.Protocol` subclass instance that will + be used internally to read and write from the + underlying transport. + + Because the base :class:`ws4py.websocket.WebSocket` + class is still coupled a bit to the socket interface, + we have to override a little more than necessary + to play nice with the :pep:`3156` interface. Hopefully, + some day this will be cleaned out. + """ + _WebSocket.__init__(self, None) + self.started = False + self.proto = proto + + @property + def local_address(self): + """ + Local endpoint address as a tuple + """ + if not self._local_address: + self._local_address = self.proto.reader.transport.get_extra_info('sockname') + if len(self._local_address) == 4: + self._local_address = self._local_address[:2] + return self._local_address + + @property + def peer_address(self): + """ + Peer endpoint address as a tuple + """ + if not self._peer_address: + self._peer_address = self.proto.reader.transport.get_extra_info('peername') + if len(self._peer_address) == 4: + self._peer_address = self._peer_address[:2] + return self._peer_address + + def once(self): + """ + The base class directly is used in conjunction with + the :class:`ws4py.manager.WebSocketManager` which is + not actually used with the asyncio implementation + of ws4py. So let's make it clear it shan't be used. + """ + raise NotImplemented() + + def close_connection(self): + """ + Close the underlying transport + """ + @asyncio.coroutine + def closeit(): + yield from self.proto.writer.drain() + self.proto.writer.close() + asyncio.async(closeit()) + + def _write(self, data): + """ + Write to the underlying transport + """ + @asyncio.coroutine + def sendit(data): + self.proto.writer.write(data) + yield from self.proto.writer.drain() + asyncio.async(sendit(data)) + + @asyncio.coroutine + def run(self): + """ + Coroutine that runs until the websocket + exchange is terminated. It also calls the + `opened()` method to indicate the exchange + has started. + """ + self.started = True + try: + self.opened() + reader = self.proto.reader + while True: + data = yield from reader.read(self.reading_buffer_size) + if not self.process(data): + return False + finally: + self.terminate() + + return True + +class EchoWebSocket(WebSocket): + def received_message(self, message): + """ + Automatically sends back the provided ``message`` to + its originating endpoint. + """ + self.send(message.data, message.is_binary) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/ws4py/client/__init__.py new/ws4py-0.5.1/ws4py/client/__init__.py --- old/ws4py-0.4.2/ws4py/client/__init__.py 2017-03-26 20:42:52.000000000 +0200 +++ new/ws4py-0.5.1/ws4py/client/__init__.py 2018-02-28 17:21:12.000000000 +0100 @@ -14,7 +14,7 @@ class WebSocketBaseClient(WebSocket): def __init__(self, url, protocols=None, extensions=None, - heartbeat_freq=None, ssl_options=None, headers=None): + heartbeat_freq=None, ssl_options=None, headers=None, exclude_headers=None): """ A websocket client that implements :rfc:`6455` and provides a simple interface to communicate with a websocket server. @@ -36,7 +36,7 @@ .. code-block:: python - >>> from websocket.client import WebSocketBaseClient + >>> from ws4py.client import WebSocketBaseClient >>> ws = WebSocketBaseClient('ws://localhost/ws') @@ -44,7 +44,7 @@ .. code-block:: python - >>> from websocket.client import WebSocketBaseClient + >>> from ws4py.client import WebSocketBaseClient >>> ws = WebSocketBaseClient('wss://localhost/ws') @@ -52,7 +52,7 @@ .. code-block:: python - >>> from websocket.client import WebSocketBaseClient + >>> from ws4py.client import WebSocketBaseClient >>> ws = WebSocketBaseClient('ws+unix:///tmp/my.sock') Note that in this case, the initial Upgrade request @@ -61,7 +61,7 @@ .. code-block:: python - >>> from websocket.client import WebSocketBaseClient + >>> from ws4py.client import WebSocketBaseClient >>> ws = WebSocketBaseClient('ws+unix:///tmp/my.sock') >>> ws.resource = '/ws' >>> ws.connect() @@ -78,6 +78,8 @@ self.resource = None self.ssl_options = ssl_options or {} self.extra_headers = headers or [] + self.exclude_headers = exclude_headers or [] + self.exclude_headers = [x.lower() for x in self.exclude_headers] if self.scheme == "wss": # Prevent check_hostname requires server_hostname (ref #187) @@ -211,7 +213,7 @@ # default port is now 443; upgrade self.sender to send ssl self.sock = ssl.wrap_socket(self.sock, **self.ssl_options) self._is_secure = True - + self.sock.connect(self.bind_addr) self._write(self.handshake_request) @@ -257,14 +259,15 @@ ('Sec-WebSocket-Key', self.key.decode('utf-8')), ('Sec-WebSocket-Version', str(max(WS_VERSION))) ] - + if self.protocols: headers.append(('Sec-WebSocket-Protocol', ','.join(self.protocols))) if self.extra_headers: headers.extend(self.extra_headers) - if not any(x for x in headers if x[0].lower() == 'origin'): + if not any(x for x in headers if x[0].lower() == 'origin') and \ + 'origin' not in self.exclude_headers: scheme, url = self.url.split(":", 1) parsed = urlsplit(url, scheme="http") @@ -277,6 +280,8 @@ origin = origin + ':' + str(parsed.port) headers.append(('Origin', origin)) + headers = [x for x in headers if x[0].lower() not in self.exclude_headers] + return headers @property @@ -328,10 +333,10 @@ raise HandshakeError("Invalid challenge response: %s" % value) elif header == b'sec-websocket-protocol': - protocols = ','.join(value) + protocols.extend([x.strip() for x in value.split(b',')]) elif header == b'sec-websocket-extensions': - extensions = ','.join(value) + extensions.extend([x.strip() for x in value.split(b',')]) return protocols, extensions diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/ws4py/client/geventclient.py new/ws4py-0.5.1/ws4py/client/geventclient.py --- old/ws4py-0.4.2/ws4py/client/geventclient.py 2017-03-23 00:21:52.000000000 +0100 +++ new/ws4py-0.5.1/ws4py/client/geventclient.py 2018-02-27 08:55:33.000000000 +0100 @@ -10,7 +10,7 @@ __all__ = ['WebSocketClient'] class WebSocketClient(WebSocketBaseClient): - def __init__(self, url, protocols=None, extensions=None, heartbeat_freq=None, ssl_options=None, headers=None): + def __init__(self, url, protocols=None, extensions=None, heartbeat_freq=None, ssl_options=None, headers=None, exclude_headers=None): """ WebSocket client that executes the :meth:`run() <ws4py.websocket.WebSocket.run>` into a gevent greenlet. @@ -41,7 +41,7 @@ gevent.joinall(greenlets) """ WebSocketBaseClient.__init__(self, url, protocols, extensions, heartbeat_freq, - ssl_options=ssl_options, headers=headers) + ssl_options=ssl_options, headers=headers, exclude_headers=exclude_headers) self._th = Greenlet(self.run) self.messages = Queue() @@ -75,18 +75,22 @@ # to wait for self.messages.put(StopIteration) - def receive(self): + def receive(self, block=True): """ Returns messages that were stored into the `messages` queue and returns `None` when the websocket is terminated or closed. + `block` is passed though the gevent queue `.get()` method, which if + True will block until an item in the queue is available. Set this to + False if you just want to check the queue, which will raise an + Empty exception you need to handle if there is no message to return. """ # If the websocket was terminated and there are no messages # left in the queue, return None immediately otherwise the client # will block forever if self.terminated and self.messages.empty(): return None - message = self.messages.get() + message = self.messages.get(block=block) if message is StopIteration: return None return message diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/ws4py/client/threadedclient.py new/ws4py-0.5.1/ws4py/client/threadedclient.py --- old/ws4py-0.4.2/ws4py/client/threadedclient.py 2017-03-23 00:21:52.000000000 +0100 +++ new/ws4py-0.5.1/ws4py/client/threadedclient.py 2017-10-17 12:52:58.000000000 +0200 @@ -7,7 +7,7 @@ class WebSocketClient(WebSocketBaseClient): def __init__(self, url, protocols=None, extensions=None, heartbeat_freq=None, - ssl_options=None, headers=None): + ssl_options=None, headers=None, exclude_headers=None): """ .. code-block:: python @@ -32,7 +32,7 @@ """ WebSocketBaseClient.__init__(self, url, protocols, extensions, heartbeat_freq, - ssl_options, headers=headers) + ssl_options, headers=headers, exclude_headers=exclude_headers) self._th = threading.Thread(target=self.run, name='WebSocketClient') self._th.daemon = True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/ws4py/client/tornadoclient.py new/ws4py-0.5.1/ws4py/client/tornadoclient.py --- old/ws4py-0.4.2/ws4py/client/tornadoclient.py 2017-03-23 00:21:52.000000000 +0100 +++ new/ws4py-0.5.1/ws4py/client/tornadoclient.py 2017-10-17 12:52:58.000000000 +0200 @@ -9,7 +9,7 @@ class TornadoWebSocketClient(WebSocketBaseClient): def __init__(self, url, protocols=None, extensions=None, - io_loop=None, ssl_options=None, headers=None): + io_loop=None, ssl_options=None, headers=None, exclude_headers=None): """ .. code-block:: python @@ -32,7 +32,7 @@ ioloop.IOLoop.instance().start() """ WebSocketBaseClient.__init__(self, url, protocols, extensions, - ssl_options=ssl_options, headers=headers) + ssl_options=ssl_options, headers=headers, exclude_headers=exclude_headers) if self.scheme == "wss": self.sock = ssl.wrap_socket(self.sock, do_handshake_on_connect=False, **self.ssl_options) self._is_secure = True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/ws4py/server/cherrypyserver.py new/ws4py-0.5.1/ws4py/server/cherrypyserver.py --- old/ws4py-0.4.2/ws4py/server/cherrypyserver.py 2017-03-23 00:21:52.000000000 +0100 +++ new/ws4py-0.5.1/ws4py/server/cherrypyserver.py 2017-12-19 10:15:47.000000000 +0100 @@ -272,14 +272,14 @@ break _locals = current.f_locals if 'self' in _locals: - if type(_locals['self']) == HTTPRequest: - _locals['self'].close_connection = True - if type(_locals['self']) == HTTPConnection: - _locals['self'].linger = True - # HTTPConnection is more inner than - # HTTPRequest so we can leave once - # we're done here - return + if isinstance(_locals['self'], HTTPRequest): + _locals['self'].close_connection = True + if isinstance(_locals['self'], HTTPConnection): + _locals['self'].linger = True + # HTTPConnection is more inner than + # HTTPRequest so we can leave once + # we're done here + return _locals = None current = current.f_back diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/ws4py/server/geventserver.py new/ws4py-0.5.1/ws4py/server/geventserver.py --- old/ws4py-0.4.2/ws4py/server/geventserver.py 2017-03-23 00:21:52.000000000 +0100 +++ new/ws4py-0.5.1/ws4py/server/geventserver.py 2018-02-27 08:55:33.000000000 +0100 @@ -78,7 +78,7 @@ def clear(self): logger.info("Terminating server and all connected websockets") - for greenlet in self: + for greenlet in list(self): try: websocket = greenlet._run.im_self if websocket: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/ws4py/server/tulipserver.py new/ws4py-0.5.1/ws4py/server/tulipserver.py --- old/ws4py-0.4.2/ws4py/server/tulipserver.py 1970-01-01 01:00:00.000000000 +0100 +++ new/ws4py-0.5.1/ws4py/server/tulipserver.py 2017-05-09 12:35:59.000000000 +0200 @@ -0,0 +1,224 @@ +# -*- coding: utf-8 -*- +import base64 +from hashlib import sha1 +from email.parser import BytesHeaderParser +import io + +import asyncio + +from ws4py import WS_KEY, WS_VERSION +from ws4py.exc import HandshakeError +from ws4py.websocket import WebSocket + +LF = b'\n' +CRLF = b'\r\n' +SPACE = b' ' +EMPTY = b'' + +__all__ = ['WebSocketProtocol'] + +class WebSocketProtocol(asyncio.StreamReaderProtocol): + def __init__(self, handler_cls): + asyncio.StreamReaderProtocol.__init__(self, asyncio.StreamReader(), + self._pseudo_connected) + self.ws = handler_cls(self) + + def _pseudo_connected(self, reader, writer): + pass + + def connection_made(self, transport): + """ + A peer is now connected and we receive an instance + of the underlying :class:`asyncio.Transport`. + + We :class:`asyncio.StreamReader` is created + and the transport is associated before the + initial HTTP handshake is undertaken. + """ + #self.transport = transport + #self.stream = asyncio.StreamReader() + #self.stream.set_transport(transport) + asyncio.StreamReaderProtocol.connection_made(self, transport) + # Let make it concurrent for others to tag along + f = asyncio.async(self.handle_initial_handshake()) + f.add_done_callback(self.terminated) + + @property + def writer(self): + return self._stream_writer + + @property + def reader(self): + return self._stream_reader + + def terminated(self, f): + if f.done() and not f.cancelled(): + ex = f.exception() + if ex: + response = [b'HTTP/1.0 400 Bad Request'] + response.append(b'Content-Length: 0') + response.append(b'Connection: close') + response.append(b'') + response.append(b'') + self.writer.write(CRLF.join(response)) + self.ws.close_connection() + + def close(self): + """ + Initiate the websocket closing handshake + which will eventuall lead to the underlying + transport. + """ + self.ws.close() + + def timeout(self): + self.ws.close_connection() + if self.ws.started: + self.ws.closed(1002, "Peer connection timed-out") + + def connection_lost(self, exc): + """ + The peer connection is now, the closing + handshake won't work so let's not even try. + However let's make the websocket handler + be aware of it by calling its `closed` + method. + """ + if exc is not None: + self.ws.close_connection() + if self.ws.started: + self.ws.closed(1002, "Peer connection was lost") + + @asyncio.coroutine + def handle_initial_handshake(self): + """ + Performs the HTTP handshake described in :rfc:`6455`. Note that + this implementation is really basic and it is strongly advised + against using it in production. It would probably break for + most clients. If you want a better support for HTTP, please + use a more reliable HTTP server implemented using asyncio. + """ + request_line = yield from self.next_line() + method, uri, req_protocol = request_line.strip().split(SPACE, 2) + + # GET required + if method.upper() != b'GET': + raise HandshakeError('HTTP method must be a GET') + + headers = yield from self.read_headers() + if req_protocol == b'HTTP/1.1' and 'Host' not in headers: + raise ValueError("Missing host header") + + for key, expected_value in [('Upgrade', 'websocket'), + ('Connection', 'upgrade')]: + actual_value = headers.get(key, '').lower() + if not actual_value: + raise HandshakeError('Header %s is not defined' % str(key)) + if expected_value not in actual_value: + raise HandshakeError('Illegal value for header %s: %s' % + (key, actual_value)) + + response_headers = {} + + ws_version = WS_VERSION + version = headers.get('Sec-WebSocket-Version') + supported_versions = ', '.join([str(v) for v in ws_version]) + version_is_valid = False + if version: + try: version = int(version) + except: pass + else: version_is_valid = version in ws_version + + if not version_is_valid: + response_headers['Sec-WebSocket-Version'] = supported_versions + raise HandshakeError('Unhandled or missing WebSocket version') + + key = headers.get('Sec-WebSocket-Key') + if key: + ws_key = base64.b64decode(key.encode('utf-8')) + if len(ws_key) != 16: + raise HandshakeError("WebSocket key's length is invalid") + + protocols = [] + ws_protocols = [] + subprotocols = headers.get('Sec-WebSocket-Protocol') + if subprotocols: + for s in subprotocols.split(','): + s = s.strip() + if s in protocols: + ws_protocols.append(s) + + exts = [] + ws_extensions = [] + extensions = headers.get('Sec-WebSocket-Extensions') + if extensions: + for ext in extensions.split(','): + ext = ext.strip() + if ext in exts: + ws_extensions.append(ext) + + self.ws.protocols = ws_protocols + self.ws.extensions = ws_extensions + self.ws.headers = headers + + response = [req_protocol + b' 101 Switching Protocols'] + response.append(b'Upgrade: websocket') + response.append(b'Content-Type: text/plain') + response.append(b'Content-Length: 0') + response.append(b'Connection: Upgrade') + response.append(b'Sec-WebSocket-Version:' + bytes(str(version), 'utf-8')) + response.append(b'Sec-WebSocket-Accept:' + base64.b64encode(sha1(key.encode('utf-8') + WS_KEY).digest())) + if ws_protocols: + response.append(b'Sec-WebSocket-Protocol:' + b', '.join(ws_protocols)) + if ws_extensions: + response.append(b'Sec-WebSocket-Extensions:' + b','.join(ws_extensions)) + response.append(b'') + response.append(b'') + self.writer.write(CRLF.join(response)) + yield from self.handle_websocket() + + @asyncio.coroutine + def handle_websocket(self): + """ + Starts the websocket process until the + exchange is completed and terminated. + """ + yield from self.ws.run() + + @asyncio.coroutine + def read_headers(self): + """ + Read all HTTP headers from the HTTP request + and returns a dictionary of them. + """ + headers = b'' + while True: + line = yield from self.next_line() + headers += line + if line == CRLF: + break + return BytesHeaderParser().parsebytes(headers) + + @asyncio.coroutine + def next_line(self): + """ + Reads data until \r\n is met and then return all read + bytes. + """ + line = yield from self.reader.readline() + if not line.endswith(CRLF): + raise ValueError("Missing mandatory trailing CRLF") + return line + +if __name__ == '__main__': + from ws4py.async_websocket import EchoWebSocket + + loop = asyncio.get_event_loop() + + def start_server(): + proto_factory = lambda: WebSocketProtocol(EchoWebSocket) + return loop.create_server(proto_factory, '', 9007) + + s = loop.run_until_complete(start_server()) + print('serving on', s.sockets[0].getsockname()) + loop.run_forever() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/ws4py/websocket.py new/ws4py-0.5.1/ws4py/websocket.py --- old/ws4py-0.4.2/ws4py/websocket.py 2017-03-29 19:56:41.000000000 +0200 +++ new/ws4py-0.5.1/ws4py/websocket.py 2018-02-27 08:55:33.000000000 +0100 @@ -387,10 +387,12 @@ logger.debug("WebSocket is already terminated") return False try: - b = self.sock.recv(self.reading_buffer_size) + b = b'' if self._is_secure: - b += self._get_from_pending() - if not b: + b = self._get_from_pending() + if not b and not self.buf: + b = self.sock.recv(self.reading_buffer_size) + if not b and not self.buf: return False self.buf += b except (socket.error, OSError, pyOpenSSLError) as e: @@ -403,9 +405,11 @@ # process as much as we can # the process will stop either if there is no buffer left # or if the stream is closed - if not self.process(self.buf): + # only pass the requested number of bytes, leave the rest in the buffer + requested = self.reading_buffer_size + if not self.process(self.buf[:requested]): return False - self.buf = b"" + self.buf = self.buf[requested:] return True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/ws4py.egg-info/PKG-INFO new/ws4py-0.5.1/ws4py.egg-info/PKG-INFO --- old/ws4py-0.4.2/ws4py.egg-info/PKG-INFO 2017-03-29 19:57:06.000000000 +0200 +++ new/ws4py-0.5.1/ws4py.egg-info/PKG-INFO 2018-02-28 18:40:21.000000000 +0100 @@ -1,12 +1,13 @@ Metadata-Version: 1.1 Name: ws4py -Version: 0.4.2 +Version: 0.5.1 Summary: WebSocket client and server library for Python 2 and 3 as well as PyPy Home-page: https://github.com/Lawouach/WebSocket-for-Python Author: Sylvain Hellegouarch Author-email: [email protected] License: BSD Download-URL: https://pypi.python.org/pypi/ws4py +Description-Content-Type: UNKNOWN Description: WebSocket client and server library for Python 2 and 3 as well as PyPy Platform: any Classifier: Development Status :: 5 - Production/Stable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ws4py-0.4.2/ws4py.egg-info/SOURCES.txt new/ws4py-0.5.1/ws4py.egg-info/SOURCES.txt --- old/ws4py-0.4.2/ws4py.egg-info/SOURCES.txt 2017-03-29 19:57:06.000000000 +0200 +++ new/ws4py-0.5.1/ws4py.egg-info/SOURCES.txt 2018-02-28 18:40:21.000000000 +0100 @@ -1,3 +1,7 @@ +CHANGELOG.md +LICENSE +MANIFEST.in +README.md setup.py test/test_cherrypy.py test/test_client.py @@ -9,6 +13,7 @@ test/test_utils.py test/test_websocket.py ws4py/__init__.py +ws4py/async_websocket.py ws4py/compat.py ws4py/exc.py ws4py/framing.py @@ -28,5 +33,6 @@ ws4py/server/__init__.py ws4py/server/cherrypyserver.py ws4py/server/geventserver.py +ws4py/server/tulipserver.py ws4py/server/wsgirefserver.py ws4py/server/wsgiutils.py \ No newline at end of file
