websocket.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import socket
  2. import ssl
  3. from frame import receive_frame
  4. from handshake import ServerHandshake, ClientHandshake
  5. from errors import SSLError
  6. class websocket(object):
  7. """
  8. Implementation of web socket, upgrades a regular TCP socket to a websocket
  9. using the HTTP handshakes and frame (un)packing, as specified by RFC 6455.
  10. The API of a websocket is identical to that of a regular socket, as
  11. illustrated by the examples below.
  12. Server example:
  13. >>> import twspy, socket
  14. >>> sock = twspy.websocket()
  15. >>> sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  16. >>> sock.bind(('', 8000))
  17. >>> sock.listen()
  18. >>> client = sock.accept()
  19. >>> client.send(twspy.Frame(twspy.OPCODE_TEXT, 'Hello, Client!'))
  20. >>> frame = client.recv()
  21. Client example:
  22. >>> import twspy
  23. >>> sock = twspy.websocket(location='/my/path')
  24. >>> sock.connect(('', 8000))
  25. >>> sock.send(twspy.Frame(twspy.OPCODE_TEXT, 'Hello, Server!'))
  26. """
  27. def __init__(self, sock=None, protocols=[], extensions=[], origin=None,
  28. trusted_origins=[], location='/', auth=None,
  29. sfamily=socket.AF_INET, sproto=0):
  30. """
  31. Create a regular TCP socket of family `family` and protocol
  32. `sock` is an optional regular TCP socket to be used for sending binary
  33. data. If not specified, a new socket is created.
  34. `protocols` is a list of supported protocol names.
  35. `extensions` is a list of supported extension classes.
  36. `origin` (for client sockets) is the value for the "Origin" header sent
  37. in a client handshake .
  38. `trusted_origins` (for servere sockets) is a list of expected values
  39. for the "Origin" header sent by a client. If the received Origin header
  40. has value not in this list, a HandshakeError is raised. If the list is
  41. empty (default), all origins are excepted.
  42. `location` is optional, used for the HTTP handshake. In a URL, this
  43. would show as ws://host[:port]/path.
  44. `auth` is optional, used for HTTP Basic or Digest authentication during
  45. the handshake. It must be specified as a (username, password) tuple.
  46. `sfamily` and `sproto` are used for the regular socket constructor.
  47. """
  48. self.protocols = protocols
  49. self.extensions = extensions
  50. self.origin = origin
  51. self.trusted_origins = trusted_origins
  52. self.location = location
  53. self.auth = auth
  54. self.sock = sock or socket.socket(sfamily, socket.SOCK_STREAM, sproto)
  55. self.secure = False
  56. self.handshake_sent = False
  57. def bind(self, address):
  58. self.sock.bind(address)
  59. def listen(self, backlog):
  60. self.sock.listen(backlog)
  61. def accept(self):
  62. """
  63. Equivalent to socket.accept(), but transforms the socket into a
  64. websocket instance and sends a server handshake (after receiving a
  65. client handshake). Note that the handshake may raise a HandshakeError
  66. exception.
  67. """
  68. sock, address = self.sock.accept()
  69. wsock = websocket(sock)
  70. ServerHandshake(wsock).perform()
  71. wsock.handshake_sent = True
  72. return wsock, address
  73. def connect(self, address):
  74. """
  75. Equivalent to socket.connect(), but sends an client handshake request
  76. after connecting.
  77. `address` is a (host, port) tuple of the server to connect to.
  78. """
  79. self.sock.connect(address)
  80. ClientHandshake(self).perform()
  81. self.handshake_sent = True
  82. def send(self, *args):
  83. """
  84. Send a number of frames.
  85. """
  86. for frame in args:
  87. #print 'send frame:', frame, 'to %s:%d' % self.sock.getpeername()
  88. self.sock.sendall(frame.pack())
  89. def recv(self):
  90. """
  91. Receive a single frames. This can be either a data frame or a control
  92. frame.
  93. """
  94. frame = receive_frame(self.sock)
  95. #print 'receive frame:', frame, 'from %s:%d' % self.sock.getpeername()
  96. return frame
  97. def recvn(self, n):
  98. """
  99. Receive exactly `n` frames. These can be either data frames or control
  100. frames, or a combination of both.
  101. """
  102. return [self.recv() for i in xrange(n)]
  103. def getpeername(self):
  104. return self.sock.getpeername()
  105. def getsockname(self):
  106. return self.sock.getsockname()
  107. def setsockopt(self, level, optname, value):
  108. self.sock.setsockopt(level, optname, value)
  109. def getsockopt(self, level, optname):
  110. return self.sock.getsockopt(level, optname)
  111. def close(self):
  112. self.sock.close()
  113. def enable_ssl(self, *args, **kwargs):
  114. """
  115. Transforms the regular socket.socket to an ssl.SSLSocket for secure
  116. connections. Any arguments are passed to ssl.wrap_socket:
  117. http://docs.python.org/dev/library/ssl.html#ssl.wrap_socket
  118. """
  119. if self.handshake_sent:
  120. raise SSLError('can only enable SSL before handshake')
  121. self.secure = True
  122. self.sock = ssl.wrap_socket(self.sock, *args, **kwargs)