예제 #1
0
    def test_no_limit_error_when_content_just_right(self):
        decoder = netstring.Decoder(1)
        try:
            self.assertEqual([b'X'], decoder.feed(b'1:X,'))
        except netstring.TooLong:
            self.assertFalse(True)

        decoder = netstring.Decoder(10)
        try:
            self.assertEqual([b'XXXXXXXXXX'], decoder.feed(b'10:XXXXXXXXXX,'))
        except netstring.TooLong:
            self.assertFalse(True)
예제 #2
0
 def __init__(self, loop, readfd, writefd) -> None:
     self._loop = loop
     self._readfd = readfd
     self._writefd = writefd
     self._reader = Union[StreamReader, None]
     self._writer = Union[StreamWriter, None]
     self._nsDecoder = pynetstring.Decoder()
     self._connected = False
예제 #3
0
 def test_limit_error_when_length_declaration_inplausibly_long(self):
     decoder = netstring.Decoder(100)
     with self.assertRaises(netstring.TooLong):
         # The length declaration of a netstring with content of 100 bytes
         # takes up at most log10(100) + 1 = 3 bytes.
         # Error raised already here because 4 bytes of length parsed but
         # no length end marker ":" found yet.
         decoder.feed(b'1000')
예제 #4
0
    def create_input_packages(self, data, endpoint):
        with self._mutex:
            decoder = self._decoder_dict.get(endpoint, pynetstring.Decoder())

            input_pack_list = []
            message_data_list = decoder.feed(data)
            for message_data in message_data_list:
                message = pickle.loads(message_data)
                input_pack_list.append(InputPack(message, endpoint))

            return input_pack_list
 async def query(host, port, domain):
     reader, writer = await asyncio.open_connection(host, port)
     decoder = pynetstring.Decoder()
     writer.write(pynetstring.encode(b'test ' + domain.encode('ascii')))
     try:
         while True:
             data = await reader.read(4096)
             assert data
             res = decoder.feed(data)
             if res:
                 return res[0]
     finally:
         writer.close()
예제 #6
0
    def test_invalid_length_characters_raise_exception(self):
        decoder = netstring.Decoder()
        with self.assertRaises(netstring.BadLength):
            decoder.feed(b'1e2:X,')

        with self.assertRaises(netstring.BadLength):
            decoder.feed(b'+3:XXX,')

        with self.assertRaises(netstring.BadLength):
            decoder.feed(b' 3 :XXX,')

        with self.assertRaises(netstring.BadLength):
            decoder.feed(b'b\n\r\t\v\x0b\x0c +3:XXX,')
예제 #7
0
async def test_responder(responder, params):
    (request, response), bufsize = params
    resp, host, port = responder
    decoder = pynetstring.Decoder()
    reader, writer = await asyncio.open_connection(host, port)
    try:
        writer.write(pynetstring.encode(request))
        while True:
            data = await reader.read(bufsize)
            assert data
            res = decoder.feed(data)
            if res:
                assert res[0] == response
                break
    finally:
        writer.close()
async def test_unix_responder(unix_responder, params):
    (request, response), bufsize = params
    resp, path = unix_responder
    assert os.stat(path).st_mode & 0o777 == 0o666
    decoder = pynetstring.Decoder()
    reader, writer = await asyncio.open_unix_connection(path)
    try:
        writer.write(pynetstring.encode(request))
        while True:
            data = await reader.read(bufsize)
            assert data
            res = decoder.feed(data)
            if res:
                assert res[0] == response
                break
    finally:
        writer.close()
async def test_cached(responder):
    resp, host, port = responder
    decoder = pynetstring.Decoder()
    reader, writer = await asyncio.open_connection(host, port)
    writer.write(pynetstring.encode(b'test good.loc'))
    writer.write(pynetstring.encode(b'test good.loc'))
    answers = []
    try:
        while True:
            data = await reader.read(4096)
            assert data
            res = decoder.feed(data)
            if res:
                answers += res
                if len(answers) == 2:
                    break
        assert answers[0] == answers[1]
    finally:
        writer.close()
예제 #10
0
async def test_fast_expire(responder):
    resp, host, port = responder
    decoder = pynetstring.Decoder()
    reader, writer = await asyncio.open_connection(host, port)
    async def answer():
        while True:
            data = await reader.read(4096)
            assert data
            res = decoder.feed(data)
            if res:
                return res[0]
    try:
        writer.write(pynetstring.encode(b'test fast-expire.loc'))
        answer_a = await answer()
        await asyncio.sleep(2)
        writer.write(pynetstring.encode(b'test fast-expire.loc'))
        answer_b = await answer()
        assert answer_a == answer_b == b'OK secure match=mail.loc'
    finally:
        writer.close()
async def test_responder_with_custom_socket(event_loop, responder, params):
    (request, response), bufsize = params
    resp, host, port = responder
    decoder = pynetstring.Decoder()
    sock = await utils.create_custom_socket(host,
                                            0,
                                            flags=0,
                                            options=[(socket.SOL_SOCKET,
                                                      socket.SO_REUSEADDR, 1)])
    await event_loop.run_in_executor(None, sock.connect, (host, port))
    reader, writer = await asyncio.open_connection(sock=sock)
    try:
        writer.write(pynetstring.encode(request))
        while True:
            data = await reader.read(bufsize)
            assert data
            res = decoder.feed(data)
            if res:
                assert res[0] == response
                break
    finally:
        writer.close()
예제 #12
0
 def test_no_limit_error_when_content_shorter(self):
     decoder = netstring.Decoder(10)
     try:
         self.assertEqual([b'XXXXXXXXX'], decoder.feed(b'9:XXXXXXXXX,'))
     except netstring.TooLong:
         self.assertFalse(True)
예제 #13
0
 def test_feed_multiple_and_partial(self):
     decoder = netstring.Decoder()
     self.assertEqual([], decoder.feed('1:'))
     self.assertEqual([b'X', b'abc'], decoder.feed('X,3:abc,2:'))
     self.assertEqual([b'ok'], decoder.feed('ok,'))
예제 #14
0
 def test_feed_empty_string_partially(self):
     decoder = netstring.Decoder()
     self.assertEqual([], decoder.feed('0'))
     self.assertEqual([], decoder.feed(':'))
     self.assertEqual([b''], decoder.feed(','))
예제 #15
0
 def test_decoder_pending(self):
     decoder = netstring.Decoder()
     decoder.feed('3:abc,0:')
     self.assertTrue(decoder.pending())
예제 #16
0
 def test_decoder_not_pending(self):
     decoder = netstring.Decoder()
     decoder.feed('3:abc,')
     self.assertFalse(decoder.pending())
예제 #17
0
 def test_limit_error_when_content_too_long(self):
     decoder = netstring.Decoder(1)
     with self.assertRaises(netstring.TooLong):
         decoder.feed(b'2:XX,')
예제 #18
0
 def test_limit_error_when_missing_comma(self):
     decoder = netstring.Decoder(10)
     with self.assertRaises(netstring.IncompleteString):
         decoder.feed(b'10:XXXXXXXXXXX,')
예제 #19
0
    async def handler(self, reader, writer):
        # Construct netstring parser
        decoder = pynetstring.Decoder()

        # Construct queue for responses ordering
        queue = asyncio.Queue(QUEUE_LIMIT, loop=self._loop)

        # Create coroutine which awaits for steady responses and sends them
        sender = asyncio.ensure_future(self.sender(queue, writer),
                                       loop=self._loop)

        class ParserInvokationError(Exception):
            pass

        class EndOfStream(Exception):
            pass

        async def finalize():
            try:
                await queue.put(None)
            except asyncio.CancelledError:  # pragma: no cover
                sender.cancel()
                raise
            await sender

        try:
            while True:
                #Extract and parse requests
                part = await reader.read(CHUNK)
                if not part:
                    raise EndOfStream()
                self._logger.debug("Read: %s", repr(part))
                try:
                    requests = decoder.feed(part)
                except:
                    raise ParserInvokationError("Bad netstring protocol.")

                # Enqueue tasks for received requests
                for req in requests:
                    self._logger.debug("Enq request: %s", repr(req))
                    fut = asyncio.ensure_future(self.process_request(req),
                                                loop=self._loop)
                    await queue.put(fut)
        except ParserInvokationError:
            self._logger.warning("Bad netstring message received")
            await finalize()
        except (EndOfStream, ConnectionError, TimeoutError):
            self._logger.debug("Client disconnected")
            await finalize()
        except OSError as exc:  # pragma: no cover
            if exc.errno == 107:
                self._logger.debug("Client disconnected")
                await finalize()
            else:
                self._logger.exception("Unhandled exception: %s", exc)
                await finalize()
        except asyncio.CancelledError:
            sender.cancel()
            raise
        except Exception as exc:  # pragma: no cover
            self._logger.exception("Unhandled exception: %s", exc)
            await finalize()
예제 #20
0
 def test_handle_negative_length(self):
     decoder = netstring.Decoder()
     with self.assertRaises(netstring.BadLength):
         decoder.feed('-1:X,')
예제 #21
0
 def __init__(
     self,
     *,
     who,
     token,
     method="password",
     host="localhost",
     port=6551,
     local_addr=None,
     tls=False,
     tls_cert=None,
     tls_key=None,
     tls_ca=None,
     tls_server_hostname=None,
     json=False,
     logger=None,
     level=None,
     ping_timeout=300,
     ping_cb=None,
 ):
     self.who = who
     self.token = token
     self.method = method
     self.host = host
     self.port = port
     self.local_addr=local_addr
     self.tls=tls
     self.tls_server_hostname=tls_server_hostname
     self.json = json
     self.workername = None
     self.ping_timeout = ping_timeout
     self.ping_cb = ping_cb
     self._decoder = pynetstring.Decoder()
     if logger:
         self._logger = logger
     else:
         self._logger = logging.getLogger(__name__)
     if level:
         self._logger.setLevel(level)
     self.__calls = {}  # ids of call we're waiting for
     self.__id = 0
     self.__loop = asyncio.get_running_loop()
     self.__methods = {
         "rpcswitch.channel_gone": {"cb": self._rpc_channel_gone, "nf": True},
         "rpcswitch.greetings": {"cb": self._rpc_greetings, "nf": True},
         "rpcswitch.ping": {"cb": self._rpc_ping},
         "rpcswitch.result": {"cb": self._rpc_results, "nf": True},
     }
     self.__tasks = {}
     self.__waits = {}  # waitids for result notifications
     self.tls=False
     if tls:
         self._debug("setting up tls")
         ssl_context = ssl2.create_default_context(
             purpose=ssl2.Purpose.SERVER_AUTH,
             cafile=tls_ca,
         )
         if tls_key:
             ssl_context.verify_mode = ssl2.CERT_REQUIRED
             ssl_context.load_cert_chain(
                 certfile=tls_cert,
                 keyfile=tls_key,
             )
         self.tls = ssl_context