Commit 9740ce76 authored by Karsten Loesing's avatar Karsten Loesing
Browse files

Extend "version" parameter to support lists and ranges.

Changes the current behavior of the "version" parameter by moving away
from string prefix matching to actually parsing provided (partial)
versions. As a result, for example, "version=0.3.2.1" doesn't
magically include versions 0.3.2.10 to 0.3.2.19, 0.3.2.100 to
0.3.2.199, etc. anymore. Without this change, version ranges would
have become just too confusing. The downside is that this change
requires a major version bump.

Implements #6947.
parent c9218fbd
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
# Changes in version 7.0-1.1?.0 - 2018-0?-??

 * Medium changes
   - Extend "version" parameter to support lists and ranges.


# Changes in version 6.2-1.16.0 - 2018-07-??

 * Medium changes
+8 −6
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
package org.torproject.onionoo.server;

import org.torproject.onionoo.docs.SummaryDocument;
import org.torproject.onionoo.updater.TorVersion;

import java.text.SimpleDateFormat;
import java.util.Map;
@@ -170,23 +171,24 @@ class NodeIndex {
    return bridgesByLastSeenDays;
  }

  private Map<String, Set<String>> relaysByVersion;
  private Map<TorVersion, Set<String>> relaysByVersion;

  public void setRelaysByVersion(Map<String, Set<String>> relaysByVersion) {
  public void setRelaysByVersion(Map<TorVersion, Set<String>> relaysByVersion) {
    this.relaysByVersion = relaysByVersion;
  }

  public Map<String, Set<String>> getRelaysByVersion() {
  public Map<TorVersion, Set<String>> getRelaysByVersion() {
    return this.relaysByVersion;
  }

  private Map<String, Set<String>> bridgesByVersion;
  private Map<TorVersion, Set<String>> bridgesByVersion;

  public void setBridgesByVersion(Map<String, Set<String>> bridgesByVersion) {
  public void setBridgesByVersion(Map<TorVersion,
      Set<String>> bridgesByVersion) {
    this.bridgesByVersion = bridgesByVersion;
  }

  public Map<String, Set<String>> getBridgesByVersion() {
  public Map<TorVersion, Set<String>> getBridgesByVersion() {
    return this.bridgesByVersion;
  }

+6 −5
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ import org.torproject.onionoo.docs.DocumentStore;
import org.torproject.onionoo.docs.DocumentStoreFactory;
import org.torproject.onionoo.docs.SummaryDocument;
import org.torproject.onionoo.docs.UpdateStatus;
import org.torproject.onionoo.updater.TorVersion;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -155,8 +156,8 @@ public class NodeIndexer implements ServletContextListener, Runnable {
    Map<String, Set<String>> newBridgesByFlag = new HashMap<>();
    Map<String, Set<String>> newRelaysByContact = new HashMap<>();
    Map<String, Set<String>> newRelaysByFamily = new HashMap<>();
    Map<String, Set<String>> newRelaysByVersion = new HashMap<>();
    Map<String, Set<String>> newBridgesByVersion = new HashMap<>();
    Map<TorVersion, Set<String>> newRelaysByVersion = new HashMap<>();
    Map<TorVersion, Set<String>> newBridgesByVersion = new HashMap<>();
    Map<String, Set<String>> newRelaysByOperatingSystem = new HashMap<>();
    Map<String, Set<String>> newBridgesByOperatingSystem = new HashMap<>();
    Map<String, Set<String>> newRelaysByHostName = new HashMap<>();
@@ -275,10 +276,10 @@ public class NodeIndexer implements ServletContextListener, Runnable {
      }
      newRelaysByContact.get(contact).add(fingerprint);
      newRelaysByContact.get(contact).add(hashedFingerprint);
      String version = entry.getVersion();
      TorVersion version = TorVersion.of(entry.getVersion());
      if (null != version) {
        if (!newRelaysByVersion.containsKey(version)) {
          newRelaysByVersion.put(version, new HashSet<String>());
          newRelaysByVersion.put(version, new HashSet<>());
        }
        newRelaysByVersion.get(version).add(fingerprint);
        newRelaysByVersion.get(version).add(hashedFingerprint);
@@ -369,7 +370,7 @@ public class NodeIndexer implements ServletContextListener, Runnable {
          hashedFingerprint);
      newBridgesByLastSeenDays.get(daysSinceLastSeen).add(
          hashedHashedFingerprint);
      String version = entry.getVersion();
      TorVersion version = TorVersion.of(entry.getVersion());
      if (null != version) {
        if (!newBridgesByVersion.containsKey(version)) {
          newBridgesByVersion.put(version, new HashSet<>());
+21 −8
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ package org.torproject.onionoo.server;
import org.torproject.onionoo.docs.DocumentStore;
import org.torproject.onionoo.docs.DocumentStoreFactory;
import org.torproject.onionoo.docs.SummaryDocument;
import org.torproject.onionoo.updater.TorVersion;

import java.util.ArrayList;
import java.util.Arrays;
@@ -91,9 +92,9 @@ public class RequestHandler {
    System.arraycopy(contact, 0, this.contact, 0, contact.length);
  }

  private String version;
  private List<TorVersion[]> version;

  public void setVersion(String version) {
  public void setVersion(List<TorVersion[]> version) {
    this.version = version;
  }

@@ -551,20 +552,32 @@ public class RequestHandler {
      return;
    }
    Set<String> keepRelays = new HashSet<>();
    for (Map.Entry<String, Set<String>> e
    for (Map.Entry<TorVersion, Set<String>> e
        : this.nodeIndex.getRelaysByVersion().entrySet()) {
      if (e.getKey().startsWith(this.version)) {
      for (TorVersion[] versionRange : this.version) {
        if ((null == versionRange[0]
            || e.getKey().compareTo(versionRange[0]) >= 0)
            && (null == versionRange[1]
            || e.getKey().compareTo(versionRange[1]) <= 0
            || e.getKey().matchingPrefix(versionRange[1]))) {
          keepRelays.addAll(e.getValue());
        }
      }
    }
    this.filteredRelays.keySet().retainAll(keepRelays);
    Set<String> keepBridges = new HashSet<>();
    for (Map.Entry<String, Set<String>> e
    for (Map.Entry<TorVersion, Set<String>> e
        : this.nodeIndex.getBridgesByVersion().entrySet()) {
      if (e.getKey().startsWith(this.version)) {
      for (TorVersion[] versionRange : this.version) {
        if ((null == versionRange[0]
            || e.getKey().compareTo(versionRange[0]) >= 0)
            && (null == versionRange[1]
            || e.getKey().compareTo(versionRange[1]) <= 0
            || e.getKey().matchingPrefix(versionRange[1]))) {
          keepBridges.addAll(e.getValue());
        }
      }
    }
    this.filteredBridges.keySet().retainAll(keepBridges);
  }

+28 −5
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@

package org.torproject.onionoo.server;

import org.torproject.onionoo.updater.TorVersion;

import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
@@ -283,7 +285,7 @@ public class ResourceServlet extends HttpServlet {
      rh.setContact(contactParts);
    }
    if (parameterMap.containsKey("version")) {
      String versionParameter = this.parseVersionParameter(
      List<TorVersion[]> versionParameter = this.parseVersionParameter(
          parameterMap.get("version"));
      if (null == versionParameter) {
        response.sendError(HttpServletResponse.SC_BAD_REQUEST);
@@ -599,14 +601,35 @@ public class ResourceServlet extends HttpServlet {
  }

  private static Pattern versionParameterPattern =
      Pattern.compile("^[0-9a-zA-Z\\.-]+$");
      Pattern.compile("^[0-9a-zA-Z,\\.-]+$");

  private String parseVersionParameter(String parameter) {
  private List<TorVersion[]> parseVersionParameter(String parameter) {
    if (!versionParameterPattern.matcher(parameter).matches()) {
      /* Version contains illegal character(s). */
      return null;
    }
    return parameter;
    List<TorVersion[]> result = new ArrayList<>();
    for (String listElement : parameter.split(",")) {
      TorVersion fromVersion;
      TorVersion toVersion;
      if (listElement.contains("..")) {
        fromVersion = TorVersion.of(
            listElement.substring(0, listElement.lastIndexOf("..")));
        toVersion = TorVersion.of(
            listElement.substring(listElement.lastIndexOf("..") + 2));
      } else {
        fromVersion = toVersion = TorVersion.of(listElement);
      }
      if (null == fromVersion && null == toVersion) {
        return null;
      }
      if (null != fromVersion && null != toVersion
          && fromVersion.compareTo(toVersion) > 0) {
        return null;
      }
      result.add(new TorVersion[] { fromVersion, toVersion });
    }
    return result;
  }

  private String parseOperatingSystemParameter(String parameter) {
Loading