[tor-commits] [onionoo/master] Add country parameter to search by country code.

karsten at torproject.org karsten at torproject.org
Thu Jun 14 15:43:01 UTC 2012


commit cedd372a13a49c11da9b4327e8b7e373c750eab6
Author: Karsten Loesing <karsten.loesing at 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>



More information about the tor-commits mailing list