Anonymous avatar Anonymous committed d7fb9d5

Complete implementation of wait

- Now supports fragmented messages

Comments (0)

Files changed (2)

geventwebsocket/websocket.py

     MASK = int("10000000", 2)
     PAYLOAD = int("01111111", 2)
 
+    OPCODE_FRAG = 0x0
     OPCODE_TEXT = 0x1
     OPCODE_BINARY = 0x2
     OPCODE_CLOSE = 0x8
 
     REASON_NORMAL = 1000
     REASON_GOING_AWAY = 1001
+    REASON_PROTOCOL_ERROR = 1002
 
     LEN_16 = 126
     LEN_64 = 127
         self.protocol = environ.get('HTTP_SEC_WEBSOCKET_PROTOCOL', 'unknown')
         self.path = environ.get('PATH_INFO')
         self.websocket_closed = False
+        self._fragments = []
 
     def _read_from_socket(self, count):
         return self.rfile.read(count)
 
+    # TODO: replace all magic numbers with constants
     def wait(self):
-        msg = ''
         while True:
+            payload = ''
             if self.websocket_closed:
                 return None
 
                 return None
 
             opcode = opcode_octet & self.OPCODE
+            is_final_frag = (self.FIN & opcode_octet) != 0
+
             if self._is_opcode_invalid(opcode):
                 self.close(1002, 'Invalid opcode %x' % opcode)
                 return None
+            
+            if not is_final_frag and self.OPCODE_CLOSE <= opcode <= self.OPCODE_PONG:
+                self.close(self.REASON_PROTOCOL_ERROR, 'Control frames cannot be fragmented')
+                return None
+
+            if len(self._fragments) > 0 and not is_final_frag and opcode != self.OPCODE_FRAG:
+                self.close(self.REASON_PROTOCOL_ERROR,
+                        'Received new fragment frame with non-zero opcode')
+                return None
+
+            if len(self._fragments) > 0 and is_final_frag and (
+                    self.OPCODE_TEXT <= opcode <= self.OPCODE_BINARY):
+                self.close(self.REASON_PROTOCOL_ERROR,
+                        'Received new unfragmented data frame during fragmented message')
+                return None
 
             if not self.MASK & length_octet:
                 self.close(1002, 'MASK must be set')
                 return None
 
             length_code = length_octet & self.PAYLOAD
-            is_final_frag = (self.FIN & opcode) != 0
+
+            if length_code > 125 and (self.OPCODE_CLOSE <= opcode <= self.OPCODE_PONG):
+                self.close(1002, 'Control frame payload cannot be larger than 125 bytes')
+                return None
 
             if length_code < 126:
                 length = length_code
 
             mask_octets = struct.unpack('!BBBB', self._read_from_socket(4))
             masked_payload = self._read_from_socket(length)
+
             payload = ''
 
-            # TODO: optimize me
             j = 0
             for c in masked_payload:
+                # TODO: optimize me? http://www.skymind.com/~ocrow/python_string/
                 payload += chr(ord(c) ^ mask_octets[j])
                 j = (j + 1) % 4
 
             if opcode == self.OPCODE_TEXT:
                 payload = payload.decode('utf-8')
+            elif opcode == self.OPCODE_CLOSE:
+                if length >= 2:
+                    reason, message = struct.unpack('!H%ds' % (length - 2), payload)
+                else:
+                    reason = message = None
 
-            return payload
+                self.close(1000, '')
+                return (reason, message)
+
+            if opcode == self.OPCODE_PING:
+                self.send(self.OPCODE_PONG, payload)
+                return (self.OPCODE_PING, payload)
+            elif opcode == self.OPCODE_PONG:
+                return (self.OPCODE_PONG, payload)
+
+            if is_final_frag:
+                payload = ''.join(self._fragments) + payload
+                self._fragments = []
+                return payload
+            else:
+                self._fragments.append(payload)
 
     def _encode_text(self, s):
         if isinstance(s, unicode):
             raise Exception('Invalid encoding')
 
     def _is_opcode_invalid(self, opcode):
-        return opcode < self.OPCODE_TEXT or (opcode > self.OPCODE_BINARY and 
+        return opcode < self.OPCODE_FRAG or (opcode > self.OPCODE_BINARY and 
                 opcode < self.OPCODE_CLOSE) or opcode > self.OPCODE_PONG
 
     def send(self, opcode, message):

tests/test__websocket.py

 
         fd.close();
 
+    def test_wait_control_frames_of_unusual_size(self):
+        opcodes = [WebSocketVersion7.OPCODE_CLOSE,
+                WebSocketVersion7.OPCODE_PING,
+                WebSocketVersion7.OPCODE_PONG]
+        expected_msg = 'Control frame payload cannot be larger than 125 bytes'
+        for test_opcode in opcodes:
+            msg = ''
+            mask = 0x42424242
+            encoded_msg = self._get_payload(mask, msg)
+
+            fd = self.connect().makefile(bufsize=1)
+
+            fd.write(self.GOOD_HEADERS)
+            read_http(fd, code=101, reason='Switching Protocols')
+
+            fd.write(struct.pack('!BBHL',
+                WebSocketVersion7.FIN | test_opcode, 
+                WebSocketVersion7.MASK | 126, 0, mask))
+
+            frame = self.ws.wait()
+            assert self.ws.websocket_closed, \
+                    'Failed to close connection when sent a frame of unusual size'
+
+            preamble = fd.read(2)
+
+            opcode, length = struct.unpack('!BB', preamble)
+            assert opcode & WebSocketVersion7.FIN, 'FIN must be set'
+            assert (opcode & WebSocketVersion7.OPCODE) == 8, 'Opcode must be 0x8'
+            assert (length & WebSocketVersion7.MASK) == 0, 'MASK must not be set'
+
+            reason = fd.read(2)
+            reason = struct.unpack('!H', reason)[0]
+            assert reason == 1002, 'Expected reason to be 1002, but got %d' % reason
+
+            rxd_msg = fd.read(length - 2).decode('utf-8', 'replace')
+            assert rxd_msg == expected_msg, 'Wrong message "%s"' % rxd_msg
+
+            fd.close();
+
+            fd = self.connect().makefile(bufsize=1)
+
+            fd.write(self.GOOD_HEADERS)
+            read_http(fd, code=101, reason='Switching Protocols')
+
+            fd.write(struct.pack('!BBQL',
+                WebSocketVersion7.FIN | test_opcode, 
+                WebSocketVersion7.MASK | 127, length, mask))
+
+            frame = self.ws.wait()
+            assert self.ws.websocket_closed, \
+                    'Failed to close connection when sent a frame of unusual size'
+
+            preamble = fd.read(2)
+
+            opcode, length = struct.unpack('!BB', preamble)
+            assert opcode & WebSocketVersion7.FIN, 'FIN must be set'
+            assert (opcode & WebSocketVersion7.OPCODE) == 8, 'Opcode must be 0x8'
+            assert (length & WebSocketVersion7.MASK) == 0, 'MASK must not be set'
+
+            reason = fd.read(2)
+            reason = struct.unpack('!H', reason)[0]
+            assert reason == 1002, 'Expected reason to be 1002, but got %d' % reason
+
+            rxd_msg = fd.read(length - 2).decode('utf-8', 'replace')
+            assert rxd_msg == expected_msg, 'Wrong message "%s"' % rxd_msg
+
+            fd.close();
+
+    def test_wait_close_frame(self):
+        fd = self.connect().makefile(bufsize=1)
+
+        fd.write(self.GOOD_HEADERS)
+        read_http(fd, code=101, reason='Switching Protocols')
+
+        msg = 'Hello, websocket'
+        mask = 0x42424242
+        reason = 1000
+        encoded_msg = self._get_payload(mask, msg)
+        length = len(encoded_msg) + 2
+        fd.write(struct.pack('!BBLH%ds' % length,
+            WebSocketVersion7.FIN | WebSocketVersion7.OPCODE_CLOSE,
+            WebSocketVersion7.MASK | length, mask, reason ^ (mask >> 16), encoded_msg))
+
+        rxd_msg = self.ws.wait()
+        assert self.ws.websocket_closed, 'Did not close connection when sent a close frame'
+        assert rxd_msg == (reason, msg), 'Wrong result "%s"' % (rxd_msg,)
+
+        preamble = fd.read(2)
+        opcode, length = struct.unpack('!BB', preamble)
+        assert opcode & WebSocketVersion7.FIN, 'FIN must be set'
+        assert (opcode & WebSocketVersion7.OPCODE) == WebSocketVersion7.OPCODE_CLOSE, \
+                'Opcode must be %x' % WebSocketVersion7.OPCODE_CLOSE
+        assert (length & WebSocketVersion7.MASK) == 0, 'MASK must not be set'
+        assert length == 2, 'The payload length must be 2, but got %d' % length
+        
+        reason = struct.unpack('!H', fd.read(2))[0]
+        assert reason == 1000, 'The reason must be 1000, but got %d' % reason
+
+        fd.close();
+
+    def test_wait_close_frame_no_payload(self):
+        fd = self.connect().makefile(bufsize=1)
+
+        fd.write(self.GOOD_HEADERS)
+        read_http(fd, code=101, reason='Switching Protocols')
+
+        msg = ''
+        mask = 0x42424242
+        encoded_msg = self._get_payload(mask, msg)
+        length = 0
+        fd.write(struct.pack('!BBL',
+            WebSocketVersion7.FIN | WebSocketVersion7.OPCODE_CLOSE,
+            WebSocketVersion7.MASK | length, mask))
+
+        rxd_msg = self.ws.wait()
+        assert self.ws.websocket_closed, \
+                'Did not close connection when sent a close frame with no payload'
+        assert rxd_msg == (None, None), 'Wrong result "%s"' % (rxd_msg,)
+
+        preamble = fd.read(2)
+        opcode, length = struct.unpack('!BB', preamble)
+        assert opcode & WebSocketVersion7.FIN, 'FIN must be set'
+        assert (opcode & WebSocketVersion7.OPCODE) == WebSocketVersion7.OPCODE_CLOSE, \
+                'Opcode must be %x' % WebSocketVersion7.OPCODE_CLOSE
+        assert (length & WebSocketVersion7.MASK) == 0, 'MASK must not be set'
+        assert length == 2, 'The payload length must be 2, but got %d' % length
+        
+        reason = struct.unpack('!H', fd.read(2))[0]
+        assert reason == WebSocketVersion7.REASON_NORMAL, \
+                'The reason must be 1000, but got %d' % reason
+
+        fd.close();
+
+    def test_wait_ping_frame(self):
+        fd = self.connect().makefile(bufsize=1)
+
+        fd.write(self.GOOD_HEADERS)
+        read_http(fd, code=101, reason='Switching Protocols')
+
+        msg = 'Hello, websocket'
+        mask = 0x42424242
+        encoded_msg = self._get_payload(mask, msg)
+        length = len(encoded_msg)
+        fd.write(struct.pack('!BBL%ds' % length,
+            WebSocketVersion7.FIN | WebSocketVersion7.OPCODE_PING,
+            WebSocketVersion7.MASK | length, mask, encoded_msg))
+
+        rxd_msg = self.ws.wait()
+        assert not self.ws.websocket_closed, 'Closed connection when sent a ping frame'
+        assert rxd_msg == (WebSocketVersion7.OPCODE_PING, msg.encode('utf-8')), \
+                'Wrong result "%s"' % (rxd_msg,)
+
+        preamble = fd.read(2)
+        opcode, length = struct.unpack('!BB', preamble)
+        assert opcode & WebSocketVersion7.FIN, 'FIN must be set'
+        assert (opcode & WebSocketVersion7.OPCODE) == WebSocketVersion7.OPCODE_PONG, \
+                'Opcode must be %x' % WebSocketVersion7.OPCODE_PONG
+        assert (length & WebSocketVersion7.MASK) == 0, 'MASK must not be set'
+        assert length == len(encoded_msg), 'Wrong payload length. Got %d' % length
+
+        txd_msg = fd.read(length)
+        assert txd_msg == msg.encode('utf-8'), 'Wrong message "%s", expected "%s"' % (txd_msg, msg)
+
+        fd.close();
+
+    def test_wait_pong_frame(self):
+        fd = self.connect().makefile(bufsize=1)
+
+        fd.write(self.GOOD_HEADERS)
+        read_http(fd, code=101, reason='Switching Protocols')
+
+        msg = 'Hello, websocket'
+        mask = 0x42424242
+        encoded_msg = self._get_payload(mask, msg)
+        length = len(encoded_msg)
+        fd.write(struct.pack('!BBL%ds' % length,
+            WebSocketVersion7.FIN | WebSocketVersion7.OPCODE_PONG,
+            WebSocketVersion7.MASK | length, mask, encoded_msg))
+
+        rxd_msg = self.ws.wait()
+        assert not self.ws.websocket_closed, 'Closed connection when sent a pong frame'
+        assert rxd_msg == (WebSocketVersion7.OPCODE_PONG, msg.encode('utf-8')), \
+                'Wrong result "%s"' % (rxd_msg,)
+
+        fd.close();
+
+    def test_wait_fragmented_control_frame(self):
+        opcodes = [WebSocketVersion7.OPCODE_CLOSE,
+                WebSocketVersion7.OPCODE_PING,
+                WebSocketVersion7.OPCODE_PONG]
+        expected_msg = 'Control frames cannot be fragmented'
+        for test_opcode in opcodes:
+            msg = ''
+            mask = 0x42424242
+            encoded_msg = self._get_payload(mask, msg)
+
+            fd = self.connect().makefile(bufsize=1)
+
+            fd.write(self.GOOD_HEADERS)
+            read_http(fd, code=101, reason='Switching Protocols')
+
+            fd.write(struct.pack('!BBL', test_opcode, WebSocketVersion7.MASK | 0, mask))
+
+            frame = self.ws.wait()
+            assert self.ws.websocket_closed, \
+                    'Failed to close connection when sent a fragmented control frame'
+
+            preamble = fd.read(2)
+
+            opcode, length = struct.unpack('!BB', preamble)
+            assert opcode & WebSocketVersion7.FIN, 'FIN must be set'
+            assert (opcode & WebSocketVersion7.OPCODE) == 8, 'Opcode must be 0x8'
+            assert (length & WebSocketVersion7.MASK) == 0, 'MASK must not be set'
+
+            reason = fd.read(2)
+            reason = struct.unpack('!H', reason)[0]
+            assert reason == 1002, 'Expected reason to be 1002, but got %d' % reason
+
+            rxd_msg = fd.read(length - 2).decode('utf-8', 'replace')
+            assert rxd_msg == expected_msg, 'Wrong message "%s"' % rxd_msg
+
+            fd.close();
+
+    def test_wait_unfinished_fragmented_message(self):
+        fd = self.connect().makefile(bufsize=1)
+
+        fd.write(self.GOOD_HEADERS)
+        read_http(fd, code=101, reason='Switching Protocols')
+
+        expected_msg = 'Received new unfragmented data frame during fragmented message'
+
+        msg = 'Hello, '
+        mask = 42
+        encoded_msg = self._get_payload(mask, msg)
+        length = len(encoded_msg)
+        fd.write(struct.pack('!BBL%ds' % length,
+            WebSocketVersion7.OPCODE_TEXT, 
+            WebSocketVersion7.MASK | length, mask, encoded_msg))
+
+        fd.write(struct.pack('!BBL%ds' % length,
+            WebSocketVersion7.FIN | WebSocketVersion7.OPCODE_TEXT, 
+            WebSocketVersion7.MASK | length, mask, encoded_msg))
+
+        frame = self.ws.wait()
+        assert self.ws.websocket_closed, \
+                'Failed to close connection when sent new unfragmented ' + \
+                'data frame during fragmented message'
+
+        preamble = fd.read(2)
+
+        opcode, length = struct.unpack('!BB', preamble)
+        assert opcode & WebSocketVersion7.FIN, 'FIN must be set'
+        assert (opcode & WebSocketVersion7.OPCODE) == 8, 'Opcode must be 0x8'
+        assert (length & WebSocketVersion7.MASK) == 0, 'MASK must not be set'
+
+        reason = fd.read(2)
+        reason = struct.unpack('!H', reason)[0]
+        assert reason == 1002, 'Expected reason to be 1002, but got %d' % reason
+
+        rxd_msg = fd.read(length - 2).decode('utf-8', 'replace')
+        assert rxd_msg == expected_msg, 'Wrong message "%s"' % rxd_msg
+
+        fd.close();
+
+    def test_wait_bad_fragment_opcode(self):
+        fd = self.connect().makefile(bufsize=1)
+
+        fd.write(self.GOOD_HEADERS)
+        read_http(fd, code=101, reason='Switching Protocols')
+
+        expected_msg = 'Received new fragment frame with non-zero opcode'
+
+        msg = 'Hello, '
+        mask = 42
+        encoded_msg = self._get_payload(mask, msg)
+        length = len(encoded_msg)
+        fd.write(struct.pack('!BBL%ds' % length,
+            WebSocketVersion7.OPCODE_TEXT, 
+            WebSocketVersion7.MASK | length, mask, encoded_msg))
+
+        fd.write(struct.pack('!BBL%ds' % length,
+            WebSocketVersion7.OPCODE_TEXT, 
+            WebSocketVersion7.MASK | length, mask, encoded_msg))
+
+        frame = self.ws.wait()
+        assert self.ws.websocket_closed, \
+                'Failed to close connection when sent fragment with non-zero opcode'
+
+        preamble = fd.read(2)
+
+        opcode, length = struct.unpack('!BB', preamble)
+        assert opcode & WebSocketVersion7.FIN, 'FIN must be set'
+        assert (opcode & WebSocketVersion7.OPCODE) == 8, 'Opcode must be 0x8'
+        assert (length & WebSocketVersion7.MASK) == 0, 'MASK must not be set'
+
+        reason = fd.read(2)
+        reason = struct.unpack('!H', reason)[0]
+        assert reason == 1002, 'Expected reason to be 1002, but got %d' % reason
+
+        rxd_msg = fd.read(length - 2).decode('utf-8', 'replace')
+        assert rxd_msg == expected_msg, 'Wrong message "%s"' % rxd_msg
+
+        fd.close();
+
+    def test_wait_two_fragments(self):
+        fd = self.connect().makefile(bufsize=1)
+
+        fd.write(self.GOOD_HEADERS)
+        read_http(fd, code=101, reason='Switching Protocols')
+
+        expected_msg = ''
+
+        msg = 'Hello, '
+        expected_msg += msg
+        mask = 42
+        encoded_msg = self._get_payload(mask, msg)
+        length = len(encoded_msg)
+        fd.write(struct.pack('!BBL%ds' % length,
+            WebSocketVersion7.OPCODE_TEXT, 
+            WebSocketVersion7.MASK | length, mask, encoded_msg))
+
+        msg = 'websocket'
+        expected_msg += msg
+        mask = 23
+        encoded_msg = self._get_payload(mask, msg)
+        length = len(encoded_msg)
+        fd.write(struct.pack('!BBL%ds' % length,
+            WebSocketVersion7.FIN | WebSocketVersion7.OPCODE_FRAG, 
+            WebSocketVersion7.MASK | length, mask, encoded_msg))
+
+        rxd_msg = self.ws.wait()
+        assert not self.ws.websocket_closed, 'Closed connection when sent a good frame'
+        assert rxd_msg == expected_msg, 'Wrong message "%s"' % rxd_msg
+
+        fd.close();
+
+    def test_wait_three_fragments(self):
+        fd = self.connect().makefile(bufsize=1)
+
+        fd.write(self.GOOD_HEADERS)
+        read_http(fd, code=101, reason='Switching Protocols')
+
+        expected_msg = ''
+
+        msg = 'Hello, '
+        expected_msg += msg
+        mask = 42
+        encoded_msg = self._get_payload(mask, msg)
+        length = len(encoded_msg)
+        fd.write(struct.pack('!BBL%ds' % length,
+            WebSocketVersion7.OPCODE_TEXT, 
+            WebSocketVersion7.MASK | length, mask, encoded_msg))
+
+        msg = 'websocket'
+        expected_msg += msg
+        mask = 1337
+        encoded_msg = self._get_payload(mask, msg)
+        length = len(encoded_msg)
+        fd.write(struct.pack('!BBL%ds' % length,
+            WebSocketVersion7.OPCODE_FRAG, 
+            WebSocketVersion7.MASK | length, mask, encoded_msg))
+
+        msg = '!'
+        expected_msg += msg
+        mask = 23
+        encoded_msg = self._get_payload(mask, msg)
+        length = len(encoded_msg)
+        fd.write(struct.pack('!BBL%ds' % length,
+            WebSocketVersion7.FIN | WebSocketVersion7.OPCODE_FRAG, 
+            WebSocketVersion7.MASK | length, mask, encoded_msg))
+
+        rxd_msg = self.ws.wait()
+        assert not self.ws.websocket_closed, 'Closed connection when sent a good frame'
+        assert rxd_msg == expected_msg, 'Wrong message "%s"' % rxd_msg
+
+        fd.close();
+
+    def test_wait_control_frame_during_fragmented_message(self):
+        fd = self.connect().makefile(bufsize=1)
+
+        fd.write(self.GOOD_HEADERS)
+        read_http(fd, code=101, reason='Switching Protocols')
+
+        expected_msg = ''
+
+        msg = 'Hello, '
+        expected_msg += msg
+        mask = 42
+        encoded_msg = self._get_payload(mask, msg)
+        length = len(encoded_msg)
+        fd.write(struct.pack('!BBL%ds' % length,
+            WebSocketVersion7.OPCODE_TEXT, 
+            WebSocketVersion7.MASK | length, mask, encoded_msg))
+
+        ping_msg = 'Marco!'
+        mask = 0x42424242
+        encoded_ping_msg = self._get_payload(mask, ping_msg)
+        length = len(encoded_ping_msg)
+        fd.write(struct.pack('!BBL%ds' % length,
+            WebSocketVersion7.FIN | WebSocketVersion7.OPCODE_PING,
+            WebSocketVersion7.MASK | length, mask, encoded_ping_msg))
+
+        msg = 'websocket'
+        expected_msg += msg
+        mask = 23
+        encoded_msg = self._get_payload(mask, msg)
+        length = len(encoded_msg)
+        fd.write(struct.pack('!BBL%ds' % length,
+            WebSocketVersion7.FIN | WebSocketVersion7.OPCODE_FRAG, 
+            WebSocketVersion7.MASK | length, mask, encoded_msg))
+
+        rxd_msg = self.ws.wait()
+        assert not self.ws.websocket_closed, 'Closed connection when sent a ping frame'
+        assert rxd_msg == (WebSocketVersion7.OPCODE_PING, ping_msg.encode('utf-8')), \
+                'Wrong result "%s"' % (rxd_msg,)
+
+        preamble = fd.read(2)
+        opcode, length = struct.unpack('!BB', preamble)
+        assert opcode & WebSocketVersion7.FIN, 'FIN must be set'
+        assert (opcode & WebSocketVersion7.OPCODE) == WebSocketVersion7.OPCODE_PONG, \
+                'Opcode must be %x' % WebSocketVersion7.OPCODE_PONG
+        assert (length & WebSocketVersion7.MASK) == 0, 'MASK must not be set'
+        assert length == len(encoded_ping_msg), 'Wrong payload length. Got %d' % length
+
+        txd_msg = fd.read(length)
+        assert txd_msg == ping_msg.encode('utf-8'), \
+                'Wrong message "%s", expected "%s"' % (txd_msg, ping_msg)
+
+        rxd_msg = self.ws.wait()
+        assert not self.ws.websocket_closed, 'Closed connection when sent a good frame'
+        assert rxd_msg == expected_msg, \
+                'Wrong message "%s", expected "%s"' % (rxd_msg, expected_msg)
+
+        fd.close();
+
+    def test_wait_two_fragmented_messages(self):
+        fd = self.connect().makefile(bufsize=1)
+
+        fd.write(self.GOOD_HEADERS)
+        read_http(fd, code=101, reason='Switching Protocols')
+
+        for x in xrange(0, 2):
+            expected_msg = ''
+
+            msg = 'Hello, '
+            expected_msg += msg
+            mask = 42
+            encoded_msg = self._get_payload(mask, msg)
+            length = len(encoded_msg)
+            fd.write(struct.pack('!BBL%ds' % length,
+                WebSocketVersion7.OPCODE_TEXT, 
+                WebSocketVersion7.MASK | length, mask, encoded_msg))
+
+            msg = 'websocket %d' % x
+            expected_msg += msg
+            mask = 23
+            encoded_msg = self._get_payload(mask, msg)
+            length = len(encoded_msg)
+            fd.write(struct.pack('!BBL%ds' % length,
+                WebSocketVersion7.FIN | WebSocketVersion7.OPCODE_FRAG, 
+                WebSocketVersion7.MASK | length, mask, encoded_msg))
+
+            rxd_msg = self.ws.wait()
+            assert not self.ws.websocket_closed, 'Closed connection when sent a good frame'
+            assert rxd_msg == expected_msg, 'Wrong message "%s"' % rxd_msg
+
+        fd.close();
+    """
+    TODO: write fragmentation test cases:
+          - too large of a message
+            - make this a config attribute that applies to individual messages as well
+    """
+
 if __name__ == '__main__':
     greentest.main()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.