websocket.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. import socket
  2. import ssl
  3. from frame import receive_frame, pop_frame, contains_frame
  4. from handshake import ServerHandshake, ClientHandshake
  5. from errors import SSLError
  6. INHERITED_ATTRS = ['bind', 'close', 'listen', 'fileno', 'getpeername',
  7. 'getsockname', 'getsockopt', 'setsockopt', 'setblocking',
  8. 'settimeout', 'gettimeout', 'shutdown', 'family', 'type',
  9. 'proto']
  10. class websocket(object):
  11. """
  12. Implementation of web socket, upgrades a regular TCP socket to a websocket
  13. using the HTTP handshakes and frame (un)packing, as specified by RFC 6455.
  14. The API of a websocket is identical to that of a regular socket, as
  15. illustrated by the examples below.
  16. Server example:
  17. >>> import wspy, socket
  18. >>> sock = wspy.websocket()
  19. >>> sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  20. >>> sock.bind(('', 8000))
  21. >>> sock.listen(5)
  22. >>> client = sock.accept()
  23. >>> client.send(wspy.Frame(wspy.OPCODE_TEXT, 'Hello, Client!'))
  24. >>> frame = client.recv()
  25. Client example:
  26. >>> import wspy
  27. >>> sock = wspy.websocket(location='/my/path')
  28. >>> sock.connect(('', 8000))
  29. >>> sock.send(wspy.Frame(wspy.OPCODE_TEXT, 'Hello, Server!'))
  30. """
  31. def __init__(self, sock=None, origin=None, protocols=[], extensions=[],
  32. location='/', trusted_origins=[], locations=[], auth=None,
  33. recv_callback=None, sfamily=socket.AF_INET, sproto=0):
  34. """
  35. Create a regular TCP socket of family `family` and protocol
  36. `sock` is an optional regular TCP socket to be used for sending binary
  37. data. If not specified, a new socket is created.
  38. `origin` (for client sockets) is the value for the "Origin" header sent
  39. in a client handshake .
  40. `protocols` is a list of supported protocol names.
  41. `extensions` (for server sockets) is a list of supported extensions
  42. (`Extension` instances).
  43. `location` (for client sockets) is optional, used to request a
  44. particular resource in the HTTP handshake. In a URL, this would show as
  45. ws://host[:port]/<location>. Use this when the server serves multiple
  46. resources (see `locations`).
  47. `trusted_origins` (for server sockets) is a list of expected values
  48. for the "Origin" header sent by a client. If the received Origin header
  49. has value not in this list, a HandshakeError is raised. If the list is
  50. empty (default), all origins are excepted.
  51. `locations` (for server sockets) is an optional list of resources
  52. serverd by this server. If specified (without trailing slashes), these
  53. are used to verify the resource location requested by a client. The
  54. requested location may be used to distinquish different services in a
  55. server implementation.
  56. `auth` is optional, used for HTTP Basic or Digest authentication during
  57. the handshake. It must be specified as a (username, password) tuple.
  58. `recv_callback` is the callback for received frames in asynchronous
  59. sockets. Use in conjunction with setblocking(0). The callback itself
  60. may for example change the recv_callback attribute to change the
  61. behaviour for the next received message. Can be set when calling
  62. `queue_send`.
  63. `sfamily` and `sproto` are used for the regular socket constructor.
  64. """
  65. self.protocols = protocols
  66. self.extensions = extensions
  67. self.extension_hooks = []
  68. self.origin = origin
  69. self.location = location
  70. self.trusted_origins = trusted_origins
  71. self.locations = locations
  72. self.auth = auth
  73. self.secure = False
  74. self.handshake_sent = False
  75. self.sendbuf_frames = []
  76. self.sendbuf = ''
  77. self.recvbuf = ''
  78. self.recv_callback = recv_callback
  79. self.sock = sock or socket.socket(sfamily, socket.SOCK_STREAM, sproto)
  80. def set_extensions(self, extensions):
  81. self.extensions = [ext.Hook() for ext in extensions]
  82. def __getattr__(self, name):
  83. if name in INHERITED_ATTRS:
  84. return getattr(self.sock, name)
  85. raise AttributeError("'%s' has no attribute '%s'"
  86. % (self.__class__.__name__, name))
  87. def accept(self):
  88. """
  89. Equivalent to socket.accept(), but transforms the socket into a
  90. websocket instance and sends a server handshake (after receiving a
  91. client handshake). Note that the handshake may raise a HandshakeError
  92. exception.
  93. """
  94. sock, address = self.sock.accept()
  95. wsock = websocket(sock)
  96. wsock.secure = self.secure
  97. ServerHandshake(wsock).perform(self)
  98. wsock.handshake_sent = True
  99. return wsock, address
  100. def connect(self, address):
  101. """
  102. Equivalent to socket.connect(), but sends an client handshake request
  103. after connecting.
  104. `address` is a (host, port) tuple of the server to connect to.
  105. """
  106. self.sock.connect(address)
  107. ClientHandshake(self).perform()
  108. self.handshake_sent = True
  109. def apply_send_hooks(self, frame):
  110. for hook in self.extension_hooks:
  111. frame = hook.send(frame)
  112. return frame
  113. def apply_recv_hooks(self, frame):
  114. for hook in reversed(self.extension_hooks):
  115. frame = hook.recv(frame)
  116. return frame
  117. def send(self, *args):
  118. """
  119. Send a number of frames.
  120. """
  121. for frame in args:
  122. self.sock.sendall(self.apply_send_hooks(frame).pack())
  123. def recv(self):
  124. """
  125. Receive a single frames. This can be either a data frame or a control
  126. frame.
  127. """
  128. return self.apply_recv_hooks(receive_frame(self.sock))
  129. def recvn(self, n):
  130. """
  131. Receive exactly `n` frames. These can be either data frames or control
  132. frames, or a combination of both.
  133. """
  134. return [self.recv() for i in xrange(n)]
  135. def queue_send(self, frame, callback=None, recv_callback=None):
  136. """
  137. Enqueue `frame` to the send buffer so that it is send on the next
  138. `do_async_send`. `callback` is an optional callable to call when the
  139. frame has been fully written. `recv_callback` is an optional callable
  140. to quickly set the `recv_callback` attribute to.
  141. """
  142. frame = self.apply_send_hooks(frame)
  143. self.sendbuf += frame.pack()
  144. self.sendbuf_frames.append([frame, len(self.sendbuf), callback])
  145. if recv_callback:
  146. self.recv_callback = recv_callback
  147. def do_async_send(self):
  148. """
  149. Send any queued data. This function should only be called after a write
  150. event on a file descriptor.
  151. """
  152. assert len(self.sendbuf)
  153. nwritten = self.sock.send(self.sendbuf)
  154. nframes = 0
  155. for entry in self.sendbuf_frames:
  156. frame, offset, callback = entry
  157. if offset <= nwritten:
  158. nframes += 1
  159. if callback:
  160. callback()
  161. else:
  162. entry[1] -= nwritten
  163. self.sendbuf = self.sendbuf[nwritten:]
  164. self.sendbuf_frames = self.sendbuf_frames[nframes:]
  165. def do_async_recv(self, bufsize):
  166. """
  167. Receive any completed frames from the socket. This function should only
  168. be called after a read event on a file descriptor.
  169. """
  170. data = self.sock.recv(bufsize)
  171. if len(data) == 0:
  172. raise socket.error('no data to receive')
  173. self.recvbuf += data
  174. while contains_frame(self.recvbuf):
  175. frame, self.recvbuf = pop_frame(self.recvbuf)
  176. frame = self.apply_recv_hooks(frame)
  177. if not self.recv_callback:
  178. raise ValueError('no callback installed for %s' % frame)
  179. self.recv_callback(frame)
  180. def can_send(self):
  181. return len(self.sendbuf) > 0
  182. def can_recv(self):
  183. return self.recv_callback is not None
  184. def enable_ssl(self, *args, **kwargs):
  185. """
  186. Transforms the regular socket.socket to an ssl.SSLSocket for secure
  187. connections. Any arguments are passed to ssl.wrap_socket:
  188. http://docs.python.org/dev/library/ssl.html#ssl.wrap_socket
  189. """
  190. if self.handshake_sent:
  191. raise SSLError('can only enable SSL before handshake')
  192. self.secure = True
  193. self.sock = ssl.wrap_socket(self.sock, *args, **kwargs)