Skip to content

Commit c7381cf

Browse files
authored
'#' is not treated as a reserved character in RelativePath's text format (#2264)
* updated reserve char check in RelativePath * updated logic and added tests
1 parent cb99f46 commit c7381cf

File tree

2 files changed

+91
-14
lines changed

2 files changed

+91
-14
lines changed

Stack/Opc.Ua.Core/Types/Utils/RelativePath.cs

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ private static QualifiedName ParseName(
740740

741741
int last = reader.Peek();
742742

743-
for (int next = last; next != -1; next = reader.Peek(), last=next)
743+
for (int next = last; next != -1; next = reader.Peek(), last = next)
744744
{
745745
if (!Char.IsDigit((char)next))
746746
{
@@ -783,22 +783,37 @@ private static QualifiedName ParseName(
783783
}
784784
}
785785

786-
// check for invalid character.
787-
if (next == '!' || next == ':' || next == '<' || next == '>' || next == '/' || next == '.')
788-
{
789-
throw new ServiceResultException(
790-
StatusCodes.BadSyntaxError,
791-
Utils.Format("Unexpected character '{0}' in browse path.", next));
792-
793-
}
794-
795786
// check for escape character.
796787
if (next == '&')
797788
{
798789
next = reader.Read();
790+
if (next == -1)
791+
{
792+
throw new ServiceResultException(
793+
StatusCodes.BadSyntaxError,
794+
"Unexpected end after escape character '&'.");
795+
}
799796
next = reader.Read();
800-
buffer.Append((char)next);
801-
continue;
797+
798+
if (next == '!' || next == ':' || next == '<' || next == '>' || next == '/' || next == '.' || next == '#' || next == '&')
799+
{
800+
buffer.Append((char)next);
801+
continue;
802+
}
803+
else
804+
{
805+
throw new ServiceResultException(
806+
StatusCodes.BadSyntaxError,
807+
Utils.Format("Invalid escape sequence '&{0}' in browse path.", next));
808+
}
809+
}
810+
811+
// check for invalid character.
812+
if (next == '!' || next == ':' || next == '<' || next == '>' || next == '/' || next == '.' || next == '#' || next == '&')
813+
{
814+
throw new ServiceResultException(
815+
StatusCodes.BadSyntaxError,
816+
Utils.Format("Unexpected character '{0}' in browse path.", next));
802817
}
803818

804819
// append character.
@@ -812,8 +827,8 @@ private static QualifiedName ParseName(
812827
if (last != '>')
813828
{
814829
throw new ServiceResultException(
815-
StatusCodes.BadSyntaxError,
816-
Utils.Format("Missing file '>' for reference type name in browse path."));
830+
StatusCodes.BadSyntaxError,
831+
Utils.Format("Missing closing '>' for reference type name in browse path."));
817832
}
818833
}
819834

Tests/Opc.Ua.Core.Tests/Types/Utils/UtilTests.cs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,68 @@ public void ValidateXmlReaderSettings()
290290
Assert.AreEqual(false, settings.CloseInput);
291291
}
292292
#endregion
293+
294+
#region RelativePath.Parse Escaping
295+
296+
/// <summary>
297+
/// Parse a path containing non-escaped hash character.
298+
/// </summary>
299+
[Test]
300+
public void RelativePathParseNonEscapedHash()
301+
{
302+
TypeTable typeTable = new TypeTable(new NamespaceTable());
303+
string str = "/abc#def";
304+
Assert.Throws<ServiceResultException>(() => RelativePath.Parse(str, typeTable).Format(typeTable));
305+
}
306+
307+
/// <summary>
308+
/// Parse a path containing correctly escaped hash character.
309+
/// </summary>
310+
[Test]
311+
public void RelativePathParseEscapedHash()
312+
{
313+
TypeTable typeTable = new TypeTable(new NamespaceTable());
314+
string str = "/abc&#def";
315+
string expected = "/abc#def";
316+
Assert.AreEqual(expected, RelativePath.Parse(str, typeTable).Format(typeTable));
317+
}
318+
319+
/// <summary>
320+
/// Parse a path containing correctly escaped hash character folowed by exclamation.
321+
/// </summary>
322+
[Test]
323+
public void RelativePathParseEscapedHashFollowedByExclamation()
324+
{
325+
TypeTable typeTable = new TypeTable(new NamespaceTable());
326+
string str = "/abc&#!def";
327+
Assert.Throws<ServiceResultException>(() => RelativePath.Parse(str, typeTable).Format(typeTable));
328+
}
329+
330+
/// <summary>
331+
/// Parse a path containing correctly escaped hash character by exclamation within the reference type delimeters.
332+
/// </summary>
333+
[Test]
334+
public void RelativePathParseEscapedHashFollowedByExclamationInReferenceType()
335+
{
336+
TypeTable typeTable = new TypeTable(new NamespaceTable());
337+
string str = "<abc&#!def>";
338+
Assert.Throws<ServiceResultException>(() => RelativePath.Parse(str, typeTable).Format(typeTable));
339+
}
340+
341+
/// <summary>
342+
/// Parse a path containing incorrectly escaped character sequence.
343+
/// </summary>
344+
[Test]
345+
public void RelativePathParseInvalidEscapeSequence()
346+
{
347+
TypeTable typeTable = new TypeTable(new NamespaceTable());
348+
string str = "/abc&$!def";
349+
Assert.Throws<ServiceResultException>(() => RelativePath.Parse(str, typeTable).Format(typeTable));
350+
}
351+
352+
353+
#endregion
354+
293355
}
294356

295357
}

0 commit comments

Comments
 (0)