mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-16 20:59:54 +01:00
Removed the restriction that transport updates have to be written in
delimited form.
This commit is contained in:
@@ -19,6 +19,7 @@ public interface Tags {
|
|||||||
static final int OFFER = 9;
|
static final int OFFER = 9;
|
||||||
static final int OFFER_ID = 10;
|
static final int OFFER_ID = 10;
|
||||||
static final int REQUEST = 11;
|
static final int REQUEST = 11;
|
||||||
static final int SUBSCRIPTIONS = 12;
|
static final int SUBSCRIPTION_UPDATE = 12;
|
||||||
static final int TRANSPORTS = 13;
|
static final int TRANSPORT_PROPERTIES = 13;
|
||||||
|
static final int TRANSPORT_UPDATE = 14;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,12 @@ public interface Reader {
|
|||||||
boolean eof() throws IOException;
|
boolean eof() throws IOException;
|
||||||
void close() throws IOException;
|
void close() throws IOException;
|
||||||
|
|
||||||
|
void setMaxStringLength(int length);
|
||||||
|
void resetMaxStringLength();
|
||||||
|
|
||||||
|
void setMaxBytesLength(int length);
|
||||||
|
void resetMaxBytesLength();
|
||||||
|
|
||||||
void addConsumer(Consumer c);
|
void addConsumer(Consumer c);
|
||||||
void removeConsumer(Consumer c);
|
void removeConsumer(Consumer c);
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ class ProtocolReaderImpl implements ProtocolReader {
|
|||||||
reader.addObjectReader(Tags.BATCH, batchReader);
|
reader.addObjectReader(Tags.BATCH, batchReader);
|
||||||
reader.addObjectReader(Tags.OFFER, offerReader);
|
reader.addObjectReader(Tags.OFFER, offerReader);
|
||||||
reader.addObjectReader(Tags.REQUEST, requestReader);
|
reader.addObjectReader(Tags.REQUEST, requestReader);
|
||||||
reader.addObjectReader(Tags.SUBSCRIPTIONS, subscriptionReader);
|
reader.addObjectReader(Tags.SUBSCRIPTION_UPDATE, subscriptionReader);
|
||||||
reader.addObjectReader(Tags.TRANSPORTS, transportReader);
|
reader.addObjectReader(Tags.TRANSPORT_UPDATE, transportReader);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasAck() throws IOException {
|
public boolean hasAck() throws IOException {
|
||||||
@@ -67,19 +67,19 @@ class ProtocolReaderImpl implements ProtocolReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasSubscriptionUpdate() throws IOException {
|
public boolean hasSubscriptionUpdate() throws IOException {
|
||||||
return reader.hasUserDefined(Tags.SUBSCRIPTIONS);
|
return reader.hasUserDefined(Tags.SUBSCRIPTION_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubscriptionUpdate readSubscriptionUpdate() throws IOException {
|
public SubscriptionUpdate readSubscriptionUpdate() throws IOException {
|
||||||
return reader.readUserDefined(Tags.SUBSCRIPTIONS,
|
return reader.readUserDefined(Tags.SUBSCRIPTION_UPDATE,
|
||||||
SubscriptionUpdate.class);
|
SubscriptionUpdate.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasTransportUpdate() throws IOException {
|
public boolean hasTransportUpdate() throws IOException {
|
||||||
return reader.hasUserDefined(Tags.TRANSPORTS);
|
return reader.hasUserDefined(Tags.TRANSPORT_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransportUpdate readTransportUpdate() throws IOException {
|
public TransportUpdate readTransportUpdate() throws IOException {
|
||||||
return reader.readUserDefined(Tags.TRANSPORTS, TransportUpdate.class);
|
return reader.readUserDefined(Tags.TRANSPORT_UPDATE, TransportUpdate.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class SubscriptionReader implements ObjectReader<SubscriptionUpdate> {
|
|||||||
Consumer counting = new CountingConsumer(SubscriptionUpdate.MAX_SIZE);
|
Consumer counting = new CountingConsumer(SubscriptionUpdate.MAX_SIZE);
|
||||||
// Read the data
|
// Read the data
|
||||||
r.addConsumer(counting);
|
r.addConsumer(counting);
|
||||||
r.readUserDefinedTag(Tags.SUBSCRIPTIONS);
|
r.readUserDefinedTag(Tags.SUBSCRIPTION_UPDATE);
|
||||||
r.addObjectReader(Tags.GROUP, groupReader);
|
r.addObjectReader(Tags.GROUP, groupReader);
|
||||||
Map<Group, Long> subs = r.readMap(Group.class, Long.class);
|
Map<Group, Long> subs = r.readMap(Group.class, Long.class);
|
||||||
r.removeObjectReader(Tags.GROUP);
|
r.removeObjectReader(Tags.GROUP);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package net.sf.briar.protocol;
|
package net.sf.briar.protocol;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
@@ -13,9 +14,11 @@ import net.sf.briar.api.serial.Reader;
|
|||||||
class TransportReader implements ObjectReader<TransportUpdate> {
|
class TransportReader implements ObjectReader<TransportUpdate> {
|
||||||
|
|
||||||
private final TransportFactory transportFactory;
|
private final TransportFactory transportFactory;
|
||||||
|
private final ObjectReader<TransportProperties> propertiesReader;
|
||||||
|
|
||||||
TransportReader(TransportFactory transportFactory) {
|
TransportReader(TransportFactory transportFactory) {
|
||||||
this.transportFactory = transportFactory;
|
this.transportFactory = transportFactory;
|
||||||
|
propertiesReader = new TransportPropertiesReader();
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransportUpdate readObject(Reader r) throws IOException {
|
public TransportUpdate readObject(Reader r) throws IOException {
|
||||||
@@ -23,27 +26,41 @@ class TransportReader implements ObjectReader<TransportUpdate> {
|
|||||||
Consumer counting = new CountingConsumer(TransportUpdate.MAX_SIZE);
|
Consumer counting = new CountingConsumer(TransportUpdate.MAX_SIZE);
|
||||||
// Read the data
|
// Read the data
|
||||||
r.addConsumer(counting);
|
r.addConsumer(counting);
|
||||||
r.readUserDefinedTag(Tags.TRANSPORTS);
|
r.readUserDefinedTag(Tags.TRANSPORT_UPDATE);
|
||||||
// Transport maps are always written in delimited form
|
r.addObjectReader(Tags.TRANSPORT_PROPERTIES, propertiesReader);
|
||||||
|
r.setMaxStringLength(TransportUpdate.MAX_SIZE);
|
||||||
|
List<TransportProperties> l = r.readList(TransportProperties.class);
|
||||||
|
r.resetMaxStringLength();
|
||||||
|
r.removeObjectReader(Tags.TRANSPORT_PROPERTIES);
|
||||||
Map<String, Map<String, String>> transports =
|
Map<String, Map<String, String>> transports =
|
||||||
new TreeMap<String, Map<String, String>>();
|
new TreeMap<String, Map<String, String>>();
|
||||||
r.readMapStart();
|
for(TransportProperties t : l) transports.put(t.name, t.properties);
|
||||||
while(!r.hasMapEnd()) {
|
|
||||||
String name = r.readString(TransportUpdate.MAX_SIZE);
|
|
||||||
Map<String, String> properties = new TreeMap<String, String>();
|
|
||||||
r.readMapStart();
|
|
||||||
while(!r.hasMapEnd()) {
|
|
||||||
String key = r.readString(TransportUpdate.MAX_SIZE);
|
|
||||||
String value = r.readString(TransportUpdate.MAX_SIZE);
|
|
||||||
properties.put(key, value);
|
|
||||||
}
|
|
||||||
r.readMapEnd();
|
|
||||||
transports.put(name, properties);
|
|
||||||
}
|
|
||||||
r.readMapEnd();
|
|
||||||
long timestamp = r.readInt64();
|
long timestamp = r.readInt64();
|
||||||
r.removeConsumer(counting);
|
r.removeConsumer(counting);
|
||||||
// Build and return the transport update
|
// Build and return the transport update
|
||||||
return transportFactory.createTransports(transports, timestamp);
|
return transportFactory.createTransports(transports, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class TransportProperties {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final Map<String, String> properties;
|
||||||
|
|
||||||
|
TransportProperties(String name, Map<String, String> properties) {
|
||||||
|
this.name = name;
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TransportPropertiesReader
|
||||||
|
implements ObjectReader<TransportProperties> {
|
||||||
|
|
||||||
|
public TransportProperties readObject(Reader r) throws IOException {
|
||||||
|
r.readUserDefinedTag(Tags.TRANSPORT_PROPERTIES);
|
||||||
|
String name = r.readString();
|
||||||
|
Map<String, String> properties =
|
||||||
|
r.readMap(String.class, String.class);
|
||||||
|
return new TransportProperties(name, properties);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class SubscriptionWriterImpl implements SubscriptionWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void writeSubscriptions(Map<Group, Long> subs) throws IOException {
|
public void writeSubscriptions(Map<Group, Long> subs) throws IOException {
|
||||||
w.writeUserDefinedTag(Tags.SUBSCRIPTIONS);
|
w.writeUserDefinedTag(Tags.SUBSCRIPTION_UPDATE);
|
||||||
w.writeMap(subs);
|
w.writeMap(subs);
|
||||||
w.writeInt64(System.currentTimeMillis());
|
w.writeInt64(System.currentTimeMillis());
|
||||||
out.flush();
|
out.flush();
|
||||||
|
|||||||
@@ -22,19 +22,14 @@ class TransportWriterImpl implements TransportWriter {
|
|||||||
|
|
||||||
public void writeTransports(Map<String, Map<String, String>> transports)
|
public void writeTransports(Map<String, Map<String, String>> transports)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
w.writeUserDefinedTag(Tags.TRANSPORTS);
|
w.writeUserDefinedTag(Tags.TRANSPORT_UPDATE);
|
||||||
// Transport maps are always written in delimited form
|
w.writeListStart();
|
||||||
w.writeMapStart();
|
|
||||||
for(Entry<String, Map<String, String>> e : transports.entrySet()) {
|
for(Entry<String, Map<String, String>> e : transports.entrySet()) {
|
||||||
|
w.writeUserDefinedTag(Tags.TRANSPORT_PROPERTIES);
|
||||||
w.writeString(e.getKey());
|
w.writeString(e.getKey());
|
||||||
w.writeMapStart();
|
w.writeMap(e.getValue());
|
||||||
for(Entry<String, String> e1 : e.getValue().entrySet()) {
|
|
||||||
w.writeString(e1.getKey());
|
|
||||||
w.writeString(e1.getValue());
|
|
||||||
}
|
|
||||||
w.writeMapEnd();
|
|
||||||
}
|
}
|
||||||
w.writeMapEnd();
|
w.writeListEnd();
|
||||||
w.writeInt64(System.currentTimeMillis());
|
w.writeInt64(System.currentTimeMillis());
|
||||||
out.flush();
|
out.flush();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ class ReaderImpl implements Reader {
|
|||||||
private boolean hasLookahead = false, eof = false;
|
private boolean hasLookahead = false, eof = false;
|
||||||
private byte next, nextNext;
|
private byte next, nextNext;
|
||||||
private byte[] buf = null;
|
private byte[] buf = null;
|
||||||
|
private int maxStringLength = Integer.MAX_VALUE;
|
||||||
|
private int maxBytesLength = Integer.MAX_VALUE;
|
||||||
|
|
||||||
ReaderImpl(InputStream in) {
|
ReaderImpl(InputStream in) {
|
||||||
this.in = in;
|
this.in = in;
|
||||||
@@ -71,6 +73,22 @@ class ReaderImpl implements Reader {
|
|||||||
in.close();
|
in.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMaxStringLength(int length) {
|
||||||
|
maxStringLength = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetMaxStringLength() {
|
||||||
|
maxStringLength = Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxBytesLength(int length) {
|
||||||
|
maxBytesLength = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetMaxBytesLength() {
|
||||||
|
maxBytesLength = Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
public void addConsumer(Consumer c) {
|
public void addConsumer(Consumer c) {
|
||||||
Consumer[] newConsumers = new Consumer[consumers.length + 1];
|
Consumer[] newConsumers = new Consumer[consumers.length + 1];
|
||||||
System.arraycopy(consumers, 0, newConsumers, 0, consumers.length);
|
System.arraycopy(consumers, 0, newConsumers, 0, consumers.length);
|
||||||
@@ -268,21 +286,26 @@ class ReaderImpl implements Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String readString() throws IOException {
|
public String readString() throws IOException {
|
||||||
return readString(Integer.MAX_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String readString(int maxLength) throws IOException {
|
|
||||||
if(!hasString()) throw new FormatException();
|
if(!hasString()) throw new FormatException();
|
||||||
consumeLookahead();
|
consumeLookahead();
|
||||||
int length;
|
int length;
|
||||||
if(next == Tag.STRING) length = readLength();
|
if(next == Tag.STRING) length = readLength();
|
||||||
else length = 0xFF & next ^ Tag.SHORT_STRING;
|
else length = 0xFF & next ^ Tag.SHORT_STRING;
|
||||||
if(length > maxLength) throw new FormatException();
|
if(length > maxStringLength) throw new FormatException();
|
||||||
if(length == 0) return "";
|
if(length == 0) return "";
|
||||||
readIntoBuffer(length);
|
readIntoBuffer(length);
|
||||||
return new String(buf, 0, length, "UTF-8");
|
return new String(buf, 0, length, "UTF-8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String readString(int maxLength) throws IOException {
|
||||||
|
setMaxStringLength(maxLength);
|
||||||
|
try {
|
||||||
|
return readString();
|
||||||
|
} finally {
|
||||||
|
resetMaxStringLength();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int readLength() throws IOException {
|
private int readLength() throws IOException {
|
||||||
if(!hasLength()) throw new FormatException();
|
if(!hasLength()) throw new FormatException();
|
||||||
if(next >= 0) return readUint7();
|
if(next >= 0) return readUint7();
|
||||||
@@ -306,22 +329,27 @@ class ReaderImpl implements Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public byte[] readBytes() throws IOException {
|
public byte[] readBytes() throws IOException {
|
||||||
return readBytes(Integer.MAX_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] readBytes(int maxLength) throws IOException {
|
|
||||||
if(!hasBytes()) throw new FormatException();
|
if(!hasBytes()) throw new FormatException();
|
||||||
consumeLookahead();
|
consumeLookahead();
|
||||||
int length;
|
int length;
|
||||||
if(next == Tag.BYTES) length = readLength();
|
if(next == Tag.BYTES) length = readLength();
|
||||||
else length = 0xFF & next ^ Tag.SHORT_BYTES;
|
else length = 0xFF & next ^ Tag.SHORT_BYTES;
|
||||||
if(length > maxLength) throw new FormatException();
|
if(length > maxBytesLength) throw new FormatException();
|
||||||
if(length == 0) return EMPTY_BUFFER;
|
if(length == 0) return EMPTY_BUFFER;
|
||||||
byte[] b = new byte[length];
|
byte[] b = new byte[length];
|
||||||
readIntoBuffer(b, length);
|
readIntoBuffer(b, length);
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] readBytes(int maxLength) throws IOException {
|
||||||
|
setMaxBytesLength(maxLength);
|
||||||
|
try {
|
||||||
|
return readBytes();
|
||||||
|
} finally {
|
||||||
|
resetMaxBytesLength();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasList() throws IOException {
|
public boolean hasList() throws IOException {
|
||||||
if(!hasLookahead) readLookahead(true);
|
if(!hasLookahead) readLookahead(true);
|
||||||
if(eof) return false;
|
if(eof) return false;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import java.io.ByteArrayInputStream;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@@ -485,6 +486,31 @@ public class ReaderImplTest extends TestCase {
|
|||||||
assertEquals("bar", e.getValue().s);
|
assertEquals("bar", e.getValue().s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMaxLengthAppliesInsideMap() throws Exception {
|
||||||
|
setContents("B" + "1" + "83666F6F" + "93010203");
|
||||||
|
r.setMaxStringLength(3);
|
||||||
|
r.setMaxBytesLength(3);
|
||||||
|
Map<String, Bytes> m = r.readMap(String.class, Bytes.class);
|
||||||
|
String key = "foo";
|
||||||
|
Bytes value = new Bytes(new byte[] {1, 2, 3});
|
||||||
|
assertEquals(Collections.singletonMap(key, value), m);
|
||||||
|
// The max string length should be applied inside the map
|
||||||
|
setContents("B" + "1" + "83666F6F" + "93010203");
|
||||||
|
r.setMaxStringLength(2);
|
||||||
|
try {
|
||||||
|
r.readMap(String.class, Bytes.class);
|
||||||
|
fail();
|
||||||
|
} catch(FormatException expected) {}
|
||||||
|
// The max bytes length should be applied inside the map
|
||||||
|
setContents("B" + "1" + "83666F6F" + "93010203");
|
||||||
|
r.setMaxBytesLength(2);
|
||||||
|
try {
|
||||||
|
r.readMap(String.class, Bytes.class);
|
||||||
|
fail();
|
||||||
|
} catch(FormatException expected) {}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadEmptyInput() throws Exception {
|
public void testReadEmptyInput() throws Exception {
|
||||||
setContents("");
|
setContents("");
|
||||||
|
|||||||
Reference in New Issue
Block a user