commit cedd372a13a49c11da9b4327e8b7e373c750eab6 Author: Karsten Loesing karsten.loesing@gmx.net Date: Thu Jun 14 17:36:33 2012 +0200
Add country parameter to search by country code.
Implements #5960. --- src/org/torproject/onionoo/CurrentNodes.java | 22 ++++++--- src/org/torproject/onionoo/Node.java | 4 +- src/org/torproject/onionoo/ResourceServlet.java | 56 ++++++++++++++++++++++- web/index.html | 5 ++ 4 files changed, 78 insertions(+), 9 deletions(-)
diff --git a/src/org/torproject/onionoo/CurrentNodes.java b/src/org/torproject/onionoo/CurrentNodes.java index 74879af..63fb8c6 100644 --- a/src/org/torproject/onionoo/CurrentNodes.java +++ b/src/org/torproject/onionoo/CurrentNodes.java @@ -71,9 +71,13 @@ public class CurrentNodes { if (parts.length > 9) { consensusWeight = Long.parseLong(parts[9]); } + String countryCode = "??"; + if (parts.length > 10) { + countryCode = parts[10]; + } this.addRelay(nickname, fingerprint, address, validAfterMillis, orPort, dirPort, relayFlags, - consensusWeight); + consensusWeight, countryCode); } else if (line.startsWith("b ")) { String[] parts = line.split(" "); if (parts.length < 9) { @@ -136,9 +140,11 @@ public class CurrentNodes { String relayFlags = sb.toString().substring(1); String consensusWeight = String.valueOf( entry.getConsensusWeight()); + String countryCode = entry.getCountryCode() != null + ? entry.getCountryCode() : "??"; bw.write("r " + nickname + " " + fingerprint + " " + address + " " + validAfter + " " + orPort + " " + dirPort + " " + relayFlags - + " " + consensusWeight + "\n"); + + " " + consensusWeight + " " + countryCode + "\n"); } for (Node entry : this.currentBridges.values()) { String nickname = entry.getNickname(); @@ -155,7 +161,7 @@ public class CurrentNodes { String relayFlags = sb.toString().substring(1); bw.write("b " + nickname + " " + fingerprint + " " + address + " " + published + " " + orPort + " " + dirPort + " " + relayFlags - + " -1\n"); + + " -1 ??\n"); } bw.close(); } catch (IOException e) { @@ -214,19 +220,21 @@ public class CurrentNodes { SortedSet<String> relayFlags = entry.getFlags(); long consensusWeight = entry.getBandwidth(); this.addRelay(nickname, fingerprint, address, validAfterMillis, - orPort, dirPort, relayFlags, consensusWeight); + orPort, dirPort, relayFlags, consensusWeight, null); } }
public void addRelay(String nickname, String fingerprint, String address, long validAfterMillis, int orPort, int dirPort, - SortedSet<String> relayFlags, long consensusWeight) { + SortedSet<String> relayFlags, long consensusWeight, + String countryCode) { if (validAfterMillis >= cutoff && (!this.currentRelays.containsKey(fingerprint) || this.currentRelays.get(fingerprint).getLastSeenMillis() < validAfterMillis)) { Node entry = new Node(nickname, fingerprint, address, - validAfterMillis, orPort, dirPort, relayFlags, consensusWeight); + validAfterMillis, orPort, dirPort, relayFlags, consensusWeight, + countryCode); this.currentRelays.put(fingerprint, entry); if (validAfterMillis > this.lastValidAfterMillis) { this.lastValidAfterMillis = validAfterMillis; @@ -333,7 +341,7 @@ public class CurrentNodes { this.currentBridges.get(fingerprint).getLastSeenMillis() < publishedMillis)) { Node entry = new Node(nickname, fingerprint, address, - publishedMillis, orPort, dirPort, relayFlags, -1L); + publishedMillis, orPort, dirPort, relayFlags, -1L, null); this.currentBridges.put(fingerprint, entry); if (publishedMillis > this.lastPublishedMillis) { this.lastPublishedMillis = publishedMillis; diff --git a/src/org/torproject/onionoo/Node.java b/src/org/torproject/onionoo/Node.java index b7bc126..887a600 100644 --- a/src/org/torproject/onionoo/Node.java +++ b/src/org/torproject/onionoo/Node.java @@ -31,7 +31,8 @@ public class Node { private boolean running; public Node(String nickname, String fingerprint, String address, long lastSeenMillis, int orPort, int dirPort, - SortedSet<String> relayFlags, long consensusWeight) { + SortedSet<String> relayFlags, long consensusWeight, + String countryCode) { this.nickname = nickname; this.fingerprint = fingerprint; try { @@ -47,6 +48,7 @@ public class Node { this.dirPort = dirPort; this.relayFlags = relayFlags; this.consensusWeight = consensusWeight; + this.countryCode = countryCode; } public String getFingerprint() { return this.fingerprint; diff --git a/src/org/torproject/onionoo/ResourceServlet.java b/src/org/torproject/onionoo/ResourceServlet.java index e821500..8744150 100644 --- a/src/org/torproject/onionoo/ResourceServlet.java +++ b/src/org/torproject/onionoo/ResourceServlet.java @@ -47,6 +47,8 @@ public class ResourceServlet extends HttpServlet { private Map<String, String> relayFingerprintSummaryLines = new HashMap<String, String>(), bridgeFingerprintSummaryLines = new HashMap<String, String>(); + private Map<String, Set<String>> relaysByCountryCode = + new HashMap<String, Set<String>>(); private void readSummaryFile() { if (!summaryFile.exists()) { readSummaryFile = false; @@ -75,6 +77,16 @@ public class ResourceServlet extends HttpServlet { consensusWeight, fingerprint)); orderRelaysByConsensusWeight.add(String.format("%020d %s", consensusWeight, hashedFingerprint)); + String countryCode = entry.getCountryCode(); + if (countryCode == null) { + countryCode = "??"; + } + if (!this.relaysByCountryCode.containsKey(countryCode)) { + this.relaysByCountryCode.put(countryCode, + new HashSet<String>()); + } + this.relaysByCountryCode.get(countryCode).add(fingerprint); + this.relaysByCountryCode.get(countryCode).add(hashedFingerprint); } Collections.sort(orderRelaysByConsensusWeight); this.relaysByConsensusWeight = new ArrayList<String>(); @@ -178,7 +190,8 @@ public class ResourceServlet extends HttpServlet { /* Make sure that the request doesn't contain any unknown * parameters. */ Set<String> knownParameters = new HashSet<String>(Arrays.asList( - "type,running,search,lookup,order,limit,offset".split(","))); + "type,running,search,lookup,country,order,limit,offset". + split(","))); for (String parameterKey : parameterMap.keySet()) { if (!knownParameters.contains(parameterKey)) { response.sendError(HttpServletResponse.SC_BAD_REQUEST); @@ -235,6 +248,16 @@ public class ResourceServlet extends HttpServlet { this.filterByFingerprint(filteredRelays, filteredBridges, fingerprint); } + if (parameterMap.containsKey("country")) { + String countryCodeParameter = this.parseCountryCodeParameter( + parameterMap.get("country")); + if (countryCodeParameter == null) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + this.filterByCountryCode(filteredRelays, filteredBridges, + countryCodeParameter); + }
/* Re-order and limit results. */ List<String> orderedRelays = new ArrayList<String>(); @@ -389,6 +412,15 @@ public class ResourceServlet extends HttpServlet { return parameter; }
+ private static Pattern countryCodeParameterPattern = + Pattern.compile("^[0-9a-zA-Z]{2}$"); + private String parseCountryCodeParameter(String parameter) { + if (!countryCodeParameterPattern.matcher(parameter).matches()) { + return null; + } + return parameter; + } + private void filterByType(Map<String, String> filteredRelays, Map<String, String> filteredBridges, boolean relaysRequested) { if (relaysRequested) { @@ -502,6 +534,28 @@ public class ResourceServlet extends HttpServlet { } }
+ private void filterByCountryCode(Map<String, String> filteredRelays, + Map<String, String> filteredBridges, String countryCodeParameter) { + String countryCode = countryCodeParameter.toLowerCase(); + if (!this.relaysByCountryCode.containsKey(countryCode)) { + filteredRelays.clear(); + } else { + Set<String> relaysWithCountryCode = + this.relaysByCountryCode.get(countryCode); + Set<String> removeRelays = new HashSet<String>(); + for (Map.Entry<String, String> e : filteredRelays.entrySet()) { + String fingerprint = e.getKey(); + if (!relaysWithCountryCode.contains(fingerprint)) { + removeRelays.add(fingerprint); + } + } + for (String fingerprint : removeRelays) { + filteredRelays.remove(fingerprint); + } + } + filteredBridges.clear(); + } + private void writeRelays(List<String> relays, PrintWriter pw, String resourceType) { pw.write("{"relays_published":"" + this.relaysPublishedString diff --git a/web/index.html b/web/index.html index 5ea7743..589d347 100755 --- a/web/index.html +++ b/web/index.html @@ -623,6 +623,11 @@ Fingerprints should always be hashed using SHA-1, regardless of looking up a relay or a bridge, in order to not accidentally leak non-hashed bridge fingerprints in the URL. </td></tr> +<tr><td><b><font color="blue">country</font></b></td><td>Return only +relays which are located in the given country as identified by a +two-letter lower-case country code. +<font color="blue">Added parameter on June 14, 2012.</font> +</td></tr> </table> <p>Relay and/or bridge documents in the response can be ordered and limited by providing further parameters.</p>