From 1983ff03a3223ecb7c2f3537a70c592518474467 Mon Sep 17 00:00:00 2001 From: Jakub Morvay Date: Mon, 12 Nov 2018 19:14:20 +0100 Subject: [PATCH] Support consecutive slashes in RFC 8040 URIs Users often assume restconf URLs behave just as HTTP does by squashing multiple slashes into a single one. Make sure we do not trigger an error about an empty element in this case. This deals with URIs in RFC 8040 restconf implementation. NETCONF-24 Change-Id: I1c3a2085528e4177b09a2d330a6b05bb1b100147 Signed-off-by: Jakub Morvay --- .../YangInstanceIdentifierDeserializer.java | 8 ++- ...angInstanceIdentifierDeserializerTest.java | 63 ++++++++++++++++--- 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/utils/parser/YangInstanceIdentifierDeserializer.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/utils/parser/YangInstanceIdentifierDeserializer.java index 2009a072c6..89b6fc899b 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/utils/parser/YangInstanceIdentifierDeserializer.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/utils/parser/YangInstanceIdentifierDeserializer.java @@ -394,8 +394,12 @@ public final class YangInstanceIdentifierDeserializer { checkValid(RestconfConstants.SLASH == currentChar(variables.getOffset(), variables.getData()), "Identifier must start with '/'.", variables.getData(), variables.getOffset()); - // skip slash - skipCurrentChar(variables); + // skip consecutive slashes, users often assume restconf URLs behave just as HTTP does by squashing + // multiple slashes into a single one + while (!allCharsConsumed(variables) + && RestconfConstants.SLASH == currentChar(variables.getOffset(), variables.getData())) { + skipCurrentChar(variables); + } // check if slash is not also the last char in identifier checkValid(!allCharsConsumed(variables), "Identifier cannot end with '/'.", diff --git a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/utils/parser/YangInstanceIdentifierDeserializerTest.java b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/utils/parser/YangInstanceIdentifierDeserializerTest.java index 86aa0307b6..8ff0572f0e 100644 --- a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/utils/parser/YangInstanceIdentifierDeserializerTest.java +++ b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/utils/parser/YangInstanceIdentifierDeserializerTest.java @@ -223,6 +223,41 @@ public class YangInstanceIdentifierDeserializerTest { assertTrue("Empty result expected", Iterables.isEmpty(result)); } + /** + * Test of deserialization String URI with identifiers separated by multiple slashes to + * {@code Iterable}. + */ + @Test + public void deserializeMultipleSlashesTest() { + final Iterable result = YangInstanceIdentifierDeserializer + .create(this.schemaContext, "deserializer-test:contA////list-A=40//list-key"); + + assertEquals("Result does not contains expected number of path arguments", 4, Iterables.size(result)); + + final Iterator iterator = result.iterator(); + + // container + assertEquals("Not expected path argument", + YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")), + iterator.next()); + + // list + final QName list = QName.create("deserializer:test", "2016-06-06", "list-A"); + assertEquals("Not expected path argument", + YangInstanceIdentifier.NodeIdentifier.create(list), + iterator.next()); + assertEquals("Not expected path argument", + new YangInstanceIdentifier.NodeIdentifierWithPredicates( + list, QName.create(list, "list-key"), 40).toString(), + iterator.next().toString()); + + // leaf + assertEquals("Not expected path argument", + new YangInstanceIdentifier.NodeIdentifier( + QName.create("deserializer:test", "2016-06-06", "list-key")), + iterator.next()); + } + /** * Negative test when supplied SchemaContext is null. Test is expected to fail with * NullPointerException. @@ -263,34 +298,44 @@ public class YangInstanceIdentifierDeserializerTest { YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:contA/"); } + /** + * Negative test of validating identifier when there are multiple slashes after container without next identifier. + * Test is expected to fail with IllegalArgumentException. + */ + @Test + public void validArgIdentifierContainerEndsWithMultipleSlashesNegativeTest() { + this.thrown.expect(IllegalArgumentException.class); + YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:contA///"); + } + /** * Negative test of validating identifier when there is a slash after list key values without next identifier. Test * is expected to fail with IllegalArgumentException. */ @Test - public void validArgIdentifierListEndsWithSlashLNegativeTest() { + public void validArgIdentifierListEndsWithSlashNegativeTest() { this.thrown.expect(IllegalArgumentException.class); YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:list-one-key=value/"); } /** - * Negative test of creating QName when identifier is empty (example: '/'). Test is expected to fail - * with IllegalArgumentException. + * Negative test of validating identifier when there are multiple slashes after list key values without next + * identifier. Test is expected to fail with IllegalArgumentException. */ @Test - public void prepareQnameEmptyIdentifierNegativeTest() { + public void validArgIdentifierListEndsWithSlashesNegativeTest() { this.thrown.expect(IllegalArgumentException.class); - YangInstanceIdentifierDeserializer.create(this.schemaContext, "/"); + YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:list-one-key=value//"); } /** - * Negative test of creating QName when two identifiers are separated by two slashes. Test is - * expected to fail with IllegalArgumentException. + * Negative test of creating QName when identifier is empty (example: '/'). Test is expected to fail + * with IllegalArgumentException. */ @Test - public void prepareQnameTwoSlashesNegativeTest() { + public void prepareQnameEmptyIdentifierNegativeTest() { this.thrown.expect(IllegalArgumentException.class); - YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:contA//leaf-A"); + YangInstanceIdentifierDeserializer.create(this.schemaContext, "/"); } /** -- 2.36.6