diff --git a/Stack/Opc.Ua.Core/Types/Utils/RelativePath.cs b/Stack/Opc.Ua.Core/Types/Utils/RelativePath.cs
index 939894158c..ebfb679d16 100644
--- a/Stack/Opc.Ua.Core/Types/Utils/RelativePath.cs
+++ b/Stack/Opc.Ua.Core/Types/Utils/RelativePath.cs
@@ -740,7 +740,7 @@ namespace Opc.Ua
int last = reader.Peek();
- for (int next = last; next != -1; next = reader.Peek(), last=next)
+ for (int next = last; next != -1; next = reader.Peek(), last = next)
{
if (!Char.IsDigit((char)next))
{
@@ -783,22 +783,37 @@ namespace Opc.Ua
}
}
- // check for invalid character.
- if (next == '!' || next == ':' || next == '<' || next == '>' || next == '/' || next == '.')
- {
- throw new ServiceResultException(
- StatusCodes.BadSyntaxError,
- Utils.Format("Unexpected character '{0}' in browse path.", next));
-
- }
-
// check for escape character.
if (next == '&')
{
next = reader.Read();
+ if (next == -1)
+ {
+ throw new ServiceResultException(
+ StatusCodes.BadSyntaxError,
+ "Unexpected end after escape character '&'.");
+ }
next = reader.Read();
- buffer.Append((char)next);
- continue;
+
+ if (next == '!' || next == ':' || next == '<' || next == '>' || next == '/' || next == '.' || next == '#' || next == '&')
+ {
+ buffer.Append((char)next);
+ continue;
+ }
+ else
+ {
+ throw new ServiceResultException(
+ StatusCodes.BadSyntaxError,
+ Utils.Format("Invalid escape sequence '&{0}' in browse path.", next));
+ }
+ }
+
+ // check for invalid character.
+ if (next == '!' || next == ':' || next == '<' || next == '>' || next == '/' || next == '.' || next == '#' || next == '&')
+ {
+ throw new ServiceResultException(
+ StatusCodes.BadSyntaxError,
+ Utils.Format("Unexpected character '{0}' in browse path.", next));
}
// append character.
@@ -812,8 +827,8 @@ namespace Opc.Ua
if (last != '>')
{
throw new ServiceResultException(
- StatusCodes.BadSyntaxError,
- Utils.Format("Missing file '>' for reference type name in browse path."));
+ StatusCodes.BadSyntaxError,
+ Utils.Format("Missing closing '>' for reference type name in browse path."));
}
}
diff --git a/Tests/Opc.Ua.Core.Tests/Types/Utils/UtilTests.cs b/Tests/Opc.Ua.Core.Tests/Types/Utils/UtilTests.cs
index 3321792b1c..9f82da6754 100644
--- a/Tests/Opc.Ua.Core.Tests/Types/Utils/UtilTests.cs
+++ b/Tests/Opc.Ua.Core.Tests/Types/Utils/UtilTests.cs
@@ -290,6 +290,68 @@ namespace Opc.Ua.Core.Tests.Types.UtilsTests
Assert.AreEqual(false, settings.CloseInput);
}
#endregion
+
+ #region RelativePath.Parse Escaping
+
+ ///
+ /// Parse a path containing non-escaped hash character.
+ ///
+ [Test]
+ public void RelativePathParseNonEscapedHash()
+ {
+ TypeTable typeTable = new TypeTable(new NamespaceTable());
+ string str = "/abc#def";
+ Assert.Throws(() => RelativePath.Parse(str, typeTable).Format(typeTable));
+ }
+
+ ///
+ /// Parse a path containing correctly escaped hash character.
+ ///
+ [Test]
+ public void RelativePathParseEscapedHash()
+ {
+ TypeTable typeTable = new TypeTable(new NamespaceTable());
+ string str = "/abcdef";
+ string expected = "/abc#def";
+ Assert.AreEqual(expected, RelativePath.Parse(str, typeTable).Format(typeTable));
+ }
+
+ ///
+ /// Parse a path containing correctly escaped hash character folowed by exclamation.
+ ///
+ [Test]
+ public void RelativePathParseEscapedHashFollowedByExclamation()
+ {
+ TypeTable typeTable = new TypeTable(new NamespaceTable());
+ string str = "/abc!def";
+ Assert.Throws(() => RelativePath.Parse(str, typeTable).Format(typeTable));
+ }
+
+ ///
+ /// Parse a path containing correctly escaped hash character by exclamation within the reference type delimeters.
+ ///
+ [Test]
+ public void RelativePathParseEscapedHashFollowedByExclamationInReferenceType()
+ {
+ TypeTable typeTable = new TypeTable(new NamespaceTable());
+ string str = "";
+ Assert.Throws(() => RelativePath.Parse(str, typeTable).Format(typeTable));
+ }
+
+ ///
+ /// Parse a path containing incorrectly escaped character sequence.
+ ///
+ [Test]
+ public void RelativePathParseInvalidEscapeSequence()
+ {
+ TypeTable typeTable = new TypeTable(new NamespaceTable());
+ string str = "/abc&$!def";
+ Assert.Throws(() => RelativePath.Parse(str, typeTable).Format(typeTable));
+ }
+
+
+ #endregion
+
}
}