Skip to content

Commit 7c85755

Browse files
authored
Improve handling of invalid urls (#45)
1 parent d755d41 commit 7c85755

File tree

3 files changed

+52
-3
lines changed

3 files changed

+52
-3
lines changed

onvif/client.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,9 @@ def get_definition(
573573
# Get other XAddr
574574
xaddr = self.xaddrs.get(namespace)
575575
if not xaddr:
576-
raise ONVIFError("Device doesn`t support service: %s" % name)
576+
raise ONVIFError(
577+
f"Device doesn`t support service: {name} with namespace {namespace}"
578+
)
577579

578580
return xaddr, wsdlpath, binding_name
579581

onvif/util.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import os
88
import ssl
99
from typing import Any
10-
from urllib.parse import urlparse, urlunparse
10+
from urllib.parse import urlparse, urlunparse, ParseResultBytes
1111

1212
from zeep.exceptions import Fault
1313

@@ -18,13 +18,18 @@
1818
path_isfile = lru_cache(maxsize=128)(os.path.isfile)
1919

2020

21-
def normalize_url(url: str) -> str:
21+
def normalize_url(url: bytes | str | None) -> str | None:
2222
"""Normalize URL.
2323
2424
Some cameras respond with <wsa5:Address>http://192.168.1.106:8106:8106/onvif/Subscription?Idx=43</wsa5:Address>
2525
https://github.com/home-assistant/core/issues/92603#issuecomment-1537213126
2626
"""
27+
if url is None:
28+
return None
2729
parsed = urlparse(url)
30+
# If the URL is not a string, return None
31+
if isinstance(parsed, ParseResultBytes):
32+
return None
2833
if "[" not in parsed.netloc and parsed.netloc.count(":") > 1:
2934
net_location = parsed.netloc.split(":", 3)
3035
net_location.pop()

tests/test_util.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from __future__ import annotations
2+
3+
import os
4+
5+
import pytest
6+
from zeep.loader import parse_xml
7+
8+
from onvif.client import ONVIFCamera
9+
from onvif.settings import DEFAULT_SETTINGS
10+
from onvif.transport import ASYNC_TRANSPORT
11+
from onvif.util import normalize_url
12+
13+
PULL_POINT_RESPONSE_MISSING_URL = b'<?xml version="1.0" encoding="UTF-8"?>\n<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsdd="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:chan="http://schemas.microsoft.com/ws/2005/02/duplex" xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:ns1="http://www.onvif.org/ver10/pacs" xmlns:xmime="http://tempuri.org/xmime.xsd" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:wsrfbf="http://docs.oasis-open.org/wsrf/bf-2" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:wsrfr="http://docs.oasis-open.org/wsrf/r-2" xmlns:tdn="http://www.onvif.org/ver10/network/wsdl" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:trv="http://www.onvif.org/ver10/receiver/wsdl" xmlns:tse="http://www.onvif.org/ver10/search/wsdl"><SOAP-ENV:Header><wsa5:MessageID>urn:uuid:76acd0bc-498e-4657-9414-b386bd4b0985</wsa5:MessageID><wsa5:To SOAP-ENV:mustUnderstand="1">http://192.168.2.18:8080/onvif/device_service</wsa5:To><wsa5:Action SOAP-ENV:mustUnderstand="1">http://www.onvif.org/ver10/events/wsdl/EventPortType/CreatePullPointSubscriptionRequest</wsa5:Action></SOAP-ENV:Header><SOAP-ENV:Body><tev:CreatePullPointSubscriptionResponse><tev:SubscriptionReference><wsa5:Address/></tev:SubscriptionReference><wsnt:CurrentTime>1970-01-01T00:00:00Z</wsnt:CurrentTime><wsnt:TerminationTime>1970-01-01T00:00:00Z</wsnt:TerminationTime></tev:CreatePullPointSubscriptionResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>\r\n'
14+
_WSDL_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "onvif", "wsdl")
15+
16+
17+
def test_normalize_url():
18+
assert normalize_url("http://1.2.3.4:80") == "http://1.2.3.4:80"
19+
assert normalize_url("http://1.2.3.4:80:80") == "http://1.2.3.4:80"
20+
assert normalize_url("http://[:dead:beef::1]:80") == "http://[:dead:beef::1]:80"
21+
assert normalize_url(None) is None
22+
assert normalize_url(b"http://[:dead:beef::1]:80") is None
23+
24+
25+
@pytest.mark.asyncio
26+
async def test_normalize_url_with_missing_url():
27+
device = ONVIFCamera("127.0.0.1", 80, "user", "pass", wsdl_dir=_WSDL_PATH)
28+
device.xaddrs = {
29+
"http://www.onvif.org/ver10/events/wsdl": "http://192.168.210.102:6688/onvif/event_service"
30+
}
31+
# Create subscription manager
32+
subscription = await device.create_notification_service()
33+
operation = subscription.document.bindings[subscription.binding_name].get(
34+
"Subscribe"
35+
)
36+
envelope = parse_xml(
37+
PULL_POINT_RESPONSE_MISSING_URL, # type: ignore[arg-type]
38+
ASYNC_TRANSPORT,
39+
settings=DEFAULT_SETTINGS,
40+
)
41+
result = operation.process_reply(envelope)
42+
assert normalize_url(result.SubscriptionReference.Address._value_1) is None

0 commit comments

Comments
 (0)