def format(self): """ format this object to string(byte array) to send data to server. """ if any(x not in (0, 1) for x in [self.fin, self.rsv1, self.rsv2, self.rsv3]): raise ValueError("not 0 or 1") if self.opcode not in ABNF.OPCODES: raise ValueError("Invalid OPCODE") length = len(self.data) if length >= ABNF.LENGTH_63: raise ValueError("data is too long") frame_header = chr(self.fin << 7 | self.rsv1 << 6 | self.rsv2 << 5 | self.rsv3 << 4 | self.opcode) if length < ABNF.LENGTH_7: frame_header += chr(self.mask << 7 | length) frame_header = six.b(frame_header) elif length < ABNF.LENGTH_16: frame_header += chr(self.mask << 7 | 0x7e) frame_header = six.b(frame_header) frame_header += struct.pack("!H", length) else: frame_header += chr(self.mask << 7 | 0x7f) frame_header = six.b(frame_header) frame_header += struct.pack("!Q", length) if not self.mask: return frame_header + self.data else: mask_key = self.get_mask_key(4) return frame_header + self._get_masked(mask_key)
def recv_line(sock): line = [] while True: c = recv(sock, 1) line.append(c) if c == six.b("\n"): break return six.b("").join(line)
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 receive a close frame. If None, it will wait forever until receive a close frame. """ if self.connected: if status < 0 or status >= ABNF.LENGTH_16: raise ValueError("code is invalid range") try: self.connected = False self.send(struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE) sock_timeout = self.sock.gettimeout() self.sock.settimeout(timeout) try: frame = self.recv_frame() if isEnabledForError(): recv_status = struct.unpack("!H", frame.data)[0] if recv_status != STATUS_NORMAL: error("close status: " + repr(recv_status)) except: pass self.sock.settimeout(sock_timeout) self.sock.shutdown(socket.SHUT_RDWR) except: pass self.shutdown()
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 receive a close frame. If None, it will wait forever until receive a close frame. """ if self.connected: if status < 0 or status >= ABNF.LENGTH_16: raise ValueError("code is invalid range") try: self.connected = False self.send( struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE) sock_timeout = self.sock.gettimeout() self.sock.settimeout(timeout) try: frame = self.recv_frame() if isEnabledForError(): recv_status = struct.unpack("!H", frame.data)[0] if recv_status != STATUS_NORMAL: error("close status: " + repr(recv_status)) except: pass self.sock.settimeout(sock_timeout) self.sock.shutdown(socket.SHUT_RDWR) except: pass self.shutdown()
def mask(mask_key, data): """ mask or unmask data. Just do xor for each byte mask_key: 4 byte string(byte). data: data to mask/unmask. """ if data == None: data = "" if isinstance(mask_key, six.text_type): mask_key = six.b(mask_key) if isinstance(data, six.text_type): data = six.b(data) _m = array.array("B", mask_key) _d = array.array("B", data) return _mask(_m, _d)
def send_close(self, status=STATUS_NORMAL, reason=six.b("")): """ send close data to the server. status: status code to send. see STATUS_XXX. reason: the reason to close. This must be string or bytes. """ if status < 0 or status >= ABNF.LENGTH_16: raise ValueError("code is invalid range") self.connected = False self.send(struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE)
def recv_strict(self, bufsize): shortage = bufsize - sum(len(x) for x in self.recv_buffer) while shortage > 0: # Limit buffer size that we pass to socket.recv() to avoid # fragmenting the heap -- the number of bytes recv() actually # reads is limited by socket buffer and is relatively small, # yet passing large numbers repeatedly causes lots of large # buffers allocated and then shrunk, which results in fragmentation. bytes = self.recv(min(16384, shortage)) self.recv_buffer.append(bytes) shortage -= len(bytes) unified = six.b("").join(self.recv_buffer) if shortage == 0: self.recv_buffer = [] return unified else: self.recv_buffer = [unified[bufsize:]] return unified[:bufsize]