commit 723e71a09ea6bfb8ebc4d4b40b51c2ff0aebd510
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Sat Jan 7 10:50:52 2017 +0100
Don't require searches by IPv6 address to start with [.
Implements #16552.
---
CHANGELOG.md | 7 +++++
.../torproject/onionoo/server/RequestHandler.java | 3 +-
.../torproject/onionoo/server/ResourceServlet.java | 18 ++++++++---
.../torproject/onionoo/server/ResponseBuilder.java | 4 +--
src/main/resources/web/index.html | 10 +++----
.../onionoo/server/ResourceServletTest.java | 35 ++++++++++++++++++++++
6 files changed, 65 insertions(+), 12 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bd30ca0..465e145 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# Changes in version 4.0-x.x.x - 2017-xx-xx
+
+ * Medium changes
+ - Accept searches by IPv6 addresses even without leading or
+ enclosing square brackets.
+
+
# Changes in version 3.2-1.1.0 - 2017-01-27
* Major changes
diff --git a/src/main/java/org/torproject/onionoo/server/RequestHandler.java b/src/main/java/org/torproject/onionoo/server/RequestHandler.java
index 49e0259..98ece58 100644
--- a/src/main/java/org/torproject/onionoo/server/RequestHandler.java
+++ b/src/main/java/org/torproject/onionoo/server/RequestHandler.java
@@ -261,7 +261,8 @@ public class RequestHandler {
} else {
List<String> addresses = entry.getAddresses();
for (String address : addresses) {
- if (address.startsWith(searchTerm.toLowerCase())) {
+ if (address.startsWith(searchTerm.toLowerCase())
+ || address.startsWith("[" + searchTerm.toLowerCase())) {
/* Address matches. */
lineMatches = true;
break;
diff --git a/src/main/java/org/torproject/onionoo/server/ResourceServlet.java b/src/main/java/org/torproject/onionoo/server/ResourceServlet.java
index 9a4c679..c5fd949 100644
--- a/src/main/java/org/torproject/onionoo/server/ResourceServlet.java
+++ b/src/main/java/org/torproject/onionoo/server/ResourceServlet.java
@@ -75,6 +75,12 @@ public class ResourceServlet extends HttpServlet {
new HashSet<>(Arrays.asList(("search,fingerprint,order,limit,"
+ "offset,fields").split(",")));
+ private static String ipv6AddressPatternString =
+ "^\\[?[0-9a-fA-F:\\.]{1,39}\\]?$";
+
+ private static Pattern ipv6AddressPattern =
+ Pattern.compile(ipv6AddressPatternString);
+
/** Handles the HTTP GET request in the wrapped <code>request</code> by
* writing an HTTP GET response to the likewise <code>response</code>,
* both of which are wrapped to facilitate testing. */
@@ -150,13 +156,17 @@ public class ResourceServlet extends HttpServlet {
}
List<String> unqualifiedSearchTerms = new ArrayList<>();
for (String searchTerm : searchTerms) {
- if (searchTerm.contains(":") && !searchTerm.startsWith("[")) {
+ if (searchTerm.contains(":")) {
String[] parts = searchTerm.split(":", 2);
String parameterKey = parts[0];
if (!knownParameters.contains(parameterKey)
|| illegalSearchQualifiers.contains(parameterKey)) {
- response.sendError(HttpServletResponse.SC_BAD_REQUEST);
- return;
+ if (ipv6AddressPattern.matcher(parameterKey).matches()) {
+ unqualifiedSearchTerms.add(searchTerm);
+ } else {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ }
}
if (!parameterMap.containsKey(parameterKey)) {
String parameterValue = parts[1];
@@ -369,7 +379,7 @@ public class ResourceServlet extends HttpServlet {
Pattern.compile("^\\$?[0-9a-fA-F]{1,40}$|" /* Hex fingerprint. */
+ "^[0-9a-zA-Z+/]{1,27}$|" /* Base64 fingerprint. */
+ "^[0-9a-zA-Z\\.]{1,19}$|" /* Nickname or IPv4 address. */
- + "^\\[[0-9a-fA-F:\\.]{1,39}\\]?$|" /* IPv6 address. */
+ + ipv6AddressPatternString + "|" /* IPv6 address. */
+ "^[a-zA-Z_]+:\\p{Graph}+$" /* Qualified search term. */);
protected static String[] parseSearchParameters(String queryString) {
diff --git a/src/main/java/org/torproject/onionoo/server/ResponseBuilder.java b/src/main/java/org/torproject/onionoo/server/ResponseBuilder.java
index e07868a..c9cec32 100644
--- a/src/main/java/org/torproject/onionoo/server/ResponseBuilder.java
+++ b/src/main/java/org/torproject/onionoo/server/ResponseBuilder.java
@@ -102,9 +102,9 @@ public class ResponseBuilder {
return this.charsWritten;
}
- private static final String PROTOCOL_VERSION = "3.2";
+ private static final String PROTOCOL_VERSION = "4.0";
- private static final String NEXT_MAJOR_VERSION_SCHEDULED = "2017-02-27";
+ private static final String NEXT_MAJOR_VERSION_SCHEDULED = null;
private void writeRelays(List<SummaryDocument> relays, PrintWriter pw) {
this.write(pw, "{\"version\":\"%s\",\n", PROTOCOL_VERSION);
diff --git a/src/main/resources/web/index.html b/src/main/resources/web/index.html
index 6e863e5..d8fe74a 100644
--- a/src/main/resources/web/index.html
+++ b/src/main/resources/web/index.html
@@ -346,10 +346,9 @@ characters of a space-separated fingerprint on November 15, 2015.</li>
<li><strong>3.2</strong>: Extended order parameter to "first_seen" and
added response meta data fields "relays_skipped", "relays_truncated",
"bridges_skipped", and "bridges_truncated" on January 27, 2017.</li>
-<li><strong>4.0</strong>: (scheduled, but not deployed yet!): Extend
-search parameter to not require leading or enclosing square brackets
-around IPv6 addresses anymore, to be deployed by February 27,
-2017.</li>
+<li><strong>4.0</strong>: Extended search parameter to not require
+leading or enclosing square brackets around IPv6 addresses anymore on
+February 28, 2017.</li>
</ul>
@@ -456,7 +455,8 @@ Return only (1) relays with the parameter value matching (part of a)
nickname, (possibly $-prefixed) beginning of a hex-encoded fingerprint,
any 4 hex characters of a space-separated fingerprint, beginning of a
base64-encoded fingerprint without trailing equal signs, or beginning of
-an IP address, (2) bridges with (part of a) nickname or (possibly
+an IP address (possibly enclosed in square brackets in case of IPv6),
+(2) bridges with (part of a) nickname or (possibly
$-prefixed) beginning of a hashed hex-encoded fingerprint, and (3) relays
and/or bridges matching a given qualified search term.
Searches by relay IP address include all known addresses used for onion
diff --git a/src/test/java/org/torproject/onionoo/server/ResourceServletTest.java b/src/test/java/org/torproject/onionoo/server/ResourceServletTest.java
index e4a9e3d..a28c66b 100644
--- a/src/test/java/org/torproject/onionoo/server/ResourceServletTest.java
+++ b/src/test/java/org/torproject/onionoo/server/ResourceServletTest.java
@@ -707,6 +707,34 @@ public class ResourceServletTest {
}
@Test()
+ public void testSearchIpv6Slash64NoBrackets() {
+ this.assertSummaryDocument(
+ "/summary?search=2001:4f8:3:2e::", 1,
+ new String[] { "Ferrari458" }, 0, null);
+ }
+
+ @Test()
+ public void testSearchIpv6Slash8Colon() {
+ this.assertSummaryDocument(
+ "/summary?search=[2001:", 1,
+ new String[] { "Ferrari458" }, 0, null);
+ }
+
+ @Test()
+ public void testSearchIpv6Slash8NoColon() {
+ this.assertSummaryDocument(
+ "/summary?search=[2001", 1,
+ new String[] { "Ferrari458" }, 0, null);
+ }
+
+ @Test()
+ public void testSearchIpv6Slash8NoColonNoBrackets() {
+ this.assertSummaryDocument(
+ "/summary?search=2001", 1,
+ new String[] { "Ferrari458" }, 0, null);
+ }
+
+ @Test()
public void testSearchIpv6Uncompressed() {
this.assertSummaryDocument(
"/summary?search=[2001:04f8:0003:002e:0000:0000:0000:0051]", 0,
@@ -887,6 +915,13 @@ public class ResourceServletTest {
this.assertErrorStatusCode("/summary?search=limit:1", 400);
}
+ @Test()
+ public void testSearchDeadBeef() {
+ /* This does not return 400 Bad Request, even though "dead" is not a valid
+ * search term qualifier, because this could be the start of an IPv6 address
+ * without leading bracket. */
+ this.assertSummaryDocument("/summary?search=dead:beef", 0, null, 0, null);
+ }
@Test()
public void testSearchEmailAddress() {