tor-commits
Threads by month
- ----- 2025 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
June 2017
- 13 participants
- 1918 discussions
commit 595f87a584fe0d7d9307e68443bd1dee204f59f5
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Wed Jun 7 09:16:39 2017 +0200
Update to metrics-lib 1.8.0.
---
build.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.xml b/build.xml
index e89b8a6..74e81e5 100644
--- a/build.xml
+++ b/build.xml
@@ -11,7 +11,7 @@
<property name="onionoo.protocol.version" value="4.0"/>
<property name="release.version"
value="${onionoo.protocol.version}-1.2.0-dev"/>
- <property name="descriptorversion" value="1.7.0"/>
+ <property name="descriptorversion" value="1.8.0"/>
<property name="jetty.version" value="-8.1.16.v20140903" />
<property name="warfile"
value="onionoo-${release.version}.war"/>
1
0
commit 1c4cb3afd5c4ffb1904cba59a2877f1228c8cabf
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Wed Jun 7 09:15:01 2017 +0200
Update to metrics-lib 1.8.0.
---
build.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.xml b/build.xml
index 111423f..27500d4 100644
--- a/build.xml
+++ b/build.xml
@@ -12,7 +12,7 @@
<property name="webxmlfile" value="src/main/webapp/web.xml"/>
<property name="warfile" value="${dist}/exonerator.war"/>
<property name="source-and-target-java-version" value="1.7" />
- <property name="descriptorversion" value="1.7.0" />
+ <property name="descriptorversion" value="1.8.0" />
<path id="classpath">
<pathelement path="${classes}"/>
<fileset dir="${libs}">
1
0
commit d739229ebc41c30b3db54c725f1e07e2985068f2
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Wed Jun 7 09:07:48 2017 +0200
Bump version to 1.8.0-dev.
---
CHANGELOG.md | 3 +++
build.xml | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f364b6a..2e08e97 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+# Changes in version 1.9.0 - 2017-06-??
+
+
# Changes in version 1.8.0 - 2017-06-07
* Medium changes
diff --git a/build.xml b/build.xml
index 89f249b..df1c36e 100644
--- a/build.xml
+++ b/build.xml
@@ -6,7 +6,7 @@
<project default="usage" name="descriptor" basedir=".">
- <property name="release.version" value="1.8.0" />
+ <property name="release.version" value="1.8.0-dev" />
<property name="javadoc-title" value="DescripTor API Documentation"/>
<property name="javadoc-excludes" value="**/impl/** **/index/**" />
<property name="implementation-title" value="DescripTor" />
1
0

07 Jun '17
commit a3f4168467fc1823aab68ac587a60a2968388850
Author: iwakeh <iwakeh(a)torproject.org>
Date: Sun Jun 4 20:58:32 2017 +0000
Added simple tests for DescriptorImpl.
---
.../descriptor/impl/DescriptorImplTest.java | 147 +++++++++++++++++++++
1 file changed, 147 insertions(+)
diff --git a/src/test/java/org/torproject/descriptor/impl/DescriptorImplTest.java b/src/test/java/org/torproject/descriptor/impl/DescriptorImplTest.java
new file mode 100644
index 0000000..cbe57ff
--- /dev/null
+++ b/src/test/java/org/torproject/descriptor/impl/DescriptorImplTest.java
@@ -0,0 +1,147 @@
+/* Copyright 2017 The Tor Project
+ * See LICENSE for licensing information */
+
+package org.torproject.descriptor.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.util.List;
+
+/* Test parsing of descriptors. */
+public class DescriptorImplTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ private static final String DESC = Key.CRYPTO_BEGIN.keyword
+ + "\ncryptostuff\ncryptique\n" + Key.CRYPTO_END.keyword;
+ private static final String KW = "dummy-kw";
+ private static final String NL = "\n";
+ private static final byte[] DESCBYTES1 = DESC.getBytes();
+ private static final byte[] DESCBYTES2 = (DESC + "\n" + DESC).getBytes();
+ private static final byte[] DESCBYTES3
+ = (KW + NL + DESC + KW + NL + DESC + KW + NL).getBytes();
+
+ @Test
+ public void testSplitByKey() throws Exception {
+ TestDescriptor des = makeTestDesc(DESCBYTES2);
+ List<int[]> res = des.splitByKey(Key.CRYPTO_BEGIN, 0, DESCBYTES2.length,
+ false);
+ int count = 0;
+ for (int[] i : res) {
+ assertEquals("Offset.", count * 42, i[0]);
+ assertEquals("Length.", 42 - count++, i[1]);
+ }
+ }
+
+ @Test
+ public void testDigestsSha256Base64() throws Exception {
+ TestDescriptor des = makeTestDesc(DESCBYTES3);
+ des.calculateDigestSha256Base64(KW);
+ assertEquals("1bEECw9nT5KRzPG8dAzEFJgSI4OBQfyWn+wjREb8oa8",
+ des.getDigestSha256Base64());
+ assertNull(des.getDigestSha1Hex());
+ }
+
+ private TestDescriptor makeTestDesc(byte[] bytes) throws Exception {
+ return new TestDescriptor(bytes, new int[]{0, bytes.length}, false, false);
+ }
+
+ @Test
+ public void testDigestsSha256Base64EndToken() throws Exception {
+ TestDescriptor des = this.makeTestDesc(DESCBYTES3);
+ des.calculateDigestSha256Base64(KW, KW);
+ assertEquals("MHFj9sNLRXdDo/O62uJgNujuNnNbCtpUZiGwthfLH9E",
+ des.getDigestSha256Base64());
+ assertNull(des.getDigestSha1Hex());
+ }
+
+ @Test
+ public void testDigestsSha1Hex() throws Exception {
+ TestDescriptor des = makeTestDesc(DESCBYTES3);
+ des.calculateDigestSha1Hex(KW, KW);
+ assertEquals("2fc934e9523937c07cb9f4b395827a11c7b18c9d",
+ des.getDigestSha1Hex());
+ assertNull(des.getDigestSha256Base64());
+ }
+
+ @Test
+ public void testDigestsSha1HexNoToken() throws Exception {
+ TestDescriptor des = makeTestDesc(DESCBYTES1);
+ this.thrown.expect(DescriptorParseException.class);
+ this.thrown.expectMessage("Could not calculate descriptor digest.");
+ des.calculateDigestSha1Hex(KW, KW);
+ }
+
+ @Test
+ public void testNoAnnotation() throws Exception {
+ this.thrown.expect(DescriptorParseException.class);
+ this.thrown.expectMessage("Annotation line does not contain a newline.");
+ TestDescriptor des = makeTestDesc("@@@".getBytes());
+ }
+
+ @Test
+ public void testDescriptorEmpty() throws Exception {
+ this.thrown.expect(DescriptorParseException.class);
+ this.thrown.expectMessage("Descriptor is empty.");
+ TestDescriptor des = makeTestDesc("".getBytes());
+ }
+
+ @Test
+ public void testDescriptorBlankLine() throws Exception {
+ this.thrown.expect(DescriptorParseException.class);
+ this.thrown.expectMessage("Blank lines are not allowed.");
+ TestDescriptor des = makeTestDesc("\n\n".getBytes());
+ }
+
+ @Test
+ public void testDigestsNothing() throws Exception {
+ TestDescriptor des = makeTestDesc("\n".getBytes());
+ des.checkFirstKey(Key.EMPTY);
+ des.checkLastKey(Key.EMPTY);
+ }
+
+ @Test
+ public void testDigestsOnlyAnnotations() throws Exception {
+ TestDescriptor des = makeTestDesc("@a@b\n".getBytes());
+ des.checkFirstKey(Key.EMPTY);
+ des.checkLastKey(Key.EMPTY);
+ }
+
+ @Test
+ public void testDigestsSha256Base64NoToken() throws Exception {
+ TestDescriptor des = makeTestDesc(DESCBYTES1);
+ this.thrown.expect(DescriptorParseException.class);
+ this.thrown.expectMessage("Could not calculate descriptor digest.");
+ des.calculateDigestSha256Base64(KW);
+ }
+
+ @Test
+ public void testDigestsSha256Base64NoReCalculation() throws Exception {
+ TestDescriptor des = makeTestDesc(DESCBYTES3);
+ des.calculateDigestSha256Base64(KW);
+ String digest = des.getDigestSha256Base64();
+ assertEquals("1bEECw9nT5KRzPG8dAzEFJgSI4OBQfyWn+wjREb8oa8", digest);
+ des.calculateDigestSha256Base64(Key.CRYPTO_END.keyword);
+ digest = des.getDigestSha256Base64();
+ assertEquals("1bEECw9nT5KRzPG8dAzEFJgSI4OBQfyWn+wjREb8oa8", digest);
+ }
+
+ class TestDescriptor extends DescriptorImpl {
+
+ protected TestDescriptor(byte[] rawDescriptorBytes, int[] offsetAndLength,
+ boolean failUnrecognizedDescriptorLines, boolean blankLinesAllowed)
+ throws DescriptorParseException {
+ super(rawDescriptorBytes, offsetAndLength,
+ failUnrecognizedDescriptorLines, blankLinesAllowed);
+ }
+ }
+
+}
+
+
1
0
commit 086b046057867de7a2606f77793ef23e8a8fb268
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Tue Jun 6 15:28:52 2017 +0200
Prepare for 1.8.0 release.
---
CHANGELOG.md | 2 +-
build.xml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cf64603..f364b6a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,4 @@
-# Changes in version 1.8.0 - ??
+# Changes in version 1.8.0 - 2017-06-07
* Medium changes
- Store raw descriptor contents as offset and length into a
diff --git a/build.xml b/build.xml
index 0d6608f..89f249b 100644
--- a/build.xml
+++ b/build.xml
@@ -6,7 +6,7 @@
<project default="usage" name="descriptor" basedir=".">
- <property name="release.version" value="1.7.0-dev" />
+ <property name="release.version" value="1.8.0" />
<property name="javadoc-title" value="DescripTor API Documentation"/>
<property name="javadoc-excludes" value="**/impl/** **/index/**" />
<property name="implementation-title" value="DescripTor" />
1
0
commit df6bdc8d9bdd0ee0bf66b6d5587751bc3f86aa46
Author: iwakeh <iwakeh(a)torproject.org>
Date: Fri May 26 08:52:00 2017 +0000
Implements task-19607.
Use enums for keywords as well as enum sets and maps.
Use constants for repeated strings.
---
CHANGELOG.md | 5 +
.../impl/BridgeExtraInfoDescriptorImpl.java | 2 +-
.../descriptor/impl/BridgeNetworkStatusImpl.java | 10 +-
.../descriptor/impl/BridgePoolAssignmentImpl.java | 20 +-
.../impl/BridgeServerDescriptorImpl.java | 2 +-
.../torproject/descriptor/impl/DescriptorImpl.java | 185 +++++++++--------
.../descriptor/impl/DirSourceEntryImpl.java | 82 ++++----
.../impl/DirectoryKeyCertificateImpl.java | 95 +++++----
.../descriptor/impl/DirectorySignatureImpl.java | 23 ++-
.../descriptor/impl/ExtraInfoDescriptorImpl.java | 218 +++++++++++----------
.../java/org/torproject/descriptor/impl/Key.java | 177 +++++++++++++++++
.../descriptor/impl/MicrodescriptorImpl.java | 56 +++---
.../descriptor/impl/NetworkStatusEntryImpl.java | 70 ++++---
.../descriptor/impl/NetworkStatusImpl.java | 29 +--
.../descriptor/impl/RelayDirectoryImpl.java | 137 ++++++-------
.../impl/RelayExtraInfoDescriptorImpl.java | 2 +-
.../impl/RelayNetworkStatusConsensusImpl.java | 90 ++++-----
.../descriptor/impl/RelayNetworkStatusImpl.java | 102 +++++-----
.../impl/RelayNetworkStatusVoteImpl.java | 168 ++++++++--------
.../descriptor/impl/RelayServerDescriptorImpl.java | 2 +-
.../descriptor/impl/ServerDescriptorImpl.java | 192 +++++++++---------
21 files changed, 930 insertions(+), 737 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c76bbc1..0e39147 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,11 @@
descriptor lines, as permitted by dir-spec.txt.
- Streamline digest method names.
+ * Minor changes
+ - Turn keyword strings into enums and use the appropriate enum sets
+ and maps to avoid repeating string literals and to use more speedy
+ collection types.
+
# Changes in version 1.6.0 - 2017-02-17
diff --git a/src/main/java/org/torproject/descriptor/impl/BridgeExtraInfoDescriptorImpl.java b/src/main/java/org/torproject/descriptor/impl/BridgeExtraInfoDescriptorImpl.java
index 080dde1..0518392 100644
--- a/src/main/java/org/torproject/descriptor/impl/BridgeExtraInfoDescriptorImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/BridgeExtraInfoDescriptorImpl.java
@@ -19,7 +19,7 @@ public class BridgeExtraInfoDescriptorImpl
List<ExtraInfoDescriptor> parsedDescriptors = new ArrayList<>();
List<byte[]> splitDescriptorsBytes =
DescriptorImpl.splitRawDescriptorBytes(descriptorsBytes,
- "extra-info ");
+ Key.EXTRA_INFO.keyword + SP);
for (byte[] descriptorBytes : splitDescriptorsBytes) {
ExtraInfoDescriptor parsedDescriptor =
new BridgeExtraInfoDescriptorImpl(descriptorBytes,
diff --git a/src/main/java/org/torproject/descriptor/impl/BridgeNetworkStatusImpl.java b/src/main/java/org/torproject/descriptor/impl/BridgeNetworkStatusImpl.java
index 80aba01..88411e6 100644
--- a/src/main/java/org/torproject/descriptor/impl/BridgeNetworkStatusImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/BridgeNetworkStatusImpl.java
@@ -71,16 +71,16 @@ public class BridgeNetworkStatusImpl extends NetworkStatusImpl
this.enoughMtbfInfo = -1;
this.ignoringAdvertisedBws = -1;
- Scanner scanner = new Scanner(new String(headerBytes)).useDelimiter("\n");
+ Scanner scanner = new Scanner(new String(headerBytes)).useDelimiter(NL);
while (scanner.hasNext()) {
String line = scanner.next();
String[] parts = line.split("[ \t]+");
- String keyword = parts[0];
- switch (keyword) {
- case "published":
+ Key key = Key.get(parts[0]);
+ switch (key) {
+ case PUBLISHED:
this.parsePublishedLine(line, parts);
break;
- case "flag-thresholds":
+ case FLAG_THRESHOLDS:
this.parseFlagThresholdsLine(line, parts);
break;
default:
diff --git a/src/main/java/org/torproject/descriptor/impl/BridgePoolAssignmentImpl.java b/src/main/java/org/torproject/descriptor/impl/BridgePoolAssignmentImpl.java
index e2579e5..609797e 100644
--- a/src/main/java/org/torproject/descriptor/impl/BridgePoolAssignmentImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/BridgePoolAssignmentImpl.java
@@ -7,11 +7,9 @@ import org.torproject.descriptor.BridgePoolAssignment;
import org.torproject.descriptor.DescriptorParseException;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
+import java.util.EnumSet;
import java.util.List;
import java.util.Scanner;
-import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
@@ -24,7 +22,7 @@ public class BridgePoolAssignmentImpl extends DescriptorImpl
List<BridgePoolAssignment> parsedDescriptors = new ArrayList<>();
List<byte[]> splitDescriptorsBytes =
DescriptorImpl.splitRawDescriptorBytes(descriptorsBytes,
- "bridge-pool-assignment ");
+ Key.BRIDGE_POOL_ASSIGNMENT.keyword + SP);
for (byte[] descriptorBytes : splitDescriptorsBytes) {
BridgePoolAssignment parsedDescriptor =
new BridgePoolAssignmentImpl(descriptorBytes,
@@ -39,20 +37,18 @@ public class BridgePoolAssignmentImpl extends DescriptorImpl
throws DescriptorParseException {
super(descriptorBytes, failUnrecognizedDescriptorLines, false);
this.parseDescriptorBytes();
- Set<String> exactlyOnceKeywords = new HashSet<>(Arrays.asList(
- new String[] { "bridge-pool-assignment" }));
- this.checkExactlyOnceKeywords(exactlyOnceKeywords);
- this.checkFirstKeyword("bridge-pool-assignment");
- this.clearParsedKeywords();
+ this.checkExactlyOnceKeys(EnumSet.of(Key.BRIDGE_POOL_ASSIGNMENT));
+ this.checkFirstKey(Key.BRIDGE_POOL_ASSIGNMENT);
+ this.clearParsedKeys();
return;
}
private void parseDescriptorBytes() throws DescriptorParseException {
Scanner scanner = new Scanner(new String(this.rawDescriptorBytes))
- .useDelimiter("\n");
+ .useDelimiter(NL);
while (scanner.hasNext()) {
String line = scanner.next();
- if (line.startsWith("bridge-pool-assignment ")) {
+ if (line.startsWith(Key.BRIDGE_POOL_ASSIGNMENT.keyword + SP)) {
this.parseBridgePoolAssignmentLine(line);
} else {
this.parseBridgeLine(line);
@@ -80,7 +76,7 @@ public class BridgePoolAssignmentImpl extends DescriptorImpl
}
String fingerprint = ParseHelper.parseTwentyByteHexString(line,
parts[0]);
- String poolAndDetails = line.substring(line.indexOf(" ") + 1);
+ String poolAndDetails = line.substring(line.indexOf(SP) + 1);
this.entries.put(fingerprint, poolAndDetails);
}
diff --git a/src/main/java/org/torproject/descriptor/impl/BridgeServerDescriptorImpl.java b/src/main/java/org/torproject/descriptor/impl/BridgeServerDescriptorImpl.java
index 43548fc..900f6cd 100644
--- a/src/main/java/org/torproject/descriptor/impl/BridgeServerDescriptorImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/BridgeServerDescriptorImpl.java
@@ -19,7 +19,7 @@ public class BridgeServerDescriptorImpl extends ServerDescriptorImpl
List<ServerDescriptor> parsedDescriptors = new ArrayList<>();
List<byte[]> splitDescriptorsBytes =
DescriptorImpl.splitRawDescriptorBytes(descriptorsBytes,
- "router ");
+ Key.ROUTER.keyword + SP);
for (byte[] descriptorBytes : splitDescriptorsBytes) {
ServerDescriptor parsedDescriptor =
new BridgeServerDescriptorImpl(descriptorBytes,
diff --git a/src/main/java/org/torproject/descriptor/impl/DescriptorImpl.java b/src/main/java/org/torproject/descriptor/impl/DescriptorImpl.java
index 49f4a2e..f963fef 100644
--- a/src/main/java/org/torproject/descriptor/impl/DescriptorImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/DescriptorImpl.java
@@ -8,7 +8,7 @@ import org.torproject.descriptor.DescriptorParseException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
@@ -16,6 +16,10 @@ import java.util.Set;
public abstract class DescriptorImpl implements Descriptor {
+ public static final String NL = "\n";
+
+ public static final String SP = " ";
+
protected static List<Descriptor> parseDescriptors(
byte[] rawDescriptorBytes, String fileName,
boolean failUnrecognizedDescriptorLines)
@@ -30,33 +34,38 @@ public abstract class DescriptorImpl implements Descriptor {
first100Chars.length);
String firstLines = new String(first100Chars);
if (firstLines.startsWith("@type network-status-consensus-3 1.")
- || firstLines.startsWith("@type network-status-microdesc-"
- + "consensus-3 1.")
- || ((firstLines.startsWith("network-status-version 3")
- || firstLines.contains("\nnetwork-status-version 3"))
- && firstLines.contains("\nvote-status consensus\n"))) {
+ || firstLines.startsWith(
+ "@type network-status-microdesc-consensus-3 1.")
+ || ((firstLines.startsWith(
+ Key.NETWORK_STATUS_VERSION.keyword + SP + "3")
+ || firstLines.contains(
+ NL + Key.NETWORK_STATUS_VERSION.keyword + SP + "3"))
+ && firstLines.contains(
+ NL + Key.VOTE_STATUS.keyword + SP + "consensus" + NL))) {
parsedDescriptors.addAll(RelayNetworkStatusConsensusImpl
.parseConsensuses(rawDescriptorBytes,
failUnrecognizedDescriptorLines));
} else if (firstLines.startsWith("@type network-status-vote-3 1.")
- || ((firstLines.startsWith("network-status-version 3\n")
- || firstLines.contains("\nnetwork-status-version 3\n"))
- && firstLines.contains("\nvote-status vote\n"))) {
+ || ((firstLines.startsWith(
+ Key.NETWORK_STATUS_VERSION.keyword + SP + "3" + NL)
+ || firstLines.contains(
+ NL + Key.NETWORK_STATUS_VERSION.keyword + SP + "3" + NL))
+ && firstLines.contains(
+ NL + Key.VOTE_STATUS.keyword + SP + "vote" + NL))) {
parsedDescriptors.addAll(RelayNetworkStatusVoteImpl
.parseVotes(rawDescriptorBytes,
failUnrecognizedDescriptorLines));
} else if (firstLines.startsWith("@type bridge-network-status 1.")
- || firstLines.startsWith("r ")) {
+ || firstLines.startsWith(Key.R.keyword + SP)) {
parsedDescriptors.add(new BridgeNetworkStatusImpl(
rawDescriptorBytes, fileName, failUnrecognizedDescriptorLines));
- } else if (firstLines.startsWith(
- "@type bridge-server-descriptor 1.")) {
+ } else if (firstLines.startsWith("@type bridge-server-descriptor 1.")) {
parsedDescriptors.addAll(BridgeServerDescriptorImpl
.parseDescriptors(rawDescriptorBytes,
failUnrecognizedDescriptorLines));
} else if (firstLines.startsWith("@type server-descriptor 1.")
- || firstLines.startsWith("router ")
- || firstLines.contains("\nrouter ")) {
+ || firstLines.startsWith(Key.ROUTER.keyword + SP)
+ || firstLines.contains(NL + Key.ROUTER.keyword + SP)) {
parsedDescriptors.addAll(RelayServerDescriptorImpl
.parseDescriptors(rawDescriptorBytes,
failUnrecognizedDescriptorLines));
@@ -65,42 +74,45 @@ public abstract class DescriptorImpl implements Descriptor {
.parseDescriptors(rawDescriptorBytes,
failUnrecognizedDescriptorLines));
} else if (firstLines.startsWith("@type extra-info 1.")
- || firstLines.startsWith("extra-info ")
- || firstLines.contains("\nextra-info ")) {
+ || firstLines.startsWith(Key.EXTRA_INFO.keyword + SP)
+ || firstLines.contains(NL + Key.EXTRA_INFO.keyword + SP)) {
parsedDescriptors.addAll(RelayExtraInfoDescriptorImpl
.parseDescriptors(rawDescriptorBytes,
failUnrecognizedDescriptorLines));
} else if (firstLines.startsWith("@type microdescriptor 1.")
- || firstLines.startsWith("onion-key\n")
- || firstLines.contains("\nonion-key\n")) {
+ || firstLines.startsWith(Key.ONION_KEY.keyword + NL)
+ || firstLines.contains(NL + Key.ONION_KEY.keyword + NL)) {
parsedDescriptors.addAll(MicrodescriptorImpl
.parseDescriptors(rawDescriptorBytes,
failUnrecognizedDescriptorLines));
} else if (firstLines.startsWith("@type bridge-pool-assignment 1.")
- || firstLines.startsWith("bridge-pool-assignment ")
- || firstLines.contains("\nbridge-pool-assignment ")) {
+ || firstLines.startsWith(Key.BRIDGE_POOL_ASSIGNMENT.keyword + SP)
+ || firstLines.contains(NL + Key.BRIDGE_POOL_ASSIGNMENT.keyword + SP)) {
parsedDescriptors.addAll(BridgePoolAssignmentImpl
.parseDescriptors(rawDescriptorBytes,
failUnrecognizedDescriptorLines));
} else if (firstLines.startsWith("@type dir-key-certificate-3 1.")
- || firstLines.startsWith("dir-key-certificate-version ")
- || firstLines.contains("\ndir-key-certificate-version ")) {
+ || firstLines.startsWith(Key.DIR_KEY_CERTIFICATE_VERSION.keyword + SP)
+ || firstLines.contains(
+ NL + Key.DIR_KEY_CERTIFICATE_VERSION.keyword + SP)) {
parsedDescriptors.addAll(DirectoryKeyCertificateImpl
.parseDescriptors(rawDescriptorBytes,
failUnrecognizedDescriptorLines));
} else if (firstLines.startsWith("@type tordnsel 1.")
- || firstLines.startsWith("ExitNode ")
- || firstLines.contains("\nExitNode ")) {
+ || firstLines.startsWith("ExitNode" + SP)
+ || firstLines.contains(NL + "ExitNode" + SP)) {
parsedDescriptors.add(new ExitListImpl(rawDescriptorBytes, fileName,
failUnrecognizedDescriptorLines));
} else if (firstLines.startsWith("@type network-status-2 1.")
- || firstLines.startsWith("network-status-version 2\n")
- || firstLines.contains("\nnetwork-status-version 2\n")) {
+ || firstLines.startsWith(
+ Key.NETWORK_STATUS_VERSION.keyword + SP + "2" + NL)
+ || firstLines.contains(
+ NL + Key.NETWORK_STATUS_VERSION.keyword + SP + "2" + NL)) {
parsedDescriptors.add(new RelayNetworkStatusImpl(rawDescriptorBytes,
failUnrecognizedDescriptorLines));
} else if (firstLines.startsWith("@type directory 1.")
- || firstLines.startsWith("signed-directory\n")
- || firstLines.contains("\nsigned-directory\n")) {
+ || firstLines.startsWith(Key.SIGNED_DIRECTORY.keyword + NL)
+ || firstLines.contains(NL + Key.SIGNED_DIRECTORY.keyword + NL)) {
parsedDescriptors.add(new RelayDirectoryImpl(rawDescriptorBytes,
failUnrecognizedDescriptorLines));
} else if (firstLines.startsWith("@type torperf 1.")) {
@@ -116,7 +128,7 @@ public abstract class DescriptorImpl implements Descriptor {
protected static List<byte[]> splitRawDescriptorBytes(
byte[] rawDescriptorBytes, String startToken) {
List<byte[]> rawDescriptors = new ArrayList<>();
- String splitToken = "\n" + startToken;
+ String splitToken = NL + startToken;
String ascii;
try {
ascii = new String(rawDescriptorBytes, "US-ASCII");
@@ -126,7 +138,7 @@ public abstract class DescriptorImpl implements Descriptor {
int endAllDescriptors = rawDescriptorBytes.length;
int startAnnotations = 0;
boolean containsAnnotations = ascii.startsWith("@")
- || ascii.contains("\n@");
+ || ascii.contains(NL + "@");
while (startAnnotations < endAllDescriptors) {
int startDescriptor;
if (ascii.indexOf(startToken, startAnnotations) == 0) {
@@ -141,7 +153,7 @@ public abstract class DescriptorImpl implements Descriptor {
}
int endDescriptor = -1;
if (containsAnnotations) {
- endDescriptor = ascii.indexOf("\n@", startDescriptor);
+ endDescriptor = ascii.indexOf(NL + "@", startDescriptor);
}
if (endDescriptor < 0) {
endDescriptor = ascii.indexOf(splitToken, startDescriptor);
@@ -183,7 +195,7 @@ public abstract class DescriptorImpl implements Descriptor {
this.failUnrecognizedDescriptorLines =
failUnrecognizedDescriptorLines;
this.cutOffAnnotations(rawDescriptorBytes);
- this.countKeywords(rawDescriptorBytes, blankLinesAllowed);
+ this.countKeys(rawDescriptorBytes, blankLinesAllowed);
}
/* Parse annotation lines from the descriptor bytes. */
@@ -194,8 +206,8 @@ public abstract class DescriptorImpl implements Descriptor {
String ascii = new String(rawDescriptorBytes);
int start = 0;
while ((start == 0 && ascii.startsWith("@"))
- || (start > 0 && ascii.indexOf("\n@", start - 1) >= 0)) {
- int end = ascii.indexOf("\n", start);
+ || (start > 0 && ascii.indexOf(NL + "@", start - 1) >= 0)) {
+ int end = ascii.indexOf(NL, start);
if (end < 0) {
throw new DescriptorParseException("Annotation line does not "
+ "contain a newline.");
@@ -217,130 +229,129 @@ public abstract class DescriptorImpl implements Descriptor {
return new ArrayList<>(this.annotations);
}
- private String firstKeyword;
+ private Key firstKey = Key.EMPTY;
- private String lastKeyword;
+ private Key lastKey = Key.EMPTY;
- private Map<String, Integer> parsedKeywords = new HashMap<>();
+ private Map<Key, Integer> parsedKeys = new EnumMap<>(Key.class);
/* Count parsed keywords for consistency checks by subclasses. */
- private void countKeywords(byte[] rawDescriptorBytes,
+ private void countKeys(byte[] rawDescriptorBytes,
boolean blankLinesAllowed) throws DescriptorParseException {
if (rawDescriptorBytes.length == 0) {
throw new DescriptorParseException("Descriptor is empty.");
}
String descriptorString = new String(rawDescriptorBytes);
- if (!blankLinesAllowed && (descriptorString.startsWith("\n")
- || descriptorString.contains("\n\n"))) {
+ if (!blankLinesAllowed && (descriptorString.startsWith(NL)
+ || descriptorString.contains(NL + NL))) {
throw new DescriptorParseException("Blank lines are not allowed.");
}
boolean skipCrypto = false;
- Scanner scanner = new Scanner(descriptorString).useDelimiter("\n");
+ Scanner scanner = new Scanner(descriptorString).useDelimiter(NL);
while (scanner.hasNext()) {
String line = scanner.next();
- if (line.startsWith("-----BEGIN")) {
+ if (line.startsWith(Key.CRYPTO_BEGIN.keyword)) {
skipCrypto = true;
- } else if (line.startsWith("-----END")) {
+ } else if (line.startsWith(Key.CRYPTO_END.keyword)) {
skipCrypto = false;
} else if (!line.isEmpty() && !line.startsWith("@")
&& !skipCrypto) {
- String lineNoOpt = line.startsWith("opt ")
- ? line.substring("opt ".length()) : line;
- String keyword = lineNoOpt.split(" ", -1)[0];
+ String lineNoOpt = line.startsWith(Key.OPT.keyword + SP)
+ ? line.substring(Key.OPT.keyword.length() + 1) : line;
+ String keyword = lineNoOpt.split(SP, -1)[0];
if (keyword.equals("")) {
throw new DescriptorParseException("Illegal keyword in line '"
+ line + "'.");
}
- if (this.firstKeyword == null) {
- this.firstKeyword = keyword;
+ Key key = Key.get(keyword);
+ if (Key.EMPTY == this.firstKey) {
+ this.firstKey = key;
}
- lastKeyword = keyword;
- if (parsedKeywords.containsKey(keyword)) {
- parsedKeywords.put(keyword, parsedKeywords.get(keyword) + 1);
+ lastKey = key;
+ if (parsedKeys.containsKey(key)) {
+ parsedKeys.put(key, parsedKeys.get(key) + 1);
} else {
- parsedKeywords.put(keyword, 1);
+ parsedKeys.put(key, 1);
}
}
}
}
- protected void checkFirstKeyword(String keyword)
+ protected void checkFirstKey(Key key)
throws DescriptorParseException {
- if (this.firstKeyword == null
- || !this.firstKeyword.equals(keyword)) {
- throw new DescriptorParseException("Keyword '" + keyword + "' must "
+ if (this.firstKey != key) {
+ throw new DescriptorParseException("Keyword '" + key.keyword + "' must "
+ "be contained in the first line.");
}
}
- protected void checkLastKeyword(String keyword)
+ protected void checkLastKey(Key key)
throws DescriptorParseException {
- if (this.lastKeyword == null
- || !this.lastKeyword.equals(keyword)) {
- throw new DescriptorParseException("Keyword '" + keyword + "' must "
+ if (this.lastKey != key) {
+ throw new DescriptorParseException("Keyword '" + key.keyword + "' must "
+ "be contained in the last line.");
}
}
- protected void checkExactlyOnceKeywords(Set<String> keywords)
+ protected void checkExactlyOnceKeys(Set<Key> keys)
throws DescriptorParseException {
- for (String keyword : keywords) {
+ for (Key key : keys) {
int contained = 0;
- if (this.parsedKeywords.containsKey(keyword)) {
- contained = this.parsedKeywords.get(keyword);
+ if (this.parsedKeys.containsKey(key)) {
+ contained = this.parsedKeys.get(key);
}
if (contained != 1) {
- throw new DescriptorParseException("Keyword '" + keyword + "' is "
+ throw new DescriptorParseException("Keyword '" + key.keyword + "' is "
+ "contained " + contained + " times, but must be contained "
+ "exactly once.");
}
}
}
- protected void checkAtLeastOnceKeywords(Set<String> keywords)
+ protected void checkAtLeastOnceKeys(Set<Key> keys)
throws DescriptorParseException {
- for (String keyword : keywords) {
- if (!this.parsedKeywords.containsKey(keyword)) {
- throw new DescriptorParseException("Keyword '" + keyword + "' is "
+ for (Key key : keys) {
+ if (!this.parsedKeys.containsKey(key)) {
+ throw new DescriptorParseException("Keyword '" + key.keyword + "' is "
+ "contained 0 times, but must be contained at least once.");
}
}
}
- protected void checkAtMostOnceKeywords(Set<String> keywords)
+ protected void checkAtMostOnceKeys(Set<Key> keys)
throws DescriptorParseException {
- for (String keyword : keywords) {
- if (this.parsedKeywords.containsKey(keyword)
- && this.parsedKeywords.get(keyword) > 1) {
- throw new DescriptorParseException("Keyword '" + keyword + "' is "
- + "contained " + this.parsedKeywords.get(keyword) + " times, "
+ for (Key key : keys) {
+ if (this.parsedKeys.containsKey(key)
+ && this.parsedKeys.get(key) > 1) {
+ throw new DescriptorParseException("Keyword '" + key.keyword + "' is "
+ + "contained " + this.parsedKeys.get(key) + " times, "
+ "but must be contained at most once.");
}
}
}
- protected void checkKeywordsDependOn(Set<String> dependentKeywords,
- String dependingKeyword) throws DescriptorParseException {
- for (String dependentKeyword : dependentKeywords) {
- if (this.parsedKeywords.containsKey(dependentKeyword)
- && !this.parsedKeywords.containsKey(dependingKeyword)) {
- throw new DescriptorParseException("Keyword '" + dependentKeyword
- + "' is contained, but keyword '" + dependingKeyword + "' is "
+ protected void checkKeysDependOn(Set<Key> dependentKeys,
+ Key dependingKey) throws DescriptorParseException {
+ for (Key dependentKey : dependentKeys) {
+ if (this.parsedKeys.containsKey(dependentKey)
+ && !this.parsedKeys.containsKey(dependingKey)) {
+ throw new DescriptorParseException("Keyword '" + dependentKey.keyword
+ + "' is contained, but keyword '" + dependingKey.keyword + "' is "
+ "not.");
}
}
}
- protected int getKeywordCount(String keyword) {
- if (!this.parsedKeywords.containsKey(keyword)) {
+ protected int getKeyCount(Key key) {
+ if (!this.parsedKeys.containsKey(key)) {
return 0;
} else {
- return this.parsedKeywords.get(keyword);
+ return this.parsedKeys.get(key);
}
}
- protected void clearParsedKeywords() {
- this.parsedKeywords = null;
+ protected void clearParsedKeys() {
+ this.parsedKeys = null;
}
}
diff --git a/src/main/java/org/torproject/descriptor/impl/DirSourceEntryImpl.java b/src/main/java/org/torproject/descriptor/impl/DirSourceEntryImpl.java
index 539d211..fd2c783 100644
--- a/src/main/java/org/torproject/descriptor/impl/DirSourceEntryImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/DirSourceEntryImpl.java
@@ -3,14 +3,17 @@
package org.torproject.descriptor.impl;
+import static org.torproject.descriptor.impl.DescriptorImpl.NL;
+import static org.torproject.descriptor.impl.DescriptorImpl.SP;
+
import org.torproject.descriptor.DescriptorParseException;
import org.torproject.descriptor.DirSourceEntry;
import java.util.ArrayList;
+import java.util.EnumSet;
import java.util.List;
import java.util.Scanner;
-import java.util.SortedSet;
-import java.util.TreeSet;
+import java.util.Set;
public class DirSourceEntryImpl implements DirSourceEntry {
@@ -37,72 +40,67 @@ public class DirSourceEntryImpl implements DirSourceEntry {
this.dirSourceEntryBytes = dirSourceEntryBytes;
this.failUnrecognizedDescriptorLines =
failUnrecognizedDescriptorLines;
- this.initializeKeywords();
this.parseDirSourceEntryBytes();
- this.checkAndClearKeywords();
+ this.checkAndClearKeys();
}
- private SortedSet<String> exactlyOnceKeywords;
-
- private SortedSet<String> atMostOnceKeywords;
+ private Set<Key> exactlyOnceKeys = EnumSet.of(
+ Key.DIR_SOURCE, Key.VOTE_DIGEST);
- private void initializeKeywords() {
- this.exactlyOnceKeywords = new TreeSet<>();
- this.exactlyOnceKeywords.add("dir-source");
- this.exactlyOnceKeywords.add("vote-digest");
- this.atMostOnceKeywords = new TreeSet<>();
- this.atMostOnceKeywords.add("contact");
- }
+ private Set<Key> atMostOnceKeys = EnumSet.of(Key.CONTACT);
- private void parsedExactlyOnceKeyword(String keyword)
+ private void parsedExactlyOnceKey(Key key)
throws DescriptorParseException {
- if (!this.exactlyOnceKeywords.contains(keyword)) {
- throw new DescriptorParseException("Duplicate '" + keyword
+ if (!this.exactlyOnceKeys.contains(key)) {
+ throw new DescriptorParseException("Duplicate '" + key.keyword
+ "' line in dir-source.");
}
- this.exactlyOnceKeywords.remove(keyword);
+ this.exactlyOnceKeys.remove(key);
}
- private void parsedAtMostOnceKeyword(String keyword)
+ private void parsedAtMostOnceKey(Key key)
throws DescriptorParseException {
- if (!this.atMostOnceKeywords.contains(keyword)) {
- throw new DescriptorParseException("Duplicate " + keyword + "line "
+ if (!this.atMostOnceKeys.contains(key)) {
+ throw new DescriptorParseException("Duplicate " + key.keyword + "line "
+ "in dir-source.");
}
- this.atMostOnceKeywords.remove(keyword);
+ this.atMostOnceKeys.remove(key);
}
- private void checkAndClearKeywords() throws DescriptorParseException {
- if (!this.exactlyOnceKeywords.isEmpty()) {
- throw new DescriptorParseException("dir-source does not contain a '"
- + this.exactlyOnceKeywords.first() + "' line.");
+ private void checkAndClearKeys() throws DescriptorParseException {
+ if (!this.exactlyOnceKeys.isEmpty()) {
+ for (Key key : this.exactlyOnceKeys) {
+ throw new DescriptorParseException("dir-source does not contain a '"
+ + key.keyword + "' line.");
+ }
}
- this.exactlyOnceKeywords = null;
- this.atMostOnceKeywords = null;
+ this.exactlyOnceKeys = null;
+ this.atMostOnceKeys = null;
}
private void parseDirSourceEntryBytes()
throws DescriptorParseException {
Scanner scanner = new Scanner(new String(this.dirSourceEntryBytes))
- .useDelimiter("\n");
+ .useDelimiter(NL);
boolean skipCrypto = false;
while (scanner.hasNext()) {
String line = scanner.next();
- String[] parts = line.split(" ");
- switch (parts[0]) {
- case "dir-source":
+ String[] parts = line.split(SP);
+ Key key = Key.get(parts[0]);
+ switch (key) {
+ case DIR_SOURCE:
this.parseDirSourceLine(line);
break;
- case "contact":
+ case CONTACT:
this.parseContactLine(line);
break;
- case "vote-digest":
+ case VOTE_DIGEST:
this.parseVoteDigestLine(line);
break;
- case "-----BEGIN":
+ case CRYPTO_BEGIN:
skipCrypto = true;
break;
- case "-----END":
+ case CRYPTO_END:
skipCrypto = false;
break;
default:
@@ -123,7 +121,7 @@ public class DirSourceEntryImpl implements DirSourceEntry {
private void parseDirSourceLine(String line)
throws DescriptorParseException {
- this.parsedExactlyOnceKeyword("dir-source");
+ this.parsedExactlyOnceKey(Key.DIR_SOURCE);
String[] parts = line.split("[ \t]+");
if (parts.length != 7) {
throw new DescriptorParseException("Invalid line '" + line + "'.");
@@ -133,7 +131,7 @@ public class DirSourceEntryImpl implements DirSourceEntry {
nickname = nickname.substring(0, nickname.length()
- "-legacy".length());
this.isLegacy = true;
- this.parsedExactlyOnceKeyword("vote-digest");
+ this.parsedExactlyOnceKey(Key.VOTE_DIGEST);
}
this.nickname = ParseHelper.parseNickname(line, nickname);
this.identity = ParseHelper.parseTwentyByteHexString(line, parts[2]);
@@ -149,9 +147,9 @@ public class DirSourceEntryImpl implements DirSourceEntry {
private void parseContactLine(String line)
throws DescriptorParseException {
- this.parsedAtMostOnceKeyword("contact");
- if (line.length() > "contact ".length()) {
- this.contactLine = line.substring("contact ".length());
+ this.parsedAtMostOnceKey(Key.CONTACT);
+ if (line.length() > Key.CONTACT.keyword.length() + 1) {
+ this.contactLine = line.substring(Key.CONTACT.keyword.length() + 1);
} else {
this.contactLine = "";
}
@@ -159,7 +157,7 @@ public class DirSourceEntryImpl implements DirSourceEntry {
private void parseVoteDigestLine(String line)
throws DescriptorParseException {
- this.parsedExactlyOnceKeyword("vote-digest");
+ this.parsedExactlyOnceKey(Key.VOTE_DIGEST);
String[] parts = line.split("[ \t]+");
if (parts.length != 2) {
throw new DescriptorParseException("Invalid line '" + line + "'.");
diff --git a/src/main/java/org/torproject/descriptor/impl/DirectoryKeyCertificateImpl.java b/src/main/java/org/torproject/descriptor/impl/DirectoryKeyCertificateImpl.java
index 64df7aa..0bb08fd 100644
--- a/src/main/java/org/torproject/descriptor/impl/DirectoryKeyCertificateImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/DirectoryKeyCertificateImpl.java
@@ -10,8 +10,7 @@ import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
+import java.util.EnumSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
@@ -27,7 +26,7 @@ public class DirectoryKeyCertificateImpl extends DescriptorImpl
List<DirectoryKeyCertificate> parsedDescriptors = new ArrayList<>();
List<byte[]> splitDescriptorsBytes =
DirectoryKeyCertificateImpl.splitRawDescriptorBytes(
- descriptorsBytes, "dir-key-certificate-version ");
+ descriptorsBytes, Key.DIR_KEY_CERTIFICATE_VERSION.keyword + SP);
for (byte[] descriptorBytes : splitDescriptorsBytes) {
DirectoryKeyCertificate parsedDescriptor =
new DirectoryKeyCertificateImpl(descriptorBytes,
@@ -43,90 +42,90 @@ public class DirectoryKeyCertificateImpl extends DescriptorImpl
super(rawDescriptorBytes, failUnrecognizedDescriptorLines, false);
this.parseDescriptorBytes();
this.calculateDigest();
- Set<String> exactlyOnceKeywords = new HashSet<>(Arrays.asList((
- "dir-key-certificate-version,fingerprint,dir-identity-key,"
- + "dir-key-published,dir-key-expires,dir-signing-key,"
- + "dir-key-certification").split(",")));
- this.checkExactlyOnceKeywords(exactlyOnceKeywords);
- Set<String> atMostOnceKeywords = new HashSet<>(Arrays.asList((
- "dir-address,dir-key-crosscert").split(",")));
- this.checkAtMostOnceKeywords(atMostOnceKeywords);
- this.checkFirstKeyword("dir-key-certificate-version");
- this.checkLastKeyword("dir-key-certification");
- this.clearParsedKeywords();
+ Set<Key> exactlyOnceKeys = EnumSet.of(
+ Key.DIR_KEY_CERTIFICATE_VERSION, Key.FINGERPRINT, Key.DIR_IDENTITY_KEY,
+ Key.DIR_KEY_PUBLISHED, Key.DIR_KEY_EXPIRES, Key.DIR_SIGNING_KEY,
+ Key.DIR_KEY_CERTIFICATION);
+ this.checkExactlyOnceKeys(exactlyOnceKeys);
+ Set<Key> atMostOnceKeys = EnumSet.of(
+ Key.DIR_ADDRESS, Key.DIR_KEY_CROSSCERT);
+ this.checkAtMostOnceKeys(atMostOnceKeys);
+ this.checkFirstKey(Key.DIR_KEY_CERTIFICATE_VERSION);
+ this.checkLastKey(Key.DIR_KEY_CERTIFICATION);
+ this.clearParsedKeys();
}
private void parseDescriptorBytes() throws DescriptorParseException {
Scanner scanner = new Scanner(new String(this.rawDescriptorBytes))
- .useDelimiter("\n");
- String nextCrypto = "";
+ .useDelimiter(NL);
+ Key nextCrypto = Key.EMPTY;
StringBuilder crypto = null;
while (scanner.hasNext()) {
String line = scanner.next();
String[] parts = line.split("[ \t]+");
- String keyword = parts[0];
- switch (keyword) {
- case "dir-key-certificate-version":
+ Key key = Key.get(parts[0]);
+ switch (key) {
+ case DIR_KEY_CERTIFICATE_VERSION:
this.parseDirKeyCertificateVersionLine(line, parts);
break;
- case "dir-address":
+ case DIR_ADDRESS:
this.parseDirAddressLine(line, parts);
break;
- case "fingerprint":
+ case FINGERPRINT:
this.parseFingerprintLine(line, parts);
break;
- case "dir-identity-key":
+ case DIR_IDENTITY_KEY:
this.parseDirIdentityKeyLine(line, parts);
- nextCrypto = "dir-identity-key";
+ nextCrypto = key;
break;
- case "dir-key-published":
+ case DIR_KEY_PUBLISHED:
this.parseDirKeyPublishedLine(line, parts);
break;
- case "dir-key-expires":
+ case DIR_KEY_EXPIRES:
this.parseDirKeyExpiresLine(line, parts);
break;
- case "dir-signing-key":
+ case DIR_SIGNING_KEY:
this.parseDirSigningKeyLine(line, parts);
- nextCrypto = "dir-signing-key";
+ nextCrypto = key;
break;
- case "dir-key-crosscert":
+ case DIR_KEY_CROSSCERT:
this.parseDirKeyCrosscertLine(line, parts);
- nextCrypto = "dir-key-crosscert";
+ nextCrypto = key;
break;
- case "dir-key-certification":
+ case DIR_KEY_CERTIFICATION:
this.parseDirKeyCertificationLine(line, parts);
- nextCrypto = "dir-key-certification";
+ nextCrypto = key;
break;
- case "-----BEGIN":
+ case CRYPTO_BEGIN:
crypto = new StringBuilder();
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
break;
- case "-----END":
- crypto.append(line).append("\n");
+ case CRYPTO_END:
+ crypto.append(line).append(NL);
String cryptoString = crypto.toString();
crypto = null;
switch (nextCrypto) {
- case "dir-identity-key":
+ case DIR_IDENTITY_KEY:
this.dirIdentityKey = cryptoString;
break;
- case "dir-signing-key":
+ case DIR_SIGNING_KEY:
this.dirSigningKey = cryptoString;
break;
- case "dir-key-crosscert":
+ case DIR_KEY_CROSSCERT:
this.dirKeyCrosscert = cryptoString;
break;
- case "dir-key-certification":
+ case DIR_KEY_CERTIFICATION:
this.dirKeyCertification = cryptoString;
break;
default:
throw new DescriptorParseException("Unrecognized crypto "
+ "block in directory key certificate.");
}
- nextCrypto = "";
+ nextCrypto = Key.EMPTY;
break;
default:
if (crypto != null) {
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
} else {
if (this.failUnrecognizedDescriptorLines) {
throw new DescriptorParseException("Unrecognized line '"
@@ -144,7 +143,7 @@ public class DirectoryKeyCertificateImpl extends DescriptorImpl
private void parseDirKeyCertificateVersionLine(String line,
String[] parts) throws DescriptorParseException {
- if (!line.equals("dir-key-certificate-version 3")) {
+ if (!line.equals(Key.DIR_KEY_CERTIFICATE_VERSION.keyword + SP + "3")) {
throw new DescriptorParseException("Illegal directory key "
+ "certificate version number in line '" + line + "'.");
}
@@ -174,7 +173,7 @@ public class DirectoryKeyCertificateImpl extends DescriptorImpl
private void parseDirIdentityKeyLine(String line, String[] parts)
throws DescriptorParseException {
- if (!line.equals("dir-identity-key")) {
+ if (!line.equals(Key.DIR_IDENTITY_KEY.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
}
@@ -193,21 +192,21 @@ public class DirectoryKeyCertificateImpl extends DescriptorImpl
private void parseDirSigningKeyLine(String line, String[] parts)
throws DescriptorParseException {
- if (!line.equals("dir-signing-key")) {
+ if (!line.equals(Key.DIR_SIGNING_KEY.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
}
private void parseDirKeyCrosscertLine(String line, String[] parts)
throws DescriptorParseException {
- if (!line.equals("dir-key-crosscert")) {
+ if (!line.equals(Key.DIR_KEY_CROSSCERT.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
}
private void parseDirKeyCertificationLine(String line, String[] parts)
throws DescriptorParseException {
- if (!line.equals("dir-key-certification")) {
+ if (!line.equals(Key.DIR_KEY_CERTIFICATION.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
}
@@ -215,8 +214,8 @@ public class DirectoryKeyCertificateImpl extends DescriptorImpl
private void calculateDigest() throws DescriptorParseException {
try {
String ascii = new String(this.getRawDescriptorBytes(), "US-ASCII");
- String startToken = "dir-key-certificate-version ";
- String sigToken = "\ndir-key-certification\n";
+ String startToken = Key.DIR_KEY_CERTIFICATE_VERSION.keyword + SP;
+ String sigToken = NL + Key.DIR_KEY_CERTIFICATION.keyword + NL;
int start = ascii.indexOf(startToken);
int sig = ascii.indexOf(sigToken) + sigToken.length();
if (start >= 0 && sig >= 0 && sig > start) {
diff --git a/src/main/java/org/torproject/descriptor/impl/DirectorySignatureImpl.java b/src/main/java/org/torproject/descriptor/impl/DirectorySignatureImpl.java
index 7cf427a..674b634 100644
--- a/src/main/java/org/torproject/descriptor/impl/DirectorySignatureImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/DirectorySignatureImpl.java
@@ -3,6 +3,9 @@
package org.torproject.descriptor.impl;
+import static org.torproject.descriptor.impl.DescriptorImpl.NL;
+import static org.torproject.descriptor.impl.DescriptorImpl.SP;
+
import org.torproject.descriptor.DescriptorParseException;
import org.torproject.descriptor.DirectorySignature;
@@ -36,14 +39,14 @@ public class DirectorySignatureImpl implements DirectorySignature {
private void parseDirectorySignatureBytes()
throws DescriptorParseException {
Scanner scanner = new Scanner(new String(this.directorySignatureBytes))
- .useDelimiter("\n");
+ .useDelimiter(NL);
StringBuilder crypto = null;
while (scanner.hasNext()) {
String line = scanner.next();
- String[] parts = line.split(" ", -1);
- String keyword = parts[0];
- switch (keyword) {
- case "directory-signature":
+ String[] parts = line.split(SP, -1);
+ Key key = Key.get(parts[0]);
+ switch (key) {
+ case DIRECTORY_SIGNATURE:
int algorithmOffset = 0;
switch (parts.length) {
case 4:
@@ -61,19 +64,19 @@ public class DirectorySignatureImpl implements DirectorySignature {
this.signingKeyDigest = ParseHelper.parseHexString(
line, parts[2 + algorithmOffset]);
break;
- case "-----BEGIN":
+ case CRYPTO_BEGIN:
crypto = new StringBuilder();
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
break;
- case "-----END":
- crypto.append(line).append("\n");
+ case CRYPTO_END:
+ crypto.append(line).append(NL);
String cryptoString = crypto.toString();
crypto = null;
this.signature = cryptoString;
break;
default:
if (crypto != null) {
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
} else {
if (this.failUnrecognizedDescriptorLines) {
throw new DescriptorParseException("Unrecognized line '"
diff --git a/src/main/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java b/src/main/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java
index dd1bc07..fd55925 100644
--- a/src/main/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java
@@ -14,8 +14,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
+import java.util.EnumSet;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
@@ -28,6 +28,16 @@ import javax.xml.bind.DatatypeConverter;
public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
implements ExtraInfoDescriptor {
+ private Set<Key> exactlyOnceKeys = EnumSet.of(
+ Key.EXTRA_INFO, Key.PUBLISHED);
+
+ private static final Set<Key> atMostOnceKeys = EnumSet.of(
+ Key.IDENTITY_ED25519, Key.MASTER_KEY_ED25519, Key.READ_HISTORY,
+ Key.WRITE_HISTORY, Key.DIRREQ_READ_HISTORY, Key.DIRREQ_WRITE_HISTORY,
+ Key.GEOIP_DB_DIGEST, Key.GEOIP6_DB_DIGEST, Key.ROUTER_SIG_ED25519,
+ Key.ROUTER_SIGNATURE, Key.ROUTER_DIGEST_SHA256, Key.ROUTER_DIGEST,
+ Key.PADDING_COUNTS);
+
protected ExtraInfoDescriptorImpl(byte[] descriptorBytes,
boolean failUnrecognizedDescriptorLines)
throws DescriptorParseException {
@@ -35,231 +45,223 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
this.parseDescriptorBytes();
this.calculateDigest();
this.calculateDigestSha256();
- Set<String> exactlyOnceKeywords = new HashSet<>(Arrays.asList((
- "extra-info,published").split(",")));
- this.checkExactlyOnceKeywords(exactlyOnceKeywords);
- Set<String> dirreqStatsKeywords = new HashSet<>(Arrays.asList((
- "dirreq-stats-end,dirreq-v2-ips,dirreq-v3-ips,dirreq-v2-reqs,"
- + "dirreq-v3-reqs,dirreq-v2-share,dirreq-v3-share,dirreq-v2-resp,"
- + "dirreq-v3-resp,dirreq-v2-direct-dl,dirreq-v3-direct-dl,"
- + "dirreq-v2-tunneled-dl,dirreq-v3-tunneled-dl,").split(",")));
- Set<String> entryStatsKeywords = new HashSet<>(Arrays.asList(
- "entry-stats-end,entry-ips".split(",")));
- Set<String> cellStatsKeywords = new HashSet<>(Arrays.asList((
- "cell-stats-end,cell-processed-cells,cell-queued-cells,"
- + "cell-time-in-queue,cell-circuits-per-decile").split(",")));
- Set<String> connBiDirectStatsKeywords = new HashSet<>(
- Arrays.asList("conn-bi-direct".split(",")));
- Set<String> exitStatsKeywords = new HashSet<>(Arrays.asList((
- "exit-stats-end,exit-kibibytes-written,exit-kibibytes-read,"
- + "exit-streams-opened").split(",")));
- Set<String> bridgeStatsKeywords = new HashSet<>(Arrays.asList(
- "bridge-stats-end,bridge-stats-ips".split(",")));
- Set<String> atMostOnceKeywords = new HashSet<>(Arrays.asList((
- "identity-ed25519,master-key-ed25519,read-history,write-history,"
- + "dirreq-read-history,dirreq-write-history,geoip-db-digest,"
- + "router-sig-ed25519,router-signature,router-digest-sha256,"
- + "router-digest").split(",")));
- atMostOnceKeywords.addAll(dirreqStatsKeywords);
- atMostOnceKeywords.addAll(entryStatsKeywords);
- atMostOnceKeywords.addAll(cellStatsKeywords);
- atMostOnceKeywords.addAll(connBiDirectStatsKeywords);
- atMostOnceKeywords.addAll(exitStatsKeywords);
- atMostOnceKeywords.addAll(bridgeStatsKeywords);
- atMostOnceKeywords.add("padding-counts");
- this.checkAtMostOnceKeywords(atMostOnceKeywords);
- this.checkKeywordsDependOn(dirreqStatsKeywords, "dirreq-stats-end");
- this.checkKeywordsDependOn(entryStatsKeywords, "entry-stats-end");
- this.checkKeywordsDependOn(cellStatsKeywords, "cell-stats-end");
- this.checkKeywordsDependOn(exitStatsKeywords, "exit-stats-end");
- this.checkKeywordsDependOn(bridgeStatsKeywords, "bridge-stats-end");
- this.checkFirstKeyword("extra-info");
- this.clearParsedKeywords();
+ this.checkExactlyOnceKeys(exactlyOnceKeys);
+ Set<Key> dirreqStatsKeys = EnumSet.of(
+ Key.DIRREQ_STATS_END, Key.DIRREQ_V2_IPS, Key.DIRREQ_V3_IPS,
+ Key.DIRREQ_V2_REQS, Key.DIRREQ_V3_REQS, Key.DIRREQ_V2_SHARE,
+ Key.DIRREQ_V3_SHARE, Key.DIRREQ_V2_RESP, Key.DIRREQ_V3_RESP,
+ Key.DIRREQ_V2_DIRECT_DL, Key.DIRREQ_V3_DIRECT_DL,
+ Key.DIRREQ_V2_TUNNELED_DL, Key.DIRREQ_V3_TUNNELED_DL);
+ Set<Key> entryStatsKeys = EnumSet.of(
+ Key.ENTRY_STATS_END, Key.ENTRY_IPS);
+ Set<Key> cellStatsKeys = EnumSet.of(
+ Key.CELL_STATS_END, Key.CELL_PROCESSED_CELLS, Key.CELL_QUEUED_CELLS,
+ Key.CELL_TIME_IN_QUEUE, Key.CELL_CIRCUITS_PER_DECILE);
+ Set<Key> connBiDirectStatsKeys = EnumSet.of(Key.CONN_BI_DIRECT);
+ Set<Key> exitStatsKeys = EnumSet.of(
+ Key.EXIT_STATS_END, Key.EXIT_KIBIBYTES_WRITTEN, Key.EXIT_KIBIBYTES_READ,
+ Key.EXIT_STREAMS_OPENED);
+ Set<Key> bridgeStatsKeys = EnumSet.of(
+ Key.BRIDGE_STATS_END, Key.BRIDGE_IPS);
+ atMostOnceKeys.addAll(dirreqStatsKeys);
+ atMostOnceKeys.addAll(entryStatsKeys);
+ atMostOnceKeys.addAll(cellStatsKeys);
+ atMostOnceKeys.addAll(connBiDirectStatsKeys);
+ atMostOnceKeys.addAll(exitStatsKeys);
+ atMostOnceKeys.addAll(bridgeStatsKeys);
+ this.checkAtMostOnceKeys(atMostOnceKeys);
+ this.checkKeysDependOn(dirreqStatsKeys, Key.DIRREQ_STATS_END);
+ this.checkKeysDependOn(entryStatsKeys, Key.ENTRY_STATS_END);
+ this.checkKeysDependOn(cellStatsKeys, Key.CELL_STATS_END);
+ this.checkKeysDependOn(exitStatsKeys, Key.EXIT_STATS_END);
+ this.checkKeysDependOn(bridgeStatsKeys, Key.BRIDGE_STATS_END);
+ this.checkFirstKey(Key.EXTRA_INFO);
+ this.clearParsedKeys();
return;
}
private void parseDescriptorBytes() throws DescriptorParseException {
Scanner scanner = new Scanner(new String(this.rawDescriptorBytes))
- .useDelimiter("\n");
- String nextCrypto = "";
+ .useDelimiter(NL);
+ Key nextCrypto = Key.EMPTY;
List<String> cryptoLines = null;
while (scanner.hasNext()) {
String line = scanner.next();
- String lineNoOpt = line.startsWith("opt ")
- ? line.substring("opt ".length()) : line;
+ String lineNoOpt = line.startsWith(Key.OPT.keyword + SP)
+ ? line.substring(Key.OPT.keyword.length() + 1) : line;
String[] partsNoOpt = lineNoOpt.split("[ \t]+");
- String keyword = partsNoOpt[0];
- switch (keyword) {
- case "extra-info":
+ Key key = Key.get(partsNoOpt[0]);
+ switch (key) {
+ case EXTRA_INFO:
this.parseExtraInfoLine(line, lineNoOpt, partsNoOpt);
break;
- case "published":
+ case PUBLISHED:
this.parsePublishedLine(line, lineNoOpt, partsNoOpt);
break;
- case "read-history":
+ case READ_HISTORY:
this.parseReadHistoryLine(line, lineNoOpt, partsNoOpt);
break;
- case "write-history":
+ case WRITE_HISTORY:
this.parseWriteHistoryLine(line, lineNoOpt, partsNoOpt);
break;
- case "geoip-db-digest":
+ case GEOIP_DB_DIGEST:
this.parseGeoipDbDigestLine(line, lineNoOpt, partsNoOpt);
break;
- case "geoip6-db-digest":
+ case GEOIP6_DB_DIGEST:
this.parseGeoip6DbDigestLine(line, lineNoOpt, partsNoOpt);
break;
- case "geoip-start-time":
+ case GEOIP_START_TIME:
this.parseGeoipStartTimeLine(line, lineNoOpt, partsNoOpt);
break;
- case "geoip-client-origins":
+ case GEOIP_CLIENT_ORIGINS:
this.parseGeoipClientOriginsLine(line, lineNoOpt, partsNoOpt);
break;
- case "dirreq-stats-end":
+ case DIRREQ_STATS_END:
this.parseDirreqStatsEndLine(line, lineNoOpt, partsNoOpt);
break;
- case "dirreq-v2-ips":
+ case DIRREQ_V2_IPS:
this.parseDirreqV2IpsLine(line, lineNoOpt, partsNoOpt);
break;
- case "dirreq-v3-ips":
+ case DIRREQ_V3_IPS:
this.parseDirreqV3IpsLine(line, lineNoOpt, partsNoOpt);
break;
- case "dirreq-v2-reqs":
+ case DIRREQ_V2_REQS:
this.parseDirreqV2ReqsLine(line, lineNoOpt, partsNoOpt);
break;
- case "dirreq-v3-reqs":
+ case DIRREQ_V3_REQS:
this.parseDirreqV3ReqsLine(line, lineNoOpt, partsNoOpt);
break;
- case "dirreq-v2-share":
+ case DIRREQ_V2_SHARE:
this.parseDirreqV2ShareLine(line, lineNoOpt, partsNoOpt);
break;
- case "dirreq-v3-share":
+ case DIRREQ_V3_SHARE:
this.parseDirreqV3ShareLine(line, lineNoOpt, partsNoOpt);
break;
- case "dirreq-v2-resp":
+ case DIRREQ_V2_RESP:
this.parseDirreqV2RespLine(line, lineNoOpt, partsNoOpt);
break;
- case "dirreq-v3-resp":
+ case DIRREQ_V3_RESP:
this.parseDirreqV3RespLine(line, lineNoOpt, partsNoOpt);
break;
- case "dirreq-v2-direct-dl":
+ case DIRREQ_V2_DIRECT_DL:
this.parseDirreqV2DirectDlLine(line, lineNoOpt, partsNoOpt);
break;
- case "dirreq-v3-direct-dl":
+ case DIRREQ_V3_DIRECT_DL:
this.parseDirreqV3DirectDlLine(line, lineNoOpt, partsNoOpt);
break;
- case "dirreq-v2-tunneled-dl":
+ case DIRREQ_V2_TUNNELED_DL:
this.parseDirreqV2TunneledDlLine(line, lineNoOpt, partsNoOpt);
break;
- case "dirreq-v3-tunneled-dl":
+ case DIRREQ_V3_TUNNELED_DL:
this.parseDirreqV3TunneledDlLine(line, lineNoOpt, partsNoOpt);
break;
- case "dirreq-read-history":
+ case DIRREQ_READ_HISTORY:
this.parseDirreqReadHistoryLine(line, lineNoOpt, partsNoOpt);
break;
- case "dirreq-write-history":
+ case DIRREQ_WRITE_HISTORY:
this.parseDirreqWriteHistoryLine(line, lineNoOpt, partsNoOpt);
break;
- case "entry-stats-end":
+ case ENTRY_STATS_END:
this.parseEntryStatsEndLine(line, lineNoOpt, partsNoOpt);
break;
- case "entry-ips":
+ case ENTRY_IPS:
this.parseEntryIpsLine(line, lineNoOpt, partsNoOpt);
break;
- case "cell-stats-end":
+ case CELL_STATS_END:
this.parseCellStatsEndLine(line, lineNoOpt, partsNoOpt);
break;
- case "cell-processed-cells":
+ case CELL_PROCESSED_CELLS:
this.parseCellProcessedCellsLine(line, lineNoOpt, partsNoOpt);
break;
- case "cell-queued-cells":
+ case CELL_QUEUED_CELLS:
this.parseCellQueuedCellsLine(line, lineNoOpt, partsNoOpt);
break;
- case "cell-time-in-queue":
+ case CELL_TIME_IN_QUEUE:
this.parseCellTimeInQueueLine(line, lineNoOpt, partsNoOpt);
break;
- case "cell-circuits-per-decile":
+ case CELL_CIRCUITS_PER_DECILE:
this.parseCellCircuitsPerDecileLine(line, lineNoOpt,
partsNoOpt);
break;
- case "conn-bi-direct":
+ case CONN_BI_DIRECT:
this.parseConnBiDirectLine(line, lineNoOpt, partsNoOpt);
break;
- case "exit-stats-end":
+ case EXIT_STATS_END:
this.parseExitStatsEndLine(line, lineNoOpt, partsNoOpt);
break;
- case "exit-kibibytes-written":
+ case EXIT_KIBIBYTES_WRITTEN:
this.parseExitKibibytesWrittenLine(line, lineNoOpt, partsNoOpt);
break;
- case "exit-kibibytes-read":
+ case EXIT_KIBIBYTES_READ:
this.parseExitKibibytesReadLine(line, lineNoOpt, partsNoOpt);
break;
- case "exit-streams-opened":
+ case EXIT_STREAMS_OPENED:
this.parseExitStreamsOpenedLine(line, lineNoOpt, partsNoOpt);
break;
- case "bridge-stats-end":
+ case BRIDGE_STATS_END:
this.parseBridgeStatsEndLine(line, lineNoOpt, partsNoOpt);
break;
- case "bridge-ips":
+ case BRIDGE_IPS:
this.parseBridgeStatsIpsLine(line, lineNoOpt, partsNoOpt);
break;
- case "bridge-ip-versions":
+ case BRIDGE_IP_VERSIONS:
this.parseBridgeIpVersionsLine(line, lineNoOpt, partsNoOpt);
break;
- case "bridge-ip-transports":
+ case BRIDGE_IP_TRANSPORTS:
this.parseBridgeIpTransportsLine(line, lineNoOpt, partsNoOpt);
break;
- case "transport":
+ case TRANSPORT:
this.parseTransportLine(line, lineNoOpt, partsNoOpt);
break;
- case "hidserv-stats-end":
+ case HIDSERV_STATS_END:
this.parseHidservStatsEndLine(line, lineNoOpt, partsNoOpt);
break;
- case "hidserv-rend-relayed-cells":
+ case HIDSERV_REND_RELAYED_CELLS:
this.parseHidservRendRelayedCellsLine(line, lineNoOpt,
partsNoOpt);
break;
- case "hidserv-dir-onions-seen":
+ case HIDSERV_DIR_ONIONS_SEEN:
this.parseHidservDirOnionsSeenLine(line, lineNoOpt, partsNoOpt);
break;
- case "padding-counts":
+ case PADDING_COUNTS:
this.parsePaddingCountsLine(line, lineNoOpt, partsNoOpt);
break;
- case "identity-ed25519":
+ case IDENTITY_ED25519:
this.parseIdentityEd25519Line(line, lineNoOpt, partsNoOpt);
- nextCrypto = "identity-ed25519";
+ nextCrypto = key;
break;
- case "master-key-ed25519":
+ case MASTER_KEY_ED25519:
this.parseMasterKeyEd25519Line(line, lineNoOpt, partsNoOpt);
break;
- case "router-sig-ed25519":
+ case ROUTER_SIG_ED25519:
this.parseRouterSigEd25519Line(line, lineNoOpt, partsNoOpt);
break;
- case "router-signature":
+ case ROUTER_SIGNATURE:
this.parseRouterSignatureLine(line, lineNoOpt, partsNoOpt);
- nextCrypto = "router-signature";
+ nextCrypto = key;
break;
- case "router-digest":
+ case ROUTER_DIGEST:
this.parseRouterDigestLine(line, lineNoOpt, partsNoOpt);
break;
- case "router-digest-sha256":
+ case ROUTER_DIGEST_SHA256:
this.parseRouterDigestSha256Line(line, lineNoOpt, partsNoOpt);
break;
- case "-----BEGIN":
+ case CRYPTO_BEGIN:
cryptoLines = new ArrayList<>();
cryptoLines.add(line);
break;
- case "-----END":
+ case CRYPTO_END:
cryptoLines.add(line);
StringBuilder sb = new StringBuilder();
for (String cryptoLine : cryptoLines) {
- sb.append("\n").append(cryptoLine);
+ sb.append(NL).append(cryptoLine);
}
String cryptoString = sb.toString().substring(1);
switch (nextCrypto) {
- case "router-signature":
+ case ROUTER_SIGNATURE:
this.routerSignature = cryptoString;
break;
- case "identity-ed25519":
+ case IDENTITY_ED25519:
this.identityEd25519 = cryptoString;
this.parseIdentityEd25519CryptoBlock(cryptoString);
break;
@@ -276,7 +278,7 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
}
}
cryptoLines = null;
- nextCrypto = "";
+ nextCrypto = Key.EMPTY;
break;
default:
if (cryptoLines != null) {
@@ -845,8 +847,8 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
}
try {
String ascii = new String(this.getRawDescriptorBytes(), "US-ASCII");
- String startToken = "extra-info ";
- String sigToken = "\nrouter-signature\n";
+ String startToken = Key.EXTRA_INFO.keyword + SP;
+ String sigToken = NL + Key.ROUTER_SIGNATURE.keyword + NL;
int start = ascii.indexOf(startToken);
int sig = ascii.indexOf(sigToken) + sigToken.length();
if (start >= 0 && sig >= 0 && sig > start) {
@@ -876,7 +878,7 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
}
try {
String ascii = new String(this.getRawDescriptorBytes(), "US-ASCII");
- String startToken = "extra-info ";
+ String startToken = Key.EXTRA_INFO.keyword + SP;
String sigToken = "\n-----END SIGNATURE-----\n";
int start = ascii.indexOf(startToken);
int sig = ascii.indexOf(sigToken) + sigToken.length();
diff --git a/src/main/java/org/torproject/descriptor/impl/Key.java b/src/main/java/org/torproject/descriptor/impl/Key.java
new file mode 100644
index 0000000..763ecbf
--- /dev/null
+++ b/src/main/java/org/torproject/descriptor/impl/Key.java
@@ -0,0 +1,177 @@
+package org.torproject.descriptor.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum Key {
+
+ EMPTY("the-empty-key"),
+ INVALID("the-invalid-key"),
+
+ /* crypto keys */
+ CRYPTO_BEGIN("-----BEGIN"),
+ CRYPTO_END("-----END"),
+
+ /* descriptor keys (in alphabetic order) */
+ A("a"),
+ ACCEPT("accept"),
+ ALLOW_SINGLE_HOP_EXITS("allow-single-hop-exits"),
+ BANDWIDTH("bandwidth"),
+ BANDWIDTH_WEIGHTS("bandwidth-weights"),
+ BRIDGE_IPS("bridge-ips"),
+ BRIDGE_IP_TRANSPORTS("bridge-ip-transports"),
+ BRIDGE_IP_VERSIONS("bridge-ip-versions"),
+ BRIDGE_POOL_ASSIGNMENT("bridge-pool-assignment"),
+ BRIDGE_STATS_END("bridge-stats-end"),
+ CACHES_EXTRA_INFO("caches-extra-info"),
+ CELL_CIRCUITS_PER_DECILE("cell-circuits-per-decile"),
+ CELL_PROCESSED_CELLS("cell-processed-cells"),
+ CELL_QUEUED_CELLS("cell-queued-cells"),
+ CELL_STATS_END("cell-stats-end"),
+ CELL_TIME_IN_QUEUE("cell-time-in-queue"),
+ CLIENT_VERSIONS("client-versions"),
+ CONN_BI_DIRECT("conn-bi-direct"),
+ CONSENSUS_METHOD("consensus-method"),
+ CONSENSUS_METHODS("consensus-methods"),
+ CONTACT("contact"),
+ DIRCACHEPORT("dircacheport"),
+ DIRECTORY_FOOTER("directory-footer"),
+ DIRECTORY_SIGNATURE("directory-signature"),
+ DIRREQ_READ_HISTORY("dirreq-read-history"),
+ DIRREQ_STATS_END("dirreq-stats-end"),
+ DIRREQ_V2_DIRECT_DL("dirreq-v2-direct-dl"),
+ DIRREQ_V2_IPS("dirreq-v2-ips"),
+ DIRREQ_V2_REQS("dirreq-v2-reqs"),
+ DIRREQ_V2_RESP("dirreq-v2-resp"),
+ DIRREQ_V2_SHARE("dirreq-v2-share"),
+ DIRREQ_V2_TUNNELED_DL("dirreq-v2-tunneled-dl"),
+ DIRREQ_V3_DIRECT_DL("dirreq-v3-direct-dl"),
+ DIRREQ_V3_IPS("dirreq-v3-ips"),
+ DIRREQ_V3_REQS("dirreq-v3-reqs"),
+ DIRREQ_V3_RESP("dirreq-v3-resp"),
+ DIRREQ_V3_SHARE("dirreq-v3-share"),
+ DIRREQ_V3_TUNNELED_DL("dirreq-v3-tunneled-dl"),
+ DIRREQ_WRITE_HISTORY("dirreq-write-history"),
+ DIR_ADDRESS("dir-address"),
+ DIR_IDENTITY_KEY("dir-identity-key"),
+ DIR_KEY_CERTIFICATE_VERSION("dir-key-certificate-version"),
+ DIR_KEY_CERTIFICATION("dir-key-certification"),
+ DIR_KEY_CROSSCERT("dir-key-crosscert"),
+ DIR_KEY_EXPIRES("dir-key-expires"),
+ DIR_KEY_PUBLISHED("dir-key-published"),
+ DIR_OPTIONS("dir-options"),
+ DIR_SIGNING_KEY("dir-signing-key"),
+ DIR_SOURCE("dir-source"),
+ ENTRY_IPS("entry-ips"),
+ ENTRY_STATS_END("entry-stats-end"),
+ EVENTDNS("eventdns"),
+ EXIT_KIBIBYTES_READ("exit-kibibytes-read"),
+ EXIT_KIBIBYTES_WRITTEN("exit-kibibytes-written"),
+ EXIT_STATS_END("exit-stats-end"),
+ EXIT_STREAMS_OPENED("exit-streams-opened"),
+ EXTRA_INFO("extra-info"),
+ EXTRA_INFO_DIGEST("extra-info-digest"),
+ FAMILY("family"),
+ FINGERPRINT("fingerprint"),
+ FLAG_THRESHOLDS("flag-thresholds"),
+ FRESH_UNTIL("fresh-until"),
+ GEOIP6_DB_DIGEST("geoip6-db-digest"),
+ GEOIP_CLIENT_ORIGINS("geoip-client-origins"),
+ GEOIP_DB_DIGEST("geoip-db-digest"),
+ GEOIP_START_TIME("geoip-start-time"),
+ HIBERNATING("hibernating"),
+ HIDDEN_SERVICE_DIR("hidden-service-dir"),
+ HIDSERV_DIR_ONIONS_SEEN("hidserv-dir-onions-seen"),
+ HIDSERV_REND_RELAYED_CELLS("hidserv-rend-relayed-cells"),
+ HIDSERV_STATS_END("hidserv-stats-end"),
+ ID("id"),
+ IDENTITY_ED25519("identity-ed25519"),
+ IPV6_POLICY("ipv6-policy"),
+ KNOWN_FLAGS("known-flags"),
+ LEGACY_DIR_KEY("legacy-dir-key"),
+ LEGACY_KEY("legacy-key"),
+ M("m"),
+ MASTER_KEY_ED25519("master-key-ed25519"),
+ NETWORK_STATUS_VERSION("network-status-version"),
+ NTOR_ONION_KEY("ntor-onion-key"),
+ NTOR_ONION_KEY_CROSSCERT("ntor-onion-key-crosscert"),
+ ONION_KEY("onion-key"),
+ ONION_KEY_CROSSCERT("onion-key-crosscert"),
+ OPT("opt"),
+ OR_ADDRESS("or-address"),
+ P("p"),
+ P6("p6"),
+ PACKAGE("package"),
+ PADDING_COUNTS("padding-counts"),
+ PARAMS("params"),
+ PLATFORM("platform"),
+ PR("pr"),
+ PROTO("proto"),
+ PROTOCOLS("protocols"),
+ PUBLISHED("published"),
+ R("r"),
+ READ_HISTORY("read-history"),
+ RECOMMENDED_CLIENT_PROTOCOLS("recommended-client-protocols"),
+ RECOMMENDED_RELAY_PROTOCOLS("recommended-relay-protocols"),
+ RECOMMENDED_SOFTWARE("recommended-software"),
+ REJECT("reject"),
+ REQUIRED_CLIENT_PROTOCOLS("required-client-protocols"),
+ REQUIRED_RELAY_PROTOCOLS("required-relay-protocols"),
+ ROUTER("router"),
+ ROUTER_DIGEST("router-digest"),
+ ROUTER_DIGEST_SHA256("router-digest-sha256"),
+ ROUTER_SIGNATURE("router-signature"),
+ ROUTER_SIG_ED25519("router-sig-ed25519"),
+ ROUTER_STATUS("router-status"),
+ RUNNING_ROUTERS("running-routers"),
+ S("s"),
+ SERVER_VERSIONS("server-versions"),
+ SHARED_RAND_COMMIT("shared-rand-commit"),
+ SHARED_RAND_CURRENT_VALUE("shared-rand-current-value"),
+ SHARED_RAND_PARTICIPATE("shared-rand-participate"),
+ SHARED_RAND_PREVIOUS_VALUE("shared-rand-previous-value"),
+ SIGNED_DIRECTORY("signed-directory"),
+ SIGNING_KEY("signing-key"),
+ TRANSPORT("transport"),
+ TUNNELLED_DIR_SERVER("tunnelled-dir-server"),
+ UPTIME("uptime"),
+ V("v"),
+ VALID_AFTER("valid-after"),
+ VALID_UNTIL("valid-until"),
+ VOTE_DIGEST("vote-digest"),
+ VOTE_STATUS("vote-status"),
+ VOTING_DELAY("voting-delay"),
+ W("w"),
+ WRITE_HISTORY("write-history");
+
+ /** The keyword as it appears in descriptors. */
+ public final String keyword;
+
+ private static final Map<String, Key> keywordMap = new HashMap<>();
+ static {
+ for (Key key : values()) {
+ keywordMap.put(key.keyword, key);
+ }
+ keywordMap.remove(INVALID.keyword);
+ keywordMap.remove(EMPTY.keyword);
+ }
+
+ private Key(String keyword) {
+ this.keyword = keyword;
+ }
+
+ /** Retrieve a Key for a keyword.
+ * Returns Key.INVALID for non-existing keywords. */
+ public static Key get(String keyword) {
+ Key res = INVALID;
+ try {
+ res = keywordMap.get(keyword);
+ } catch (Throwable th) {
+ res = INVALID;
+ }
+ if (null == res) {
+ res = INVALID;
+ }
+ return res;
+ }
+}
diff --git a/src/main/java/org/torproject/descriptor/impl/MicrodescriptorImpl.java b/src/main/java/org/torproject/descriptor/impl/MicrodescriptorImpl.java
index 5c94371..e8329cc 100644
--- a/src/main/java/org/torproject/descriptor/impl/MicrodescriptorImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/MicrodescriptorImpl.java
@@ -11,7 +11,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashSet;
+import java.util.EnumSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
@@ -28,7 +28,7 @@ public class MicrodescriptorImpl extends DescriptorImpl
List<Microdescriptor> parsedDescriptors = new ArrayList<>();
List<byte[]> splitDescriptorsBytes =
DescriptorImpl.splitRawDescriptorBytes(descriptorsBytes,
- "onion-key\n");
+ Key.ONION_KEY + NL);
for (byte[] descriptorBytes : splitDescriptorsBytes) {
Microdescriptor parsedDescriptor =
new MicrodescriptorImpl(descriptorBytes,
@@ -44,21 +44,19 @@ public class MicrodescriptorImpl extends DescriptorImpl
super(descriptorBytes, failUnrecognizedDescriptorLines, false);
this.parseDescriptorBytes();
this.calculateDigest();
- Set<String> exactlyOnceKeywords = new HashSet<>(Arrays.asList(
- "onion-key".split(",")));
- this.checkExactlyOnceKeywords(exactlyOnceKeywords);
- Set<String> atMostOnceKeywords = new HashSet<>(Arrays.asList((
- "ntor-onion-key,family,p,p6,id").split(",")));
- this.checkAtMostOnceKeywords(atMostOnceKeywords);
- this.checkFirstKeyword("onion-key");
- this.clearParsedKeywords();
+ this.checkExactlyOnceKeys(EnumSet.of(Key.ONION_KEY));
+ Set<Key> atMostOnceKeys = EnumSet.of(
+ Key.NTOR_ONION_KEY, Key.FAMILY, Key.P, Key.P6, Key.ID);
+ this.checkAtMostOnceKeys(atMostOnceKeys);
+ this.checkFirstKey(Key.ONION_KEY);
+ this.clearParsedKeys();
return;
}
private void parseDescriptorBytes() throws DescriptorParseException {
Scanner scanner = new Scanner(new String(this.rawDescriptorBytes))
- .useDelimiter("\n");
- String nextCrypto = "";
+ .useDelimiter(NL);
+ Key nextCrypto = Key.EMPTY;
StringBuilder crypto = null;
while (scanner.hasNext()) {
String line = scanner.next();
@@ -66,49 +64,49 @@ public class MicrodescriptorImpl extends DescriptorImpl
continue;
}
String[] parts = line.split("[ \t]+");
- String keyword = parts[0];
- switch (keyword) {
- case "onion-key":
+ Key key = Key.get(parts[0]);
+ switch (key) {
+ case ONION_KEY:
this.parseOnionKeyLine(line, parts);
- nextCrypto = "onion-key";
+ nextCrypto = key;
break;
- case "ntor-onion-key":
+ case NTOR_ONION_KEY:
this.parseNtorOnionKeyLine(line, parts);
break;
- case "a":
+ case A:
this.parseALine(line, parts);
break;
- case "family":
+ case FAMILY:
this.parseFamilyLine(line, parts);
break;
- case "p":
+ case P:
this.parsePLine(line, parts);
break;
- case "p6":
+ case P6:
this.parseP6Line(line, parts);
break;
- case "id":
+ case ID:
this.parseIdLine(line, parts);
break;
- case "-----BEGIN":
+ case CRYPTO_BEGIN:
crypto = new StringBuilder();
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
break;
- case "-----END":
- crypto.append(line).append("\n");
+ case CRYPTO_END:
+ crypto.append(line).append(NL);
String cryptoString = crypto.toString();
crypto = null;
- if (nextCrypto.equals("onion-key")) {
+ if (nextCrypto.equals(Key.ONION_KEY)) {
this.onionKey = cryptoString;
} else {
throw new DescriptorParseException("Unrecognized crypto "
+ "block in microdescriptor.");
}
- nextCrypto = "";
+ nextCrypto = Key.EMPTY;
break;
default:
if (crypto != null) {
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
} else {
ParseHelper.parseKeyword(line, parts[0]);
if (this.failUnrecognizedDescriptorLines) {
diff --git a/src/main/java/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java b/src/main/java/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java
index 152546a..cb4eca8 100644
--- a/src/main/java/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java
@@ -3,11 +3,15 @@
package org.torproject.descriptor.impl;
+import static org.torproject.descriptor.impl.DescriptorImpl.NL;
+import static org.torproject.descriptor.impl.DescriptorImpl.SP;
+
import org.torproject.descriptor.DescriptorParseException;
import org.torproject.descriptor.NetworkStatusEntry;
import java.util.ArrayList;
import java.util.BitSet;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -46,34 +50,25 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry {
this.microdescConsensus = microdescConsensus;
this.failUnrecognizedDescriptorLines =
failUnrecognizedDescriptorLines;
- this.initializeKeywords();
this.parseStatusEntryBytes();
- this.clearAtMostOnceKeywords();
+ this.clearAtMostOnceKeys();
}
- private SortedSet<String> atMostOnceKeywords;
-
- private void initializeKeywords() {
- this.atMostOnceKeywords = new TreeSet<>();
- this.atMostOnceKeywords.add("s");
- this.atMostOnceKeywords.add("v");
- this.atMostOnceKeywords.add("pr");
- this.atMostOnceKeywords.add("w");
- this.atMostOnceKeywords.add("p");
- }
+ private Set<Key> atMostOnceKeys = EnumSet.of(
+ Key.S, Key.V, Key.PR, Key.W, Key.P);
- private void parsedAtMostOnceKeyword(String keyword)
+ private void parsedAtMostOnceKey(Key key)
throws DescriptorParseException {
- if (!this.atMostOnceKeywords.contains(keyword)) {
- throw new DescriptorParseException("Duplicate '" + keyword
+ if (!this.atMostOnceKeys.contains(key)) {
+ throw new DescriptorParseException("Duplicate '" + key.keyword
+ "' line in status entry.");
}
- this.atMostOnceKeywords.remove(keyword);
+ this.atMostOnceKeys.remove(key);
}
private void parseStatusEntryBytes() throws DescriptorParseException {
Scanner scanner = new Scanner(new String(this.statusEntryBytes))
- .useDelimiter("\n");
+ .useDelimiter(NL);
String line = null;
if (!scanner.hasNext() || !(line = scanner.next()).startsWith("r ")) {
throw new DescriptorParseException("Status entry must start with "
@@ -83,32 +78,33 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry {
this.parseRLine(line, rlineParts);
while (scanner.hasNext()) {
line = scanner.next();
- String[] parts = !line.startsWith("opt ") ? line.split("[ \t]+")
- : line.substring("opt ".length()).split("[ \t]+");
- String keyword = parts[0];
- switch (keyword) {
- case "a":
+ String[] parts = !line.startsWith(Key.OPT.keyword + SP)
+ ? line.split("[ \t]+")
+ : line.substring(Key.OPT.keyword.length() + 1).split("[ \t]+");
+ Key key = Key.get(parts[0]);
+ switch (key) {
+ case A:
this.parseALine(line, parts);
break;
- case "s":
+ case S:
this.parseSLine(line, parts);
break;
- case "v":
+ case V:
this.parseVLine(line, parts);
break;
- case "pr":
+ case PR:
this.parsePrLine(line, parts);
break;
- case "w":
+ case W:
this.parseWLine(line, parts);
break;
- case "p":
+ case P:
this.parsePLine(line, parts);
break;
- case "m":
+ case M:
this.parseMLine(line, parts);
break;
- case "id":
+ case ID:
this.parseIdLine(line, parts);
break;
default:
@@ -167,7 +163,7 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry {
private void parseSLine(String line, String[] parts)
throws DescriptorParseException {
- this.parsedAtMostOnceKeyword("s");
+ this.parsedAtMostOnceKey(Key.S);
BitSet flags = new BitSet(flagIndexes.size());
for (int i = 1; i < parts.length; i++) {
String flag = parts[i];
@@ -182,9 +178,9 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry {
private void parseVLine(String line, String[] parts)
throws DescriptorParseException {
- this.parsedAtMostOnceKeyword("v");
+ this.parsedAtMostOnceKey(Key.V);
String noOptLine = line;
- if (noOptLine.startsWith("opt ")) {
+ if (noOptLine.startsWith(Key.OPT.keyword + SP)) {
noOptLine = noOptLine.substring(4);
}
if (noOptLine.length() < 3) {
@@ -197,13 +193,13 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry {
private void parsePrLine(String line, String[] parts)
throws DescriptorParseException {
- this.parsedAtMostOnceKeyword("pr");
+ this.parsedAtMostOnceKey(Key.PR);
this.protocols = ParseHelper.parseProtocolVersions(line, line, parts);
}
private void parseWLine(String line, String[] parts)
throws DescriptorParseException {
- this.parsedAtMostOnceKeyword("w");
+ this.parsedAtMostOnceKey(Key.W);
SortedMap<String, Integer> pairs =
ParseHelper.parseKeyValueIntegerPairs(line, parts, 1, "=");
if (pairs.isEmpty()) {
@@ -225,7 +221,7 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry {
private void parsePLine(String line, String[] parts)
throws DescriptorParseException {
- this.parsedAtMostOnceKeyword("p");
+ this.parsedAtMostOnceKey(Key.P);
boolean isValid = true;
if (parts.length != 3) {
isValid = false;
@@ -280,8 +276,8 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry {
}
}
- private void clearAtMostOnceKeywords() {
- this.atMostOnceKeywords = null;
+ private void clearAtMostOnceKeys() {
+ this.atMostOnceKeys = null;
}
private String nickname;
diff --git a/src/main/java/org/torproject/descriptor/impl/NetworkStatusImpl.java b/src/main/java/org/torproject/descriptor/impl/NetworkStatusImpl.java
index e3891a6..f67c32a 100644
--- a/src/main/java/org/torproject/descriptor/impl/NetworkStatusImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/NetworkStatusImpl.java
@@ -34,15 +34,16 @@ public abstract class NetworkStatusImpl extends DescriptorImpl {
throw new DescriptorParseException("Descriptor is empty.");
}
String descriptorString = new String(rawDescriptorBytes);
- int firstRIndex = this.findFirstIndexOfKeyword(descriptorString, "r");
+ int firstRIndex = this.findFirstIndexOfKeyword(descriptorString,
+ Key.R.keyword);
int endIndex = descriptorString.length();
int firstDirectorySignatureIndex = this.findFirstIndexOfKeyword(
- descriptorString, "directory-signature");
+ descriptorString, Key.DIRECTORY_SIGNATURE.keyword);
if (firstDirectorySignatureIndex < 0) {
firstDirectorySignatureIndex = endIndex;
}
int directoryFooterIndex = this.findFirstIndexOfKeyword(
- descriptorString, "directory-footer");
+ descriptorString, Key.DIRECTORY_FOOTER.keyword);
if (directoryFooterIndex < 0) {
directoryFooterIndex = firstDirectorySignatureIndex;
}
@@ -50,7 +51,8 @@ public abstract class NetworkStatusImpl extends DescriptorImpl {
firstRIndex = directoryFooterIndex;
}
int firstDirSourceIndex = !containsDirSourceEntries ? -1
- : this.findFirstIndexOfKeyword(descriptorString, "dir-source");
+ : this.findFirstIndexOfKeyword(descriptorString,
+ Key.DIR_SOURCE.keyword);
if (firstDirSourceIndex < 0) {
firstDirSourceIndex = firstRIndex;
}
@@ -79,10 +81,10 @@ public abstract class NetworkStatusImpl extends DescriptorImpl {
String keyword) {
if (descriptorString.startsWith(keyword)) {
return 0;
- } else if (descriptorString.contains("\n" + keyword + " ")) {
- return descriptorString.indexOf("\n" + keyword + " ") + 1;
- } else if (descriptorString.contains("\n" + keyword + "\n")) {
- return descriptorString.indexOf("\n" + keyword + "\n") + 1;
+ } else if (descriptorString.contains(NL + keyword + SP)) {
+ return descriptorString.indexOf(NL + keyword + SP) + 1;
+ } else if (descriptorString.contains(NL + keyword + NL)) {
+ return descriptorString.indexOf(NL + keyword + NL) + 1;
} else {
return -1;
}
@@ -99,7 +101,8 @@ public abstract class NetworkStatusImpl extends DescriptorImpl {
private void parseDirSourceBytes(String descriptorString, int start,
int end) throws DescriptorParseException {
List<byte[]> splitDirSourceBytes =
- this.splitByKeyword(descriptorString, "dir-source", start, end);
+ this.splitByKeyword(
+ descriptorString, Key.DIR_SOURCE.keyword, start, end);
for (byte[] dirSourceBytes : splitDirSourceBytes) {
this.parseDirSource(dirSourceBytes);
}
@@ -108,7 +111,7 @@ public abstract class NetworkStatusImpl extends DescriptorImpl {
private void parseStatusEntryBytes(String descriptorString, int start,
int end) throws DescriptorParseException {
List<byte[]> splitStatusEntryBytes =
- this.splitByKeyword(descriptorString, "r", start, end);
+ this.splitByKeyword(descriptorString, Key.R.keyword, start, end);
for (byte[] statusEntryBytes : splitStatusEntryBytes) {
this.parseStatusEntry(statusEntryBytes);
}
@@ -125,7 +128,7 @@ public abstract class NetworkStatusImpl extends DescriptorImpl {
private void parseDirectorySignatureBytes(String descriptorString,
int start, int end) throws DescriptorParseException {
List<byte[]> splitDirectorySignatureBytes = this.splitByKeyword(
- descriptorString, "directory-signature", start, end);
+ descriptorString, Key.DIRECTORY_SIGNATURE.keyword, start, end);
for (byte[] directorySignatureBytes : splitDirectorySignatureBytes) {
this.parseDirectorySignature(directorySignatureBytes);
}
@@ -136,9 +139,9 @@ public abstract class NetworkStatusImpl extends DescriptorImpl {
List<byte[]> splitParts = new ArrayList<>();
int from = start;
while (from < end) {
- int to = descriptorString.indexOf("\n" + keyword + " ", from);
+ int to = descriptorString.indexOf(NL + keyword + SP, from);
if (to < 0) {
- to = descriptorString.indexOf("\n" + keyword + "\n", from);
+ to = descriptorString.indexOf(NL + keyword + NL, from);
}
if (to < 0) {
to = end;
diff --git a/src/main/java/org/torproject/descriptor/impl/RelayDirectoryImpl.java b/src/main/java/org/torproject/descriptor/impl/RelayDirectoryImpl.java
index fc8f07b..fae54f4 100644
--- a/src/main/java/org/torproject/descriptor/impl/RelayDirectoryImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/RelayDirectoryImpl.java
@@ -12,8 +12,7 @@ import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
+import java.util.EnumSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
@@ -29,7 +28,7 @@ public class RelayDirectoryImpl extends DescriptorImpl
List<RelayDirectory> parsedDirectories = new ArrayList<>();
List<byte[]> splitDirectoriesBytes =
DescriptorImpl.splitRawDescriptorBytes(directoriesBytes,
- "signed-directory\n");
+ Key.SIGNED_DIRECTORY.keyword + NL);
for (byte[] directoryBytes : splitDirectoriesBytes) {
RelayDirectory parsedDirectory =
new RelayDirectoryImpl(directoryBytes,
@@ -45,28 +44,28 @@ public class RelayDirectoryImpl extends DescriptorImpl
super(directoryBytes, failUnrecognizedDescriptorLines, true);
this.splitAndParseParts(rawDescriptorBytes);
this.calculateDigest();
- Set<String> exactlyOnceKeywords = new HashSet<>(Arrays.asList((
- "signed-directory,recommended-software,"
- + "directory-signature").split(",")));
- this.checkExactlyOnceKeywords(exactlyOnceKeywords);
- Set<String> atMostOnceKeywords = new HashSet<>(Arrays.asList(
- "dir-signing-key,running-routers,router-status".split(",")));
- this.checkAtMostOnceKeywords(atMostOnceKeywords);
- this.checkFirstKeyword("signed-directory");
- this.clearParsedKeywords();
+ Set<Key> exactlyOnceKeys = EnumSet.of(
+ Key.SIGNED_DIRECTORY, Key.RECOMMENDED_SOFTWARE,
+ Key.DIRECTORY_SIGNATURE);
+ this.checkExactlyOnceKeys(exactlyOnceKeys);
+ Set<Key> atMostOnceKeys = EnumSet.of(
+ Key.DIR_SIGNING_KEY, Key.RUNNING_ROUTERS, Key.ROUTER_STATUS);
+ this.checkAtMostOnceKeys(atMostOnceKeys);
+ this.checkFirstKey(Key.SIGNED_DIRECTORY);
+ this.clearParsedKeys();
}
private void calculateDigest() throws DescriptorParseException {
try {
String ascii = new String(this.getRawDescriptorBytes(), "US-ASCII");
- String startToken = "signed-directory\n";
- String sigToken = "\ndirectory-signature ";
+ String startToken = Key.SIGNED_DIRECTORY.keyword + NL;
+ String sigToken = NL + Key.DIRECTORY_SIGNATURE.keyword + SP;
if (!ascii.contains(sigToken)) {
return;
}
int start = ascii.indexOf(startToken);
int sig = ascii.indexOf(sigToken) + sigToken.length();
- sig = ascii.indexOf("\n", sig) + 1;
+ sig = ascii.indexOf(NL, sig) + 1;
if (start >= 0 && sig >= 0 && sig > start) {
byte[] forDigest = new byte[sig - start];
System.arraycopy(this.getRawDescriptorBytes(), start,
@@ -94,9 +93,9 @@ public class RelayDirectoryImpl extends DescriptorImpl
String descriptorString = new String(rawDescriptorBytes);
int startIndex = 0;
int firstRouterIndex = this.findFirstIndexOfKeyword(descriptorString,
- "router");
+ Key.ROUTER.keyword);
int directorySignatureIndex = this.findFirstIndexOfKeyword(
- descriptorString, "directory-signature");
+ descriptorString, Key.DIRECTORY_SIGNATURE.keyword);
int endIndex = descriptorString.length();
if (directorySignatureIndex < 0) {
directorySignatureIndex = endIndex;
@@ -122,10 +121,10 @@ public class RelayDirectoryImpl extends DescriptorImpl
String keyword) {
if (descriptorString.startsWith(keyword)) {
return 0;
- } else if (descriptorString.contains("\n" + keyword + " ")) {
- return descriptorString.indexOf("\n" + keyword + " ") + 1;
- } else if (descriptorString.contains("\n" + keyword + "\n")) {
- return descriptorString.indexOf("\n" + keyword + "\n") + 1;
+ } else if (descriptorString.contains(NL + keyword + SP)) {
+ return descriptorString.indexOf(NL + keyword + SP) + 1;
+ } else if (descriptorString.contains(NL + keyword + NL)) {
+ return descriptorString.indexOf(NL + keyword + NL) + 1;
} else {
return -1;
}
@@ -142,7 +141,7 @@ public class RelayDirectoryImpl extends DescriptorImpl
private void parseServerDescriptorBytes(String descriptorString,
int start, int end) throws DescriptorParseException {
List<byte[]> splitServerDescriptorBytes =
- this.splitByKeyword(descriptorString, "router", start, end);
+ this.splitByKeyword(descriptorString, Key.ROUTER.keyword, start, end);
for (byte[] statusEntryBytes : splitServerDescriptorBytes) {
this.parseServerDescriptor(statusEntryBytes);
}
@@ -162,9 +161,9 @@ public class RelayDirectoryImpl extends DescriptorImpl
List<byte[]> splitParts = new ArrayList<>();
int from = start;
while (from < end) {
- int to = descriptorString.indexOf("\n" + keyword + " ", from);
+ int to = descriptorString.indexOf(NL + keyword + SP, from);
if (to < 0) {
- to = descriptorString.indexOf("\n" + keyword + "\n", from);
+ to = descriptorString.indexOf(NL + keyword + NL, from);
}
if (to < 0) {
to = end;
@@ -187,9 +186,9 @@ public class RelayDirectoryImpl extends DescriptorImpl
private void parseHeader(byte[] headerBytes)
throws DescriptorParseException {
- Scanner scanner = new Scanner(new String(headerBytes)).useDelimiter("\n");
+ Scanner scanner = new Scanner(new String(headerBytes)).useDelimiter(NL);
String publishedLine = null;
- String nextCrypto = "";
+ Key nextCrypto = Key.EMPTY;
String runningRoutersLine = null;
String routerStatusLine = null;
StringBuilder crypto = null;
@@ -198,15 +197,15 @@ public class RelayDirectoryImpl extends DescriptorImpl
if (line.isEmpty() || line.startsWith("@")) {
continue;
}
- String lineNoOpt = line.startsWith("opt ")
- ? line.substring("opt ".length()) : line;
+ String lineNoOpt = line.startsWith(Key.OPT.keyword + SP)
+ ? line.substring(Key.OPT.keyword.length() + 1) : line;
String[] partsNoOpt = lineNoOpt.split("[ \t]+");
- String keyword = partsNoOpt[0];
- switch (keyword) {
- case "signed-directory":
+ Key key = Key.get(partsNoOpt[0]);
+ switch (key) {
+ case SIGNED_DIRECTORY:
this.parseSignedDirectoryLine(line, lineNoOpt, partsNoOpt);
break;
- case "published":
+ case PUBLISHED:
if (publishedLine != null) {
throw new DescriptorParseException("Keyword 'published' is "
+ "contained more than once, but must be contained "
@@ -215,39 +214,39 @@ public class RelayDirectoryImpl extends DescriptorImpl
publishedLine = line;
}
break;
- case "dir-signing-key":
+ case DIR_SIGNING_KEY:
this.parseDirSigningKeyLine(line, lineNoOpt, partsNoOpt);
- nextCrypto = "dir-signing-key";
+ nextCrypto = key;
break;
- case "recommended-software":
+ case RECOMMENDED_SOFTWARE:
this.parseRecommendedSoftwareLine(line, lineNoOpt, partsNoOpt);
break;
- case "running-routers":
+ case RUNNING_ROUTERS:
runningRoutersLine = line;
break;
- case "router-status":
+ case ROUTER_STATUS:
routerStatusLine = line;
break;
- case "-----BEGIN":
+ case CRYPTO_BEGIN:
crypto = new StringBuilder();
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
break;
- case "-----END":
- crypto.append(line).append("\n");
+ case CRYPTO_END:
+ crypto.append(line).append(NL);
String cryptoString = crypto.toString();
crypto = null;
- if (nextCrypto.equals("dir-signing-key")
+ if (nextCrypto.equals(Key.DIR_SIGNING_KEY)
&& this.dirSigningKey == null) {
this.dirSigningKey = cryptoString;
} else {
throw new DescriptorParseException("Unrecognized crypto "
+ "block in v1 directory.");
}
- nextCrypto = "";
+ nextCrypto = Key.EMPTY;
break;
default:
if (crypto != null) {
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
} else {
if (this.failUnrecognizedDescriptorLines) {
throw new DescriptorParseException("Unrecognized line '"
@@ -265,15 +264,17 @@ public class RelayDirectoryImpl extends DescriptorImpl
throw new DescriptorParseException("Keyword 'published' is "
+ "contained 0 times, but must be contained exactly once.");
} else {
- String publishedLineNoOpt = publishedLine.startsWith("opt ")
- ? publishedLine.substring("opt ".length()) : publishedLine;
+ String publishedLineNoOpt = publishedLine.startsWith(Key.OPT.keyword + SP)
+ ? publishedLine.substring(Key.OPT.keyword.length() + 1)
+ : publishedLine;
String[] publishedPartsNoOpt = publishedLineNoOpt.split("[ \t]+");
this.parsePublishedLine(publishedLine, publishedLineNoOpt,
publishedPartsNoOpt);
}
if (routerStatusLine != null) {
- String routerStatusLineNoOpt = routerStatusLine.startsWith("opt ")
- ? routerStatusLine.substring("opt ".length())
+ String routerStatusLineNoOpt =
+ routerStatusLine.startsWith(Key.OPT.keyword + SP)
+ ? routerStatusLine.substring(Key.OPT.keyword.length() + 1)
: routerStatusLine;
String[] routerStatusPartsNoOpt =
routerStatusLineNoOpt.split("[ \t]+");
@@ -281,8 +282,8 @@ public class RelayDirectoryImpl extends DescriptorImpl
routerStatusPartsNoOpt);
} else if (runningRoutersLine != null) {
String runningRoutersLineNoOpt =
- runningRoutersLine.startsWith("opt ")
- ? runningRoutersLine.substring("opt ".length())
+ runningRoutersLine.startsWith(Key.OPT.keyword + SP)
+ ? runningRoutersLine.substring(Key.OPT.keyword.length() + 1)
: runningRoutersLine;
String[] runningRoutersPartsNoOpt =
runningRoutersLineNoOpt.split("[ \t]+");
@@ -308,39 +309,39 @@ public class RelayDirectoryImpl extends DescriptorImpl
private void parseDirectorySignature(byte[] directorySignatureBytes)
throws DescriptorParseException {
Scanner scanner = new Scanner(new String(directorySignatureBytes))
- .useDelimiter("\n");
- String nextCrypto = "";
+ .useDelimiter(NL);
+ Key nextCrypto = Key.EMPTY;
StringBuilder crypto = null;
while (scanner.hasNext()) {
String line = scanner.next();
- String lineNoOpt = line.startsWith("opt ")
- ? line.substring("opt ".length()) : line;
+ String lineNoOpt = line.startsWith(Key.OPT.keyword + SP)
+ ? line.substring(Key.OPT.keyword.length() + 1) : line;
String[] partsNoOpt = lineNoOpt.split("[ \t]+");
- String keyword = partsNoOpt[0];
- switch (keyword) {
- case "directory-signature":
+ Key key = Key.get(partsNoOpt[0]);
+ switch (key) {
+ case DIRECTORY_SIGNATURE:
this.parseDirectorySignatureLine(line, lineNoOpt, partsNoOpt);
- nextCrypto = "directory-signature";
+ nextCrypto = key;
break;
- case "-----BEGIN":
+ case CRYPTO_BEGIN:
crypto = new StringBuilder();
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
break;
- case "-----END":
- crypto.append(line).append("\n");
+ case CRYPTO_END:
+ crypto.append(line).append(NL);
String cryptoString = crypto.toString();
crypto = null;
- if (nextCrypto.equals("directory-signature")) {
+ if (nextCrypto.equals(Key.DIRECTORY_SIGNATURE)) {
this.directorySignature = cryptoString;
} else {
throw new DescriptorParseException("Unrecognized crypto "
+ "block in v2 network status.");
}
- nextCrypto = "";
+ nextCrypto = Key.EMPTY;
break;
default:
if (crypto != null) {
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
} else if (this.failUnrecognizedDescriptorLines) {
throw new DescriptorParseException("Unrecognized line '"
+ line + "' in v2 network status.");
@@ -356,7 +357,7 @@ public class RelayDirectoryImpl extends DescriptorImpl
private void parseSignedDirectoryLine(String line, String lineNoOpt,
String[] partsNoOpt) throws DescriptorParseException {
- if (!lineNoOpt.equals("signed-directory")) {
+ if (!lineNoOpt.equals(Key.SIGNED_DIRECTORY.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
}
@@ -379,11 +380,11 @@ public class RelayDirectoryImpl extends DescriptorImpl
sb.append("-----BEGIN RSA PUBLIC KEY-----\n");
String keyString = partsNoOpt[1];
while (keyString.length() > 64) {
- sb.append(keyString.substring(0, 64)).append("\n");
+ sb.append(keyString.substring(0, 64)).append(NL);
keyString = keyString.substring(64);
}
if (keyString.length() > 0) {
- sb.append(keyString).append("\n");
+ sb.append(keyString).append(NL);
}
sb.append("-----END RSA PUBLIC KEY-----\n");
this.dirSigningKey = sb.toString();
diff --git a/src/main/java/org/torproject/descriptor/impl/RelayExtraInfoDescriptorImpl.java b/src/main/java/org/torproject/descriptor/impl/RelayExtraInfoDescriptorImpl.java
index 3ec4869..6ee86b1 100644
--- a/src/main/java/org/torproject/descriptor/impl/RelayExtraInfoDescriptorImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/RelayExtraInfoDescriptorImpl.java
@@ -19,7 +19,7 @@ public class RelayExtraInfoDescriptorImpl
List<ExtraInfoDescriptor> parsedDescriptors = new ArrayList<>();
List<byte[]> splitDescriptorsBytes =
DescriptorImpl.splitRawDescriptorBytes(descriptorsBytes,
- "extra-info ");
+ Key.EXTRA_INFO.keyword + SP);
for (byte[] descriptorBytes : splitDescriptorsBytes) {
ExtraInfoDescriptor parsedDescriptor =
new RelayExtraInfoDescriptorImpl(descriptorBytes,
diff --git a/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java b/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java
index ef135d4..4570931 100644
--- a/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java
@@ -11,7 +11,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashSet;
+import java.util.EnumSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
@@ -33,7 +33,7 @@ public class RelayNetworkStatusConsensusImpl extends NetworkStatusImpl
new ArrayList<>();
List<byte[]> splitConsensusBytes =
DescriptorImpl.splitRawDescriptorBytes(consensusesBytes,
- "network-status-version 3");
+ Key.NETWORK_STATUS_VERSION.keyword + SP + "3");
for (byte[] consensusBytes : splitConsensusBytes) {
RelayNetworkStatusConsensus parsedConsensus =
new RelayNetworkStatusConsensusImpl(consensusBytes,
@@ -47,27 +47,27 @@ public class RelayNetworkStatusConsensusImpl extends NetworkStatusImpl
boolean failUnrecognizedDescriptorLines)
throws DescriptorParseException {
super(consensusBytes, failUnrecognizedDescriptorLines, true, false);
- Set<String> exactlyOnceKeywords = new HashSet<>(Arrays.asList((
- "vote-status,consensus-method,valid-after,fresh-until,"
- + "valid-until,voting-delay,known-flags").split(",")));
- this.checkExactlyOnceKeywords(exactlyOnceKeywords);
- Set<String> atMostOnceKeywords = new HashSet<>(Arrays.asList((
- "client-versions,server-versions,recommended-client-protocols,"
- + "recommended-relay-protocols,required-client-protocols,"
- + "required-relay-protocols,params,shared-rand-previous-value,"
- + "shared-rand-current-value,directory-footer,bandwidth-weights")
- .split(",")));
- this.checkAtMostOnceKeywords(atMostOnceKeywords);
- this.checkFirstKeyword("network-status-version");
- this.clearParsedKeywords();
+ Set<Key> exactlyOnceKeys = EnumSet.of(
+ Key.VOTE_STATUS, Key.CONSENSUS_METHOD, Key.VALID_AFTER, Key.FRESH_UNTIL,
+ Key.VALID_UNTIL, Key.VOTING_DELAY, Key.KNOWN_FLAGS);
+ this.checkExactlyOnceKeys(exactlyOnceKeys);
+ Set<Key> atMostOnceKeys = EnumSet.of(
+ Key.CLIENT_VERSIONS, Key.SERVER_VERSIONS,
+ Key.RECOMMENDED_CLIENT_PROTOCOLS, Key.RECOMMENDED_RELAY_PROTOCOLS,
+ Key.REQUIRED_CLIENT_PROTOCOLS, Key.REQUIRED_RELAY_PROTOCOLS, Key.PARAMS,
+ Key.SHARED_RAND_PREVIOUS_VALUE, Key.SHARED_RAND_CURRENT_VALUE,
+ Key.DIRECTORY_FOOTER, Key.BANDWIDTH_WEIGHTS);
+ this.checkAtMostOnceKeys(atMostOnceKeys);
+ this.checkFirstKey(Key.NETWORK_STATUS_VERSION);
+ this.clearParsedKeys();
this.calculateDigest();
}
private void calculateDigest() throws DescriptorParseException {
try {
String ascii = new String(this.getRawDescriptorBytes(), "US-ASCII");
- String startToken = "network-status-version ";
- String sigToken = "\ndirectory-signature ";
+ String startToken = Key.NETWORK_STATUS_VERSION.keyword + SP;
+ String sigToken = NL + Key.DIRECTORY_SIGNATURE.keyword + SP;
if (!ascii.contains(sigToken)) {
return;
}
@@ -94,64 +94,64 @@ public class RelayNetworkStatusConsensusImpl extends NetworkStatusImpl
protected void parseHeader(byte[] headerBytes)
throws DescriptorParseException {
- Scanner scanner = new Scanner(new String(headerBytes)).useDelimiter("\n");
+ Scanner scanner = new Scanner(new String(headerBytes)).useDelimiter(NL);
while (scanner.hasNext()) {
String line = scanner.next();
String[] parts = line.split("[ \t]+");
- String keyword = parts[0];
- switch (keyword) {
- case "network-status-version":
+ Key key = Key.get(parts[0]);
+ switch (key) {
+ case NETWORK_STATUS_VERSION:
this.parseNetworkStatusVersionLine(line, parts);
break;
- case "vote-status":
+ case VOTE_STATUS:
this.parseVoteStatusLine(line, parts);
break;
- case "consensus-method":
+ case CONSENSUS_METHOD:
this.parseConsensusMethodLine(line, parts);
break;
- case "valid-after":
+ case VALID_AFTER:
this.parseValidAfterLine(line, parts);
break;
- case "fresh-until":
+ case FRESH_UNTIL:
this.parseFreshUntilLine(line, parts);
break;
- case "valid-until":
+ case VALID_UNTIL:
this.parseValidUntilLine(line, parts);
break;
- case "voting-delay":
+ case VOTING_DELAY:
this.parseVotingDelayLine(line, parts);
break;
- case "client-versions":
+ case CLIENT_VERSIONS:
this.parseClientVersionsLine(line, parts);
break;
- case "server-versions":
+ case SERVER_VERSIONS:
this.parseServerVersionsLine(line, parts);
break;
- case "recommended-client-protocols":
+ case RECOMMENDED_CLIENT_PROTOCOLS:
this.parseRecommendedClientProtocolsLine(line, parts);
break;
- case "recommended-relay-protocols":
+ case RECOMMENDED_RELAY_PROTOCOLS:
this.parseRecommendedRelayProtocolsLine(line, parts);
break;
- case "required-client-protocols":
+ case REQUIRED_CLIENT_PROTOCOLS:
this.parseRequiredClientProtocolsLine(line, parts);
break;
- case "required-relay-protocols":
+ case REQUIRED_RELAY_PROTOCOLS:
this.parseRequiredRelayProtocolsLine(line, parts);
break;
- case "package":
+ case PACKAGE:
this.parsePackageLine(line, parts);
break;
- case "known-flags":
+ case KNOWN_FLAGS:
this.parseKnownFlagsLine(line, parts);
break;
- case "params":
+ case PARAMS:
this.parseParamsLine(line, parts);
break;
- case "shared-rand-previous-value":
+ case SHARED_RAND_PREVIOUS_VALUE:
this.parseSharedRandPreviousValueLine(line, parts);
break;
- case "shared-rand-current-value":
+ case SHARED_RAND_CURRENT_VALUE:
this.parseSharedRandCurrentValueLine(line, parts);
break;
default:
@@ -188,15 +188,15 @@ public class RelayNetworkStatusConsensusImpl extends NetworkStatusImpl
protected void parseFooter(byte[] footerBytes)
throws DescriptorParseException {
- Scanner scanner = new Scanner(new String(footerBytes)).useDelimiter("\n");
+ Scanner scanner = new Scanner(new String(footerBytes)).useDelimiter(NL);
while (scanner.hasNext()) {
String line = scanner.next();
String[] parts = line.split("[ \t]+");
- String keyword = parts[0];
- switch (keyword) {
- case "directory-footer":
+ Key key = Key.get(parts[0]);
+ switch (key) {
+ case DIRECTORY_FOOTER:
break;
- case "bandwidth-weights":
+ case BANDWIDTH_WEIGHTS:
this.parseBandwidthWeightsLine(line, parts);
break;
default:
@@ -215,7 +215,7 @@ public class RelayNetworkStatusConsensusImpl extends NetworkStatusImpl
private void parseNetworkStatusVersionLine(String line, String[] parts)
throws DescriptorParseException {
- if (!line.startsWith("network-status-version 3")) {
+ if (!line.startsWith(Key.NETWORK_STATUS_VERSION.keyword + SP + "3")) {
throw new DescriptorParseException("Illegal network status version "
+ "number in line '" + line + "'.");
}
@@ -335,7 +335,7 @@ public class RelayNetworkStatusConsensusImpl extends NetworkStatusImpl
if (this.packageLines == null) {
this.packageLines = new ArrayList<>();
}
- this.packageLines.add(line.substring("package ".length()));
+ this.packageLines.add(line.substring(Key.PACKAGE.keyword.length() + 1));
}
private void parseKnownFlagsLine(String line, String[] parts)
diff --git a/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusImpl.java b/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusImpl.java
index 143540c..121cdc9 100644
--- a/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusImpl.java
@@ -11,7 +11,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashSet;
+import java.util.EnumSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
@@ -42,29 +42,29 @@ public class RelayNetworkStatusImpl extends NetworkStatusImpl
boolean failUnrecognizedDescriptorLines)
throws DescriptorParseException {
super(statusBytes, failUnrecognizedDescriptorLines, false, true);
- Set<String> exactlyOnceKeywords = new HashSet<>(Arrays.asList((
- "network-status-version,dir-source,fingerprint,contact,"
- + "dir-signing-key,published").split(",")));
- this.checkExactlyOnceKeywords(exactlyOnceKeywords);
- Set<String> atMostOnceKeywords = new HashSet<>(Arrays.asList(
- "dir-options,client-versions,server-versions".split(",")));
- this.checkAtMostOnceKeywords(atMostOnceKeywords);
- this.checkFirstKeyword("network-status-version");
- this.clearParsedKeywords();
+ Set<Key> exactlyOnceKeys = EnumSet.of(
+ Key.NETWORK_STATUS_VERSION, Key.DIR_SOURCE, Key.FINGERPRINT,
+ Key.CONTACT, Key.DIR_SIGNING_KEY, Key.PUBLISHED);
+ this.checkExactlyOnceKeys(exactlyOnceKeys);
+ Set<Key> atMostOnceKeys = EnumSet.of(
+ Key.DIR_OPTIONS, Key.CLIENT_VERSIONS, Key.SERVER_VERSIONS);
+ this.checkAtMostOnceKeys(atMostOnceKeys);
+ this.checkFirstKey(Key.NETWORK_STATUS_VERSION);
+ this.clearParsedKeys();
this.calculateDigest();
}
private void calculateDigest() throws DescriptorParseException {
try {
String ascii = new String(this.getRawDescriptorBytes(), "US-ASCII");
- String startToken = "network-status-version ";
- String sigToken = "\ndirectory-signature ";
+ String startToken = Key.NETWORK_STATUS_VERSION.keyword + SP;
+ String sigToken = NL + Key.DIRECTORY_SIGNATURE.keyword + SP;
if (!ascii.contains(sigToken)) {
return;
}
int start = ascii.indexOf(startToken);
int sig = ascii.indexOf(sigToken) + sigToken.length();
- sig = ascii.indexOf("\n", sig) + 1;
+ sig = ascii.indexOf(NL, sig) + 1;
if (start >= 0 && sig >= 0 && sig > start) {
byte[] forDigest = new byte[sig - start];
System.arraycopy(this.getRawDescriptorBytes(), start,
@@ -86,8 +86,8 @@ public class RelayNetworkStatusImpl extends NetworkStatusImpl
protected void parseHeader(byte[] headerBytes)
throws DescriptorParseException {
- Scanner scanner = new Scanner(new String(headerBytes)).useDelimiter("\n");
- String nextCrypto = "";
+ Scanner scanner = new Scanner(new String(headerBytes)).useDelimiter(NL);
+ Key nextCrypto = Key.EMPTY;
StringBuilder crypto = null;
while (scanner.hasNext()) {
String line = scanner.next();
@@ -95,55 +95,55 @@ public class RelayNetworkStatusImpl extends NetworkStatusImpl
continue;
}
String[] parts = line.split("[ \t]+");
- String keyword = parts[0];
- switch (keyword) {
- case "network-status-version":
+ Key key = Key.get(parts[0]);
+ switch (key) {
+ case NETWORK_STATUS_VERSION:
this.parseNetworkStatusVersionLine(line, parts);
break;
- case "dir-source":
+ case DIR_SOURCE:
this.parseDirSourceLine(line, parts);
break;
- case "fingerprint":
+ case FINGERPRINT:
this.parseFingerprintLine(line, parts);
break;
- case "contact":
+ case CONTACT:
this.parseContactLine(line, parts);
break;
- case "dir-signing-key":
+ case DIR_SIGNING_KEY:
this.parseDirSigningKeyLine(line, parts);
- nextCrypto = "dir-signing-key";
+ nextCrypto = key;
break;
- case "client-versions":
+ case CLIENT_VERSIONS:
this.parseClientVersionsLine(line, parts);
break;
- case "server-versions":
+ case SERVER_VERSIONS:
this.parseServerVersionsLine(line, parts);
break;
- case "published":
+ case PUBLISHED:
this.parsePublishedLine(line, parts);
break;
- case "dir-options":
+ case DIR_OPTIONS:
this.parseDirOptionsLine(line, parts);
break;
- case "-----BEGIN":
+ case CRYPTO_BEGIN:
crypto = new StringBuilder();
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
break;
- case "-----END":
- crypto.append(line).append("\n");
+ case CRYPTO_END:
+ crypto.append(line).append(NL);
String cryptoString = crypto.toString();
crypto = null;
- if (nextCrypto.equals("dir-signing-key")) {
+ if (nextCrypto.equals(Key.DIR_SIGNING_KEY)) {
this.dirSigningKey = cryptoString;
} else {
throw new DescriptorParseException("Unrecognized crypto "
+ "block in v2 network status.");
}
- nextCrypto = "";
+ nextCrypto = Key.EMPTY;
break;
default:
if (crypto != null) {
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
} else if (this.failUnrecognizedDescriptorLines) {
throw new DescriptorParseException("Unrecognized line '"
+ line + "' in v2 network status.");
@@ -166,37 +166,37 @@ public class RelayNetworkStatusImpl extends NetworkStatusImpl
protected void parseDirectorySignature(byte[] directorySignatureBytes)
throws DescriptorParseException {
Scanner scanner = new Scanner(new String(directorySignatureBytes))
- .useDelimiter("\n");
- String nextCrypto = "";
+ .useDelimiter(NL);
+ Key nextCrypto = Key.EMPTY;
StringBuilder crypto = null;
while (scanner.hasNext()) {
String line = scanner.next();
String[] parts = line.split("[ \t]+");
- String keyword = parts[0];
- switch (keyword) {
- case "directory-signature":
+ Key key = Key.get(parts[0]);
+ switch (key) {
+ case DIRECTORY_SIGNATURE:
this.parseDirectorySignatureLine(line, parts);
- nextCrypto = "directory-signature";
+ nextCrypto = key;
break;
- case "-----BEGIN":
+ case CRYPTO_BEGIN:
crypto = new StringBuilder();
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
break;
- case "-----END":
- crypto.append(line).append("\n");
+ case CRYPTO_END:
+ crypto.append(line).append(NL);
String cryptoString = crypto.toString();
crypto = null;
- if (nextCrypto.equals("directory-signature")) {
+ if (nextCrypto.equals(Key.DIRECTORY_SIGNATURE)) {
this.directorySignature = cryptoString;
} else {
throw new DescriptorParseException("Unrecognized crypto "
+ "block in v2 network status.");
}
- nextCrypto = "";
+ nextCrypto = Key.EMPTY;
break;
default:
if (crypto != null) {
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
} else if (this.failUnrecognizedDescriptorLines) {
throw new DescriptorParseException("Unrecognized line '"
+ line + "' in v2 network status.");
@@ -212,7 +212,7 @@ public class RelayNetworkStatusImpl extends NetworkStatusImpl
private void parseNetworkStatusVersionLine(String line, String[] parts)
throws DescriptorParseException {
- if (!line.equals("network-status-version 2")) {
+ if (!line.equals(Key.NETWORK_STATUS_VERSION.keyword + SP + "2")) {
throw new DescriptorParseException("Illegal network status version "
+ "number in line '" + line + "'.");
}
@@ -246,8 +246,8 @@ public class RelayNetworkStatusImpl extends NetworkStatusImpl
private void parseContactLine(String line, String[] parts)
throws DescriptorParseException {
- if (line.length() > "contact ".length()) {
- this.contactLine = line.substring("contact ".length());
+ if (line.length() > Key.CONTACT.keyword.length() + 1) {
+ this.contactLine = line.substring(Key.CONTACT.keyword.length() + 1);
} else {
this.contactLine = "";
}
@@ -255,7 +255,7 @@ public class RelayNetworkStatusImpl extends NetworkStatusImpl
private void parseDirSigningKeyLine(String line, String[] parts)
throws DescriptorParseException {
- if (!line.equals("dir-signing-key")) {
+ if (!line.equals(Key.DIR_SIGNING_KEY.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
}
diff --git a/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java b/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java
index 05f5cc2..c645928 100644
--- a/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java
@@ -12,7 +12,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashSet;
+import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
@@ -33,7 +33,7 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl
List<RelayNetworkStatusVote> parsedVotes = new ArrayList<>();
List<byte[]> splitVotesBytes =
DescriptorImpl.splitRawDescriptorBytes(votesBytes,
- "network-status-version 3");
+ Key.NETWORK_STATUS_VERSION.keyword + SP + "3");
for (byte[] voteBytes : splitVotesBytes) {
RelayNetworkStatusVote parsedVote =
new RelayNetworkStatusVoteImpl(voteBytes,
@@ -47,27 +47,25 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl
boolean failUnrecognizedDescriptorLines)
throws DescriptorParseException {
super(voteBytes, failUnrecognizedDescriptorLines, false, false);
- Set<String> exactlyOnceKeywords = new HashSet<>(Arrays.asList((
- "vote-status,published,valid-after,fresh-until,"
- + "valid-until,voting-delay,known-flags,dir-source,"
- + "dir-key-certificate-version,fingerprint,dir-key-published,"
- + "dir-key-expires,dir-identity-key,dir-signing-key,"
- + "dir-key-certification").split(",")));
- this.checkExactlyOnceKeywords(exactlyOnceKeywords);
- Set<String> atMostOnceKeywords = new HashSet<>(Arrays.asList((
- "consensus-methods,client-versions,server-versions,"
- + "recommended-client-protocols,recommended-relay-protocols,"
- + "required-client-protocols,required-relay-protocols,"
- + "flag-thresholds,params,contact,shared-rand-participate,"
- + "shared-rand-previous-value,shared-rand-current-value,"
- + "legacy-key,dir-key-crosscert,dir-address,directory-footer")
- .split(",")));
- this.checkAtMostOnceKeywords(atMostOnceKeywords);
- Set<String> atLeastOnceKeywords = new HashSet<>(Arrays.asList(
- "directory-signature"));
- this.checkAtLeastOnceKeywords(atLeastOnceKeywords);
- this.checkFirstKeyword("network-status-version");
- this.clearParsedKeywords();
+ Set<Key> exactlyOnceKeys = EnumSet.of(
+ Key.VOTE_STATUS, Key.PUBLISHED, Key.VALID_AFTER, Key.FRESH_UNTIL,
+ Key.VALID_UNTIL, Key.VOTING_DELAY, Key.KNOWN_FLAGS, Key.DIR_SOURCE,
+ Key.DIR_KEY_CERTIFICATE_VERSION, Key.FINGERPRINT, Key.DIR_KEY_PUBLISHED,
+ Key.DIR_KEY_EXPIRES, Key.DIR_IDENTITY_KEY, Key.DIR_SIGNING_KEY,
+ Key.DIR_KEY_CERTIFICATION);
+ this.checkExactlyOnceKeys(exactlyOnceKeys);
+ Set<Key> atMostOnceKeys = EnumSet.of(
+ Key.CONSENSUS_METHODS, Key.CLIENT_VERSIONS, Key.SERVER_VERSIONS,
+ Key.RECOMMENDED_CLIENT_PROTOCOLS, Key.RECOMMENDED_RELAY_PROTOCOLS,
+ Key.REQUIRED_CLIENT_PROTOCOLS, Key.REQUIRED_RELAY_PROTOCOLS,
+ Key.FLAG_THRESHOLDS, Key.PARAMS, Key.CONTACT,
+ Key.SHARED_RAND_PARTICIPATE, Key.SHARED_RAND_PREVIOUS_VALUE,
+ Key.SHARED_RAND_CURRENT_VALUE, Key.LEGACY_KEY, Key.DIR_KEY_CROSSCERT,
+ Key.DIR_ADDRESS, Key.DIRECTORY_FOOTER);
+ this.checkAtMostOnceKeys(atMostOnceKeys);
+ this.checkAtLeastOnceKeys(EnumSet.of(Key.DIRECTORY_SIGNATURE));
+ this.checkFirstKey(Key.NETWORK_STATUS_VERSION);
+ this.clearParsedKeys();
this.calculateDigest();
}
@@ -116,150 +114,150 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl
this.enoughMtbfInfo = -1;
this.ignoringAdvertisedBws = -1;
- Scanner scanner = new Scanner(new String(headerBytes)).useDelimiter("\n");
- String nextCrypto = "";
+ Scanner scanner = new Scanner(new String(headerBytes)).useDelimiter(NL);
+ Key nextCrypto = Key.EMPTY;
StringBuilder crypto = null;
while (scanner.hasNext()) {
String line = scanner.next();
String[] parts = line.split("[ \t]+");
- String keyword = parts[0];
- switch (keyword) {
- case "network-status-version":
+ Key key = Key.get(parts[0]);
+ switch (key) {
+ case NETWORK_STATUS_VERSION:
this.parseNetworkStatusVersionLine(line, parts);
break;
- case "vote-status":
+ case VOTE_STATUS:
this.parseVoteStatusLine(line, parts);
break;
- case "consensus-methods":
+ case CONSENSUS_METHODS:
this.parseConsensusMethodsLine(line, parts);
break;
- case "published":
+ case PUBLISHED:
this.parsePublishedLine(line, parts);
break;
- case "valid-after":
+ case VALID_AFTER:
this.parseValidAfterLine(line, parts);
break;
- case "fresh-until":
+ case FRESH_UNTIL:
this.parseFreshUntilLine(line, parts);
break;
- case "valid-until":
+ case VALID_UNTIL:
this.parseValidUntilLine(line, parts);
break;
- case "voting-delay":
+ case VOTING_DELAY:
this.parseVotingDelayLine(line, parts);
break;
- case "client-versions":
+ case CLIENT_VERSIONS:
this.parseClientVersionsLine(line, parts);
break;
- case "server-versions":
+ case SERVER_VERSIONS:
this.parseServerVersionsLine(line, parts);
break;
- case "recommended-client-protocols":
+ case RECOMMENDED_CLIENT_PROTOCOLS:
this.parseRecommendedClientProtocolsLine(line, parts);
break;
- case "recommended-relay-protocols":
+ case RECOMMENDED_RELAY_PROTOCOLS:
this.parseRecommendedRelayProtocolsLine(line, parts);
break;
- case "required-client-protocols":
+ case REQUIRED_CLIENT_PROTOCOLS:
this.parseRequiredClientProtocolsLine(line, parts);
break;
- case "required-relay-protocols":
+ case REQUIRED_RELAY_PROTOCOLS:
this.parseRequiredRelayProtocolsLine(line, parts);
break;
- case "package":
+ case PACKAGE:
this.parsePackageLine(line, parts);
break;
- case "known-flags":
+ case KNOWN_FLAGS:
this.parseKnownFlagsLine(line, parts);
break;
- case "flag-thresholds":
+ case FLAG_THRESHOLDS:
this.parseFlagThresholdsLine(line, parts);
break;
- case "params":
+ case PARAMS:
this.parseParamsLine(line, parts);
break;
- case "dir-source":
+ case DIR_SOURCE:
this.parseDirSourceLine(line, parts);
break;
- case "contact":
+ case CONTACT:
this.parseContactLine(line, parts);
break;
- case "shared-rand-participate":
+ case SHARED_RAND_PARTICIPATE:
this.parseSharedRandParticipateLine(line, parts);
break;
- case "shared-rand-commit":
+ case SHARED_RAND_COMMIT:
this.parseSharedRandCommitLine(line, parts);
break;
- case "shared-rand-previous-value":
+ case SHARED_RAND_PREVIOUS_VALUE:
this.parseSharedRandPreviousValueLine(line, parts);
break;
- case "shared-rand-current-value":
+ case SHARED_RAND_CURRENT_VALUE:
this.parseSharedRandCurrentValueLine(line, parts);
break;
- case "dir-key-certificate-version":
+ case DIR_KEY_CERTIFICATE_VERSION:
this.parseDirKeyCertificateVersionLine(line, parts);
break;
- case "dir-address":
+ case DIR_ADDRESS:
this.parseDirAddressLine(line, parts);
break;
- case "fingerprint":
+ case FINGERPRINT:
this.parseFingerprintLine(line, parts);
break;
- case "legacy-dir-key":
+ case LEGACY_DIR_KEY:
this.parseLegacyDirKeyLine(line, parts);
break;
- case "dir-key-published":
+ case DIR_KEY_PUBLISHED:
this.parseDirKeyPublished(line, parts);
break;
- case "dir-key-expires":
+ case DIR_KEY_EXPIRES:
this.parseDirKeyExpiresLine(line, parts);
break;
- case "dir-identity-key":
+ case DIR_IDENTITY_KEY:
this.parseDirIdentityKeyLine(line, parts);
- nextCrypto = "dir-identity-key";
+ nextCrypto = key;
break;
- case "dir-signing-key":
+ case DIR_SIGNING_KEY:
this.parseDirSigningKeyLine(line, parts);
- nextCrypto = "dir-signing-key";
+ nextCrypto = key;
break;
- case "dir-key-crosscert":
+ case DIR_KEY_CROSSCERT:
this.parseDirKeyCrosscertLine(line, parts);
- nextCrypto = "dir-key-crosscert";
+ nextCrypto = key;
break;
- case "dir-key-certification":
+ case DIR_KEY_CERTIFICATION:
this.parseDirKeyCertificationLine(line, parts);
- nextCrypto = "dir-key-certification";
+ nextCrypto = key;
break;
- case "-----BEGIN":
+ case CRYPTO_BEGIN:
crypto = new StringBuilder();
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
break;
- case "-----END":
- crypto.append(line).append("\n");
+ case CRYPTO_END:
+ crypto.append(line).append(NL);
String cryptoString = crypto.toString();
crypto = null;
switch (nextCrypto) {
- case "dir-identity-key":
+ case DIR_IDENTITY_KEY:
this.dirIdentityKey = cryptoString;
break;
- case "dir-signing-key":
+ case DIR_SIGNING_KEY:
this.dirSigningKey = cryptoString;
break;
- case "dir-key-crosscert":
+ case DIR_KEY_CROSSCERT:
this.dirKeyCrosscert = cryptoString;
break;
- case "dir-key-certification":
+ case DIR_KEY_CERTIFICATION:
this.dirKeyCertification = cryptoString;
break;
default:
throw new DescriptorParseException("Unrecognized crypto "
+ "block in vote.");
}
- nextCrypto = "";
+ nextCrypto = Key.EMPTY;
break;
default:
if (crypto != null) {
- crypto.append(line).append("\n");
+ crypto.append(line).append(NL);
} else {
if (this.failUnrecognizedDescriptorLines) {
throw new DescriptorParseException("Unrecognized line '"
@@ -277,7 +275,7 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl
private void parseNetworkStatusVersionLine(String line, String[] parts)
throws DescriptorParseException {
- if (!line.equals("network-status-version 3")) {
+ if (!line.equals(Key.NETWORK_STATUS_VERSION.keyword + SP + "3")) {
throw new DescriptorParseException("Illegal network status version "
+ "number in line '" + line + "'.");
}
@@ -399,7 +397,7 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl
if (this.packageLines == null) {
this.packageLines = new ArrayList<>();
}
- this.packageLines.add(line.substring("package ".length()));
+ this.packageLines.add(line.substring(Key.PACKAGE.keyword.length() + 1));
}
private void parseKnownFlagsLine(String line, String[] parts)
@@ -492,8 +490,8 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl
private void parseContactLine(String line, String[] parts)
throws DescriptorParseException {
- if (line.length() > "contact ".length()) {
- this.contactLine = line.substring("contact ".length());
+ if (line.length() > Key.CONTACT.keyword.length() + 1) {
+ this.contactLine = line.substring(Key.CONTACT.keyword.length() + 1);
} else {
this.contactLine = "";
}
@@ -604,38 +602,38 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl
private void parseDirIdentityKeyLine(String line, String[] parts)
throws DescriptorParseException {
- if (!line.equals("dir-identity-key")) {
+ if (!line.equals(Key.DIR_IDENTITY_KEY.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
}
private void parseDirSigningKeyLine(String line, String[] parts)
throws DescriptorParseException {
- if (!line.equals("dir-signing-key")) {
+ if (!line.equals(Key.DIR_SIGNING_KEY.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
}
private void parseDirKeyCrosscertLine(String line, String[] parts)
throws DescriptorParseException {
- if (!line.equals("dir-key-crosscert")) {
+ if (!line.equals(Key.DIR_KEY_CROSSCERT.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
}
private void parseDirKeyCertificationLine(String line, String[] parts)
throws DescriptorParseException {
- if (!line.equals("dir-key-certification")) {
+ if (!line.equals(Key.DIR_KEY_CERTIFICATION.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
}
protected void parseFooter(byte[] footerBytes)
throws DescriptorParseException {
- Scanner scanner = new Scanner(new String(footerBytes)).useDelimiter("\n");
+ Scanner scanner = new Scanner(new String(footerBytes)).useDelimiter(NL);
while (scanner.hasNext()) {
String line = scanner.next();
- if (!line.equals("directory-footer")) {
+ if (!line.equals(Key.DIRECTORY_FOOTER.keyword)) {
if (this.failUnrecognizedDescriptorLines) {
throw new DescriptorParseException("Unrecognized line '"
+ line + "' in vote.");
diff --git a/src/main/java/org/torproject/descriptor/impl/RelayServerDescriptorImpl.java b/src/main/java/org/torproject/descriptor/impl/RelayServerDescriptorImpl.java
index 3353ec1..eefa24f 100644
--- a/src/main/java/org/torproject/descriptor/impl/RelayServerDescriptorImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/RelayServerDescriptorImpl.java
@@ -19,7 +19,7 @@ public class RelayServerDescriptorImpl extends ServerDescriptorImpl
List<ServerDescriptor> parsedDescriptors = new ArrayList<>();
List<byte[]> splitDescriptorsBytes =
DescriptorImpl.splitRawDescriptorBytes(descriptorsBytes,
- "router ");
+ Key.ROUTER.keyword + SP);
for (byte[] descriptorBytes : splitDescriptorsBytes) {
ServerDescriptor parsedDescriptor =
new RelayServerDescriptorImpl(descriptorBytes,
diff --git a/src/main/java/org/torproject/descriptor/impl/ServerDescriptorImpl.java b/src/main/java/org/torproject/descriptor/impl/ServerDescriptorImpl.java
index ac113d2..70bd42c 100644
--- a/src/main/java/org/torproject/descriptor/impl/ServerDescriptorImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/ServerDescriptorImpl.java
@@ -12,7 +12,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashSet;
+import java.util.EnumSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
@@ -25,6 +25,20 @@ import javax.xml.bind.DatatypeConverter;
public abstract class ServerDescriptorImpl extends DescriptorImpl
implements ServerDescriptor {
+ private static final Set<Key> atMostOnce = EnumSet.of(
+ Key.IDENTITY_ED25519, Key.MASTER_KEY_ED25519, Key.PLATFORM, Key.PROTO,
+ Key.FINGERPRINT, Key.HIBERNATING, Key.UPTIME, Key.CONTACT, Key.FAMILY,
+ Key.READ_HISTORY, Key.WRITE_HISTORY, Key.EVENTDNS, Key.CACHES_EXTRA_INFO,
+ Key.EXTRA_INFO_DIGEST, Key.HIDDEN_SERVICE_DIR, Key.PROTOCOLS,
+ Key.ALLOW_SINGLE_HOP_EXITS, Key.ONION_KEY, Key.SIGNING_KEY,
+ Key.IPV6_POLICY, Key.NTOR_ONION_KEY, Key.ONION_KEY_CROSSCERT,
+ Key.NTOR_ONION_KEY_CROSSCERT, Key.TUNNELLED_DIR_SERVER,
+ Key.ROUTER_SIG_ED25519, Key.ROUTER_SIGNATURE, Key.ROUTER_DIGEST_SHA256,
+ Key.ROUTER_DIGEST);
+
+ private static final Set<Key> exactlyOnce = EnumSet.of(
+ Key.ROUTER, Key.BANDWIDTH, Key.PUBLISHED);
+
protected ServerDescriptorImpl(byte[] descriptorBytes,
boolean failUnrecognizedDescriptorLines)
throws DescriptorParseException {
@@ -32,184 +46,173 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
this.parseDescriptorBytes();
this.calculateDigest();
this.calculateDigestSha256();
- Set<String> exactlyOnceKeywords = new HashSet<>(Arrays.asList(
- "router,bandwidth,published".split(",")));
- this.checkExactlyOnceKeywords(exactlyOnceKeywords);
- Set<String> atMostOnceKeywords = new HashSet<>(Arrays.asList((
- "identity-ed25519,master-key-ed25519,platform,proto,fingerprint,"
- + "hibernating,uptime,contact,family,read-history,write-history,"
- + "eventdns,caches-extra-info,extra-info-digest,"
- + "hidden-service-dir,protocols,allow-single-hop-exits,onion-key,"
- + "signing-key,ipv6-policy,ntor-onion-key,onion-key-crosscert,"
- + "ntor-onion-key-crosscert,tunnelled-dir-server,"
- + "router-sig-ed25519,router-signature,router-digest-sha256,"
- + "router-digest").split(",")));
- this.checkAtMostOnceKeywords(atMostOnceKeywords);
- this.checkFirstKeyword("router");
- if (this.getKeywordCount("accept") == 0
- && this.getKeywordCount("reject") == 0) {
+ this.checkExactlyOnceKeys(exactlyOnce);
+ this.checkAtMostOnceKeys(atMostOnce);
+ this.checkFirstKey(Key.ROUTER);
+ if (this.getKeyCount(Key.ACCEPT) == 0
+ && this.getKeyCount(Key.REJECT) == 0) {
throw new DescriptorParseException("Either keyword 'accept' or "
+ "'reject' must be contained at least once.");
}
- this.clearParsedKeywords();
+ this.clearParsedKeys();
return;
}
private void parseDescriptorBytes() throws DescriptorParseException {
Scanner scanner = new Scanner(new String(this.rawDescriptorBytes))
- .useDelimiter("\n");
- String nextCrypto = "";
+ .useDelimiter(NL);
+ Key nextCrypto = Key.EMPTY;
List<String> cryptoLines = null;
while (scanner.hasNext()) {
String line = scanner.next();
if (line.startsWith("@")) {
continue;
}
- String lineNoOpt = line.startsWith("opt ")
- ? line.substring("opt ".length()) : line;
+ String lineNoOpt = line.startsWith(Key.OPT.keyword + SP)
+ ? line.substring(Key.OPT.keyword.length() + 1) : line;
String[] partsNoOpt = lineNoOpt.split("[ \t]+");
- String keyword = partsNoOpt[0];
- switch (keyword) {
- case "router":
+ Key key = Key.get(partsNoOpt[0]);
+ switch (key) {
+ case ROUTER:
this.parseRouterLine(line, lineNoOpt, partsNoOpt);
break;
- case "or-address":
+ case OR_ADDRESS:
this.parseOrAddressLine(line, lineNoOpt, partsNoOpt);
break;
- case "bandwidth":
+ case BANDWIDTH:
this.parseBandwidthLine(line, lineNoOpt, partsNoOpt);
break;
- case "platform":
+ case PLATFORM:
this.parsePlatformLine(line, lineNoOpt, partsNoOpt);
break;
- case "proto":
+ case PROTO:
this.parseProtoLine(line, lineNoOpt, partsNoOpt);
break;
- case "published":
+ case PUBLISHED:
this.parsePublishedLine(line, lineNoOpt, partsNoOpt);
break;
- case "fingerprint":
+ case FINGERPRINT:
this.parseFingerprintLine(line, lineNoOpt, partsNoOpt);
break;
- case "hibernating":
+ case HIBERNATING:
this.parseHibernatingLine(line, lineNoOpt, partsNoOpt);
break;
- case "uptime":
+ case UPTIME:
this.parseUptimeLine(line, lineNoOpt, partsNoOpt);
break;
- case "onion-key":
+ case ONION_KEY:
this.parseOnionKeyLine(line, lineNoOpt, partsNoOpt);
- nextCrypto = "onion-key";
+ nextCrypto = key;
break;
- case "signing-key":
+ case SIGNING_KEY:
this.parseSigningKeyLine(line, lineNoOpt, partsNoOpt);
- nextCrypto = "signing-key";
+ nextCrypto = key;
break;
- case "accept":
+ case ACCEPT:
this.parseAcceptLine(line, lineNoOpt, partsNoOpt);
break;
- case "reject":
+ case REJECT:
this.parseRejectLine(line, lineNoOpt, partsNoOpt);
break;
- case "router-signature":
+ case ROUTER_SIGNATURE:
this.parseRouterSignatureLine(line, lineNoOpt, partsNoOpt);
- nextCrypto = "router-signature";
+ nextCrypto = key;
break;
- case "contact":
+ case CONTACT:
this.parseContactLine(line, lineNoOpt, partsNoOpt);
break;
- case "family":
+ case FAMILY:
this.parseFamilyLine(line, lineNoOpt, partsNoOpt);
break;
- case "read-history":
+ case READ_HISTORY:
this.parseReadHistoryLine(line, lineNoOpt, partsNoOpt);
break;
- case "write-history":
+ case WRITE_HISTORY:
this.parseWriteHistoryLine(line, lineNoOpt, partsNoOpt);
break;
- case "eventdns":
+ case EVENTDNS:
this.parseEventdnsLine(line, lineNoOpt, partsNoOpt);
break;
- case "caches-extra-info":
+ case CACHES_EXTRA_INFO:
this.parseCachesExtraInfoLine(line, lineNoOpt, partsNoOpt);
break;
- case "extra-info-digest":
+ case EXTRA_INFO_DIGEST:
this.parseExtraInfoDigestLine(line, lineNoOpt, partsNoOpt);
break;
- case "hidden-service-dir":
+ case HIDDEN_SERVICE_DIR:
this.parseHiddenServiceDirLine(line, lineNoOpt, partsNoOpt);
break;
- case "protocols":
+ case PROTOCOLS:
this.parseProtocolsLine(line, lineNoOpt, partsNoOpt);
break;
- case "allow-single-hop-exits":
+ case ALLOW_SINGLE_HOP_EXITS:
this.parseAllowSingleHopExitsLine(line, lineNoOpt, partsNoOpt);
break;
- case "dircacheport":
+ case DIRCACHEPORT:
this.parseDircacheportLine(line, lineNoOpt, partsNoOpt);
break;
- case "router-digest":
+ case ROUTER_DIGEST:
this.parseRouterDigestLine(line, lineNoOpt, partsNoOpt);
break;
- case "router-digest-sha256":
+ case ROUTER_DIGEST_SHA256:
this.parseRouterDigestSha256Line(line, lineNoOpt, partsNoOpt);
break;
- case "ipv6-policy":
+ case IPV6_POLICY:
this.parseIpv6PolicyLine(line, lineNoOpt, partsNoOpt);
break;
- case "ntor-onion-key":
+ case NTOR_ONION_KEY:
this.parseNtorOnionKeyLine(line, lineNoOpt, partsNoOpt);
break;
- case "identity-ed25519":
+ case IDENTITY_ED25519:
this.parseIdentityEd25519Line(line, lineNoOpt, partsNoOpt);
- nextCrypto = "identity-ed25519";
+ nextCrypto = key;
break;
- case "master-key-ed25519":
+ case MASTER_KEY_ED25519:
this.parseMasterKeyEd25519Line(line, lineNoOpt, partsNoOpt);
break;
- case "router-sig-ed25519":
+ case ROUTER_SIG_ED25519:
this.parseRouterSigEd25519Line(line, lineNoOpt, partsNoOpt);
break;
- case "onion-key-crosscert":
+ case ONION_KEY_CROSSCERT:
this.parseOnionKeyCrosscert(line, lineNoOpt, partsNoOpt);
- nextCrypto = "onion-key-crosscert";
+ nextCrypto = key;
break;
- case "ntor-onion-key-crosscert":
+ case NTOR_ONION_KEY_CROSSCERT:
this.parseNtorOnionKeyCrosscert(line, lineNoOpt, partsNoOpt);
- nextCrypto = "ntor-onion-key-crosscert";
+ nextCrypto = key;
break;
- case "tunnelled-dir-server":
+ case TUNNELLED_DIR_SERVER:
this.parseTunnelledDirServerLine(line, lineNoOpt, partsNoOpt);
break;
- case "-----BEGIN":
+ case CRYPTO_BEGIN:
cryptoLines = new ArrayList<>();
cryptoLines.add(line);
break;
- case "-----END":
+ case CRYPTO_END:
cryptoLines.add(line);
StringBuilder sb = new StringBuilder();
for (String cryptoLine : cryptoLines) {
- sb.append("\n").append(cryptoLine);
+ sb.append(NL).append(cryptoLine);
}
String cryptoString = sb.toString().substring(1);
switch (nextCrypto) {
- case "onion-key":
+ case ONION_KEY:
this.onionKey = cryptoString;
break;
- case "signing-key":
+ case SIGNING_KEY:
this.signingKey = cryptoString;
break;
- case "router-signature":
+ case ROUTER_SIGNATURE:
this.routerSignature = cryptoString;
break;
- case "identity-ed25519":
+ case IDENTITY_ED25519:
this.identityEd25519 = cryptoString;
this.parseIdentityEd25519CryptoBlock(cryptoString);
break;
- case "onion-key-crosscert":
+ case ONION_KEY_CROSSCERT:
this.onionKeyCrosscert = cryptoString;
break;
- case "ntor-onion-key-crosscert":
+ case NTOR_ONION_KEY_CROSSCERT:
this.ntorOnionKeyCrosscert = cryptoString;
break;
default:
@@ -224,8 +227,9 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
}
}
cryptoLines = null;
- nextCrypto = "";
+ nextCrypto = Key.EMPTY;
break;
+ case INVALID:
default:
if (cryptoLines != null) {
cryptoLines.add(line);
@@ -301,8 +305,8 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
private void parsePlatformLine(String line, String lineNoOpt,
String[] partsNoOpt) throws DescriptorParseException {
- if (lineNoOpt.length() > "platform ".length()) {
- this.platform = lineNoOpt.substring("platform ".length());
+ if (lineNoOpt.length() > Key.PLATFORM.keyword.length() + 1) {
+ this.platform = lineNoOpt.substring(Key.PLATFORM.keyword.length() + 1);
} else {
this.platform = "";
}
@@ -322,11 +326,12 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
private void parseFingerprintLine(String line, String lineNoOpt,
String[] partsNoOpt) throws DescriptorParseException {
- if (lineNoOpt.length() != "fingerprint".length() + 5 * 10) {
+ if (lineNoOpt.length() != Key.FINGERPRINT.keyword.length() + 5 * 10) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
this.fingerprint = ParseHelper.parseTwentyByteHexString(line,
- lineNoOpt.substring("fingerprint ".length()).replaceAll(" ", ""));
+ lineNoOpt.substring(Key.FINGERPRINT.keyword.length() + 1)
+ .replaceAll(SP, ""));
}
private void parseHibernatingLine(String line, String lineNoOpt,
@@ -358,14 +363,14 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
private void parseOnionKeyLine(String line, String lineNoOpt,
String[] partsNoOpt) throws DescriptorParseException {
- if (!lineNoOpt.equals("onion-key")) {
+ if (!lineNoOpt.equals(Key.ONION_KEY.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
}
private void parseSigningKeyLine(String line, String lineNoOpt,
String[] partsNoOpt) throws DescriptorParseException {
- if (!lineNoOpt.equals("signing-key")) {
+ if (!lineNoOpt.equals(Key.SIGNING_KEY.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
}
@@ -391,15 +396,15 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
private void parseRouterSignatureLine(String line, String lineNoOpt,
String[] partsNoOpt) throws DescriptorParseException {
- if (!lineNoOpt.equals("router-signature")) {
+ if (!lineNoOpt.equals(Key.ROUTER_SIGNATURE.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
}
private void parseContactLine(String line, String lineNoOpt,
String[] partsNoOpt) throws DescriptorParseException {
- if (lineNoOpt.length() > "contact ".length()) {
- this.contact = lineNoOpt.substring("contact ".length());
+ if (lineNoOpt.length() > Key.CONTACT.keyword.length() + 1) {
+ this.contact = lineNoOpt.substring(Key.CONTACT.keyword.length() + 1);
} else {
this.contact = "";
}
@@ -455,7 +460,7 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
private void parseCachesExtraInfoLine(String line, String lineNoOpt,
String[] partsNoOpt) throws DescriptorParseException {
- if (!lineNoOpt.equals("caches-extra-info")) {
+ if (!lineNoOpt.equals(Key.CACHES_EXTRA_INFO.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
this.cachesExtraInfo = true;
@@ -532,7 +537,7 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
private void parseAllowSingleHopExitsLine(String line, String lineNoOpt,
String[] partsNoOpt) throws DescriptorParseException {
- if (!lineNoOpt.equals("allow-single-hop-exits")) {
+ if (!lineNoOpt.equals(Key.ALLOW_SINGLE_HOP_EXITS.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
this.allowSingleHopExits = true;
@@ -568,9 +573,9 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
if (partsNoOpt.length != 3) {
isValid = false;
} else {
- switch (partsNoOpt[1]) {
- case "accept":
- case "reject":
+ switch (Key.get(partsNoOpt[1])) {
+ case ACCEPT:
+ case REJECT:
this.ipv6DefaultPolicy = partsNoOpt[1];
this.ipv6PortList = partsNoOpt[2];
String[] ports = partsNoOpt[2].split(",", -1);
@@ -581,6 +586,7 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
}
}
break;
+ case INVALID:
default:
isValid = false;
}
@@ -626,7 +632,7 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
private void parseTunnelledDirServerLine(String line, String lineNoOpt,
String[] partsNoOpt) throws DescriptorParseException {
- if (!lineNoOpt.equals("tunnelled-dir-server")) {
+ if (!lineNoOpt.equals(Key.TUNNELLED_DIR_SERVER.keyword)) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
this.tunnelledDirServer = true;
@@ -684,8 +690,8 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
}
try {
String ascii = new String(this.getRawDescriptorBytes(), "US-ASCII");
- String startToken = "router ";
- String sigToken = "\nrouter-signature\n";
+ String startToken = Key.ROUTER.keyword + SP;
+ String sigToken = NL + Key.ROUTER_SIGNATURE.keyword + NL;
int start = ascii.indexOf(startToken);
int sig = ascii.indexOf(sigToken) + sigToken.length();
if (start >= 0 && sig >= 0 && sig > start) {
@@ -715,7 +721,7 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
}
try {
String ascii = new String(this.getRawDescriptorBytes(), "US-ASCII");
- String startToken = "router ";
+ String startToken = Key.ROUTER.keyword + SP;
String sigToken = "\n-----END SIGNATURE-----\n";
int start = ascii.indexOf(startToken);
int sig = ascii.indexOf(sigToken) + sigToken.length();
1
0
commit bd52bcaeb549b83cdb95238cbd904a3ebe094ebf
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Wed May 17 14:00:41 2017 +0200
Bump version to 1.7.0-dev.
---
build.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.xml b/build.xml
index 950b5c7..0d6608f 100644
--- a/build.xml
+++ b/build.xml
@@ -6,7 +6,7 @@
<project default="usage" name="descriptor" basedir=".">
- <property name="release.version" value="1.7.0" />
+ <property name="release.version" value="1.7.0-dev" />
<property name="javadoc-title" value="DescripTor API Documentation"/>
<property name="javadoc-excludes" value="**/impl/** **/index/**" />
<property name="implementation-title" value="DescripTor" />
1
0

[metrics-lib/release] Move latest change log entry to next release.
by karsten@torproject.org 07 Jun '17
by karsten@torproject.org 07 Jun '17
07 Jun '17
commit 2362535963bfe93815f5e843fbc94ff6f42d6434
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Fri May 26 16:14:17 2017 +0200
Move latest change log entry to next release.
---
CHANGELOG.md | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0e39147..c907cc6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+# Changes in version 1.8.0 - ??
+
+ * Minor changes
+ - Turn keyword strings into enums and use the appropriate enum sets
+ and maps to avoid repeating string literals and to use more speedy
+ collection types.
+
+
# Changes in version 1.7.0 - 2017-05-17
* Medium changes
@@ -18,11 +26,6 @@
descriptor lines, as permitted by dir-spec.txt.
- Streamline digest method names.
- * Minor changes
- - Turn keyword strings into enums and use the appropriate enum sets
- and maps to avoid repeating string literals and to use more speedy
- collection types.
-
# Changes in version 1.6.0 - 2017-02-17
1
0

[metrics-lib/release] Simplify and avoid repetition in parse helper methods.
by karsten@torproject.org 07 Jun '17
by karsten@torproject.org 07 Jun '17
07 Jun '17
commit 38221ed0973ad63e3b47effa39f297f4af0012ae
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Mon May 22 22:15:09 2017 +0200
Simplify and avoid repetition in parse helper methods.
Implements #22279.
---
CHANGELOG.md | 1 +
.../descriptor/impl/BridgeNetworkStatusImpl.java | 2 +-
.../torproject/descriptor/impl/KeyValueMap.java | 71 ++++++++
.../descriptor/impl/NetworkStatusEntryImpl.java | 2 +-
.../torproject/descriptor/impl/ParseHelper.java | 178 ++++-----------------
.../impl/RelayNetworkStatusConsensusImpl.java | 4 +-
.../impl/RelayNetworkStatusVoteImpl.java | 4 +-
.../impl/ExtraInfoDescriptorImplTest.java | 20 ++-
8 files changed, 118 insertions(+), 164 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c907cc6..3ab6955 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
- Turn keyword strings into enums and use the appropriate enum sets
and maps to avoid repeating string literals and to use more speedy
collection types.
+ - Simplify and avoid repetition in parse helper methods.
# Changes in version 1.7.0 - 2017-05-17
diff --git a/src/main/java/org/torproject/descriptor/impl/BridgeNetworkStatusImpl.java b/src/main/java/org/torproject/descriptor/impl/BridgeNetworkStatusImpl.java
index 88411e6..6036e50 100644
--- a/src/main/java/org/torproject/descriptor/impl/BridgeNetworkStatusImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/BridgeNetworkStatusImpl.java
@@ -110,7 +110,7 @@ public class BridgeNetworkStatusImpl extends NetworkStatusImpl
+ line + "'.");
}
SortedMap<String, String> flagThresholds =
- ParseHelper.parseKeyValueStringPairs(line, parts, 1, "=");
+ ParseHelper.parseKeyValueStringPairs(line, parts, 1);
try {
for (Map.Entry<String, String> e : flagThresholds.entrySet()) {
switch (e.getKey()) {
diff --git a/src/main/java/org/torproject/descriptor/impl/KeyValueMap.java b/src/main/java/org/torproject/descriptor/impl/KeyValueMap.java
new file mode 100644
index 0000000..7b918dc
--- /dev/null
+++ b/src/main/java/org/torproject/descriptor/impl/KeyValueMap.java
@@ -0,0 +1,71 @@
+/* Copyright 2017 The Tor Project
+ * See LICENSE for licensing information */
+
+package org.torproject.descriptor.impl;
+
+import org.torproject.descriptor.DescriptorParseException;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.TreeMap;
+
+public class KeyValueMap<T> extends TreeMap<String, T> {
+
+ private Class<T> clazz;
+
+ public KeyValueMap(Class<T> clazz) {
+ super();
+ this.clazz = clazz;
+ }
+
+ private void putPair(String key, T value, String line, String listElement,
+ int keyLength) throws DescriptorParseException {
+ if (this.keySet().contains(key)) {
+ throw new DescriptorParseException("Line '" + line + "' contains "
+ + "duplicate key '" + key + "'.");
+ }
+ if (null == key || key.isEmpty()
+ || (keyLength > 0 && key.length() != keyLength)) {
+ throw new DescriptorParseException("Line '" + line + "' contains an "
+ + "illegal key in list element '" + listElement + "'.");
+ }
+ if (null == value) {
+ throw new DescriptorParseException("Line '" + line + "' contains an "
+ + "illegal value in list element '" + listElement + "'.");
+ }
+ this.put(key, value);
+ }
+
+ /** Extract key value maps of numbers and verify the key-value pairs. */
+ public KeyValueMap<T> parseKeyValueList(String line, String[] partsNoOpt,
+ int startIndex, int keyLength, String separatorPattern)
+ throws DescriptorParseException {
+ if (startIndex >= partsNoOpt.length) {
+ return this;
+ }
+ String[] keysAndValues = " ".equals(separatorPattern) ? partsNoOpt
+ : partsNoOpt[startIndex].split(separatorPattern, -1);
+ for (int i = " ".equals(separatorPattern) ? startIndex : 0;
+ i < keysAndValues.length; i++) {
+ String listElement = keysAndValues[i];
+ String[] keyAndValue = listElement.split("=");
+ String key = keyAndValue[0];
+ T value = null;
+ if (keyAndValue.length == 2) {
+ try {
+ Method method = clazz.getMethod("valueOf", String.class);
+ value = (T) method.invoke(clazz, keyAndValue[1]);
+ } catch (IllegalAccessException | SecurityException e) {
+ throw new RuntimeException("This shouldn't happen.", e);
+ } catch (IllegalArgumentException | InvocationTargetException e) {
+ value = null;
+ } catch (NoSuchMethodException e) { // use the String value
+ value = (T)keyAndValue[1];
+ }
+ }
+ this.putPair(key, value, line, listElement, keyLength);
+ }
+ return this;
+ }
+
+}
diff --git a/src/main/java/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java b/src/main/java/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java
index cb4eca8..fd4b3e3 100644
--- a/src/main/java/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java
@@ -201,7 +201,7 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry {
throws DescriptorParseException {
this.parsedAtMostOnceKey(Key.W);
SortedMap<String, Integer> pairs =
- ParseHelper.parseKeyValueIntegerPairs(line, parts, 1, "=");
+ ParseHelper.parseKeyValueIntegerPairs(line, parts, 1);
if (pairs.isEmpty()) {
throw new DescriptorParseException("Illegal line '" + line + "'.");
}
diff --git a/src/main/java/org/torproject/descriptor/impl/ParseHelper.java b/src/main/java/org/torproject/descriptor/impl/ParseHelper.java
index d5ce50f..cfd3724 100644
--- a/src/main/java/org/torproject/descriptor/impl/ParseHelper.java
+++ b/src/main/java/org/torproject/descriptor/impl/ParseHelper.java
@@ -10,7 +10,6 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.HashMap;
-import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.SortedMap;
@@ -243,37 +242,17 @@ public class ParseHelper {
}
protected static SortedMap<String, String> parseKeyValueStringPairs(
- String line, String[] parts, int startIndex, String separatorString)
+ String line, String[] parts, int startIndex)
throws DescriptorParseException {
- SortedMap<String, String> result = new TreeMap<>();
- for (int i = startIndex; i < parts.length; i++) {
- String pair = parts[i];
- String[] pairParts = pair.split(separatorString);
- if (pairParts.length != 2) {
- throw new DescriptorParseException("Illegal key-value pair in "
- + "line '" + line + "'.");
- }
- result.put(pairParts[0], pairParts[1]);
- }
- return result;
+ return (new KeyValueMap<String>(String.class))
+ .parseKeyValueList(line, parts, startIndex, 0, " ");
}
protected static SortedMap<String, Integer> parseKeyValueIntegerPairs(
- String line, String[] parts, int startIndex, String separatorString)
+ String line, String[] parts, int startIndex)
throws DescriptorParseException {
- SortedMap<String, Integer> result = new TreeMap<>();
- SortedMap<String, String> keyValueStringPairs =
- ParseHelper.parseKeyValueStringPairs(line, parts, startIndex,
- separatorString);
- for (Map.Entry<String, String> e : keyValueStringPairs.entrySet()) {
- try {
- result.put(e.getKey(), Integer.parseInt(e.getValue()));
- } catch (NumberFormatException ex) {
- throw new DescriptorParseException("Illegal value in line '"
- + line + "'.");
- }
- }
- return result;
+ return (new KeyValueMap<Integer>(Integer.class))
+ .parseKeyValueList(line, parts, startIndex, 0, " ");
}
private static Pattern nicknamePattern =
@@ -331,48 +310,22 @@ public class ParseHelper {
.toUpperCase();
}
- private static Map<Integer, Pattern>
- commaSeparatedKeyValueListPatterns = new HashMap<>();
-
protected static String parseCommaSeparatedKeyIntegerValueList(
String line, String[] partsNoOpt, int index, int keyLength)
throws DescriptorParseException {
- String result = "";
- if (partsNoOpt.length < index) {
- throw new DescriptorParseException("Line '" + line + "' does not "
- + "contain a key-value list at index " + index + ".");
- } else if (partsNoOpt.length > index) {
- if (!commaSeparatedKeyValueListPatterns.containsKey(keyLength)) {
- String keyPattern = "[0-9a-zA-Z?<>\\-_]"
- + (keyLength == 0 ? "+" : "{" + keyLength + "}");
- String valuePattern = "\\-?[0-9]{1,9}";
- String patternString = String.format("^%s=%s(,%s=%s)*$",
- keyPattern, valuePattern, keyPattern, valuePattern);
- commaSeparatedKeyValueListPatterns.put(keyLength,
- Pattern.compile(patternString));
- }
- Pattern pattern = commaSeparatedKeyValueListPatterns.get(
- keyLength);
- if (pattern.matcher(partsNoOpt[index]).matches()) {
- result = partsNoOpt[index];
- } else {
- throw new DescriptorParseException("Line '" + line + "' "
- + "contains an illegal key or value.");
- }
- }
- return result;
+ return parseStringKeyIntegerList(line, partsNoOpt, index, keyLength);
}
protected static SortedMap<String, Integer>
convertCommaSeparatedKeyIntegerValueList(String validatedString) {
- SortedMap<String, Integer> result = null;
- if (validatedString != null) {
- result = new TreeMap<>();
- if (validatedString.contains("=")) {
- for (String listElement : validatedString.split(",", -1)) {
- String[] keyAndValue = listElement.split("=");
- result.put(keyAndValue[0], Integer.parseInt(keyAndValue[1]));
- }
+ KeyValueMap<Integer> result = new KeyValueMap<>(Integer.class);
+ if (!validatedString.isEmpty()) {
+ try {
+ result.parseKeyValueList(validatedString,
+ new String[]{ validatedString }, 0, 0, ",");
+ } catch (DescriptorParseException e) {
+ throw new RuntimeException("Should have been caught in earlier "
+ + "validation step, but wasn't. ", e);
}
}
return result;
@@ -382,34 +335,8 @@ public class ParseHelper {
parseCommaSeparatedKeyLongValueList(String line,
String[] partsNoOpt, int index, int keyLength)
throws DescriptorParseException {
- SortedMap<String, Long> result = new TreeMap<>();
- if (partsNoOpt.length < index) {
- throw new DescriptorParseException("Line '" + line + "' does not "
- + "contain a key-value list at index " + index + ".");
- } else if (partsNoOpt.length > index) {
- String[] listElements = partsNoOpt[index].split(",", -1);
- for (String listElement : listElements) {
- String[] keyAndValue = listElement.split("=");
- String key = null;
- long value = -1;
- if (keyAndValue.length == 2 && (keyLength == 0
- || keyAndValue[0].length() == keyLength)) {
- try {
- value = Long.parseLong(keyAndValue[1]);
- key = keyAndValue[0];
- } catch (NumberFormatException e) {
- /* Handle below. */
- }
- }
- if (null == key || key.isEmpty()) {
- throw new DescriptorParseException("Line '" + line + "' "
- + "contains an illegal key or value in list element '"
- + listElement + "'.");
- }
- result.put(key, value);
- }
- }
- return result;
+ return (new KeyValueMap<Long>(Long.class))
+ .parseKeyValueList(line, partsNoOpt, index, keyLength, ",");
}
protected static Integer[] parseCommaSeparatedIntegerValueList(
@@ -464,70 +391,27 @@ public class ParseHelper {
parseSpaceSeparatedStringKeyDoubleValueMap(String line,
String[] partsNoOpt, int startIndex)
throws DescriptorParseException {
- Map<String, Double> result = new LinkedHashMap<>();
- if (partsNoOpt.length < startIndex) {
- throw new DescriptorParseException("Line '" + line + "' does not "
- + "contain a key-value list starting at index " + startIndex
- + ".");
- }
- for (int i = startIndex; i < partsNoOpt.length; i++) {
- String listElement = partsNoOpt[i];
- String[] keyAndValue = listElement.split("=");
- String key = null;
- Double value = null;
- if (keyAndValue.length == 2) {
- try {
- value = Double.parseDouble(keyAndValue[1]);
- key = keyAndValue[0];
- } catch (NumberFormatException e) {
- /* Handle below. */
- }
- }
- if (null == key || key.isEmpty()) {
- throw new DescriptorParseException("Line '" + line + "' contains "
- + "an illegal key or value in list element '" + listElement
- + "'.");
- }
- result.put(key, value);
- }
- return result;
+ return (new KeyValueMap<Double>(Double.class))
+ .parseKeyValueList(line, partsNoOpt, startIndex, -1, " ");
}
protected static Map<String, Long>
parseSpaceSeparatedStringKeyLongValueMap(String line,
String[] partsNoOpt, int startIndex)
throws DescriptorParseException {
- Map<String, Long> result = new LinkedHashMap<>();
- if (partsNoOpt.length < startIndex) {
- throw new DescriptorParseException("Line '" + line + "' does not "
- + "contain a key-value list starting at index " + startIndex
- + ".");
- }
- for (int i = startIndex; i < partsNoOpt.length; i++) {
- String listElement = partsNoOpt[i];
- String[] keyAndValue = listElement.split("=");
- String key = null;
- Long value = null;
- if (keyAndValue.length == 2) {
- try {
- value = Long.parseLong(keyAndValue[1]);
- key = keyAndValue[0];
- } catch (NumberFormatException e) {
- /* Handle below. */
- }
- }
- if (null == key || key.isEmpty()) {
- throw new DescriptorParseException("Line '" + line + "' contains "
- + "an illegal key or value in list element '" + listElement
- + "'.");
- }
- if (result.keySet().contains(key)) {
- throw new DescriptorParseException("Line '" + line + "' contains "
- + "an already defined key '" + key + "'.");
- }
- result.put(key, value);
+ return (new KeyValueMap<Long>(Long.class))
+ .parseKeyValueList(line, partsNoOpt, startIndex, -1, " ");
+ }
+
+ private static String parseStringKeyIntegerList(String line,
+ String[] partsNoOpt, int startIndex, int keyLength)
+ throws DescriptorParseException {
+ if (startIndex >= partsNoOpt.length) {
+ return "";
}
- return result;
+ KeyValueMap<Integer> result = new KeyValueMap<>(Integer.class);
+ result.parseKeyValueList(line, partsNoOpt, startIndex, keyLength, ",");
+ return partsNoOpt[startIndex];
}
protected static String
diff --git a/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java b/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java
index 4570931..43212f3 100644
--- a/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java
@@ -354,7 +354,7 @@ public class RelayNetworkStatusConsensusImpl extends NetworkStatusImpl
private void parseParamsLine(String line, String[] parts)
throws DescriptorParseException {
this.consensusParams = ParseHelper.parseKeyValueIntegerPairs(line,
- parts, 1, "=");
+ parts, 1);
}
private void parseSharedRandPreviousValueLine(String line, String[] parts)
@@ -390,7 +390,7 @@ public class RelayNetworkStatusConsensusImpl extends NetworkStatusImpl
private void parseBandwidthWeightsLine(String line, String[] parts)
throws DescriptorParseException {
this.bandwidthWeights = ParseHelper.parseKeyValueIntegerPairs(line,
- parts, 1, "=");
+ parts, 1);
}
private String consensusDigest;
diff --git a/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java b/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java
index c645928..e5bd052 100644
--- a/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java
@@ -420,7 +420,7 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl
+ line + "'.");
}
SortedMap<String, String> flagThresholds =
- ParseHelper.parseKeyValueStringPairs(line, parts, 1, "=");
+ ParseHelper.parseKeyValueStringPairs(line, parts, 1);
try {
for (Map.Entry<String, String> e : flagThresholds.entrySet()) {
switch (e.getKey()) {
@@ -467,7 +467,7 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl
private void parseParamsLine(String line, String[] parts)
throws DescriptorParseException {
this.consensusParams = ParseHelper.parseKeyValueIntegerPairs(line,
- parts, 1, "=");
+ parts, 1);
}
private void parseDirSourceLine(String line, String[] parts)
diff --git a/src/test/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java b/src/test/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java
index b6e1343..2e7bbc6 100644
--- a/src/test/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java
+++ b/src/test/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java
@@ -1278,12 +1278,9 @@ public class ExtraInfoDescriptorImplTest {
+ "gb=208,");
}
- @Test()
+ @Test(expected = DescriptorParseException.class)
public void testGeoipClientOriginsDuplicate()
throws DescriptorParseException {
- /* dir-spec.txt doesn't say anything about duplicate country codes, so
- * this line is valid, even though it leads to a somewhat undefined
- * parse result. */
GeoipStatsBuilder.createWithGeoipClientOriginsLine(
"geoip-client-origins de=1152,de=952,cn=896,us=712,it=504,"
+ "ru=352,fr=208,gb=208,ir=200");
@@ -1293,8 +1290,8 @@ public class ExtraInfoDescriptorImplTest {
public void testGeoipClientOriginsExtraArg()
throws DescriptorParseException {
GeoipStatsBuilder.createWithGeoipClientOriginsLine(
- "geoip-client-origins de=1152,de=952,cn=896,us=712,it=504 "
- + "ru=352 fr=208 gb=208 ir=200");
+ "geoip-client-origins de=1152,cn=896,us=712,it=504 ru=352 fr=208 "
+ + "gb=208 ir=200");
}
@Test()
@@ -1387,7 +1384,8 @@ public class ExtraInfoDescriptorImplTest {
throws DescriptorParseException {
this.thrown.expect(DescriptorParseException.class);
this.thrown.expectMessage(
- "Line 'dirreq-v3-resp =10848' contains an illegal key or value.");
+ "Line 'dirreq-v3-resp =10848' contains an illegal key in list element "
+ + "'=10848'.");
DirreqStatsBuilder.createWithDirreqV3RespLine("dirreq-v3-resp =10848");
}
@@ -1638,7 +1636,7 @@ public class ExtraInfoDescriptorImplTest {
throws DescriptorParseException {
this.thrown.expect(DescriptorParseException.class);
this.thrown.expectMessage("Line 'exit-kibibytes-written =74647' contains "
- + "an illegal key or value in list element '=74647'.");
+ + "an illegal key in list element '=74647'.");
ExitStatsBuilder.createWithExitKibibytesWrittenLine(
"exit-kibibytes-written =74647");
}
@@ -1846,7 +1844,7 @@ public class ExtraInfoDescriptorImplTest {
public void testPaddingCountsNoKey() throws DescriptorParseException {
this.thrown.expect(DescriptorParseException.class);
this.thrown.expectMessage(Matchers
- .allOf(Matchers.containsString("illegal key or value in list element"),
+ .allOf(Matchers.containsString("illegal key in list element"),
Matchers.containsString("=7")));
DescriptorBuilder.createWithPaddingCountsLine("padding-counts 2017-05-10 "
+ "01:48:43 (86400 s) write-total=9 write-drop=10000 =7 x=8");
@@ -1856,7 +1854,7 @@ public class ExtraInfoDescriptorImplTest {
public void testPaddingCountsNoValue() throws DescriptorParseException {
this.thrown.expect(DescriptorParseException.class);
this.thrown.expectMessage(Matchers
- .allOf(Matchers.containsString("illegal key or value in list element"),
+ .allOf(Matchers.containsString("illegal value in list element"),
Matchers.containsString("'write-drop='")));
DescriptorBuilder.createWithPaddingCountsLine("padding-counts 2017-05-10 "
+ "01:48:43 (86400 s) write-total=7 write-drop= bin-size=10000 ");
@@ -1866,7 +1864,7 @@ public class ExtraInfoDescriptorImplTest {
public void testPaddingCountsKeyRepeated() throws DescriptorParseException {
this.thrown.expect(DescriptorParseException.class);
this.thrown.expectMessage(Matchers
- .allOf(Matchers.containsString("contains an already defined key"),
+ .allOf(Matchers.containsString("contains duplicate key"),
Matchers.containsString("'a'")));
DescriptorBuilder.createWithPaddingCountsLine("padding-counts 2017-05-10 "
+ "01:48:43 (86400 s) a=1 b=2 a=3 b=4");
1
0

[metrics-lib/release] Fix encoding of Microdescriptor's getDigestSha256Base64().
by karsten@torproject.org 07 Jun '17
by karsten@torproject.org 07 Jun '17
07 Jun '17
commit 82f555ee3568193460811f0a20a0f22c334c3b4a
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Mon May 29 13:47:57 2017 +0200
Fix encoding of Microdescriptor's getDigestSha256Base64().
---
CHANGELOG.md | 2 ++
.../java/org/torproject/descriptor/impl/MicrodescriptorImpl.java | 4 ++--
.../org/torproject/descriptor/impl/MicrodescriptorImplTest.java | 6 +++++-
3 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3ab6955..61be7dc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,8 @@
and maps to avoid repeating string literals and to use more speedy
collection types.
- Simplify and avoid repetition in parse helper methods.
+ - Fix a bug where Microdescriptor's getDigestSha256Base64() returns
+ a hex string rather than a base64 string.
# Changes in version 1.7.0 - 2017-05-17
diff --git a/src/main/java/org/torproject/descriptor/impl/MicrodescriptorImpl.java b/src/main/java/org/torproject/descriptor/impl/MicrodescriptorImpl.java
index e8329cc..522da05 100644
--- a/src/main/java/org/torproject/descriptor/impl/MicrodescriptorImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/MicrodescriptorImpl.java
@@ -243,9 +243,9 @@ public class MicrodescriptorImpl extends DescriptorImpl
byte[] forDigest = new byte[end - start];
System.arraycopy(this.getRawDescriptorBytes(), start,
forDigest, 0, end - start);
- this.microdescriptorDigest = DatatypeConverter.printHexBinary(
+ this.microdescriptorDigest = DatatypeConverter.printBase64Binary(
MessageDigest.getInstance("SHA-256").digest(forDigest))
- .toLowerCase();
+ .replaceAll("=", "");
}
} catch (UnsupportedEncodingException e) {
/* Handle below. */
diff --git a/src/test/java/org/torproject/descriptor/impl/MicrodescriptorImplTest.java b/src/test/java/org/torproject/descriptor/impl/MicrodescriptorImplTest.java
index 20b0849..d9040f3 100644
--- a/src/test/java/org/torproject/descriptor/impl/MicrodescriptorImplTest.java
+++ b/src/test/java/org/torproject/descriptor/impl/MicrodescriptorImplTest.java
@@ -3,6 +3,8 @@
package org.torproject.descriptor.impl;
+import static org.junit.Assert.assertEquals;
+
import org.torproject.descriptor.DescriptorParseException;
import org.torproject.descriptor.Microdescriptor;
@@ -57,7 +59,9 @@ public class MicrodescriptorImplTest {
@Test()
public void testDefaults() throws DescriptorParseException {
- DescriptorBuilder.createWithDefaultLines();
+ Microdescriptor micro = DescriptorBuilder.createWithDefaultLines();
+ assertEquals("ER1AC4KqT//o3pJDrqlmej5G2qW1EQYEr/IrMQHNc6I",
+ micro.getDigestSha256Base64());
}
@Test(expected = DescriptorParseException.class)
1
0