def test_deserialize_error_response_field_not_found(self): with self.assertRaises(UPnPError) as e: deserialize_soap_post_response(self.post_response, self.method + 'derp', service_id=self.st.decode()) self.assertTrue( str(e.exception).startswith( 'unknown response fields for GetExternalIPAddressderp'))
def test_raise_from_error_response(self): raised = False try: deserialize_soap_post_response(self.error_response, self.method, service_id=self.st.decode()) except UPnPError as err: raised = True self.assertTrue(str(err) == 'SpecifiedArrayIndexInvalid') self.assertTrue(raised)
def test_raise_from_error_response_without_error_description(self): raised = False expected = 'Failed to decode error response: {"faultcode": "s:Client", "faultstring": "UPnPError", "detail": {"UPnPError": {"errorCode": "713"}}}' try: deserialize_soap_post_response(self.error_response_no_description, self.method, service_id=self.st.decode()) except UPnPError as err: raised = True self.assertTrue(str(err) == expected) self.assertTrue(raised)
def test_deserialize_blank_response(self): # TODO: these seem like they should error... this test will break and have to be updated self.assertDictEqual({}, deserialize_soap_post_response( self.blank_response, self.method, service_id=self.st.decode())) self.assertDictEqual({}, deserialize_soap_post_response( self.blank_response_body, self.method, service_id=self.st.decode()))
def test_soap_env_namespace_response(self): # tp link devices use `SOAP-ENV` namespace rather than the normal `s` response = b'HTTP/1.1 200 OK\r\nCONNECTION: close\r\nSERVER: ipos/7.0 UPnP/1.0 TL-WR940N/TL-WR941ND/3.0\r\nCONTENT-LENGTH: 404\r\nCONTENT-TYPE: text/xml; charset="utf-8"\r\n\r\n<?xml version="1.0"?>\n<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">\n<SOAP-ENV:Body>\n<u:GetExternalIPAddressResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"><NewExternalIPAddress>100.100.100.100</NewExternalIPAddress></u:GetExternalIPAddressResponse></SOAP-ENV:Body>\n</SOAP-ENV:Envelope>\n' self.assertDictEqual( deserialize_soap_post_response(response, 'GetExternalIPAddress', self.st.decode()), {'NewExternalIPAddress': '100.100.100.100'})
async def scpd_post( control_url: str, address: str, port: int, method: str, param_names: list, service_id: bytes, loop: typing.Optional[asyncio.AbstractEventLoop] = None, **kwargs: typing.Dict[str, typing.Any] ) -> typing.Tuple[typing.Dict, bytes, typing.Optional[Exception]]: loop = loop or asyncio.get_event_loop() finished: 'asyncio.Future[typing.Tuple[bytes, bytes, int, bytes]]' = loop.create_future( ) packet = serialize_soap_post(method, param_names, service_id, address.encode(), control_url.encode(), **kwargs) proto_factory: typing.Callable[[], SCPDHTTPClientProtocol] = lambda:\ SCPDHTTPClientProtocol(packet, finished, soap_method=method, soap_service_id=service_id.decode()) try: connect_tup: typing.Tuple[ asyncio.BaseTransport, asyncio.BaseProtocol] = await loop.create_connection( proto_factory, address, port) except ConnectionError as err: return {}, b'', UPnPError(f"{err.__class__.__name__}({str(err)})") protocol = connect_tup[1] transport = connect_tup[0] assert isinstance(protocol, SCPDHTTPClientProtocol) try: wait_task: typing.Awaitable[typing.Tuple[bytes, bytes, int, bytes]] = asyncio.wait_for( finished, 1.0, loop=loop) raw_response, body, response_code, response_msg = await wait_task except asyncio.TimeoutError: return {}, b'', UPnPError("Timeout") except UPnPError as err: return {}, protocol.response_buff, err finally: transport.close() try: return (deserialize_soap_post_response(body, method, service_id.decode()), raw_response, None) except Exception as err: return {}, raw_response, UPnPError(err)
async def scpd_post( control_url: str, address: str, port: int, method: str, param_names: list, service_id: bytes, loop=None, **kwargs ) -> typing.Tuple[typing.Dict, bytes, typing.Optional[Exception]]: loop = loop or asyncio.get_event_loop_policy().get_event_loop() finished: asyncio.Future = asyncio.Future() packet = serialize_soap_post(method, param_names, service_id, address.encode(), control_url.encode(), **kwargs) transport, protocol = await loop.create_connection( lambda: SCPDHTTPClientProtocol( packet, finished, soap_method=method, soap_service_id=service_id.decode(), ), address, port) assert isinstance(protocol, SCPDHTTPClientProtocol) try: body, response_code, response_msg = await asyncio.wait_for( finished, 1.0) except asyncio.TimeoutError: return {}, b'', UPnPError("Timeout") except UPnPError as err: return {}, protocol.response_buff, err finally: transport.close() try: return (deserialize_soap_post_response(body, method, service_id.decode()), body, None) except (ElementTree.ParseError, UPnPError) as err: return {}, body, UPnPError(err)
def test_deserialize_post_response(self): self.assertDictEqual( deserialize_soap_post_response(self.post_response, self.method, service_id=self.st.decode()), {'NewExternalIPAddress': '11.22.33.44'})