mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 12:19:54 +01:00
ReaderImpl now maintains either one or two bytes of lookahead,
depending on the value of the first byte, so that an object's initial tag is included in the data seen by the ObjectReader. Digests and signatures can therefore be calculated over objects by their readers without any risk of ambiguity.
This commit is contained in:
@@ -3,7 +3,6 @@ package net.sf.briar.protocol;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -65,9 +64,8 @@ public class BatchReaderTest extends TestCase {
|
||||
Reader reader = readerFactory.createReader(in);
|
||||
reader.addObjectReader(Tags.BATCH, batchReader);
|
||||
|
||||
reader.readUserDefinedTag(Tags.BATCH);
|
||||
try {
|
||||
reader.readUserDefinedObject(Tags.BATCH, Batch.class);
|
||||
reader.readUserDefined(Tags.BATCH, Batch.class);
|
||||
assertTrue(false);
|
||||
} catch(FormatException expected) {}
|
||||
context.assertIsSatisfied();
|
||||
@@ -91,17 +89,15 @@ public class BatchReaderTest extends TestCase {
|
||||
Reader reader = readerFactory.createReader(in);
|
||||
reader.addObjectReader(Tags.BATCH, batchReader);
|
||||
|
||||
reader.readUserDefinedTag(Tags.BATCH);
|
||||
assertEquals(batch, reader.readUserDefinedObject(Tags.BATCH,
|
||||
Batch.class));
|
||||
assertEquals(batch, reader.readUserDefined(Tags.BATCH, Batch.class));
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatchId() throws Exception {
|
||||
byte[] b = createBatch(Batch.MAX_SIZE);
|
||||
// Calculate the expected batch ID, skipping the initial tag
|
||||
messageDigest.update(b, 1, b.length - 1);
|
||||
// Calculate the expected batch ID
|
||||
messageDigest.update(b);
|
||||
final BatchId id = new BatchId(messageDigest.digest());
|
||||
messageDigest.reset();
|
||||
|
||||
@@ -121,9 +117,7 @@ public class BatchReaderTest extends TestCase {
|
||||
Reader reader = readerFactory.createReader(in);
|
||||
reader.addObjectReader(Tags.BATCH, batchReader);
|
||||
|
||||
reader.readUserDefinedTag(Tags.BATCH);
|
||||
assertEquals(batch, reader.readUserDefinedObject(Tags.BATCH,
|
||||
Batch.class));
|
||||
assertEquals(batch, reader.readUserDefined(Tags.BATCH, Batch.class));
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@@ -145,9 +139,7 @@ public class BatchReaderTest extends TestCase {
|
||||
Reader reader = readerFactory.createReader(in);
|
||||
reader.addObjectReader(Tags.BATCH, batchReader);
|
||||
|
||||
reader.readUserDefinedTag(Tags.BATCH);
|
||||
assertEquals(batch, reader.readUserDefinedObject(Tags.BATCH,
|
||||
Batch.class));
|
||||
assertEquals(batch, reader.readUserDefined(Tags.BATCH, Batch.class));
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@@ -156,8 +148,8 @@ public class BatchReaderTest extends TestCase {
|
||||
Writer w = writerFactory.createWriter(out);
|
||||
w.writeUserDefinedTag(Tags.BATCH);
|
||||
w.writeListStart();
|
||||
w.writeUserDefinedTag(Tags.MESSAGE);
|
||||
// We're using a fake message reader, so it's OK to use a fake message
|
||||
w.writeUserDefinedTag(Tags.MESSAGE);
|
||||
w.writeRaw(new byte[size - 10]);
|
||||
w.writeListEnd();
|
||||
w.close();
|
||||
@@ -178,8 +170,8 @@ public class BatchReaderTest extends TestCase {
|
||||
|
||||
private class TestMessageReader implements ObjectReader<Message> {
|
||||
|
||||
public Message readObject(Reader r) throws IOException,
|
||||
GeneralSecurityException {
|
||||
public Message readObject(Reader r) throws IOException {
|
||||
r.readUserDefinedTag(Tags.MESSAGE);
|
||||
r.readRaw();
|
||||
return message;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package net.sf.briar.protocol;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Collections;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
@@ -217,8 +216,7 @@ public class BundleReaderImplTest extends TestCase {
|
||||
|
||||
private class TestHeaderReader implements ObjectReader<Header> {
|
||||
|
||||
public Header readObject(Reader r) throws IOException,
|
||||
GeneralSecurityException {
|
||||
public Header readObject(Reader r) throws IOException {
|
||||
r.readList();
|
||||
r.readList();
|
||||
r.readMap();
|
||||
@@ -229,8 +227,7 @@ public class BundleReaderImplTest extends TestCase {
|
||||
|
||||
private class TestBatchReader implements ObjectReader<Batch> {
|
||||
|
||||
public Batch readObject(Reader r) throws IOException,
|
||||
GeneralSecurityException {
|
||||
public Batch readObject(Reader r) throws IOException {
|
||||
r.readList();
|
||||
return context.mock(Batch.class);
|
||||
}
|
||||
|
||||
@@ -51,9 +51,8 @@ public class HeaderReaderTest extends TestCase {
|
||||
Reader reader = readerFactory.createReader(in);
|
||||
reader.addObjectReader(Tags.HEADER, headerReader);
|
||||
|
||||
reader.readUserDefinedTag(Tags.HEADER);
|
||||
try {
|
||||
reader.readUserDefinedObject(Tags.HEADER, Header.class);
|
||||
reader.readUserDefined(Tags.HEADER, Header.class);
|
||||
assertTrue(false);
|
||||
} catch(FormatException expected) {}
|
||||
context.assertIsSatisfied();
|
||||
@@ -78,9 +77,7 @@ public class HeaderReaderTest extends TestCase {
|
||||
Reader reader = readerFactory.createReader(in);
|
||||
reader.addObjectReader(Tags.HEADER, headerReader);
|
||||
|
||||
reader.readUserDefinedTag(Tags.HEADER);
|
||||
assertEquals(header, reader.readUserDefinedObject(Tags.HEADER,
|
||||
Header.class));
|
||||
assertEquals(header, reader.readUserDefined(Tags.HEADER, Header.class));
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@@ -103,26 +100,23 @@ public class HeaderReaderTest extends TestCase {
|
||||
Reader reader = readerFactory.createReader(in);
|
||||
reader.addObjectReader(Tags.HEADER, headerReader);
|
||||
|
||||
reader.readUserDefinedTag(Tags.HEADER);
|
||||
assertEquals(header, reader.readUserDefinedObject(Tags.HEADER,
|
||||
Header.class));
|
||||
assertEquals(header, reader.readUserDefined(Tags.HEADER, Header.class));
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
private byte[] createHeader(int size) throws Exception {
|
||||
Random random = new Random();
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(size);
|
||||
Writer w = writerFactory.createWriter(out);
|
||||
w.writeUserDefinedTag(Tags.HEADER);
|
||||
// Acks
|
||||
// No acks
|
||||
w.writeListStart();
|
||||
w.writeListEnd();
|
||||
// Subs
|
||||
// Fill most of the header with subs
|
||||
w.writeListStart();
|
||||
// Fill most of the header with subscriptions
|
||||
while(w.getBytesWritten() < size - 45) {
|
||||
byte[] b = new byte[UniqueId.LENGTH];
|
||||
Random random = new Random();
|
||||
while(out.size() < size - 60) {
|
||||
w.writeUserDefinedTag(Tags.GROUP_ID);
|
||||
byte[] b = new byte[UniqueId.LENGTH];
|
||||
random.nextBytes(b);
|
||||
w.writeRaw(b);
|
||||
}
|
||||
@@ -131,7 +125,8 @@ public class HeaderReaderTest extends TestCase {
|
||||
w.writeMapStart();
|
||||
w.writeString("foo");
|
||||
// Build a string that will bring the header up to the expected size
|
||||
int length = (int) (size - w.getBytesWritten() - 12);
|
||||
int length = size - out.size() - 12;
|
||||
assertTrue(length > 0);
|
||||
StringBuilder s = new StringBuilder();
|
||||
for(int i = 0; i < length; i++) s.append((char) ('0' + i % 10));
|
||||
w.writeString(s.toString());
|
||||
@@ -139,9 +134,8 @@ public class HeaderReaderTest extends TestCase {
|
||||
// Timestamp
|
||||
w.writeInt64(System.currentTimeMillis());
|
||||
w.close();
|
||||
byte[] b = out.toByteArray();
|
||||
assertEquals(size, b.length);
|
||||
return b;
|
||||
assertEquals(size, out.size());
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
private byte[] createEmptyHeader() throws Exception {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.sf.briar.serial;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -8,6 +9,7 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import net.sf.briar.api.serial.Consumer;
|
||||
import net.sf.briar.api.serial.FormatException;
|
||||
import net.sf.briar.api.serial.ObjectReader;
|
||||
import net.sf.briar.api.serial.Raw;
|
||||
@@ -331,35 +333,77 @@ public class ReaderImplTest extends TestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadUserDefinedTag() throws Exception {
|
||||
setContents("C0" + "DF" + "EF" + "20" + "EF" + "FB7FFFFFFF");
|
||||
assertEquals(0, r.readUserDefinedTag());
|
||||
assertEquals(31, r.readUserDefinedTag());
|
||||
assertEquals(32, r.readUserDefinedTag());
|
||||
assertEquals(Integer.MAX_VALUE, r.readUserDefinedTag());
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadUserDefinedObject() throws Exception {
|
||||
setContents("C0" + "83666F6F");
|
||||
// Add an object reader for a user-defined type
|
||||
public void testReadUserDefined() throws Exception {
|
||||
setContents("C0" + "83666F6F" + "EF" + "FF" + "83666F6F");
|
||||
// Add object readers for two user-defined types
|
||||
r.addObjectReader(0, new ObjectReader<Foo>() {
|
||||
public Foo readObject(Reader r) throws IOException {
|
||||
r.readUserDefinedTag(0);
|
||||
return new Foo(r.readString());
|
||||
}
|
||||
});
|
||||
assertEquals(0, r.readUserDefinedTag());
|
||||
assertEquals("foo", r.readUserDefinedObject(0, Foo.class).s);
|
||||
r.addObjectReader(255, new ObjectReader<Bar>() {
|
||||
public Bar readObject(Reader r) throws IOException {
|
||||
r.readUserDefinedTag(255);
|
||||
return new Bar(r.readString());
|
||||
}
|
||||
});
|
||||
// Test both tag formats, short and long
|
||||
assertTrue(r.hasUserDefined(0));
|
||||
assertEquals("foo", r.readUserDefined(0, Foo.class).s);
|
||||
assertTrue(r.hasUserDefined(255));
|
||||
assertEquals("foo", r.readUserDefined(255, Bar.class).s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadUserDefinedWithConsumer() throws Exception {
|
||||
setContents("C0" + "83666F6F" + "EF" + "FF" + "83666F6F");
|
||||
// Add object readers for two user-defined types
|
||||
r.addObjectReader(0, new ObjectReader<Foo>() {
|
||||
public Foo readObject(Reader r) throws IOException {
|
||||
r.readUserDefinedTag(0);
|
||||
return new Foo(r.readString());
|
||||
}
|
||||
});
|
||||
r.addObjectReader(255, new ObjectReader<Bar>() {
|
||||
public Bar readObject(Reader r) throws IOException {
|
||||
r.readUserDefinedTag(255);
|
||||
return new Bar(r.readString());
|
||||
}
|
||||
});
|
||||
// Add a consumer
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
r.addConsumer(new Consumer() {
|
||||
|
||||
public void write(byte b) throws IOException {
|
||||
out.write(b);
|
||||
}
|
||||
|
||||
public void write(byte[] b) throws IOException {
|
||||
out.write(b);
|
||||
}
|
||||
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
out.write(b, off, len);
|
||||
}
|
||||
});
|
||||
// Test both tag formats, short and long
|
||||
assertTrue(r.hasUserDefined(0));
|
||||
assertEquals("foo", r.readUserDefined(0, Foo.class).s);
|
||||
assertTrue(r.hasUserDefined(255));
|
||||
assertEquals("foo", r.readUserDefined(255, Bar.class).s);
|
||||
// Check that everything was passed to the consumer
|
||||
assertEquals("C0" + "83666F6F" + "EF" + "FF" + "83666F6F",
|
||||
StringUtils.toHexString(out.toByteArray()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnknownTagThrowsFormatException() throws Exception {
|
||||
setContents("C0" + "83666F6F");
|
||||
assertTrue(r.hasUserDefined(0));
|
||||
// No object reader has been added for tag 0
|
||||
assertEquals(0, r.readUserDefinedTag());
|
||||
try {
|
||||
r.readUserDefinedObject(0, Foo.class);
|
||||
r.readUserDefined(0, Foo.class);
|
||||
assertTrue(false);
|
||||
} catch(FormatException expected) {}
|
||||
}
|
||||
@@ -370,13 +414,14 @@ public class ReaderImplTest extends TestCase {
|
||||
// Add an object reader for tag 0, class Foo
|
||||
r.addObjectReader(0, new ObjectReader<Foo>() {
|
||||
public Foo readObject(Reader r) throws IOException {
|
||||
r.readUserDefinedTag(0);
|
||||
return new Foo(r.readString());
|
||||
}
|
||||
});
|
||||
assertEquals(0, r.readUserDefinedTag());
|
||||
assertTrue(r.hasUserDefined(0));
|
||||
// Trying to read the object as class Bar should throw a FormatException
|
||||
try {
|
||||
r.readUserDefinedObject(0, Bar.class);
|
||||
r.readUserDefined(0, Bar.class);
|
||||
assertTrue(false);
|
||||
} catch(FormatException expected) {}
|
||||
}
|
||||
@@ -387,6 +432,7 @@ public class ReaderImplTest extends TestCase {
|
||||
// Add an object reader for a user-defined type
|
||||
r.addObjectReader(0, new ObjectReader<Foo>() {
|
||||
public Foo readObject(Reader r) throws IOException {
|
||||
r.readUserDefinedTag(0);
|
||||
return new Foo(r.readString());
|
||||
}
|
||||
});
|
||||
@@ -402,11 +448,13 @@ public class ReaderImplTest extends TestCase {
|
||||
// Add object readers for two user-defined types
|
||||
r.addObjectReader(0, new ObjectReader<Foo>() {
|
||||
public Foo readObject(Reader r) throws IOException {
|
||||
r.readUserDefinedTag(0);
|
||||
return new Foo(r.readString());
|
||||
}
|
||||
});
|
||||
r.addObjectReader(1, new ObjectReader<Bar>() {
|
||||
public Bar readObject(Reader r) throws IOException {
|
||||
r.readUserDefinedTag(1);
|
||||
return new Bar(r.readString());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -298,9 +298,9 @@ public class WriterImplTest extends TestCase {
|
||||
@Test
|
||||
public void testWriteUserDefinedTag() throws IOException {
|
||||
w.writeUserDefinedTag(32);
|
||||
w.writeUserDefinedTag(Integer.MAX_VALUE);
|
||||
// USER tag, 32 as uint7, USER tag, 2147483647 as int32
|
||||
checkContents("EF" + "20" + "EF" + "FB7FFFFFFF");
|
||||
w.writeUserDefinedTag(255);
|
||||
// USER tag, 32 as uint8, USER tag, 255 as uint8
|
||||
checkContents("EF" + "20" + "EF" + "FF");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -323,6 +323,5 @@ public class WriterImplTest extends TestCase {
|
||||
byte[] expected = StringUtils.fromHexString(hex);
|
||||
assertTrue(StringUtils.toHexString(out.toByteArray()),
|
||||
Arrays.equals(expected, out.toByteArray()));
|
||||
assertEquals(expected.length, w.getBytesWritten());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user