BUG-8039: Enforce binary/string type length 53/53553/3
authorRobert Varga <rovarga@cisco.com>
Mon, 20 Mar 2017 11:30:23 +0000 (12:30 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Wed, 22 Mar 2017 07:28:46 +0000 (08:28 +0100)
Binary type does not enforce input data length based on the supplied
constraints. Introduce two separate classes to deal with restricted
and unrestricted binary types.

String type fails to do the same, retrofit StringStringCodec with
the appropriate check.

Change-Id: I82516b39d66cbf846ed3eed39ee9e266b882f45d
Signed-off-by: Robert Varga <rovarga@cisco.com>
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/BinaryStringCodec.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/StringStringCodec.java

index 04ba7211ea544d5d1403edb9c0509ce63ff6f0a5..467d226e777ad440e5a98815e77e8d080b1c9448 100644 (file)
@@ -8,19 +8,57 @@
 package org.opendaylight.yangtools.yang.data.impl.codec;
 
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableRangeSet;
+import com.google.common.collect.Range;
+import com.google.common.collect.RangeSet;
+import com.google.common.collect.TreeRangeSet;
 import com.google.common.io.BaseEncoding;
 import javax.xml.bind.DatatypeConverter;
 import org.opendaylight.yangtools.yang.data.api.codec.BinaryCodec;
 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
 
-final class BinaryStringCodec extends TypeDefinitionAwareCodec<byte[], BinaryTypeDefinition> implements BinaryCodec<String> {
+abstract class BinaryStringCodec extends TypeDefinitionAwareCodec<byte[], BinaryTypeDefinition>
+        implements BinaryCodec<String> {
+    private static final class Restricted extends BinaryStringCodec {
+        private final RangeSet<Integer> ranges;
 
-    private BinaryStringCodec(final Optional<BinaryTypeDefinition> typeDef) {
-        super(typeDef, byte[].class);
+        Restricted(final BinaryTypeDefinition typeDef) {
+            super(typeDef);
+
+            final RangeSet<Integer> r = TreeRangeSet.create();
+            for (LengthConstraint c : typeDef.getLengthConstraints()) {
+                r.add(Range.closed(c.getMin().intValue(), c.getMax().intValue()));
+            }
+
+            ranges = ImmutableRangeSet.copyOf(r);
+        }
+
+        @Override
+        void validate(final byte[] value) {
+            Preconditions.checkArgument(ranges.contains(value.length),
+                "Value length %s does not match constraints %s", value.length, ranges);
+        }
+    }
+
+    private static final class Unrestricted extends BinaryStringCodec {
+        Unrestricted(final BinaryTypeDefinition typeDef) {
+            super(typeDef);
+        }
+
+        @Override
+        void validate(final byte[] value) {
+            // No-op
+        }
+    }
+
+    BinaryStringCodec(final BinaryTypeDefinition typeDef) {
+        super(Optional.of(typeDef), byte[].class);
     }
 
-    static TypeDefinitionAwareCodec<?,BinaryTypeDefinition> from(final BinaryTypeDefinition type) {
-        return new BinaryStringCodec(Optional.fromNullable(type));
+    static TypeDefinitionAwareCodec<?, BinaryTypeDefinition> from(final BinaryTypeDefinition type) {
+        return type.getLengthConstraints().isEmpty() ? new Unrestricted(type) : new Restricted(type);
     }
 
     @Override
@@ -30,6 +68,14 @@ final class BinaryStringCodec extends TypeDefinitionAwareCodec<byte[], BinaryTyp
 
     @Override
     public byte[] deserialize(final String stringRepresentation) {
-        return stringRepresentation == null ? null : DatatypeConverter.parseBase64Binary(stringRepresentation);
+        if (stringRepresentation == null) {
+            return null;
+        }
+
+        final byte[] ret = DatatypeConverter.parseBase64Binary(stringRepresentation);
+        validate(ret);
+        return ret;
     }
+
+    abstract void validate(byte[] value);
 }
index 4940722f1aed6e594b787b8a9bb5fdff917f5309..57602161e3c17f29151559ead11b1ea6355c3373 100644 (file)
@@ -8,16 +8,36 @@
 package org.opendaylight.yangtools.yang.data.impl.codec;
 
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableRangeSet;
+import com.google.common.collect.Range;
+import com.google.common.collect.RangeSet;
+import com.google.common.collect.TreeRangeSet;
+import java.util.Collection;
 import java.util.Objects;
 import org.opendaylight.yangtools.yang.data.api.codec.StringCodec;
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
 
 class StringStringCodec extends TypeDefinitionAwareCodec<String, StringTypeDefinition> implements
         StringCodec<String> {
 
-    protected StringStringCodec(final StringTypeDefinition typeDef) {
+    private final RangeSet<Integer> lengths;
+
+    StringStringCodec(final StringTypeDefinition typeDef) {
         super(Optional.of(typeDef), String.class);
-        typeDef.getLengthConstraints();
+
+        final Collection<LengthConstraint> constraints = typeDef.getLengthConstraints();
+        if (!constraints.isEmpty()) {
+            final RangeSet<Integer> tmp = TreeRangeSet.create();
+            for (LengthConstraint c : constraints) {
+                tmp.add(Range.closed(c.getMin().intValue(), c.getMax().intValue()));
+            }
+
+            lengths = ImmutableRangeSet.copyOf(tmp);
+        } else {
+            lengths = null;
+        }
     }
 
     static TypeDefinitionAwareCodec<?, StringTypeDefinition> from(final StringTypeDefinition normalizedType) {
@@ -43,7 +63,10 @@ class StringStringCodec extends TypeDefinitionAwareCodec<String, StringTypeDefin
         return Objects.toString(data, "");
     }
 
-    protected void validate(final String s) {
-
+    void validate(final String s) {
+        if (lengths != null) {
+            Preconditions.checkArgument(lengths.contains(s.length()), "String '%s' does not match allowed lengths %s",
+                lengths);
+        }
     }
 }