def parse_ws_frame(self, buf): if not buf: self._read_queue_put(buf) return if self.ws_data: ws_data = self.ws_data+buf self.ws_data = b"" else: ws_data = buf log("parse_ws_frame(%i bytes) total buffer is %i bytes", len(buf), len(ws_data)) while ws_data and not self._closed: parsed = decode_hybi(ws_data) if parsed is None: log("parse_ws_frame(%i bytes) not enough data", len(ws_data)) #not enough data to get a full websocket frame, #save it for later: self.ws_data = ws_data return opcode, payload, processed, fin = parsed ws_data = ws_data[processed:] log("parse_ws_frame(%i bytes) payload=%i bytes, processed=%i, remaining=%i, opcode=%s, fin=%s", len(buf), len(payload), processed, len(ws_data), OPCODES.get(opcode, opcode), fin) if opcode==OPCODE_CONTINUE: assert self.ws_payload_opcode and self.ws_payload, "continuation frame does not follow a partial frame" self.ws_payload.append(payload) if not fin: #wait for more continue #join all the frames and process the payload: full_payload = b"".join(memoryview_to_bytes(v) for v in self.ws_payload) self.ws_payload = [] opcode = self.ws_payload_opcode self.ws_payload_opcode = 0 else: if self.ws_payload and self.ws_payload_opcode: raise Exception("expected a continuation frame not %s" % OPCODES.get(opcode, opcode)) full_payload = payload if not fin: if opcode not in (OPCODE_BINARY, OPCODE_TEXT): raise Exception("cannot handle fragmented '%s' frames" % OPCODES.get(opcode, opcode)) #fragmented, keep this payload for later self.ws_payload_opcode = opcode self.ws_payload.append(payload) continue if opcode==OPCODE_BINARY: self._read_queue_put(full_payload) elif opcode==OPCODE_TEXT: if first_time("ws-text-frame-from-%s" % self._conn): log.warn("Warning: handling text websocket frame as binary") self._read_queue_put(full_payload) elif opcode==OPCODE_CLOSE: self._process_ws_close(full_payload) elif opcode==OPCODE_PING: self._process_ws_ping(full_payload) elif opcode==OPCODE_PONG: self._process_ws_pong(full_payload) else: log.warn("Warning unhandled websocket opcode '%s'", OPCODES.get(opcode, "%#x" % opcode)) log("payload=%r", payload)
def rt(opcode, payload, has_mask=False, fin=True): h = encode_hybi_header(opcode, len(payload), has_mask, fin) packet = h + payload ropcode, rpayload, rlen, rfin = decode_hybi(packet) assert opcode == ropcode assert rpayload == payload assert rlen > len(payload) assert fin == rfin
def test_invalid_decode(self): for l in (0, 10, 125, 126, 65535, 65536): for has_mask in (True, False): payload = b"\0" * l h = encode_hybi_header(0, len(payload), has_mask, True) if has_mask: packet = h + b"9" * 4 + payload else: packet = h + payload v = decode_hybi(packet) assert v v = decode_hybi(packet[:-1]) assert v is None v = decode_hybi(packet[:int(has_mask) * 4]) assert v is None, "got %s" % (v, ) if l > 0: for i in range(5): v = decode_hybi(packet[:int(has_mask) * 4 + i]) assert v is None, "got %s" % (v, )