diff options
Diffstat (limited to 'impl_core/src')
4 files changed, 71 insertions, 40 deletions
diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java b/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java index 3de44fa3..756aeb5d 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java +++ b/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java @@ -68,6 +68,7 @@ final class SerializationUtils { @VisibleForTesting static final int VERSION_ID = 0; @VisibleForTesting static final int TAG_FIELD_ID = 0; + // This size limit only applies to the bytes representing tag keys and values. @VisibleForTesting static final int TAGCONTEXT_SERIALIZED_SIZE_LIMIT = 8192; // Serializes a TagContext to the on-the-wire format. @@ -76,17 +77,19 @@ final class SerializationUtils { // Use a ByteArrayDataOutput to avoid needing to handle IOExceptions. final ByteArrayDataOutput byteArrayDataOutput = ByteStreams.newDataOutput(); byteArrayDataOutput.write(VERSION_ID); + int totalChars = 0; // Here chars are equivalent to bytes, since we're using ascii chars. for (Iterator<Tag> i = InternalUtils.getTags(tags); i.hasNext(); ) { Tag tag = i.next(); + totalChars += tag.getKey().getName().length(); + totalChars += tag.getValue().asString().length(); encodeTag(tag, byteArrayDataOutput); } - byte[] bytes = byteArrayDataOutput.toByteArray(); - if (bytes.length > TAGCONTEXT_SERIALIZED_SIZE_LIMIT) { + if (totalChars > TAGCONTEXT_SERIALIZED_SIZE_LIMIT) { throw new TagContextSerializationException( - "Size of serialized TagContext exceeds the maximum serialized size " + "Size of TagContext exceeds the maximum serialized size " + TAGCONTEXT_SERIALIZED_SIZE_LIMIT); } - return bytes; + return byteArrayDataOutput.toByteArray(); } // Deserializes input to TagContext based on the binary format standard. @@ -96,10 +99,6 @@ final class SerializationUtils { if (bytes.length == 0) { // Does not allow empty byte array. throw new TagContextDeserializationException("Input byte[] can not be empty."); - } else if (bytes.length > TAGCONTEXT_SERIALIZED_SIZE_LIMIT) { - throw new TagContextDeserializationException( - "Size of input byte[] exceeds the maximum serialized size " - + TAGCONTEXT_SERIALIZED_SIZE_LIMIT); } ByteBuffer buffer = ByteBuffer.wrap(bytes).asReadOnlyBuffer(); @@ -118,18 +117,26 @@ final class SerializationUtils { throws TagContextDeserializationException { Map<TagKey, TagValue> tags = new HashMap<TagKey, TagValue>(); int limit = buffer.limit(); + int totalChars = 0; // Here chars are equivalent to bytes, since we're using ascii chars. while (buffer.position() < limit) { int type = buffer.get(); if (type == TAG_FIELD_ID) { TagKey key = createTagKey(decodeString(buffer)); TagValue val = createTagValue(key, decodeString(buffer)); + totalChars += key.getName().length(); + totalChars += val.asString().length(); tags.put(key, val); } else { // Stop parsing at the first unknown field ID, since there is no way to know its length. // TODO(sebright): Consider storing the rest of the byte array in the TagContext. - return tags; + break; } } + if (totalChars > TAGCONTEXT_SERIALIZED_SIZE_LIMIT) { + throw new TagContextDeserializationException( + "Size of TagContext exceeds the maximum serialized size " + + TAGCONTEXT_SERIALIZED_SIZE_LIMIT); + } return tags; } diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java index 09f6878d..a2245255 100644 --- a/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java @@ -78,9 +78,30 @@ public class TagContextDeserializationTest { @Test public void testDeserializeTooLargeByteArrayThrowException() throws TagContextDeserializationException { + ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.write(SerializationUtils.VERSION_ID); + for (int i = 0; i < SerializationUtils.TAGCONTEXT_SERIALIZED_SIZE_LIMIT / 8 - 1; i++) { + // Each tag will be with format {key : "0123", value : "0123"}, so the length of it is 8. + String str; + if (i < 10) { + str = "000" + i; + } else if (i < 100) { + str = "00" + i; + } else if (i < 1000) { + str = "0" + i; + } else { + str = String.valueOf(i); + } + encodeTagToOutput(str, str, output); + } + // The last tag will be of size 9, so the total size of the TagContext (8193) will be one byte + // more than limit. + encodeTagToOutput("last", "last1", output); + + byte[] bytes = output.toByteArray(); thrown.expect(TagContextDeserializationException.class); - thrown.expectMessage("Size of input byte[] exceeds the maximum serialized size "); - serializer.fromByteArray(new byte[SerializationUtils.TAGCONTEXT_SERIALIZED_SIZE_LIMIT + 1]); + thrown.expectMessage("Size of TagContext exceeds the maximum serialized size "); + serializer.fromByteArray(bytes); } @Test diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java index c49e53a4..1b1aa042 100644 --- a/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java @@ -59,23 +59,22 @@ public class TagContextRoundtripTest { @Test public void testRoundtrip_TagContextWithMaximumSize() throws Exception { TagContextBuilder builder = tagger.emptyBuilder(); - int i = 0; - - // This loop should fill in tags that have a total size of 8185 - while (serializer.toByteArray(builder.build()).length - < SerializationUtils.TAGCONTEXT_SERIALIZED_SIZE_LIMIT - 8) { - TagKey key = TagKey.create("k" + i); - TagValue value = TagValue.create("v" + i); - builder.put(key, value); - i++; + for (int i = 0; i < SerializationUtils.TAGCONTEXT_SERIALIZED_SIZE_LIMIT / 8; i++) { + // Each tag will be with format {key : "0123", value : "0123"}, so the length of it is 8. + // Add 1024 tags, the total size should just be 8192. + String str; + if (i < 10) { + str = "000" + i; + } else if (i < 100) { + str = "00" + i; + } else if (i < 1000) { + str = "0" + i; + } else { + str = "" + i; + } + builder.put(TagKey.create(str), TagValue.create(str)); } - // The last tag has size 7, after putting it, the size of TagContext should just meet the limit - builder.put(TagKey.create("last"), TagValue.create("")); - - TagContext expected = builder.build(); - assertThat(serializer.toByteArray(expected).length) - .isEqualTo(SerializationUtils.TAGCONTEXT_SERIALIZED_SIZE_LIMIT); - testRoundtripSerialization(expected); + testRoundtripSerialization(builder.build()); } private void testRoundtripSerialization(TagContext expected) throws Exception { diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java index 551b7ff8..771b2899 100644 --- a/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java @@ -91,23 +91,27 @@ public class TagContextSerializationTest { @Test public void testSerializeTooLargeTagContext() throws TagContextSerializationException { TagContextBuilder builder = tagger.emptyBuilder(); - int i = 0; - - // This loop should fill in tags that have a total size of 8185 - while (serializer.toByteArray(builder.build()).length - < SerializationUtils.TAGCONTEXT_SERIALIZED_SIZE_LIMIT - 8) { - TagKey key = TagKey.create("k" + i); - TagValue value = TagValue.create("v" + i); - builder.put(key, value); - i++; + for (int i = 0; i < SerializationUtils.TAGCONTEXT_SERIALIZED_SIZE_LIMIT / 8 - 1; i++) { + // Each tag will be with format {key : "0123", value : "0123"}, so the length of it is 8. + String str; + if (i < 10) { + str = "000" + i; + } else if (i < 100) { + str = "00" + i; + } else if (i < 1000) { + str = "0" + i; + } else { + str = String.valueOf(i); + } + builder.put(TagKey.create(str), TagValue.create(str)); } - // The last tag has size 8, after putting it, the size of TagContext (8193) should just exceed - // the limit - builder.put(TagKey.create("last"), TagValue.create("1")); + // The last tag will be of size 9, so the total size of the TagContext (8193) will be one byte + // more than limit. + builder.put(TagKey.create("last"), TagValue.create("last1")); TagContext tagContext = builder.build(); thrown.expect(TagContextSerializationException.class); - thrown.expectMessage("Size of serialized TagContext exceeds the maximum serialized size "); + thrown.expectMessage("Size of TagContext exceeds the maximum serialized size "); serializer.toByteArray(tagContext); } |