mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-15 01:32:57 -07:00
Bump websocket-client from 1.3.2 to 1.4.2 (#1886)
* Bump websocket-client from 1.3.2 to 1.4.2 Bumps [websocket-client](https://github.com/websocket-client/websocket-client) from 1.3.2 to 1.4.2. - [Release notes](https://github.com/websocket-client/websocket-client/releases) - [Changelog](https://github.com/websocket-client/websocket-client/blob/master/ChangeLog) - [Commits](https://github.com/websocket-client/websocket-client/compare/v1.3.2...v1.4.2) --- updated-dependencies: - dependency-name: websocket-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Update websocket-client==1.4.2 Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci]
This commit is contained in:
parent
a5ccc9a1a3
commit
3af08f0d07
10 changed files with 177 additions and 101 deletions
|
@ -17,10 +17,10 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
"""
|
"""
|
||||||
from ._abnf import *
|
from ._abnf import *
|
||||||
from ._app import WebSocketApp
|
from ._app import WebSocketApp, setReconnect
|
||||||
from ._core import *
|
from ._core import *
|
||||||
from ._exceptions import *
|
from ._exceptions import *
|
||||||
from ._logging import *
|
from ._logging import *
|
||||||
from ._socket import *
|
from ._socket import *
|
||||||
|
|
||||||
__version__ = "1.3.2"
|
__version__ = "1.4.2"
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
import inspect
|
||||||
import selectors
|
import selectors
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from ._abnf import ABNF
|
from ._abnf import ABNF
|
||||||
|
from ._url import parse_url
|
||||||
from ._core import WebSocket, getdefaulttimeout
|
from ._core import WebSocket, getdefaulttimeout
|
||||||
from ._exceptions import *
|
from ._exceptions import *
|
||||||
from . import _logging
|
from . import _logging
|
||||||
|
@ -29,15 +31,40 @@ limitations under the License.
|
||||||
|
|
||||||
__all__ = ["WebSocketApp"]
|
__all__ = ["WebSocketApp"]
|
||||||
|
|
||||||
|
RECONNECT = 0
|
||||||
|
|
||||||
class Dispatcher:
|
|
||||||
|
def setReconnect(reconnectInterval):
|
||||||
|
global RECONNECT
|
||||||
|
RECONNECT = reconnectInterval
|
||||||
|
|
||||||
|
|
||||||
|
class DispatcherBase:
|
||||||
"""
|
"""
|
||||||
Dispatcher
|
DispatcherBase
|
||||||
"""
|
"""
|
||||||
def __init__(self, app, ping_timeout):
|
def __init__(self, app, ping_timeout):
|
||||||
self.app = app
|
self.app = app
|
||||||
self.ping_timeout = ping_timeout
|
self.ping_timeout = ping_timeout
|
||||||
|
|
||||||
|
def timeout(self, seconds, callback):
|
||||||
|
time.sleep(seconds)
|
||||||
|
callback()
|
||||||
|
|
||||||
|
def reconnect(self, seconds, reconnector):
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
_logging.info("reconnect() - retrying in %s seconds [%s frames in stack]" % (seconds, len(inspect.stack())))
|
||||||
|
time.sleep(seconds)
|
||||||
|
reconnector(reconnecting=True)
|
||||||
|
except KeyboardInterrupt as e:
|
||||||
|
_logging.info("User exited %s" % (e,))
|
||||||
|
|
||||||
|
|
||||||
|
class Dispatcher(DispatcherBase):
|
||||||
|
"""
|
||||||
|
Dispatcher
|
||||||
|
"""
|
||||||
def read(self, sock, read_callback, check_callback):
|
def read(self, sock, read_callback, check_callback):
|
||||||
while self.app.keep_running:
|
while self.app.keep_running:
|
||||||
sel = selectors.DefaultSelector()
|
sel = selectors.DefaultSelector()
|
||||||
|
@ -51,14 +78,10 @@ class Dispatcher:
|
||||||
sel.close()
|
sel.close()
|
||||||
|
|
||||||
|
|
||||||
class SSLDispatcher:
|
class SSLDispatcher(DispatcherBase):
|
||||||
"""
|
"""
|
||||||
SSLDispatcher
|
SSLDispatcher
|
||||||
"""
|
"""
|
||||||
def __init__(self, app, ping_timeout):
|
|
||||||
self.app = app
|
|
||||||
self.ping_timeout = ping_timeout
|
|
||||||
|
|
||||||
def read(self, sock, read_callback, check_callback):
|
def read(self, sock, read_callback, check_callback):
|
||||||
while self.app.keep_running:
|
while self.app.keep_running:
|
||||||
r = self.select()
|
r = self.select()
|
||||||
|
@ -90,10 +113,17 @@ class WrappedDispatcher:
|
||||||
self.app = app
|
self.app = app
|
||||||
self.ping_timeout = ping_timeout
|
self.ping_timeout = ping_timeout
|
||||||
self.dispatcher = dispatcher
|
self.dispatcher = dispatcher
|
||||||
|
dispatcher.signal(2, dispatcher.abort) # keyboard interrupt
|
||||||
|
|
||||||
def read(self, sock, read_callback, check_callback):
|
def read(self, sock, read_callback, check_callback):
|
||||||
self.dispatcher.read(sock, read_callback)
|
self.dispatcher.read(sock, read_callback)
|
||||||
self.ping_timeout and self.dispatcher.timeout(self.ping_timeout, check_callback)
|
self.ping_timeout and self.timeout(self.ping_timeout, check_callback)
|
||||||
|
|
||||||
|
def timeout(self, seconds, callback):
|
||||||
|
self.dispatcher.timeout(seconds, callback)
|
||||||
|
|
||||||
|
def reconnect(self, seconds, reconnector):
|
||||||
|
self.timeout(seconds, reconnector)
|
||||||
|
|
||||||
|
|
||||||
class WebSocketApp:
|
class WebSocketApp:
|
||||||
|
@ -186,6 +216,7 @@ class WebSocketApp:
|
||||||
self.last_pong_tm = 0
|
self.last_pong_tm = 0
|
||||||
self.subprotocols = subprotocols
|
self.subprotocols = subprotocols
|
||||||
self.prepared_socket = socket
|
self.prepared_socket = socket
|
||||||
|
self.has_errored = False
|
||||||
|
|
||||||
def send(self, data, opcode=ABNF.OPCODE_TEXT):
|
def send(self, data, opcode=ABNF.OPCODE_TEXT):
|
||||||
"""
|
"""
|
||||||
|
@ -228,9 +259,10 @@ class WebSocketApp:
|
||||||
ping_payload="",
|
ping_payload="",
|
||||||
http_proxy_host=None, http_proxy_port=None,
|
http_proxy_host=None, http_proxy_port=None,
|
||||||
http_no_proxy=None, http_proxy_auth=None,
|
http_no_proxy=None, http_proxy_auth=None,
|
||||||
|
http_proxy_timeout=None,
|
||||||
skip_utf8_validation=False,
|
skip_utf8_validation=False,
|
||||||
host=None, origin=None, dispatcher=None,
|
host=None, origin=None, dispatcher=None,
|
||||||
suppress_origin=False, proxy_type=None):
|
suppress_origin=False, proxy_type=None, reconnect=None):
|
||||||
"""
|
"""
|
||||||
Run event loop for WebSocket framework.
|
Run event loop for WebSocket framework.
|
||||||
|
|
||||||
|
@ -258,6 +290,10 @@ class WebSocketApp:
|
||||||
HTTP proxy port. If not set, set to 80.
|
HTTP proxy port. If not set, set to 80.
|
||||||
http_no_proxy: list
|
http_no_proxy: list
|
||||||
Whitelisted host names that don't use the proxy.
|
Whitelisted host names that don't use the proxy.
|
||||||
|
http_proxy_timeout: int or float
|
||||||
|
HTTP proxy timeout, default is 60 sec as per python-socks.
|
||||||
|
http_proxy_auth: tuple
|
||||||
|
HTTP proxy auth information. tuple of username and password. Default is None.
|
||||||
skip_utf8_validation: bool
|
skip_utf8_validation: bool
|
||||||
skip utf8 validation.
|
skip utf8 validation.
|
||||||
host: str
|
host: str
|
||||||
|
@ -268,6 +304,10 @@ class WebSocketApp:
|
||||||
customize reading data from socket.
|
customize reading data from socket.
|
||||||
suppress_origin: bool
|
suppress_origin: bool
|
||||||
suppress outputting origin header.
|
suppress outputting origin header.
|
||||||
|
proxy_type: str
|
||||||
|
type of proxy from: http, socks4, socks4a, socks5, socks5h
|
||||||
|
reconnect: int
|
||||||
|
delay interval when reconnecting
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -276,6 +316,9 @@ class WebSocketApp:
|
||||||
True if any other exception was raised during a loop.
|
True if any other exception was raised during a loop.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if reconnect is None:
|
||||||
|
reconnect = RECONNECT
|
||||||
|
|
||||||
if ping_timeout is not None and ping_timeout <= 0:
|
if ping_timeout is not None and ping_timeout <= 0:
|
||||||
raise WebSocketException("Ensure ping_timeout > 0")
|
raise WebSocketException("Ensure ping_timeout > 0")
|
||||||
if ping_interval is not None and ping_interval < 0:
|
if ping_interval is not None and ping_interval < 0:
|
||||||
|
@ -317,84 +360,105 @@ class WebSocketApp:
|
||||||
# Finally call the callback AFTER all teardown is complete
|
# Finally call the callback AFTER all teardown is complete
|
||||||
self._callback(self.on_close, close_status_code, close_reason)
|
self._callback(self.on_close, close_status_code, close_reason)
|
||||||
|
|
||||||
try:
|
def setSock(reconnecting=False):
|
||||||
self.sock = WebSocket(
|
self.sock = WebSocket(
|
||||||
self.get_mask_key, sockopt=sockopt, sslopt=sslopt,
|
self.get_mask_key, sockopt=sockopt, sslopt=sslopt,
|
||||||
fire_cont_frame=self.on_cont_message is not None,
|
fire_cont_frame=self.on_cont_message is not None,
|
||||||
skip_utf8_validation=skip_utf8_validation,
|
skip_utf8_validation=skip_utf8_validation,
|
||||||
enable_multithread=True)
|
enable_multithread=True)
|
||||||
self.sock.settimeout(getdefaulttimeout())
|
self.sock.settimeout(getdefaulttimeout())
|
||||||
self.sock.connect(
|
try:
|
||||||
self.url, header=self.header, cookie=self.cookie,
|
self.sock.connect(
|
||||||
http_proxy_host=http_proxy_host,
|
self.url, header=self.header, cookie=self.cookie,
|
||||||
http_proxy_port=http_proxy_port, http_no_proxy=http_no_proxy,
|
http_proxy_host=http_proxy_host,
|
||||||
http_proxy_auth=http_proxy_auth, subprotocols=self.subprotocols,
|
http_proxy_port=http_proxy_port, http_no_proxy=http_no_proxy,
|
||||||
host=host, origin=origin, suppress_origin=suppress_origin,
|
http_proxy_auth=http_proxy_auth, http_proxy_timeout=http_proxy_timeout,
|
||||||
proxy_type=proxy_type, socket=self.prepared_socket)
|
subprotocols=self.subprotocols,
|
||||||
dispatcher = self.create_dispatcher(ping_timeout, dispatcher)
|
host=host, origin=origin, suppress_origin=suppress_origin,
|
||||||
|
proxy_type=proxy_type, socket=self.prepared_socket)
|
||||||
|
|
||||||
self._callback(self.on_open)
|
self._callback(self.on_open)
|
||||||
|
|
||||||
if ping_interval:
|
_logging.warning("websocket connected")
|
||||||
event = threading.Event()
|
dispatcher.read(self.sock.sock, read, check)
|
||||||
thread = threading.Thread(
|
except (WebSocketConnectionClosedException, ConnectionRefusedError, KeyboardInterrupt, SystemExit, Exception) as e:
|
||||||
target=self._send_ping, args=(ping_interval, event, ping_payload))
|
_logging.error("%s - %s" % (e, reconnect and "reconnecting" or "goodbye"))
|
||||||
thread.daemon = True
|
reconnecting or handleDisconnect(e)
|
||||||
thread.start()
|
|
||||||
|
|
||||||
def read():
|
def read():
|
||||||
if not self.keep_running:
|
if not self.keep_running:
|
||||||
return teardown()
|
return teardown()
|
||||||
|
|
||||||
|
try:
|
||||||
op_code, frame = self.sock.recv_data_frame(True)
|
op_code, frame = self.sock.recv_data_frame(True)
|
||||||
if op_code == ABNF.OPCODE_CLOSE:
|
except (WebSocketConnectionClosedException, KeyboardInterrupt) as e:
|
||||||
return teardown(frame)
|
if custom_dispatcher:
|
||||||
elif op_code == ABNF.OPCODE_PING:
|
return handleDisconnect(e)
|
||||||
self._callback(self.on_ping, frame.data)
|
|
||||||
elif op_code == ABNF.OPCODE_PONG:
|
|
||||||
self.last_pong_tm = time.time()
|
|
||||||
self._callback(self.on_pong, frame.data)
|
|
||||||
elif op_code == ABNF.OPCODE_CONT and self.on_cont_message:
|
|
||||||
self._callback(self.on_data, frame.data,
|
|
||||||
frame.opcode, frame.fin)
|
|
||||||
self._callback(self.on_cont_message,
|
|
||||||
frame.data, frame.fin)
|
|
||||||
else:
|
else:
|
||||||
data = frame.data
|
raise e
|
||||||
if op_code == ABNF.OPCODE_TEXT:
|
if op_code == ABNF.OPCODE_CLOSE:
|
||||||
data = data.decode("utf-8")
|
return teardown(frame)
|
||||||
self._callback(self.on_data, data, frame.opcode, True)
|
elif op_code == ABNF.OPCODE_PING:
|
||||||
self._callback(self.on_message, data)
|
self._callback(self.on_ping, frame.data)
|
||||||
|
elif op_code == ABNF.OPCODE_PONG:
|
||||||
|
self.last_pong_tm = time.time()
|
||||||
|
self._callback(self.on_pong, frame.data)
|
||||||
|
elif op_code == ABNF.OPCODE_CONT and self.on_cont_message:
|
||||||
|
self._callback(self.on_data, frame.data,
|
||||||
|
frame.opcode, frame.fin)
|
||||||
|
self._callback(self.on_cont_message,
|
||||||
|
frame.data, frame.fin)
|
||||||
|
else:
|
||||||
|
data = frame.data
|
||||||
|
if op_code == ABNF.OPCODE_TEXT:
|
||||||
|
data = data.decode("utf-8")
|
||||||
|
self._callback(self.on_data, data, frame.opcode, True)
|
||||||
|
self._callback(self.on_message, data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def check():
|
def check():
|
||||||
if (ping_timeout):
|
if (ping_timeout):
|
||||||
has_timeout_expired = time.time() - self.last_ping_tm > ping_timeout
|
has_timeout_expired = time.time() - self.last_ping_tm > ping_timeout
|
||||||
has_pong_not_arrived_after_last_ping = self.last_pong_tm - self.last_ping_tm < 0
|
has_pong_not_arrived_after_last_ping = self.last_pong_tm - self.last_ping_tm < 0
|
||||||
has_pong_arrived_too_late = self.last_pong_tm - self.last_ping_tm > ping_timeout
|
has_pong_arrived_too_late = self.last_pong_tm - self.last_ping_tm > ping_timeout
|
||||||
|
|
||||||
if (self.last_ping_tm and
|
if (self.last_ping_tm and
|
||||||
has_timeout_expired and
|
has_timeout_expired and
|
||||||
(has_pong_not_arrived_after_last_ping or has_pong_arrived_too_late)):
|
(has_pong_not_arrived_after_last_ping or has_pong_arrived_too_late)):
|
||||||
raise WebSocketTimeoutException("ping/pong timed out")
|
raise WebSocketTimeoutException("ping/pong timed out")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
dispatcher.read(self.sock.sock, read, check)
|
def handleDisconnect(e):
|
||||||
return False
|
self.has_errored = True
|
||||||
except (Exception, KeyboardInterrupt, SystemExit) as e:
|
|
||||||
self._callback(self.on_error, e)
|
self._callback(self.on_error, e)
|
||||||
if isinstance(e, SystemExit):
|
if isinstance(e, SystemExit):
|
||||||
# propagate SystemExit further
|
# propagate SystemExit further
|
||||||
raise
|
raise
|
||||||
teardown()
|
if reconnect and not isinstance(e, KeyboardInterrupt):
|
||||||
return not isinstance(e, KeyboardInterrupt)
|
_logging.info("websocket disconnected (retrying in %s seconds) [%s frames in stack]" % (reconnect, len(inspect.stack())))
|
||||||
|
dispatcher.reconnect(reconnect, setSock)
|
||||||
|
else:
|
||||||
|
teardown()
|
||||||
|
|
||||||
def create_dispatcher(self, ping_timeout, dispatcher=None):
|
custom_dispatcher = bool(dispatcher)
|
||||||
|
dispatcher = self.create_dispatcher(ping_timeout, dispatcher, parse_url(self.url)[3])
|
||||||
|
|
||||||
|
if ping_interval:
|
||||||
|
event = threading.Event()
|
||||||
|
thread = threading.Thread(
|
||||||
|
target=self._send_ping, args=(ping_interval, event, ping_payload))
|
||||||
|
thread.daemon = True
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
setSock()
|
||||||
|
return self.has_errored
|
||||||
|
|
||||||
|
def create_dispatcher(self, ping_timeout, dispatcher=None, is_ssl=False):
|
||||||
if dispatcher: # If custom dispatcher is set, use WrappedDispatcher
|
if dispatcher: # If custom dispatcher is set, use WrappedDispatcher
|
||||||
return WrappedDispatcher(self, ping_timeout, dispatcher)
|
return WrappedDispatcher(self, ping_timeout, dispatcher)
|
||||||
timeout = ping_timeout or 10
|
timeout = ping_timeout or 10
|
||||||
if self.sock.is_ssl():
|
if is_ssl:
|
||||||
return SSLDispatcher(self, timeout)
|
return SSLDispatcher(self, timeout)
|
||||||
|
|
||||||
return Dispatcher(self, timeout)
|
return Dispatcher(self, timeout)
|
||||||
|
|
|
@ -46,8 +46,11 @@ class WebSocket:
|
||||||
|
|
||||||
>>> import websocket
|
>>> import websocket
|
||||||
>>> ws = websocket.WebSocket()
|
>>> ws = websocket.WebSocket()
|
||||||
>>> ws.connect("ws://echo.websocket.org")
|
>>> ws.connect("ws://echo.websocket.events")
|
||||||
|
>>> ws.recv()
|
||||||
|
'echo.websocket.events sponsored by Lob.com'
|
||||||
>>> ws.send("Hello, Server")
|
>>> ws.send("Hello, Server")
|
||||||
|
19
|
||||||
>>> ws.recv()
|
>>> ws.recv()
|
||||||
'Hello, Server'
|
'Hello, Server'
|
||||||
>>> ws.close()
|
>>> ws.close()
|
||||||
|
@ -203,7 +206,7 @@ class WebSocket:
|
||||||
If you set "header" list object, you can set your own custom header.
|
If you set "header" list object, you can set your own custom header.
|
||||||
|
|
||||||
>>> ws = WebSocket()
|
>>> ws = WebSocket()
|
||||||
>>> ws.connect("ws://echo.websocket.org/",
|
>>> ws.connect("ws://echo.websocket.events",
|
||||||
... header=["User-Agent: MyProgram",
|
... header=["User-Agent: MyProgram",
|
||||||
... "x-custom: header"])
|
... "x-custom: header"])
|
||||||
|
|
||||||
|
@ -233,6 +236,8 @@ class WebSocket:
|
||||||
Whitelisted host names that don't use the proxy.
|
Whitelisted host names that don't use the proxy.
|
||||||
http_proxy_auth: tuple
|
http_proxy_auth: tuple
|
||||||
HTTP proxy auth information. Tuple of username and password. Default is None.
|
HTTP proxy auth information. Tuple of username and password. Default is None.
|
||||||
|
http_proxy_timeout: int or float
|
||||||
|
HTTP proxy timeout, default is 60 sec as per python-socks.
|
||||||
redirect_limit: int
|
redirect_limit: int
|
||||||
Number of redirects to follow.
|
Number of redirects to follow.
|
||||||
subprotocols: list
|
subprotocols: list
|
||||||
|
@ -281,7 +286,7 @@ class WebSocket:
|
||||||
"""
|
"""
|
||||||
Send the data frame.
|
Send the data frame.
|
||||||
|
|
||||||
>>> ws = create_connection("ws://echo.websocket.org/")
|
>>> ws = create_connection("ws://echo.websocket.events")
|
||||||
>>> frame = ABNF.create_frame("Hello", ABNF.OPCODE_TEXT)
|
>>> frame = ABNF.create_frame("Hello", ABNF.OPCODE_TEXT)
|
||||||
>>> ws.send_frame(frame)
|
>>> ws.send_frame(frame)
|
||||||
>>> cont_frame = ABNF.create_frame("My name is ", ABNF.OPCODE_CONT, 0)
|
>>> cont_frame = ABNF.create_frame("My name is ", ABNF.OPCODE_CONT, 0)
|
||||||
|
@ -541,7 +546,7 @@ def create_connection(url, timeout=None, class_=WebSocket, **options):
|
||||||
You can customize using 'options'.
|
You can customize using 'options'.
|
||||||
If you set "header" list object, you can set your own custom header.
|
If you set "header" list object, you can set your own custom header.
|
||||||
|
|
||||||
>>> conn = create_connection("ws://echo.websocket.org/",
|
>>> conn = create_connection("ws://echo.websocket.events",
|
||||||
... header=["User-Agent: MyProgram",
|
... header=["User-Agent: MyProgram",
|
||||||
... "x-custom: header"])
|
... "x-custom: header"])
|
||||||
|
|
||||||
|
@ -572,6 +577,8 @@ def create_connection(url, timeout=None, class_=WebSocket, **options):
|
||||||
Whitelisted host names that don't use the proxy.
|
Whitelisted host names that don't use the proxy.
|
||||||
http_proxy_auth: tuple
|
http_proxy_auth: tuple
|
||||||
HTTP proxy auth information. tuple of username and password. Default is None.
|
HTTP proxy auth information. tuple of username and password. Default is None.
|
||||||
|
http_proxy_timeout: int or float
|
||||||
|
HTTP proxy timeout, default is 60 sec as per python-socks.
|
||||||
enable_multithread: bool
|
enable_multithread: bool
|
||||||
Enable lock for multithread.
|
Enable lock for multithread.
|
||||||
redirect_limit: int
|
redirect_limit: int
|
||||||
|
|
|
@ -81,7 +81,7 @@ def _get_handshake_headers(resource, url, host, port, options):
|
||||||
hostport = _pack_hostname(host)
|
hostport = _pack_hostname(host)
|
||||||
else:
|
else:
|
||||||
hostport = "%s:%d" % (_pack_hostname(host), port)
|
hostport = "%s:%d" % (_pack_hostname(host), port)
|
||||||
if "host" in options and options["host"] is not None:
|
if options.get("host"):
|
||||||
headers.append("Host: %s" % options["host"])
|
headers.append("Host: %s" % options["host"])
|
||||||
else:
|
else:
|
||||||
headers.append("Host: %s" % hostport)
|
headers.append("Host: %s" % hostport)
|
||||||
|
@ -89,7 +89,7 @@ def _get_handshake_headers(resource, url, host, port, options):
|
||||||
# scheme indicates whether http or https is used in Origin
|
# scheme indicates whether http or https is used in Origin
|
||||||
# The same approach is used in parse_url of _url.py to set default port
|
# The same approach is used in parse_url of _url.py to set default port
|
||||||
scheme, url = url.split(":", 1)
|
scheme, url = url.split(":", 1)
|
||||||
if "suppress_origin" not in options or not options["suppress_origin"]:
|
if not options.get("suppress_origin"):
|
||||||
if "origin" in options and options["origin"] is not None:
|
if "origin" in options and options["origin"] is not None:
|
||||||
headers.append("Origin: %s" % options["origin"])
|
headers.append("Origin: %s" % options["origin"])
|
||||||
elif scheme == "wss":
|
elif scheme == "wss":
|
||||||
|
@ -100,16 +100,15 @@ def _get_handshake_headers(resource, url, host, port, options):
|
||||||
key = _create_sec_websocket_key()
|
key = _create_sec_websocket_key()
|
||||||
|
|
||||||
# Append Sec-WebSocket-Key & Sec-WebSocket-Version if not manually specified
|
# Append Sec-WebSocket-Key & Sec-WebSocket-Version if not manually specified
|
||||||
if 'header' not in options or 'Sec-WebSocket-Key' not in options['header']:
|
if not options.get('header') or 'Sec-WebSocket-Key' not in options['header']:
|
||||||
key = _create_sec_websocket_key()
|
|
||||||
headers.append("Sec-WebSocket-Key: %s" % key)
|
headers.append("Sec-WebSocket-Key: %s" % key)
|
||||||
else:
|
else:
|
||||||
key = options['header']['Sec-WebSocket-Key']
|
key = options['header']['Sec-WebSocket-Key']
|
||||||
|
|
||||||
if 'header' not in options or 'Sec-WebSocket-Version' not in options['header']:
|
if not options.get('header') or 'Sec-WebSocket-Version' not in options['header']:
|
||||||
headers.append("Sec-WebSocket-Version: %s" % VERSION)
|
headers.append("Sec-WebSocket-Version: %s" % VERSION)
|
||||||
|
|
||||||
if 'connection' not in options or options['connection'] is None:
|
if not options.get('connection'):
|
||||||
headers.append('Connection: Upgrade')
|
headers.append('Connection: Upgrade')
|
||||||
else:
|
else:
|
||||||
headers.append(options['connection'])
|
headers.append(options['connection'])
|
||||||
|
@ -118,8 +117,8 @@ def _get_handshake_headers(resource, url, host, port, options):
|
||||||
if subprotocols:
|
if subprotocols:
|
||||||
headers.append("Sec-WebSocket-Protocol: %s" % ",".join(subprotocols))
|
headers.append("Sec-WebSocket-Protocol: %s" % ",".join(subprotocols))
|
||||||
|
|
||||||
if "header" in options:
|
header = options.get("header")
|
||||||
header = options["header"]
|
if header:
|
||||||
if isinstance(header, dict):
|
if isinstance(header, dict):
|
||||||
header = [
|
header = [
|
||||||
": ".join([k, v])
|
": ".join([k, v])
|
||||||
|
|
|
@ -23,7 +23,7 @@ import sys
|
||||||
|
|
||||||
from ._exceptions import *
|
from ._exceptions import *
|
||||||
from ._logging import *
|
from ._logging import *
|
||||||
from ._socket import*
|
from ._socket import *
|
||||||
from ._ssl_compat import *
|
from ._ssl_compat import *
|
||||||
from ._url import *
|
from ._url import *
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ class proxy_info:
|
||||||
self.no_proxy = options.get("http_no_proxy", None)
|
self.no_proxy = options.get("http_no_proxy", None)
|
||||||
self.proxy_protocol = options.get("proxy_type", "http")
|
self.proxy_protocol = options.get("proxy_type", "http")
|
||||||
# Note: If timeout not specified, default python-socks timeout is 60 seconds
|
# Note: If timeout not specified, default python-socks timeout is 60 seconds
|
||||||
self.proxy_timeout = options.get("timeout", None)
|
self.proxy_timeout = options.get("http_proxy_timeout", None)
|
||||||
if self.proxy_protocol not in ['http', 'socks4', 'socks4a', 'socks5', 'socks5h']:
|
if self.proxy_protocol not in ['http', 'socks4', 'socks4a', 'socks5', 'socks5h']:
|
||||||
raise ProxyError("Only http, socks4, socks5 proxy protocols are supported")
|
raise ProxyError("Only http, socks4, socks5 proxy protocols are supported")
|
||||||
else:
|
else:
|
||||||
|
@ -114,22 +114,22 @@ def connect(url, options, proxy, socket):
|
||||||
if proxy.proxy_host and not socket and not (proxy.proxy_protocol == "http"):
|
if proxy.proxy_host and not socket and not (proxy.proxy_protocol == "http"):
|
||||||
return _start_proxied_socket(url, options, proxy)
|
return _start_proxied_socket(url, options, proxy)
|
||||||
|
|
||||||
hostname, port, resource, is_secure = parse_url(url)
|
hostname, port_from_url, resource, is_secure = parse_url(url)
|
||||||
|
|
||||||
if socket:
|
if socket:
|
||||||
return socket, (hostname, port, resource)
|
return socket, (hostname, port_from_url, resource)
|
||||||
|
|
||||||
addrinfo_list, need_tunnel, auth = _get_addrinfo_list(
|
addrinfo_list, need_tunnel, auth = _get_addrinfo_list(
|
||||||
hostname, port, is_secure, proxy)
|
hostname, port_from_url, is_secure, proxy)
|
||||||
if not addrinfo_list:
|
if not addrinfo_list:
|
||||||
raise WebSocketException(
|
raise WebSocketException(
|
||||||
"Host not found.: " + hostname + ":" + str(port))
|
"Host not found.: " + hostname + ":" + str(port_from_url))
|
||||||
|
|
||||||
sock = None
|
sock = None
|
||||||
try:
|
try:
|
||||||
sock = _open_socket(addrinfo_list, options.sockopt, options.timeout)
|
sock = _open_socket(addrinfo_list, options.sockopt, options.timeout)
|
||||||
if need_tunnel:
|
if need_tunnel:
|
||||||
sock = _tunnel(sock, hostname, port, auth)
|
sock = _tunnel(sock, hostname, port_from_url, auth)
|
||||||
|
|
||||||
if is_secure:
|
if is_secure:
|
||||||
if HAVE_SSL:
|
if HAVE_SSL:
|
||||||
|
@ -137,7 +137,7 @@ def connect(url, options, proxy, socket):
|
||||||
else:
|
else:
|
||||||
raise WebSocketException("SSL not available.")
|
raise WebSocketException("SSL not available.")
|
||||||
|
|
||||||
return sock, (hostname, port, resource)
|
return sock, (hostname, port_from_url, resource)
|
||||||
except:
|
except:
|
||||||
if sock:
|
if sock:
|
||||||
sock.close()
|
sock.close()
|
||||||
|
@ -184,17 +184,16 @@ def _open_socket(addrinfo_list, sockopt, timeout):
|
||||||
try:
|
try:
|
||||||
sock.connect(address)
|
sock.connect(address)
|
||||||
except socket.error as error:
|
except socket.error as error:
|
||||||
|
sock.close()
|
||||||
error.remote_ip = str(address[0])
|
error.remote_ip = str(address[0])
|
||||||
try:
|
try:
|
||||||
eConnRefused = (errno.ECONNREFUSED, errno.WSAECONNREFUSED, errno.ENETUNREACH)
|
eConnRefused = (errno.ECONNREFUSED, errno.WSAECONNREFUSED, errno.ENETUNREACH)
|
||||||
except:
|
except AttributeError:
|
||||||
eConnRefused = (errno.ECONNREFUSED, errno.ENETUNREACH)
|
eConnRefused = (errno.ECONNREFUSED, errno.ENETUNREACH)
|
||||||
if error.errno in eConnRefused:
|
if error.errno in eConnRefused:
|
||||||
err = error
|
err = error
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
if sock:
|
|
||||||
sock.close()
|
|
||||||
raise error
|
raise error
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
|
@ -35,7 +35,7 @@ __all__ = ["enableTrace", "dump", "error", "warning", "debug", "trace",
|
||||||
"isEnabledForError", "isEnabledForDebug", "isEnabledForTrace"]
|
"isEnabledForError", "isEnabledForDebug", "isEnabledForTrace"]
|
||||||
|
|
||||||
|
|
||||||
def enableTrace(traceable, handler=logging.StreamHandler()):
|
def enableTrace(traceable, handler=logging.StreamHandler(), level="DEBUG"):
|
||||||
"""
|
"""
|
||||||
Turn on/off the traceability.
|
Turn on/off the traceability.
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ def enableTrace(traceable, handler=logging.StreamHandler()):
|
||||||
_traceEnabled = traceable
|
_traceEnabled = traceable
|
||||||
if traceable:
|
if traceable:
|
||||||
_logger.addHandler(handler)
|
_logger.addHandler(handler)
|
||||||
_logger.setLevel(logging.DEBUG)
|
_logger.setLevel(getattr(logging, level))
|
||||||
|
|
||||||
|
|
||||||
def dump(title, message):
|
def dump(title, message):
|
||||||
|
@ -70,6 +70,10 @@ def debug(msg):
|
||||||
_logger.debug(msg)
|
_logger.debug(msg)
|
||||||
|
|
||||||
|
|
||||||
|
def info(msg):
|
||||||
|
_logger.info(msg)
|
||||||
|
|
||||||
|
|
||||||
def trace(msg):
|
def trace(msg):
|
||||||
if _traceEnabled:
|
if _traceEnabled:
|
||||||
_logger.debug(msg)
|
_logger.debug(msg)
|
||||||
|
|
|
@ -80,7 +80,8 @@ class WebSocketAppTest(unittest.TestCase):
|
||||||
app = ws.WebSocketApp('ws://127.0.0.1:' + LOCAL_WS_SERVER_PORT, on_open=on_open, on_close=on_close, on_message=on_message)
|
app = ws.WebSocketApp('ws://127.0.0.1:' + LOCAL_WS_SERVER_PORT, on_open=on_open, on_close=on_close, on_message=on_message)
|
||||||
app.run_forever()
|
app.run_forever()
|
||||||
|
|
||||||
@unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled")
|
# @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled")
|
||||||
|
@unittest.skipUnless(False, "Test disabled for now (requires rel)")
|
||||||
def testRunForeverDispatcher(self):
|
def testRunForeverDispatcher(self):
|
||||||
""" A WebSocketApp should keep running as long as its self.keep_running
|
""" A WebSocketApp should keep running as long as its self.keep_running
|
||||||
is not False (in the boolean context).
|
is not False (in the boolean context).
|
||||||
|
@ -98,7 +99,9 @@ class WebSocketAppTest(unittest.TestCase):
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
app = ws.WebSocketApp('ws://127.0.0.1:' + LOCAL_WS_SERVER_PORT, on_open=on_open, on_message=on_message)
|
app = ws.WebSocketApp('ws://127.0.0.1:' + LOCAL_WS_SERVER_PORT, on_open=on_open, on_message=on_message)
|
||||||
app.run_forever(dispatcher="Dispatcher")
|
app.run_forever(dispatcher="Dispatcher") # doesn't work
|
||||||
|
# app.run_forever(dispatcher=rel) # would work
|
||||||
|
# rel.dispatch()
|
||||||
|
|
||||||
@unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled")
|
@unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled")
|
||||||
def testRunForeverTeardownCleanExit(self):
|
def testRunForeverTeardownCleanExit(self):
|
||||||
|
@ -188,7 +191,7 @@ class WebSocketAppTest(unittest.TestCase):
|
||||||
""" Test WebSocketApp binary opcode
|
""" Test WebSocketApp binary opcode
|
||||||
"""
|
"""
|
||||||
# The lack of wss:// in the URL below is on purpose
|
# The lack of wss:// in the URL below is on purpose
|
||||||
app = ws.WebSocketApp('streaming.vn.teslamotors.com/streaming/')
|
app = ws.WebSocketApp('wss://streaming.vn.teslamotors.com/streaming/')
|
||||||
app.run_forever(ping_interval=2, ping_timeout=1, ping_payload="Ping payload")
|
app.run_forever(ping_interval=2, ping_timeout=1, ping_payload="Ping payload")
|
||||||
|
|
||||||
@unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled")
|
@unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled")
|
||||||
|
|
|
@ -105,15 +105,15 @@ class HttpTest(unittest.TestCase):
|
||||||
if ws._http.HAVE_PYTHON_SOCKS:
|
if ws._http.HAVE_PYTHON_SOCKS:
|
||||||
# Need this check, otherwise case where python_socks is not installed triggers
|
# Need this check, otherwise case where python_socks is not installed triggers
|
||||||
# websocket._exceptions.WebSocketException: Python Socks is needed for SOCKS proxying but is not available
|
# websocket._exceptions.WebSocketException: Python Socks is needed for SOCKS proxying but is not available
|
||||||
self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks4", timeout=1))
|
self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks4", http_proxy_timeout=1))
|
||||||
self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks4a", timeout=1))
|
self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks4a", http_proxy_timeout=1))
|
||||||
self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks5", timeout=1))
|
self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks5", http_proxy_timeout=1))
|
||||||
self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks5h", timeout=1))
|
self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks5h", http_proxy_timeout=1))
|
||||||
self.assertRaises(ProxyConnectionError, connect, "wss://example.com", OptsList(), proxy_info(http_proxy_host="127.0.0.1", http_proxy_port=9999, proxy_type="socks4", timeout=1), None)
|
self.assertRaises(ProxyConnectionError, connect, "wss://example.com", OptsList(), proxy_info(http_proxy_host="127.0.0.1", http_proxy_port=9999, proxy_type="socks4", http_proxy_timeout=1), None)
|
||||||
|
|
||||||
self.assertRaises(TypeError, _get_addrinfo_list, None, 80, True, proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="9999", proxy_type="http"))
|
self.assertRaises(TypeError, _get_addrinfo_list, None, 80, True, proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="9999", proxy_type="http"))
|
||||||
self.assertRaises(TypeError, _get_addrinfo_list, None, 80, True, proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="9999", proxy_type="http"))
|
self.assertRaises(TypeError, _get_addrinfo_list, None, 80, True, proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="9999", proxy_type="http"))
|
||||||
self.assertRaises(socket.timeout, connect, "wss://google.com", OptsList(), proxy_info(http_proxy_host="8.8.8.8", http_proxy_port=9999, proxy_type="http", timeout=1), None)
|
self.assertRaises(socket.timeout, connect, "wss://google.com", OptsList(), proxy_info(http_proxy_host="8.8.8.8", http_proxy_port=9999, proxy_type="http", http_proxy_timeout=1), None)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
connect("wss://google.com", OptsList(), proxy_info(http_proxy_host="8.8.8.8", http_proxy_port=8080, proxy_type="http"), True),
|
connect("wss://google.com", OptsList(), proxy_info(http_proxy_host="8.8.8.8", http_proxy_port=8080, proxy_type="http"), True),
|
||||||
(True, ("google.com", 443, "/")))
|
(True, ("google.com", 443, "/")))
|
||||||
|
|
|
@ -432,7 +432,7 @@ class HandshakeTest(unittest.TestCase):
|
||||||
self.assertRaises(ws._exceptions.WebSocketBadStatusException,
|
self.assertRaises(ws._exceptions.WebSocketBadStatusException,
|
||||||
websock3.connect, "wss://api.bitfinex.com/ws/2", cookie="chocolate",
|
websock3.connect, "wss://api.bitfinex.com/ws/2", cookie="chocolate",
|
||||||
origin="testing_websockets.com",
|
origin="testing_websockets.com",
|
||||||
host="echo.websocket.org/websocket-client-test",
|
host="echo.websocket.events/websocket-client-test",
|
||||||
subprotocols=["testproto"],
|
subprotocols=["testproto"],
|
||||||
connection="Upgrade",
|
connection="Upgrade",
|
||||||
header={"CustomHeader1":"123",
|
header={"CustomHeader1":"123",
|
||||||
|
|
|
@ -47,7 +47,7 @@ tzdata==2022.6
|
||||||
tzlocal==4.2
|
tzlocal==4.2
|
||||||
urllib3==1.26.12
|
urllib3==1.26.12
|
||||||
webencodings==0.5.1
|
webencodings==0.5.1
|
||||||
websocket-client==1.3.2
|
websocket-client==1.4.2
|
||||||
xmltodict==0.13.0
|
xmltodict==0.13.0
|
||||||
zipp==3.10.0
|
zipp==3.10.0
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue