diff --git a/pkg/onvif/client.go b/pkg/onvif/client.go index 090e9ef2..97bfd8dc 100644 --- a/pkg/onvif/client.go +++ b/pkg/onvif/client.go @@ -5,7 +5,6 @@ import ( "crypto/sha1" "encoding/base64" "errors" - "github.com/AlexxIT/go2rtc/pkg/core" "html" "io" "net/http" @@ -13,6 +12,8 @@ import ( "regexp" "strings" "time" + + "github.com/AlexxIT/go2rtc/pkg/core" ) const PathDevice = "/onvif/device_service" @@ -78,10 +79,10 @@ func (c *Client) GetURI() (string, error) { return "", err } - uri := FindTagValue(b, "Uri") - uri = html.UnescapeString(uri) + rawURL := FindTagValue(b, "Uri") + rawURL = strings.TrimSpace(html.UnescapeString(rawURL)) - u, err := url.Parse(uri) + u, err := url.Parse(rawURL) if err != nil { return "", err } diff --git a/pkg/onvif/helpers.go b/pkg/onvif/helpers.go index fb65ecaf..fc9c8392 100644 --- a/pkg/onvif/helpers.go +++ b/pkg/onvif/helpers.go @@ -11,7 +11,7 @@ import ( ) func FindTagValue(b []byte, tag string) string { - re := regexp.MustCompile(`(?s)<[^/>]*` + tag + `[^>]*>([^<]+)`) + re := regexp.MustCompile(`(?s)[:<]` + tag + `>([^<]+)`) m := re.FindSubmatch(b) if len(m) != 2 { return "" diff --git a/pkg/onvif/onvif_test.go b/pkg/onvif/onvif_test.go new file mode 100644 index 00000000..cd57d60b --- /dev/null +++ b/pkg/onvif/onvif_test.go @@ -0,0 +1,199 @@ +package onvif + +import ( + "html" + "net/url" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestGetStreamUri(t *testing.T) { + tests := []struct { + name string + xml string + url string + }{ + { + name: "Dahua stream default", + xml: `rtsp://192.168.1.123:554/cam/realmonitor?channel=1&subtype=1&unicast=true&proto=OnviftruetruePT0S`, + url: "rtsp://192.168.1.123:554/cam/realmonitor?channel=1&subtype=1&unicast=true&proto=Onvif", + }, + { + name: "Dahua snapshot default", + xml: `http://192.168.1.123/onvifsnapshot/media_service/snapshot?channel=1&subtype=1falsefalsePT0S`, + url: "http://192.168.1.123/onvifsnapshot/media_service/snapshot?channel=1&subtype=1", + }, + { + name: "Dahua stream formatted", + xml: ` + + + + + + + rtsp://192.168.1.123:554/cam/realmonitor?channel=1&subtype=1&unicast=true&proto=Onvif + true + true + PT0S + + + +`, + url: "rtsp://192.168.1.123:554/cam/realmonitor?channel=1&subtype=1&unicast=true&proto=Onvif", + }, + { + name: "Dahua snapshot formatted", + xml: ` + + + + + + + http://192.168.1.123/onvifsnapshot/media_service/snapshot?channel=1&subtype=1 + false + false + PT0S + + + +`, + url: "http://192.168.1.123/onvifsnapshot/media_service/snapshot?channel=1&subtype=1", + }, + { + name: "Unknown", + xml: ` + + + + + + + rtsp://192.168.5.53:8090/profile1=r + + + + +`, + url: "rtsp://192.168.5.53:8090/profile1=r", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + uri := FindTagValue([]byte(test.xml), "Uri") + uri = strings.TrimSpace(html.UnescapeString(uri)) + u, err := url.Parse(uri) + require.Nil(t, err) + require.Equal(t, test.url, u.String()) + }) + } +} + +func TestGetCapabilities(t *testing.T) { + tests := []struct { + name string + xml string + }{ + { + name: "Dahua default", + xml: `http://192.168.1.123/onvif/analytics_servicetruetruehttp://192.168.1.123/onvif/device_servicefalsefalsefalsefalsefalsefalsetruefalsefalsetruetrue200210220230240242161218061812190619122006truefalsefalsefalse21falsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalse0falsehttp://192.168.1.123/onvif/event_servicetruetruefalsehttp://192.168.1.123/onvif/imaging_servicehttp://192.168.1.123/onvif/media_servicetruetruetrue6http://192.168.1.123/onvif/deviceIO_service10111`, + }, + { + name: "Dahua formatted", + xml: ` + + + + + + + http://192.168.1.123/onvif/analytics_service + true + true + + + http://192.168.1.123/onvif/device_service + + false + false + false + false + + false + + + + ... + + + 2 + 1 + + false + + + + + + ... + + + + http://192.168.1.123/onvif/event_service + true + true + false + + + http://192.168.1.123/onvif/imaging_service + + + http://192.168.1.123/onvif/media_service + + true + true + true + + + + 6 + + + + + + http://192.168.1.123/onvif/deviceIO_service + 1 + 0 + 1 + 1 + 1 + + + + + +`, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + rawURL := FindTagValue([]byte(test.xml), "Media.+?XAddr") + require.Equal(t, "http://192.168.1.123/onvif/media_service", rawURL) + + rawURL = FindTagValue([]byte(test.xml), "Imaging.+?XAddr") + require.Equal(t, "http://192.168.1.123/onvif/imaging_service", rawURL) + }) + } +}