Merge remote-tracking branch 'origin/master' into tweaks

* origin/master:
  fixed #192 introduced close timeout
  fixed #199 WebSocketBadStatusException for handshake error
  fixed #198 introduce on_data callback to pass data type.
  documentation
  add space.
  Typo fix in README.rst
  Fix string formatting in exception
  add support for ssl cert chains to support client certs
This commit is contained in:
Noah Levitt
2015-09-23 00:46:21 +00:00
7 changed files with 44 additions and 8 deletions

View File

@@ -7,6 +7,12 @@ ChangeLog
- fixed timeout+ssl error handling bug on python 2.7.10 (#190)
- add proxy support to wsdump.py (#194)
- use wsaccel if available (#193)
- add support for ssl cert chains to support client certs (#195)
- fix string formatting in exception (#196)
- fix typo in README.rst (#197)
- introduce on_data callback to pass data type. (#198)
- WebSocketBadStatusException for Handshake error (#199)
- set close timeout (#192)
- 0.32.0

View File

@@ -62,7 +62,7 @@ Low Level API example::
print "Sending 'Hello, World'..."
ws.send("Hello, World")
print "Sent"
print "Reeiving..."
print "Receiving..."
result = ws.recv()
print "Received '%s'" % result
ws.close()

View File

@@ -48,7 +48,8 @@ class WebSocketApp(object):
on_close=None, on_ping=None, on_pong=None,
on_cont_message=None,
keep_running=True, get_mask_key=None, cookie=None,
subprotocols=None):
subprotocols=None,
on_data=None):
"""
url: websocket url.
header: custom header for websocket handshake.
@@ -71,6 +72,14 @@ class WebSocketApp(object):
The passing 2nd arugment is utf-8 string which we get from the server.
The 3rd arugment is continue flag. if 0, the data continue
to next frame data
on_data: callback object which is called when a message recieved.
This is called before on_message or on_cont_message,
and then on_message or on_cont_message is called.
on_data has 4 argument.
The 1st arugment is this class object.
The passing 2nd arugment is utf-8 string which we get from the server.
The 3rd argument is data type. ABNF.OPCODE_TEXT or ABNF.OPCODE_BINARY will be came.
The 4rd arugment is continue flag. if 0, the data continue
keep_running: a boolean flag indicating whether the app's main loop
should keep running, defaults to True
get_mask_key: a callable to produce new mask keys,
@@ -82,6 +91,7 @@ class WebSocketApp(object):
self.cookie = cookie
self.on_open = on_open
self.on_message = on_message
self.on_data = on_data
self.on_error = on_error
self.on_close = on_close
self.on_ping = on_ping
@@ -192,11 +202,13 @@ class WebSocketApp(object):
elif op_code == ABNF.OPCODE_PONG:
self._callback(self.on_pong, frame.data)
elif op_code == ABNF.OPCODE_CONT and self.on_cont_message:
self._callback(self.on_data, data, frame.opcode, frame.fin)
self._callback(self.on_cont_message, frame.data, frame.fin)
else:
data = frame.data
if six.PY3 and frame.opcode == ABNF.OPCODE_TEXT:
data = data.decode("utf-8")
self._callback(self.on_data, data, frame.opcode, True)
self._callback(self.on_message, data)
except Exception as e:
self._callback(self.on_error, e)

View File

@@ -422,13 +422,16 @@ class WebSocket(object):
self.connected = False
self.send(struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE)
def close(self, status=STATUS_NORMAL, reason=six.b("")):
def close(self, status=STATUS_NORMAL, reason=six.b(""), timeout=3):
"""
Close Websocket object
status: status code to send. see STATUS_XXX.
reason: the reason to close. This must be string.
timeout: timeout until recieve a close frame.
If None, it will wait forever until recieve a close frame.
"""
if self.connected:
if status < 0 or status >= ABNF.LENGTH_16:
@@ -437,8 +440,8 @@ class WebSocket(object):
try:
self.connected = False
self.send(struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE)
timeout = self.sock.gettimeout()
self.sock.settimeout(3)
sock_timeout = self.sock.gettimeout()
self.sock.settimeout(timeout)
try:
frame = self.recv_frame()
if isEnabledForError():
@@ -447,7 +450,7 @@ class WebSocket(object):
error("close status: " + repr(recv_status))
except:
pass
self.sock.settimeout(timeout)
self.sock.settimeout(sock_timeout)
self.sock.shutdown(socket.SHUT_RDWR)
except:
pass

View File

@@ -31,18 +31,21 @@ class WebSocketException(Exception):
"""
pass
class WebSocketProtocolException(WebSocketException):
"""
If the webscoket protocol is invalid, this exception will be raised.
"""
pass
class WebSocketPayloadException(WebSocketException):
"""
If the webscoket payload is invalid, this exception will be raised.
"""
pass
class WebSocketConnectionClosedException(WebSocketException):
"""
If remote host closed the connection or some network error happened,
@@ -50,12 +53,14 @@ class WebSocketConnectionClosedException(WebSocketException):
"""
pass
class WebSocketTimeoutException(WebSocketException):
"""
WebSocketTimeoutException will be raised at socket timeout during read/write data.
"""
pass
class WebSocketProxyException(WebSocketException):
"""
WebSocketProxyException will be raised when proxy error occured.
@@ -63,3 +68,10 @@ class WebSocketProxyException(WebSocketException):
pass
class WebSocketBadStatusException(WebSocketException):
"""
WebSocketBadStatusException will be raised when we get bad handshake status code.
"""
def __init__(self, message, status_code):
super(WebSocketBadStatusException, self).__init__(message % status_code)
self.status_code = status_code

View File

@@ -108,7 +108,7 @@ def _get_handshake_headers(resource, host, port, options):
def _get_resp_headers(sock, success_status=101):
status, resp_headers = read_headers(sock)
if status != success_status:
raise WebSocketException("Handshake status %d" % status)
raise WebSocketBadStatusException("Handshake status %d", status)
return status, resp_headers
_HEADERS_TO_CHECK = {

View File

@@ -132,6 +132,9 @@ def _wrap_sni_socket(sock, sslopt, hostname, check_hostname):
context.check_hostname = check_hostname
if 'ciphers' in sslopt:
context.set_ciphers(sslopt['ciphers'])
if 'cert_chain' in sslopt :
certfile,keyfile,password = sslopt['cert_chain']
context.load_cert_chain(certfile, keyfile, password)
return context.wrap_socket(
sock,
@@ -183,7 +186,7 @@ def _tunnel(sock, host, port, auth):
if status != 200:
raise WebSocketProxyException(
"failed CONNECT via proxy status: %r" + status)
"failed CONNECT via proxy status: %r" % status)
return sock