diff --git a/aioupnp/protocols/scpd.py b/aioupnp/protocols/scpd.py
index a1bd4dc..01147c4 100644
--- a/aioupnp/protocols/scpd.py
+++ b/aioupnp/protocols/scpd.py
@@ -56,6 +56,7 @@ class SCPDHTTPClientProtocol(Protocol):
self._response_msg = b""
self._content_length = 0
self._got_headers = False
+ self._has_content_length = True
self._headers: typing.Dict[bytes, bytes] = {}
self._body = b""
self.transport: typing.Optional[asyncio.WriteTransport] = None
@@ -67,35 +68,57 @@ class SCPDHTTPClientProtocol(Protocol):
return None
def data_received(self, data: bytes) -> None:
+ if self.finished.done(): # possible to hit during tests
+ return
self.response_buff += data
for i, line in enumerate(self.response_buff.split(b'\r\n')):
if not line: # we hit the blank line between the headers and the body
if i == (len(self.response_buff.split(b'\r\n')) - 1):
return None # the body is still yet to be written
if not self._got_headers:
- self._headers, self._response_code, self._response_msg = parse_headers(
- b'\r\n'.join(self.response_buff.split(b'\r\n')[:i])
- )
+ try:
+ self._headers, self._response_code, self._response_msg = parse_headers(
+ b'\r\n'.join(self.response_buff.split(b'\r\n')[:i])
+ )
+ except ValueError as err:
+ self.finished.set_exception(UPnPError(str(err)))
+ return
content_length = get_dict_val_case_insensitive(
self._headers, b'Content-Length'
)
- if content_length is None:
- return None
- self._content_length = int(content_length or 0)
+ if content_length is not None:
+ self._content_length = int(content_length)
+ else:
+ self._has_content_length = False
self._got_headers = True
- body = b'\r\n'.join(self.response_buff.split(b'\r\n')[i+1:])
- if self._content_length == len(body):
- self.finished.set_result((self.response_buff, body, self._response_code, self._response_msg))
- elif self._content_length > len(body):
- pass
- else:
- self.finished.set_exception(
- UPnPError(
- "too many bytes written to response (%i vs %i expected)" % (
- len(body), self._content_length
+ if self._got_headers and self._has_content_length:
+ body = b'\r\n'.join(self.response_buff.split(b'\r\n')[i+1:])
+ if self._content_length == len(body):
+ self.finished.set_result((self.response_buff, body, self._response_code, self._response_msg))
+ elif self._content_length > len(body):
+ pass
+ else:
+ self.finished.set_exception(
+ UPnPError(
+ "too many bytes written to response (%i vs %i expected)" % (
+ len(body), self._content_length
+ )
)
)
- )
+ elif any(map(self.response_buff.endswith, (b"\r\n", b"\r\n"))):
+ # Actiontec has a router that doesn't give a Content-Length for the gateway xml
+ body = b'\r\n'.join(self.response_buff.split(b'\r\n')[i+1:])
+ self.finished.set_result((self.response_buff, body, self._response_code, self._response_msg))
+ elif len(self.response_buff) >= 65535:
+ self.finished.set_exception(
+ UPnPError(
+ "too many bytes written to response (%i) with unspecified content length" % len(self.response_buff)
+ )
+ )
+ return
+ else:
+ # needed for the actiontec case
+ pass
return None
return None
diff --git a/tests/__init__.py b/tests/__init__.py
index 45c9d29..4cf83d1 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -18,7 +18,7 @@ except ImportError:
@contextlib.contextmanager
def mock_tcp_and_udp(loop, udp_expected_addr=None, udp_replies=None, udp_delay_reply=0.0, sent_udp_packets=None,
tcp_replies=None, tcp_delay_reply=0.0, sent_tcp_packets=None, add_potato_datagrams=False,
- raise_oserror_on_bind=False, raise_connectionerror=False):
+ raise_oserror_on_bind=False, raise_connectionerror=False, tcp_chunk_size=100):
sent_udp_packets = sent_udp_packets if sent_udp_packets is not None else []
udp_replies = udp_replies or {}
@@ -36,8 +36,8 @@ def mock_tcp_and_udp(loop, udp_expected_addr=None, udp_replies=None, udp_delay_r
reply = tcp_replies[data]
i = 0
while i < len(reply):
- loop.call_later(tcp_delay_reply, p.data_received, reply[i:i+100])
- i += 100
+ loop.call_later(tcp_delay_reply, p.data_received, reply[i:i+tcp_chunk_size])
+ i += tcp_chunk_size
return
else:
pass
@@ -71,6 +71,7 @@ def mock_tcp_and_udp(loop, udp_expected_addr=None, udp_replies=None, udp_delay_r
loop.call_later(udp_delay_reply, p.datagram_received, udp_replies[(data, addr)],
(udp_expected_addr, 1900))
+
return _sendto
protocol = proto_lam()
diff --git a/tests/replays/Actiontec GT784WN b/tests/replays/Actiontec GT784WN
new file mode 100644
index 0000000..7eb2e79
--- /dev/null
+++ b/tests/replays/Actiontec GT784WN
@@ -0,0 +1,120 @@
+{
+ "gateway": {
+ "gateway_address": "192.168.0.1",
+ "soap_port": 5431,
+ "m_search_args": {
+ "HOST": "239.255.255.250:1900",
+ "MAN": "\"ssdp:discover\"",
+ "MX": 1,
+ "ST": "upnp:rootdevice"
+ },
+ "reply": {
+ "Server": "Custom/1.0 UPnP/1.0 Proc/Ver",
+ "Location": "http://192.168.0.1:5431/dyndev/uuid:deadbeef-dead-beef-dead-beefdeadbeef00",
+ "CACHE_CONTROL": "max-age=1800",
+ "ST": "upnp:rootdevice",
+ "USN": "uuid:deadbeef-dead-beef-dead-beefdeadbeef00::upnp:rootdevice"
+ },
+ "registered_soap_commands": {
+ "GetDefaultConnectionService": "urn:schemas-upnp-org:service:Layer3Forwarding:1",
+ "SetDefaultConnectionService": "urn:schemas-upnp-org:service:Layer3Forwarding:1",
+ "GetCommonLinkProperties": "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
+ "GetTotalBytesSent": "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
+ "GetTotalBytesReceived": "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
+ "GetTotalPacketsReceived": "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
+ "GetTotalPacketsSent": "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
+ "SetConnectionType": "urn:schemas-upnp-org:service:WANPPPConnection:1",
+ "GetConnectionTypeInfo": "urn:schemas-upnp-org:service:WANPPPConnection:1",
+ "RequestConnection": "urn:schemas-upnp-org:service:WANPPPConnection:1",
+ "ForceTermination": "urn:schemas-upnp-org:service:WANPPPConnection:1",
+ "GetStatusInfo": "urn:schemas-upnp-org:service:WANPPPConnection:1",
+ "GetNATRSIPStatus": "urn:schemas-upnp-org:service:WANPPPConnection:1",
+ "GetGenericPortMappingEntry": "urn:schemas-upnp-org:service:WANPPPConnection:1",
+ "GetSpecificPortMappingEntry": "urn:schemas-upnp-org:service:WANPPPConnection:1",
+ "AddPortMapping": "urn:schemas-upnp-org:service:WANPPPConnection:1",
+ "DeletePortMapping": "urn:schemas-upnp-org:service:WANPPPConnection:1",
+ "GetExternalIPAddress": "urn:schemas-upnp-org:service:WANPPPConnection:1"
+ },
+ "unsupported_soap_commands": {},
+ "gateway_xml": "HTTP/1.0 200 OK\r\nSERVER: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nDATE: Thu, 11 Oct 2018 15:42:26 GMT\r\nCONTENT-TYPE: application/octet-stream\r\nCache-Control: max-age=1\r\nPRAGMA: no-cache\r\nConnection: Close\r\n\r\n\r\n\r\n\r\n1\r\n0\r\n\r\nhttp://192.168.0.1:5431/\r\n\r\nurn:schemas-upnp-org:device:InternetGatewayDevice:1\r\nhttp://192.168.0.1:80/\r\nActiontec GT784WN\r\nActiontec\r\nhttp://www.broadcom.com/\r\n(null)\r\nGT784WN\r\n1.0\r\nhttp://www.broadcom.com/\r\nuuid:deadbeef-dead-beef-dead-beefdeadbeef00\r\n\r\n\r\nurn:schemas-upnp-org:service:Layer3Forwarding:1\r\nurn:upnp-org:serviceId:Layer3Forwarding.1\r\n/uuid:deadbeef-dead-beef-dead-beefdeadbeef00/Layer3Forwarding:1\r\n/uuid:deadbeef-dead-beef-dead-beefdeadbeef00/Layer3Forwarding:1\r\n/dynsvc/Layer3Forwarding:1.xml\r\n\r\n\r\n\r\n\r\nurn:schemas-upnp-org:device:WANDevice:1\r\nWANDevice.1\r\nActiontec\r\nhttp://www.broadcom.com/\r\n(null)\r\nGT784WN\r\n1.0\r\nhttp://www.broadcom.com/\r\nuuid:70f196f9-33f5-f533-f996-f170f1f9f50001\r\n\r\n\r\nurn:schemas-upnp-org:service:WANCommonInterfaceConfig:1\r\nurn:upnp-org:serviceId:WANCommonInterfaceConfig.1\r\n/uuid:70f196f9-33f5-f533-f996-f170f1f9f50001/WANCommonInterfaceConfig:1\r\n/uuid:70f196f9-33f5-f533-f996-f170f1f9f50001/WANCommonInterfaceConfig:1\r\n/dynsvc/WANCommonInterfaceConfig:1.xml\r\n\r\n\r\n\r\n\r\nurn:schemas-upnp-org:device:WANConnectionDevice:1\r\nWanConnectionDevice.2\r\nActiontec\r\nhttp://www.broadcom.com/\r\n(null)\r\nGT784WN\r\n1.0\r\nhttp://www.broadcom.com/\r\nuuid:70f196f9-33f5-f533-f996-f170f1f9f50002\r\n\r\n\r\nurn:schemas-upnp-org:service:WANPPPConnection:1\r\nurn:upnp-org:serviceId:WANPPPConnection.2\r\n/uuid:70f196f9-33f5-f533-f996-f170f1f9f50002/WANPPPConnection:1\r\n/uuid:70f196f9-33f5-f533-f996-f170f1f9f50002/WANPPPConnection:1\r\n/dynsvc/WANPPPConnection:1.xml\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n",
+ "service_descriptors": {
+ "/dynsvc/Layer3Forwarding:1.xml": "HTTP/1.0 200 OK\r\nSERVER: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nDATE: Thu, 11 Oct 2018 15:42:26 GMT\r\nCONTENT-TYPE: application/octet-stream\r\nCache-Control: max-age=1\r\nPRAGMA: no-cache\r\nConnection: Close\r\n\r\n\r\n\r\n \r\n 1\r\n 0\r\n \r\n\r\n\r\nGetDefaultConnectionService\r\n\r\n\r\nNewDefaultConnectionService\r\nDefaultConnectionService\r\nout\r\n\r\n\r\n\r\n\r\nSetDefaultConnectionService\r\n\r\n\r\nNewDefaultConnectionService\r\nDefaultConnectionService\r\nin\r\n\r\n\r\n\r\n\r\n\r\n\r\n DefaultConnectionService\r\n string\r\n\r\n\r\n\r\n",
+ "/dynsvc/WANCommonInterfaceConfig:1.xml": "HTTP/1.0 200 OK\r\nSERVER: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nDATE: Thu, 11 Oct 2018 15:42:26 GMT\r\nCONTENT-TYPE: application/octet-stream\r\nCache-Control: max-age=1\r\nPRAGMA: no-cache\r\nConnection: Close\r\n\r\n\r\n\r\n \r\n 1\r\n 0\r\n \r\n\r\n\r\nGetCommonLinkProperties\r\n\r\n\r\nNewWANAccessType\r\nWANAccessType\r\nout\r\n\r\n\r\nNewLayer1UpstreamMaxBitRate\r\nLayer1UpstreamMaxBitRate\r\nout\r\n\r\n\r\nNewLayer1DownstreamMaxBitRate\r\nLayer1DownstreamMaxBitRate\r\nout\r\n\r\n\r\nNewPhysicalLinkStatus\r\nPhysicalLinkStatus\r\nout\r\n\r\n\r\n\r\n\r\nGetTotalBytesSent\r\n\r\n\r\nNewTotalBytesSent\r\nTotalBytesSent\r\nout\r\n\r\n\r\n\r\n\r\nGetTotalBytesReceived\r\n\r\n\r\nNewTotalBytesReceived\r\nTotalBytesReceived\r\nout\r\n\r\n\r\n\r\n\r\nGetTotalPacketsReceived\r\n\r\n\r\nNewTotalPacketsReceived\r\nTotalPacketsReceived\r\nout\r\n\r\n\r\n\r\n\r\nGetTotalPacketsSent\r\n\r\n\r\nNewTotalPacketsSent\r\nTotalPacketsSent\r\nout\r\n\r\n\r\n\r\n\r\n\r\n\r\n WANAccessType\r\n string\r\n \r\n DSL\r\n POTS\r\n Cable\r\n Ethernet\r\n Other\r\n \r\n\r\n\r\n Layer1UpstreamMaxBitRate\r\n ui4\r\n\r\n\r\n Layer1DownstreamMaxBitRate\r\n ui4\r\n\r\n\r\n PhysicalLinkStatus\r\n string\r\n \r\n Up\r\n Down\r\n Initializing\r\n Unavailable\r\n \r\n\r\n\r\n EnabledForInternet\r\n boolean\r\n\r\n\r\n TotalBytesSent\r\n ui4\r\n\r\n\r\n TotalBytesReceived\r\n ui4\r\n\r\n\r\n TotalPacketsSent\r\n ui4\r\n\r\n\r\n TotalPacketsReceived\r\n ui4\r\n\r\n\r\n\r\n",
+ "/dynsvc/WANPPPConnection:1.xml": "HTTP/1.0 200 OK\r\nSERVER: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nDATE: Thu, 11 Oct 2018 15:42:26 GMT\r\nCONTENT-TYPE: application/octet-stream\r\nCache-Control: max-age=1\r\nPRAGMA: no-cache\r\nConnection: Close\r\n\r\n\r\n\r\n \r\n 1\r\n 0\r\n \r\n\r\n\r\nSetConnectionType\r\n\r\n\r\nNewConnectionType\r\nConnectionType\r\nin\r\n\r\n\r\n\r\n\r\nGetConnectionTypeInfo\r\n\r\n\r\nNewConnectionType\r\nConnectionType\r\nout\r\n\r\n\r\nNewPossibleConnectionTypes\r\nPossibleConnectionTypes\r\nout\r\n\r\n\r\n\r\n\r\nRequestConnection\r\n\r\n\r\nForceTermination\r\n\r\n\r\nGetStatusInfo\r\n\r\n\r\nNewConnectionStatus\r\nConnectionStatus\r\nout\r\n\r\n\r\nNewLastConnectionError\r\nLastConnectionError\r\nout\r\n\r\n\r\nNewUptime\r\nUptime\r\nout\r\n\r\n\r\n\r\n\r\nGetNATRSIPStatus\r\n\r\n\r\nNewRSIPAvailable\r\nRSIPAvailable\r\nout\r\n\r\n\r\nNewNATEnabled\r\nNATEnabled\r\nout\r\n\r\n\r\n\r\n\r\nGetGenericPortMappingEntry\r\n\r\n\r\nNewPortMappingIndex\r\nPortMappingNumberOfEntries\r\nin\r\n\r\n\r\nNewRemoteHost\r\nRemoteHost\r\nout\r\n\r\n\r\nNewExternalPort\r\nExternalPort\r\nout\r\n\r\n\r\nNewProtocol\r\nPortMappingProtocol\r\nout\r\n\r\n\r\nNewInternalPort\r\nInternalPort\r\nout\r\n\r\n\r\nNewInternalClient\r\nInternalClient\r\nout\r\n\r\n\r\nNewEnabled\r\nPortMappingEnabled\r\nout\r\n\r\n\r\nNewPortMappingDescription\r\nPortMappingDescription\r\nout\r\n\r\n\r\nNewLeaseDuration\r\nPortMappingLeaseDuration\r\nout\r\n\r\n\r\n\r\n\r\nGetSpecificPortMappingEntry\r\n\r\n\r\nNewRemoteHost\r\nRemoteHost\r\nin\r\n\r\n\r\nNewExternalPort\r\nExternalPort\r\nin\r\n\r\n\r\nNewProtocol\r\nPortMappingProtocol\r\nin\r\n\r\n\r\nNewInternalPort\r\nInternalPort\r\nout\r\n\r\n\r\nNewInternalClient\r\nInternalClient\r\nout\r\n\r\n\r\nNewEnabled\r\nPortMappingEnabled\r\nout\r\n\r\n\r\nNewPortMappingDescription\r\nPortMappingDescription\r\nout\r\n\r\n\r\nNewLeaseDuration\r\nPortMappingLeaseDuration\r\nout\r\n\r\n\r\n\r\n\r\nAddPortMapping\r\n\r\n\r\nNewRemoteHost\r\nRemoteHost\r\nin\r\n\r\n\r\nNewExternalPort\r\nExternalPort\r\nin\r\n\r\n\r\nNewProtocol\r\nPortMappingProtocol\r\nin\r\n\r\n\r\nNewInternalPort\r\nInternalPort\r\nin\r\n\r\n\r\nNewInternalClient\r\nInternalClient\r\nin\r\n\r\n\r\nNewEnabled\r\nPortMappingEnabled\r\nin\r\n\r\n\r\nNewPortMappingDescription\r\nPortMappingDescription\r\nin\r\n\r\n\r\nNewLeaseDuration\r\nPortMappingLeaseDuration\r\nin\r\n\r\n\r\n\r\n\r\nDeletePortMapping\r\n\r\n\r\nNewRemoteHost\r\nRemoteHost\r\nin\r\n\r\n\r\nNewExternalPort\r\nExternalPort\r\nin\r\n\r\n\r\nNewProtocol\r\nPortMappingProtocol\r\nin\r\n\r\n\r\n\r\n\r\nGetExternalIPAddress\r\n\r\n\r\nNewExternalIPAddress\r\nExternalIPAddress\r\nout\r\n\r\n\r\n\r\n\r\n\r\n\r\n ConnectionType\r\n string\r\n \r\n Unconfigured\r\n IP_Routed\r\n DHCP_Spoofed\r\n PPPoE_Bridged\r\n PPTP_Relay\r\n L2TP_Relay\r\n PPPoE_Relay\r\n \r\n\r\n\r\n PossibleConnectionTypes\r\n string\r\n \r\n Unconfigured\r\n IP_Routed\r\n DHCP_Spoofed\r\n PPPoE_Bridged\r\n PPTP_Relay\r\n L2TP_Relay\r\n PPPoE_Relay\r\n \r\n\r\n\r\n ConnectionStatus\r\n string\r\n \r\n Unconfigured\r\n Connecting\r\n Authenticating\r\n Connected\r\n PendingDisconnect\r\n Disconnecting\r\n Disconnected\r\n \r\n\r\n\r\n Uptime\r\n ui4\r\n\r\n\r\n UpstreamMaxBitRate\r\n ui4\r\n\r\n\r\n DownstreamMaxBitRate\r\n ui4\r\n\r\n\r\n LastConnectionError\r\n string\r\n \r\n ERROR_NONE\r\n ERROR_UNKNOWN\r\n \r\n\r\n\r\n RSIPAvailable\r\n boolean\r\n\r\n\r\n NATEnabled\r\n boolean\r\n\r\n\r\n ExternalIPAddress\r\n string\r\n\r\n\r\n PortMappingNumberOfEntries\r\n ui2\r\n\r\n\r\n PortMappingEnabled\r\n boolean\r\n\r\n\r\n PortMappingLeaseDuration\r\n ui4\r\n\r\n\r\n RemoteHost\r\n string\r\n\r\n\r\n ExternalPort\r\n ui2\r\n\r\n\r\n InternalPort\r\n ui2\r\n\r\n\r\n PortMappingProtocol\r\n string\r\n \r\n TCP\r\n UDP\r\n \r\n\r\n\r\n InternalClient\r\n string\r\n\r\n\r\n PortMappingDescription\r\n string\r\n\r\n\r\n\r\n"
+ },
+ "soap_requests": {
+ "GetDefaultConnectionService": [],
+ "SetDefaultConnectionService": [],
+ "GetCommonLinkProperties": [],
+ "GetTotalBytesSent": [],
+ "GetTotalBytesReceived": [],
+ "GetTotalPacketsReceived": [],
+ "GetTotalPacketsSent": [],
+ "SetConnectionType": [],
+ "GetConnectionTypeInfo": [],
+ "RequestConnection": [],
+ "ForceTermination": [],
+ "GetStatusInfo": [],
+ "GetNATRSIPStatus": [],
+ "GetGenericPortMappingEntry": [
+ [
+ {
+ "NewPortMappingIndex": 0
+ },
+ "HTTP/1.1 200 OK\r\nDATE: Thu, 11 Oct 2018 15:42:26 GMT\r\nConnection: Keep-Alive\r\nServer: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nContent-Length: 654\r\nContent-Type: text/xml; charset=\"utf-8\"\r\nEXT:\r\n\r\n\r\n3658UDP3658192.168.0.101192.168.0.10:3658 to 3658 (UDP)0\r\n"
+ ],
+ [
+ {
+ "NewPortMappingIndex": 1
+ },
+ "HTTP/1.1 500 Internal Server Error\r\nDATE: Thu, 11 Oct 2018 15:42:26 GMT\r\nConnection: Keep-Alive\r\nServer: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nContent-Length: 474\r\nContent-Type: text/xml; charset=\"utf-8\"\r\nEXT:\r\n\r\n\r\n \r\n \r\n s:Client\r\n UPnPError\r\n \r\n \r\n 713\r\n SpecifiedArrayIndexInvalid\r\n \r\n \r\n \r\n \r\n\r\n"
+ ],
+ [
+ {
+ "NewPortMappingIndex": 0
+ },
+ "HTTP/1.1 200 OK\r\nDATE: Thu, 11 Oct 2018 15:42:26 GMT\r\nConnection: Keep-Alive\r\nServer: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nContent-Length: 654\r\nContent-Type: text/xml; charset=\"utf-8\"\r\nEXT:\r\n\r\n\r\n3658UDP3658192.168.0.101192.168.0.10:3658 to 3658 (UDP)0\r\n"
+ ],
+ [
+ {
+ "NewPortMappingIndex": 1
+ },
+ "HTTP/1.1 500 Internal Server Error\r\nDATE: Thu, 11 Oct 2018 15:42:26 GMT\r\nConnection: Keep-Alive\r\nServer: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nContent-Length: 474\r\nContent-Type: text/xml; charset=\"utf-8\"\r\nEXT:\r\n\r\n\r\n \r\n \r\n s:Client\r\n UPnPError\r\n \r\n \r\n 713\r\n SpecifiedArrayIndexInvalid\r\n \r\n \r\n \r\n \r\n\r\n"
+ ]
+ ],
+ "GetSpecificPortMappingEntry": [],
+ "AddPortMapping": [
+ [
+ {
+ "NewRemoteHost": "",
+ "NewExternalPort": 4567,
+ "NewProtocol": "UDP",
+ "NewInternalPort": 4567,
+ "NewInternalClient": "192.168.0.9",
+ "NewEnabled": true,
+ "NewPortMappingDescription": "aioupnp test mapping",
+ "NewLeaseDuration": ""
+ },
+ ""
+ ]
+ ],
+ "DeletePortMapping": [
+ [
+ {
+ "NewRemoteHost": "",
+ "NewExternalPort": 4567,
+ "NewProtocol": "UDP"
+ },
+ ""
+ ]
+ ],
+ "GetExternalIPAddress": [
+ [
+ {},
+ "HTTP/1.1 200 OK\r\nDATE: Thu, 11 Oct 2018 15:42:26 GMT\r\nConnection: Keep-Alive\r\nServer: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nContent-Length: 360\r\nContent-Type: text/xml; charset=\"utf-8\"\r\nEXT:\r\n\r\n\r\n11.222.33.111\r\n"
+ ]
+ ]
+ }
+ },
+ "client_address": "192.168.0.9"
+}
\ No newline at end of file
diff --git a/tests/replays/NewMedia-NET GmbH Generic X86 b/tests/replays/NewMedia-NET GmbH Generic X86
new file mode 100644
index 0000000..c34840b
--- /dev/null
+++ b/tests/replays/NewMedia-NET GmbH Generic X86
@@ -0,0 +1,129 @@
+{
+ "gateway": {
+ "gateway_address": "192.168.1.1",
+ "soap_port": 5431,
+ "m_search_args": {
+ "HOST": "239.255.255.250:1900",
+ "MAN": "\"ssdp:discover\"",
+ "MX": 1,
+ "ST": "upnp:rootdevice"
+ },
+ "reply": {
+ "ST": "upnp:rootdevice",
+ "USN": "uuid:dead-beef-deadbeef2222::upnp:rootdevice",
+ "Location": "http://192.168.1.1:5431/dyndev/uuid:dead-beef-deadbeef2222",
+ "Server": "Custom/1.0 UPnP/1.0 Proc/Ver",
+ "CACHE_CONTROL": "max-age=180"
+ },
+ "registered_soap_commands": {
+ "GetDefaultConnectionService": "urn:schemas-upnp-org:service:Layer3Forwarding:1",
+ "SetDefaultConnectionService": "urn:schemas-upnp-org:service:Layer3Forwarding:1",
+ "GetCommonLinkProperties": "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
+ "GetTotalBytesSent": "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
+ "GetTotalBytesReceived": "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
+ "GetTotalPacketsReceived": "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
+ "GetTotalPacketsSent": "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
+ "SetConnectionType": "urn:schemas-upnp-org:service:WANIPConnection:1",
+ "GetConnectionTypeInfo": "urn:schemas-upnp-org:service:WANIPConnection:1",
+ "RequestConnection": "urn:schemas-upnp-org:service:WANIPConnection:1",
+ "ForceTermination": "urn:schemas-upnp-org:service:WANIPConnection:1",
+ "GetStatusInfo": "urn:schemas-upnp-org:service:WANIPConnection:1",
+ "GetNATRSIPStatus": "urn:schemas-upnp-org:service:WANIPConnection:1",
+ "GetGenericPortMappingEntry": "urn:schemas-upnp-org:service:WANIPConnection:1",
+ "GetSpecificPortMappingEntry": "urn:schemas-upnp-org:service:WANIPConnection:1",
+ "AddPortMapping": "urn:schemas-upnp-org:service:WANIPConnection:1",
+ "DeletePortMapping": "urn:schemas-upnp-org:service:WANIPConnection:1",
+ "GetExternalIPAddress": "urn:schemas-upnp-org:service:WANIPConnection:1"
+ },
+ "unsupported_soap_commands": {
+ "urn:schemas-upnp-org:service:WANPPPConnection:1": [
+ "SetConnectionType",
+ "GetConnectionTypeInfo",
+ "ConfigureConnection",
+ "RequestConnection",
+ "ForceTermination",
+ "SetIdleDisconnectTime",
+ "GetStatusInfo",
+ "GetLinkLayerMaxBitRates",
+ "GetUserName",
+ "GetPassword",
+ "GetIdleDisconnectTime",
+ "GetNATRSIPStatus",
+ "GetGenericPortMappingEntry",
+ "GetSpecificPortMappingEntry",
+ "AddPortMapping",
+ "DeletePortMapping",
+ "GetExternalIPAddress"
+ ]
+ },
+ "gateway_xml": "HTTP/1.0 200 OK\r\nServer: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nDate: Thu, 01 Jan 1970 00:23:13 GMT\r\nContent-Type: text/xml\r\nCache-Control: max-age=1\r\nPragma: no-cache\r\nConnection: close\r\n\r\n\r\n\r\n \r\n 1\r\n 0\r\n \r\n \r\n urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n DD-WRT Router (192.168.1.1)\r\n NewMedia-NET GmbH\r\n http://www.dd-wrt.com/\r\n Internet Gateway Device\r\n Generic X86\r\n DD-WRT v24 (05/20/08)\r\n http://www.dd-wrt.com/\r\n Not Available\r\n uuid:dead-beef-deadbeef2222\r\n \r\n \r\n urn:schemas-upnp-org:service:Layer3Forwarding:1\r\n urn:upnp-org:serviceId:L3Forwarding1\r\n /dynsvc/Layer3Forwarding:1.xml\r\n /uuid:dead-beef-deadbeef2222/Layer3Forwarding:1\r\n /uuid:dead-beef-deadbeef2222/Layer3Forwarding:1\r\n \r\n \r\n \r\n \r\n urn:schemas-upnp-org:device:WANDevice:1\r\n urn:schemas-upnp-org:device:WANDevice:1\r\n NewMedia-NET GmbH\r\n http://www.dd-wrt.com/\r\n Internet Gateway Device\r\n Generic X86\r\n DD-WRT v24 (05/20/08)\r\n http://www.dd-wrt.com/\r\n Not Available\r\n uuid:000c-29ea-247501c00098\r\n \r\n \r\n urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1\r\n urn:upnp-org:serviceId:WANCommonIFC1\r\n /dynsvc/WANCommonInterfaceConfig:1.xml\r\n /uuid:000c-29ea-247501c00098/WANCommonInterfaceConfig:1\r\n /uuid:000c-29ea-247501c00098/WANCommonInterfaceConfig:1\r\n \r\n \r\n \r\n \r\n urn:schemas-upnp-org:device:WANConnectionDevice:1\r\n urn:schemas-upnp-org:device:WANConnectionDevice:1\r\n NewMedia-NET GmbH\r\n http://www.dd-wrt.com/\r\n Internet Gateway Device\r\n Generic X86\r\n DD-WRT v24 (05/20/08)\r\n http://www.dd-wrt.com/\r\n Not Available\r\n uuid:dead-beef-deadbeef0000\r\n \r\n \r\n urn:schemas-upnp-org:service:WANIPConnection:1\r\n urn:upnp-org:serviceId:WANIPConn1\r\n /dynsvc/WANIPConnection:1.xml\r\n /uuid:dead-beef-deadbeef0000/WANIPConnection:1\r\n /uuid:dead-beef-deadbeef0000/WANIPConnection:1\r\n \r\n \r\n urn:schemas-upnp-org:service:WANPPPConnection:1\r\n urn:upnp-org:serviceId:WANPPPConn1\r\n /dynsvc/WANPPPConnection:1.xml\r\n /uuid:dead-beef-deadbeef0000/WANPPPConnection:1\r\n /uuid:dead-beef-deadbeef0000/WANPPPConnection:1\r\n \r\n \r\n\r\n \r\n\r\n \r\n\r\n\r\n",
+ "service_descriptors": {
+ "/dynsvc/Layer3Forwarding:1.xml": "HTTP/1.0 200 OK\r\nServer: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nDate: Thu, 01 Jan 1970 00:23:13 GMT\r\nContent-Type: text/xml\r\nCache-Control: max-age=1\r\nPragma: no-cache\r\nConnection: close\r\n\r\n\r\n\r\n \r\n 1\r\n 0\r\n \r\n\r\n\r\nGetDefaultConnectionService\r\n\r\n\r\nNewDefaultConnectionService\r\nDefaultConnectionService\r\nout\r\n\r\n\r\n\r\n\r\nSetDefaultConnectionService\r\n\r\n\r\nNewDefaultConnectionService\r\nDefaultConnectionService\r\nin\r\n\r\n\r\n\r\n\r\n\r\n\r\n DefaultConnectionService\r\n string\r\n\r\n\r\n\r\n",
+ "/dynsvc/WANCommonInterfaceConfig:1.xml": "HTTP/1.0 200 OK\r\nServer: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nDate: Thu, 01 Jan 1970 00:23:13 GMT\r\nContent-Type: text/xml\r\nCache-Control: max-age=1\r\nPragma: no-cache\r\nConnection: close\r\n\r\n\r\n\r\n \r\n 1\r\n 0\r\n \r\n\r\n\r\nGetCommonLinkProperties\r\n\r\n\r\nNewWANAccessType\r\nWANAccessType\r\nout\r\n\r\n\r\nNewLayer1UpstreamMaxBitRate\r\nLayer1UpstreamMaxBitRate\r\nout\r\n\r\n\r\nNewLayer1DownstreamMaxBitRate\r\nLayer1DownstreamMaxBitRate\r\nout\r\n\r\n\r\nNewPhysicalLinkStatus\r\nPhysicalLinkStatus\r\nout\r\n\r\n\r\n\r\n\r\nGetTotalBytesSent\r\n\r\n\r\nNewTotalBytesSent\r\nTotalBytesSent\r\nout\r\n\r\n\r\n\r\n\r\nGetTotalBytesReceived\r\n\r\n\r\nNewTotalBytesReceived\r\nTotalBytesReceived\r\nout\r\n\r\n\r\n\r\n\r\nGetTotalPacketsReceived\r\n\r\n\r\nNewTotalPacketsReceived\r\nTotalPacketsReceived\r\nout\r\n\r\n\r\n\r\n\r\nGetTotalPacketsSent\r\n\r\n\r\nNewTotalPacketsSent\r\nTotalPacketsSent\r\nout\r\n\r\n\r\n\r\n\r\n\r\n\r\n WANAccessType\r\n string\r\n \r\n DSL\r\n POTS\r\n Cable\r\n Ethernet\r\n Other\r\n \r\n\r\n\r\n Layer1UpstreamMaxBitRate\r\n ui4\r\n\r\n\r\n Layer1DownstreamMaxBitRate\r\n ui4\r\n\r\n\r\n PhysicalLinkStatus\r\n string\r\n \r\n Up\r\n Down\r\n Initializing\r\n Unavailable\r\n \r\n\r\n\r\n EnabledForInternet\r\n boolean\r\n\r\n\r\n TotalBytesSent\r\n ui4\r\n\r\n\r\n TotalBytesReceived\r\n ui4\r\n\r\n\r\n TotalPacketsSent\r\n ui4\r\n\r\n\r\n TotalPacketsReceived\r\n ui4\r\n\r\n\r\n\r\n",
+ "/dynsvc/WANIPConnection:1.xml": "HTTP/1.0 200 OK\r\nServer: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nDate: Thu, 01 Jan 1970 00:23:13 GMT\r\nContent-Type: text/xml\r\nCache-Control: max-age=1\r\nPragma: no-cache\r\nConnection: close\r\n\r\n\r\n\r\n \r\n 1\r\n 0\r\n \r\n\r\n\r\nSetConnectionType\r\n\r\n\r\nNewConnectionType\r\nConnectionType\r\nin\r\n\r\n\r\n\r\n\r\nGetConnectionTypeInfo\r\n\r\n\r\nNewConnectionType\r\nConnectionType\r\nout\r\n\r\n\r\nNewPossibleConnectionTypes\r\nPossibleConnectionTypes\r\nout\r\n\r\n\r\n\r\n\r\nRequestConnection\r\n\r\n\r\nForceTermination\r\n\r\n\r\nGetStatusInfo\r\n\r\n\r\nNewConnectionStatus\r\nConnectionStatus\r\nout\r\n\r\n\r\nNewLastConnectionError\r\nLastConnectionError\r\nout\r\n\r\n\r\nNewUptime\r\nUptime\r\nout\r\n\r\n\r\n\r\n\r\nGetNATRSIPStatus\r\n\r\n\r\nNewRSIPAvailable\r\nRSIPAvailable\r\nout\r\n\r\n\r\nNewNATEnabled\r\nNATEnabled\r\nout\r\n\r\n\r\n\r\n\r\nGetGenericPortMappingEntry\r\n\r\n\r\nNewPortMappingIndex\r\nPortMappingNumberOfEntries\r\nin\r\n\r\n\r\nNewRemoteHost\r\nRemoteHost\r\nout\r\n\r\n\r\nNewExternalPort\r\nExternalPort\r\nout\r\n\r\n\r\nNewProtocol\r\nPortMappingProtocol\r\nout\r\n\r\n\r\nNewInternalPort\r\nInternalPort\r\nout\r\n\r\n\r\nNewInternalClient\r\nInternalClient\r\nout\r\n\r\n\r\nNewEnabled\r\nPortMappingEnabled\r\nout\r\n\r\n\r\nNewPortMappingDescription\r\nPortMappingDescription\r\nout\r\n\r\n\r\nNewLeaseDuration\r\nPortMappingLeaseDuration\r\nout\r\n\r\n\r\n\r\n\r\nGetSpecificPortMappingEntry\r\n\r\n\r\nNewRemoteHost\r\nRemoteHost\r\nin\r\n\r\n\r\nNewExternalPort\r\nExternalPort\r\nin\r\n\r\n\r\nNewProtocol\r\nPortMappingProtocol\r\nin\r\n\r\n\r\nNewInternalPort\r\nInternalPort\r\nout\r\n\r\n\r\nNewInternalClient\r\nInternalClient\r\nout\r\n\r\n\r\nNewEnabled\r\nPortMappingEnabled\r\nout\r\n\r\n\r\nNewPortMappingDescription\r\nPortMappingDescription\r\nout\r\n\r\n\r\nNewLeaseDuration\r\nPortMappingLeaseDuration\r\nout\r\n\r\n\r\n\r\n\r\nAddPortMapping\r\n\r\n\r\nNewRemoteHost\r\nRemoteHost\r\nin\r\n\r\n\r\nNewExternalPort\r\nExternalPort\r\nin\r\n\r\n\r\nNewProtocol\r\nPortMappingProtocol\r\nin\r\n\r\n\r\nNewInternalPort\r\nInternalPort\r\nin\r\n\r\n\r\nNewInternalClient\r\nInternalClient\r\nin\r\n\r\n\r\nNewEnabled\r\nPortMappingEnabled\r\nin\r\n\r\n\r\nNewPortMappingDescription\r\nPortMappingDescription\r\nin\r\n\r\n\r\nNewLeaseDuration\r\nPortMappingLeaseDuration\r\nin\r\n\r\n\r\n\r\n\r\nDeletePortMapping\r\n\r\n\r\nNewRemoteHost\r\nRemoteHost\r\nin\r\n\r\n\r\nNewExternalPort\r\nExternalPort\r\nin\r\n\r\n\r\nNewProtocol\r\nPortMappingProtocol\r\nin\r\n\r\n\r\n\r\n\r\nGetExternalIPAddress\r\n\r\n\r\nNewExternalIPAddress\r\nExternalIPAddress\r\nout\r\n\r\n\r\n\r\n\r\n\r\n\r\n ConnectionType\r\n string\r\n\r\n\r\n PossibleConnectionTypes\r\n string\r\n \r\n Unconfigured\r\n IP_Routed\r\n IP_Bridged\r\n \r\n\r\n\r\n ConnectionStatus\r\n string\r\n \r\n Unconfigured\r\n Connecting\r\n Authenticating\r\n Connected\r\n PendingDisconnect\r\n Disconnecting\r\n Disconnected\r\n \r\n\r\n\r\n Uptime\r\n ui4\r\n\r\n\r\n LastConnectionError\r\n string\r\n \r\n ERROR_NONE\r\n ERROR_UNKNOWN\r\n \r\n\r\n\r\n RSIPAvailable\r\n boolean\r\n\r\n\r\n NATEnabled\r\n boolean\r\n\r\n\r\n ExternalIPAddress\r\n string\r\n\r\n\r\n PortMappingNumberOfEntries\r\n ui2\r\n\r\n\r\n PortMappingEnabled\r\n boolean\r\n\r\n\r\n PortMappingLeaseDuration\r\n ui4\r\n\r\n\r\n RemoteHost\r\n string\r\n\r\n\r\n ExternalPort\r\n ui2\r\n\r\n\r\n InternalPort\r\n ui2\r\n\r\n\r\n PortMappingProtocol\r\n string\r\n \r\n TCP\r\n UDP\r\n \r\n\r\n\r\n InternalClient\r\n string\r\n\r\n\r\n PortMappingDescription\r\n string\r\n\r\n\r\n\r\n",
+ "/dynsvc/WANPPPConnection:1.xml": "HTTP/1.0 200 OK\r\nServer: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nDate: Thu, 01 Jan 1970 00:23:13 GMT\r\nContent-Type: text/xml\r\nCache-Control: max-age=1\r\nPragma: no-cache\r\nConnection: close\r\n\r\n\r\n\r\n \r\n 1\r\n 0\r\n \r\n\r\n\r\nSetConnectionType\r\n\r\n\r\nNewConnectionType\r\nConnectionType\r\nin\r\n\r\n\r\n\r\n\r\nGetConnectionTypeInfo\r\n\r\n\r\nNewConnectionType\r\nConnectionType\r\nout\r\n\r\n\r\nNewPossibleConnectionTypes\r\nPossibleConnectionTypes\r\nout\r\n\r\n\r\n\r\n\r\nConfigureConnection\r\n\r\n\r\nNewUserName\r\nUserName\r\nin\r\n\r\n\r\nNewPassword\r\nPassword\r\nin\r\n\r\n\r\n\r\n\r\nRequestConnection\r\n\r\n\r\nForceTermination\r\n\r\n\r\nSetIdleDisconnectTime\r\n\r\n\r\nNewIdleDisconnectTime\r\nIdleDisconnectTime\r\nin\r\n\r\n\r\n\r\n\r\nGetStatusInfo\r\n\r\n\r\nNewConnectionStatus\r\nConnectionStatus\r\nout\r\n\r\n\r\nNewLastConnectionError\r\nLastConnectionError\r\nout\r\n\r\n\r\nNewUptime\r\nUptime\r\nout\r\n\r\n\r\n\r\n\r\nGetLinkLayerMaxBitRates\r\n\r\n\r\nNewUpstreamMaxBitRate\r\nUpstreamMaxBitRate\r\nout\r\n\r\n\r\nNewDownstreamMaxBitRate\r\nDownstreamMaxBitRate\r\nout\r\n\r\n\r\n\r\n\r\nGetUserName\r\n\r\n\r\nNewUserName\r\nUserName\r\nout\r\n\r\n\r\n\r\n\r\nGetPassword\r\n\r\n\r\nNewPassword\r\nPassword\r\nout\r\n\r\n\r\n\r\n\r\nGetIdleDisconnectTime\r\n\r\n\r\nNewIdleDisconnectTime\r\nIdleDisconnectTime\r\nout\r\n\r\n\r\n\r\n\r\nGetNATRSIPStatus\r\n\r\n\r\nNewRSIPAvailable\r\nRSIPAvailable\r\nout\r\n\r\n\r\nNewNATEnabled\r\nNATEnabled\r\nout\r\n\r\n\r\n\r\n\r\nGetGenericPortMappingEntry\r\n\r\n\r\nNewPortMappingIndex\r\nPortMappingNumberOfEntries\r\nin\r\n\r\n\r\nNewRemoteHost\r\nRemoteHost\r\nout\r\n\r\n\r\nNewExternalPort\r\nExternalPort\r\nout\r\n\r\n\r\nNewProtocol\r\nPortMappingProtocol\r\nout\r\n\r\n\r\nNewInternalPort\r\nInternalPort\r\nout\r\n\r\n\r\nNewInternalClient\r\nInternalClient\r\nout\r\n\r\n\r\nNewEnabled\r\nPortMappingEnabled\r\nout\r\n\r\n\r\nNewPortMappingDescription\r\nPortMappingDescription\r\nout\r\n\r\n\r\nNewLeaseDuration\r\nPortMappingLeaseDuration\r\nout\r\n\r\n\r\n\r\n\r\nGetSpecificPortMappingEntry\r\n\r\n\r\nNewRemoteHost\r\nRemoteHost\r\nin\r\n\r\n\r\nNewExternalPort\r\nExternalPort\r\nin\r\n\r\n\r\nNewProtocol\r\nPortMappingProtocol\r\nin\r\n\r\n\r\nNewInternalPort\r\nInternalPort\r\nout\r\n\r\n\r\nNewInternalClient\r\nInternalClient\r\nout\r\n\r\n\r\nNewEnabled\r\nPortMappingEnabled\r\nout\r\n\r\n\r\nNewPortMappingDescription\r\nPortMappingDescription\r\nout\r\n\r\n\r\nNewLeaseDuration\r\nPortMappingLeaseDuration\r\nout\r\n\r\n\r\n\r\n\r\nAddPortMapping\r\n\r\n\r\nNewRemoteHost\r\nRemoteHost\r\nin\r\n\r\n\r\nNewExternalPort\r\nExternalPort\r\nin\r\n\r\n\r\nNewProtocol\r\nPortMappingProtocol\r\nin\r\n\r\n\r\nNewInternalPort\r\nInternalPort\r\nin\r\n\r\n\r\nNewInternalClient\r\nInternalClient\r\nin\r\n\r\n\r\nNewEnabled\r\nPortMappingEnabled\r\nin\r\n\r\n\r\nNewPortMappingDescription\r\nPortMappingDescription\r\nin\r\n\r\n\r\nNewLeaseDuration\r\nPortMappingLeaseDuration\r\nin\r\n\r\n\r\n\r\n\r\nDeletePortMapping\r\n\r\n\r\nNewRemoteHost\r\nRemoteHost\r\nin\r\n\r\n\r\nNewExternalPort\r\nExternalPort\r\nin\r\n\r\n\r\nNewProtocol\r\nPortMappingProtocol\r\nin\r\n\r\n\r\n\r\n\r\nGetExternalIPAddress\r\n\r\n\r\nNewExternalIPAddress\r\nExternalIPAddress\r\nout\r\n\r\n\r\n\r\n\r\n\r\n\r\n ConnectionType\r\n string\r\n\r\n\r\n PossibleConnectionTypes\r\n string\r\n \r\n Unconfigured\r\n IP_Routed\r\n DHCP_Spoofed\r\n PPPoE_Bridged\r\n PPTP_Relay\r\n L2TP_Relay\r\n PPPoE_Relay\r\n \r\n\r\n\r\n ConnectionStatus\r\n string\r\n \r\n Unconfigured\r\n Connecting\r\n Authenticating\r\n Connected\r\n PendingDisconnect\r\n Disconnecting\r\n Disconnected\r\n \r\n\r\n\r\n Uptime\r\n ui4\r\n\r\n\r\n UpstreamMaxBitRate\r\n ui4\r\n\r\n\r\n DownstreamMaxBitRate\r\n ui4\r\n\r\n\r\n LastConnectionError\r\n string\r\n \r\n ERROR_NONE\r\n ERROR_UNKNOWN\r\n \r\n\r\n\r\n IdleDisconnectTime\r\n ui4\r\n\r\n\r\n RSIPAvailable\r\n boolean\r\n\r\n\r\n NATEnabled\r\n boolean\r\n\r\n\r\n UserName\r\n string\r\n\r\n\r\n Password\r\n string\r\n\r\n\r\n ExternalIPAddress\r\n string\r\n\r\n\r\n PortMappingNumberOfEntries\r\n ui2\r\n\r\n\r\n PortMappingEnabled\r\n boolean\r\n\r\n\r\n PortMappingLeaseDuration\r\n ui4\r\n\r\n\r\n RemoteHost\r\n string\r\n\r\n\r\n ExternalPort\r\n ui2\r\n\r\n\r\n InternalPort\r\n ui2\r\n\r\n\r\n PortMappingProtocol\r\n string\r\n \r\n TCP\r\n UDP\r\n \r\n\r\n\r\n InternalClient\r\n string\r\n\r\n\r\n PortMappingDescription\r\n string\r\n\r\n\r\n\r\n"
+ },
+ "soap_requests": {
+ "GetDefaultConnectionService": [],
+ "SetDefaultConnectionService": [],
+ "GetCommonLinkProperties": [],
+ "GetTotalBytesSent": [],
+ "GetTotalBytesReceived": [],
+ "GetTotalPacketsReceived": [],
+ "GetTotalPacketsSent": [],
+ "SetConnectionType": [],
+ "GetConnectionTypeInfo": [],
+ "RequestConnection": [],
+ "ForceTermination": [],
+ "GetStatusInfo": [],
+ "GetNATRSIPStatus": [],
+ "GetGenericPortMappingEntry": [
+ [
+ {
+ "NewPortMappingIndex": 0
+ },
+ "HTTP/1.1 500 Internal Server Error\r\nDATE: Thu, 01 Jan 1970 00:23:13 GMT\r\nConnection: Keep-Alive\r\nServer: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nContent-Length: 474\r\nContent-Type: text/xml; charset=\"utf-8\"\r\nEXT:\r\n\r\n\r\n \r\n \r\n s:Client\r\n UPnPError\r\n \r\n \r\n 713\r\n SpecifiedArrayIndexInvalid\r\n \r\n \r\n \r\n \r\n\r\n"
+ ],
+ [
+ {
+ "NewPortMappingIndex": 0
+ },
+ "HTTP/1.1 500 Internal Server Error\r\nDATE: Thu, 01 Jan 1970 00:23:13 GMT\r\nConnection: Keep-Alive\r\nServer: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nContent-Length: 474\r\nContent-Type: text/xml; charset=\"utf-8\"\r\nEXT:\r\n\r\n\r\n \r\n \r\n s:Client\r\n UPnPError\r\n \r\n \r\n 713\r\n SpecifiedArrayIndexInvalid\r\n \r\n \r\n \r\n \r\n\r\n"
+ ]
+ ],
+ "GetSpecificPortMappingEntry": [],
+ "AddPortMapping": [
+ [
+ {
+ "NewRemoteHost": "",
+ "NewExternalPort": 4567,
+ "NewProtocol": "UDP",
+ "NewInternalPort": 4567,
+ "NewInternalClient": "192.168.1.137",
+ "NewEnabled": true,
+ "NewPortMappingDescription": "aioupnp test mapping",
+ "NewLeaseDuration": ""
+ },
+ ""
+ ]
+ ],
+ "DeletePortMapping": [
+ [
+ {
+ "NewRemoteHost": "",
+ "NewExternalPort": 4567,
+ "NewProtocol": "UDP"
+ },
+ ""
+ ]
+ ],
+ "GetExternalIPAddress": [
+ [
+ {},
+ "HTTP/1.1 200 OK\r\nDATE: Thu, 01 Jan 1970 00:23:13 GMT\r\nConnection: Keep-Alive\r\nServer: LINUX/2.4 UPnP/1.0 BRCM400/1.0\r\nContent-Length: 359\r\nContent-Type: text/xml; charset=\"utf-8\"\r\nEXT:\r\n\r\n\r\n11.222.33.111\r\n"
+ ]
+ ]
+ }
+ },
+ "client_address": "192.168.1.137"
+}
\ No newline at end of file
diff --git a/tests/test_gateway.py b/tests/test_gateway.py
index 6b0a50b..e0965ae 100644
--- a/tests/test_gateway.py
+++ b/tests/test_gateway.py
@@ -1,8 +1,12 @@
+import os
+import json
+from collections import OrderedDict
from aioupnp.fault import UPnPError
from tests import AsyncioTestCase, mock_tcp_and_udp
-from collections import OrderedDict
from aioupnp.gateway import Gateway, get_action_list
from aioupnp.serialization.ssdp import SSDPDatagram
+from aioupnp.serialization.soap import serialize_soap_post
+from aioupnp.upnp import UPnP
def gen_get_bytes(location: str, host: str) -> bytes:
@@ -296,3 +300,71 @@ class TestDiscoverNetgearNighthawkAC2350(TestDiscoverDLinkDIR890L):
'RequestConnection', 'ForceTermination',
'GetStatusInfo', 'GetNATRSIPStatus']},
'soap_requests': []}
+
+
+class TestActiontec(AsyncioTestCase):
+ name = "Actiontec GT784WN"
+ _location_key = 'Location'
+
+ @property
+ def data_path(self):
+ return os.path.join(os.path.dirname(os.path.abspath(__file__)), "replays", self.name)
+
+ def _get_location(self):
+ # return self.gateway_info['reply']['Location'].split(self.gateway_address)[-1]
+ return self.gateway_info['reply'][self._location_key].split(f"{self.gateway_address}:{self.gateway_info['soap_port']}")[-1]
+
+ def setUp(self) -> None:
+ with open(self.data_path, 'r') as f:
+ data = json.loads(f.read())
+ self.gateway_info = data['gateway']
+ self.client_address = data['client_address']
+ self.gateway_address = self.gateway_info['gateway_address']
+ self.udp_replies = {
+ (SSDPDatagram('M-SEARCH', self.gateway_info['m_search_args']).encode().encode(), ("239.255.255.250", 1900)): SSDPDatagram("OK", self.gateway_info['reply']).encode().encode()
+ }
+ self.tcp_replies = {
+ (
+ f"GET {path} HTTP/1.1\r\n"
+ f"Accept-Encoding: gzip\r\n"
+ f"Host: {self.gateway_info['gateway_address']}\r\n"
+ f"Connection: Close\r\n"
+ f"\r\n"
+ ).encode(): xml_bytes.encode()
+ for path, xml_bytes in self.gateway_info['service_descriptors'].items()
+ }
+ self.tcp_replies.update({
+ (
+ f"GET {self._get_location()} HTTP/1.1\r\n"
+ f"Accept-Encoding: gzip\r\n"
+ f"Host: {self.gateway_info['gateway_address']}\r\n"
+ f"Connection: Close\r\n"
+ f"\r\n"
+ ).encode(): self.gateway_info['gateway_xml'].encode()
+ })
+ self.registered_soap_commands = self.gateway_info['registered_soap_commands']
+ super().setUp()
+
+ async def setup_request_replay(self, u: UPnP):
+ for method, reqs in self.gateway_info['soap_requests'].items():
+ if not reqs:
+ continue
+ self.tcp_replies.update({
+ serialize_soap_post(
+ method, list(args.keys()), self.registered_soap_commands[method].encode(),
+ self.gateway_address.encode(), u.gateway.services[self.registered_soap_commands[method]].controlURL.encode()
+ ): response.encode() for args, response in reqs
+ })
+
+ async def replay(self, u: UPnP):
+ self.assertEqual('11.222.33.111', await u.get_external_ip())
+
+ async def test_replay(self):
+ with mock_tcp_and_udp(self.loop, udp_replies=self.udp_replies, tcp_replies=self.tcp_replies, udp_expected_addr=self.gateway_address, tcp_chunk_size=1450):
+ u = await UPnP.discover(lan_address=self.client_address, gateway_address=self.gateway_address, loop=self.loop)
+ await self.setup_request_replay(u)
+ await self.replay(u)
+
+
+class TestNewMediaNet(TestActiontec):
+ name = "NewMedia-NET GmbH Generic X86"