commit 05f8a74fb1d3b1c074f106c1d2045092545288d2 Author: Karsten Loesing karsten.loesing@gmx.net Date: Sun Aug 20 20:19:34 2017 +0200
Fetch CollecTor's index.json for our own directory listings.
Implements #22836. --- website/build.xml | 6 ++ .../torproject/metrics/web/CollecTorServlet.java | 54 +++++++++-- .../metrics/web/CollectorDirectoryProvider.java | 79 +++++++++++++++ .../torproject/metrics/web/DirectoryListing.java | 90 +++++++++++++++++ website/src/main/resources/etc/web.xml | 1 + website/src/main/resources/web/WEB-INF/bottom.jsp | 2 +- .../main/resources/web/WEB-INF/collector-files.jsp | 40 ++++++++ .../src/main/resources/web/WEB-INF/collector.jsp | 108 ++++++++++----------- website/src/main/resources/web/WEB-INF/top.jsp | 52 +++++----- .../metrics/web/DirectoryListingTest.java | 81 ++++++++++++++++ 10 files changed, 425 insertions(+), 88 deletions(-)
diff --git a/website/build.xml b/website/build.xml index dfa0b18..07bf84e 100644 --- a/website/build.xml +++ b/website/build.xml @@ -1,10 +1,13 @@ <project default="war" name="metrics-web" basedir=".">
+ <property name="metricslibversion" value="2.0.0"/> + <property name="libs" value="../shared/lib"/>
<include file="../shared/build-base.xml" as="basetask"/> <target name="clean" depends="basetask.clean"/> <target name="compile" depends="basetask.compile"/> + <target name="test" depends="basetask.test"/>
<patternset id="compile.libs" > <include name="postgresql-jdbc3-9.2.jar"/> @@ -19,6 +22,9 @@ <include name="commons-codec-1.10.jar"/> <include name="commons-lang-2.6.jar"/> <include name="gson-2.4.jar"/> + <include name="metrics-lib-${metricslibversion}.jar"/> + <include name="commons-compress-1.13.jar"/> + <include name="slf4j-api-1.7.22.jar"/> </patternset>
<path id="classpath"> diff --git a/website/src/main/java/org/torproject/metrics/web/CollecTorServlet.java b/website/src/main/java/org/torproject/metrics/web/CollecTorServlet.java index 74ca163..2b0a13a 100644 --- a/website/src/main/java/org/torproject/metrics/web/CollecTorServlet.java +++ b/website/src/main/java/org/torproject/metrics/web/CollecTorServlet.java @@ -4,28 +4,68 @@ package org.torproject.metrics.web;
import java.io.IOException; +import java.util.List; +import java.util.Map;
+import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
+/** Servlet for CollecTor's "home" page and for CollecTor's directory listings + * based on the periodically fetched index.json file. */ public class CollecTorServlet extends AnyServlet {
private static final long serialVersionUID = -7054057945737357463L;
+ /** Host name of the CollecTor host with trailing slash omitted. */ + private static final String COLLECTOR_HOST + = "https://collector.torproject.org"; + + /** Parsed and formatted directory listings. */ + private CollectorDirectoryProvider collectorDirectory; + + /** Initializes this servlet by retrieving the CollecTor host name from the + * configuration file and starting the periodic index.json downloader. */ @Override - public void init() throws ServletException { - super.init(); + public void init(ServletConfig config) throws ServletException { + super.init(config); + this.collectorDirectory = new CollectorDirectoryProvider(COLLECTOR_HOST); }
+ /** Handles requests for either CollecTor's "home" page or for directory + * listings. */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - - /* Forward the request to the JSP that does all the hard work. */ - request.setAttribute("categories", this.categories); - request.getRequestDispatcher("WEB-INF/collector.jsp").forward(request, - response); + String requestedPath = request.getRequestURI(); + if (requestedPath.contains("/collector")) { + /* Possibly truncate any path prefix (like "/metrics") added by deploying + * this webapp as metrics.war rather than, say, ROOT.war. */ + requestedPath = requestedPath.substring(requestedPath.indexOf( + "/collector")); + } + Map<String, List<String[]>> index; + if ("/collector.html".equals(requestedPath)) { + request.setAttribute("categories", this.categories); + request.getRequestDispatcher("WEB-INF/collector.jsp").forward(request, + response); + } else if (null == (index = this.collectorDirectory.getIndex())) { + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, + "Index of CollecTor files unavailable."); + } else if (!requestedPath.endsWith("/") + && index.containsKey(requestedPath + "/")) { + response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); + response.setHeader("Location", requestedPath + "/"); + } else if (index.containsKey(requestedPath)) { + request.setAttribute("categories", this.categories); + request.setAttribute("files", index.get(requestedPath)); + request.getRequestDispatcher("/WEB-INF/collector-files.jsp").forward( + request, response); + } else { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + "Unknown directory: " + requestedPath); + } } }
diff --git a/website/src/main/java/org/torproject/metrics/web/CollectorDirectoryProvider.java b/website/src/main/java/org/torproject/metrics/web/CollectorDirectoryProvider.java new file mode 100644 index 0000000..9cd1e1e --- /dev/null +++ b/website/src/main/java/org/torproject/metrics/web/CollectorDirectoryProvider.java @@ -0,0 +1,79 @@ +/* Copyright 2017 The Tor Project + * See LICENSE for licensing information */ + +package org.torproject.metrics.web; + +import org.torproject.descriptor.index.DirectoryNode; +import org.torproject.descriptor.index.FileNode; +import org.torproject.descriptor.index.IndexNode; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +/** Periodically fetches a remote index.json file and provides formatted + * directory listings for all contained directories and subdirectories. */ +public class CollectorDirectoryProvider implements Runnable { + + /** Host name of the host serving the remote index.json with trailing slash + * omitted. */ + private String host; + + /** Scheduler for periodically downloading the remote index.json file. */ + private final ScheduledExecutorService scheduler = + Executors.newScheduledThreadPool(1); + + /** Last known directory listings. */ + private final AtomicReference<Map<String, List<String[]>>> index + = new AtomicReference<>(null); + + CollectorDirectoryProvider(String host) { + this.host = host; + this.scheduler.scheduleAtFixedRate(this, 0, 1, TimeUnit.MINUTES); + } + + /** Returns the index object in a thread-safe way, blocking the invoking + * thread at most 10 seconds if no index object is available. */ + Map<String, List<String[]>> getIndex() { + if (null == this.index.get()) { + long waitingSinceMillis = System.currentTimeMillis(); + do { + try { + this.wait(200L); + } catch (InterruptedException e) { + /* Ignore. */ + } + } while (null == index.get() + && System.currentTimeMillis() < waitingSinceMillis + 10000L); + } + return this.index.get(); + } + + /** Fetch the remote index.json and extract all we need to know to later + * produce directory listings as requested. */ + @Override + public void run() { + IndexNode indexNode; + try { + indexNode = IndexNode.fetchIndex(this.host + "/index/index.json.gz"); + } catch (Exception e) { + /* If we failed to fetch the remote index.json this time, abort the + * update and don't override what we possibly fetched last time. If this + * is a temporary problem, one of the next runs will update the index. If + * it's a permanent problem, we'll at least serve the last known files. + * Unless it's a permanent problem right from when we started in which + * case there's nothing we can do other than return 500. */ + return; + } + this.index.set(new DirectoryListing(indexNode)); + } + +} + diff --git a/website/src/main/java/org/torproject/metrics/web/DirectoryListing.java b/website/src/main/java/org/torproject/metrics/web/DirectoryListing.java new file mode 100644 index 0000000..6dd09e4 --- /dev/null +++ b/website/src/main/java/org/torproject/metrics/web/DirectoryListing.java @@ -0,0 +1,90 @@ +/* Copyright 2017 The Tor Project + * See LICENSE for licensing information */ + +package org.torproject.metrics.web; + +import org.torproject.descriptor.index.DirectoryNode; +import org.torproject.descriptor.index.FileNode; +import org.torproject.descriptor.index.IndexNode; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; + +/** Map with all directory listings for all directories and subdirectories + * contained in an index.json file. */ +public class DirectoryListing extends HashMap<String, List<String[]>> + implements Map<String, List<String[]>> { + + private IndexNode index; + + DirectoryListing(IndexNode index) { + this.index = index; + extractDirectoryListings(); + } + + /** Extracts directory listing from an index node by visiting all nodes. */ + private void extractDirectoryListings() { + Map<DirectoryNode, String> directoryNodes = new HashMap<>(); + this.put("/collector/", + formatTableEntries("", "/", this.index.directories, this.index.files)); + for (DirectoryNode directory : this.index.directories) { + directoryNodes.put(directory, "/"); + } + while (!directoryNodes.isEmpty()) { + DirectoryNode currentDirectoryNode = + directoryNodes.keySet().iterator().next(); + String parentPath = directoryNodes.remove(currentDirectoryNode); + if (null != currentDirectoryNode.directories) { + for (DirectoryNode subDirectoryNode + : currentDirectoryNode.directories) { + directoryNodes.put(subDirectoryNode, String.format("%s%s/", + parentPath, currentDirectoryNode.path)); + } + } + this.put(String + .format("/collector%s%s/", parentPath, currentDirectoryNode.path), + formatTableEntries(parentPath, currentDirectoryNode.path + "/", + currentDirectoryNode.directories, currentDirectoryNode.files)); + } + } + + /** Formats table entries for a given directory. */ + private List<String[]> formatTableEntries(String parentPath, String path, + SortedSet<DirectoryNode> directories, SortedSet<FileNode> files) { + List<String[]> tableEntries = new ArrayList<>(); + tableEntries.add(new String[] { "Parent Directory", + String.format("/collector%s", + parentPath.isEmpty() ? ".html" : parentPath), "", "" }); + if (null != directories) { + for (DirectoryNode subDirectoryNode : directories) { + tableEntries.add(new String[] { subDirectoryNode.path, + String.format("/collector%s%s%s/", parentPath, path, + subDirectoryNode.path), "", "" }); + } + } + if (null != files) { + for (FileNode fileNode : new TreeSet<>(files).descendingSet()) { + tableEntries.add(new String[] { fileNode.path, + String.format("%s%s%s%s", this.index.path, parentPath, + path, fileNode.path), fileNode.lastModified, + formatBytes(fileNode.size) }); + } + } + return tableEntries; + } + + /** Formats a number of bytes to units B, KiB, MiB, etc. */ + static String formatBytes(long bytes) { + if (bytes < 1024) { + return bytes + " B"; + } + int exp = (int) (Math.log(bytes) / Math.log(1024)); + char pre = "KMGTPE".charAt(exp - 1); + return String.format("%.1f %siB", bytes / Math.pow(1024, exp), pre); + } +} + diff --git a/website/src/main/resources/etc/web.xml b/website/src/main/resources/etc/web.xml index 38a30bb..830e8e7 100644 --- a/website/src/main/resources/etc/web.xml +++ b/website/src/main/resources/etc/web.xml @@ -303,6 +303,7 @@ <servlet-mapping> <servlet-name>CollecTorServlet</servlet-name> <url-pattern>/collector.html</url-pattern> + <url-pattern>/collector/*</url-pattern> </servlet-mapping>
<servlet> diff --git a/website/src/main/resources/web/WEB-INF/bottom.jsp b/website/src/main/resources/web/WEB-INF/bottom.jsp index 835b286..6719adc 100644 --- a/website/src/main/resources/web/WEB-INF/bottom.jsp +++ b/website/src/main/resources/web/WEB-INF/bottom.jsp @@ -9,7 +9,7 @@ <div class="col-xs-6"> <p class="pull-right">
- <a href="about.html#contact">Contact</a> + <a href="/about.html#contact">Contact</a>
</p> </div> diff --git a/website/src/main/resources/web/WEB-INF/collector-files.jsp b/website/src/main/resources/web/WEB-INF/collector-files.jsp new file mode 100644 index 0000000..da57144 --- /dev/null +++ b/website/src/main/resources/web/WEB-INF/collector-files.jsp @@ -0,0 +1,40 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<jsp:include page="top.jsp"> + <jsp:param name="pageTitle" value="Sources – Tor Metrics"/> + <jsp:param name="navActive" value="Sources"/> +</jsp:include> + + <div class="container"> + <ul class="breadcrumb"> + <li><a href="/">Home</a></li> + <li><a href="/sources.html">Sources</a></li> + <li><a href="/collector.html">CollecTor</a></li> + </ul> + </div> + + <div class="container"> + <div class="row"> + <div class="col-xs-12"> + <table class="table"> + <thead> + <tr> + <th>Name</th> + <th>Last modified</th> + <th>Size</th> + </tr> + </thead> + <tbody> + <c:forEach var="file" items="${files}"><tr> + <td><a href="${file[1]}">${file[0]}</a></td> + <td>${file[2]}</td> + <td>${file[3]}</td> + </tr></c:forEach> + </tbody> + </table> + </div><!-- col --> + </div><!-- row --> + </div><!-- container --> + +<jsp:include page="bottom.jsp"/> + diff --git a/website/src/main/resources/web/WEB-INF/collector.jsp b/website/src/main/resources/web/WEB-INF/collector.jsp index f57ccb8..871415c 100644 --- a/website/src/main/resources/web/WEB-INF/collector.jsp +++ b/website/src/main/resources/web/WEB-INF/collector.jsp @@ -32,8 +32,8 @@ network, or if you're developing an application that uses Tor network data, this is your place to start. </p> -<a class="btn btn-primary btn-lg" style="margin: 10px" href="https://collector.torproject.org/recent/" target="_blank"><i class="fa fa-chevron-right" aria-hidden="true"></i> Browse Recent Descriptors</a> -<a class="btn btn-primary btn-lg" style="margin: 10px" href="https://collector.torproject.org/archive/" target="_blank"><i class="fa fa-chevron-right" aria-hidden="true"></i> Browse Archived Descriptors</a> +<a class="btn btn-primary btn-lg" style="margin: 10px" href="/collector/recent/"><i class="fa fa-chevron-right" aria-hidden="true"></i> Browse Recent Descriptors</a> +<a class="btn btn-primary btn-lg" style="margin: 10px" href="/collector/archive/"><i class="fa fa-chevron-right" aria-hidden="true"></i> Browse Archived Descriptors</a> </div><!-- text-center -->
@@ -65,53 +65,53 @@ <tr> <td><a href="#type-server-descriptor">Relay Server Descriptors</a></td> <td><code>@type server-descriptor 1.0</code></td> - <td><a href="https://collector.torproject.org/recent/relay-descriptors/server-descriptors/" target="_blank" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> - <a href="https://collector.torproject.org/archive/relay-descriptors/server-descriptors/" target="_blank" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> + <td><a href="/collector/recent/relay-descriptors/server-descriptors/" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> + <a href="/collector/archive/relay-descriptors/server-descriptors/" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> </tr> <tr> <td><a href="#type-extra-info">Relay Extra-info Descriptors</a></td> <td><code>@type extra-info 1.0</code></td> - <td><a href="https://collector.torproject.org/recent/relay-descriptors/extra-infos/" target="_blank" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> - <a href="https://collector.torproject.org/archive/relay-descriptors/extra-infos/" target="_blank" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> + <td><a href="/collector/recent/relay-descriptors/extra-infos/" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> + <a href="/collector/archive/relay-descriptors/extra-infos/" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> </tr> <tr> <td><a href="#type-network-status-consensus-3">Network Status Consensuses</a></td> <td><code>@type network-status-consensus-3 1.0</code></td> - <td><a href="https://collector.torproject.org/recent/relay-descriptors/consensuses/" target="_blank" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> - <a href="https://collector.torproject.org/archive/relay-descriptors/consensuses/" target="_blank" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> + <td><a href="/collector/recent/relay-descriptors/consensuses/" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> + <a href="/collector/archive/relay-descriptors/consensuses/" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> </tr> <tr> <td><a href="#type-network-status-vote-3">Network Status Votes</a></td> <td><code>@type network-status-vote-3 1.0</code></td> - <td><a href="https://collector.torproject.org/recent/relay-descriptors/votes/" target="_blank" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> - <a href="https://collector.torproject.org/archive/relay-descriptors/votes/" target="_blank" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> + <td><a href="/collector/recent/relay-descriptors/votes/" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> + <a href="/collector/archive/relay-descriptors/votes/" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> </tr> <tr> <td><a href="#type-dir-key-certificate-3">Directory Key Certificates</a></td> <td><code>@type dir-key-certificate-3 1.0</code></td> - <td><a href="https://collector.torproject.org/archive/relay-descriptors/" target="_blank" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> + <td><a href="/collector/archive/relay-descriptors/" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> </tr> <tr> <td><a href="#type-network-status-microdesc-consensus-3">Microdescriptor Consensuses</a></td> <td><code>@type network-status-microdesc-consensus-3 1.0</code></td> - <td><a href="https://collector.torproject.org/recent/relay-descriptors/microdescs/consensus-microdesc/" target="_blank" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> - <a href="https://collector.torproject.org/archive/relay-descriptors/microdescs/" target="_blank" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> + <td><a href="/collector/recent/relay-descriptors/microdescs/consensus-microdesc/" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> + <a href="/collector/archive/relay-descriptors/microdescs/" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> </tr> <tr> <td><a href="#type-microdescriptor">Microdescriptors</a></td> <td><code>@type microdescriptor 1.0</code></td> - <td><a href="https://collector.torproject.org/recent/relay-descriptors/microdescs/micro/" target="_blank" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> - <a href="https://collector.torproject.org/archive/relay-descriptors/microdescs/" target="_blank" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> + <td><a href="/collector/recent/relay-descriptors/microdescs/micro/" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> + <a href="/collector/archive/relay-descriptors/microdescs/" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> </tr> <tr> <td><a href="#type-network-status-2">Version 2 Network Statuses</a></td> <td><code>@type network-status-2 1.0</code></td> - <td><a href="https://collector.torproject.org/archive/relay-descriptors/statuses/" target="_blank" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> + <td><a href="/collector/archive/relay-descriptors/statuses/" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> </tr> <tr> <td><a href="#type-directory">Version 1 Directories</a></td> <td><code>@type directory 1.0</code></td> - <td><a href="https://collector.torproject.org/archive/relay-descriptors/tor/" target="_blank" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> + <td><a href="/collector/archive/relay-descriptors/tor/" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> </tr> <tr class="tableHeadline"> <td colspan="3"><b><a href="#bridge-descriptors">Tor Bridge Descriptors</a></b></td> @@ -119,20 +119,20 @@ <tr> <td><a href="#type-bridge-network-status">Bridge Network Statuses</a></td> <td><code>@type bridge-network-status 1.2</code></td> - <td><a href="https://collector.torproject.org/recent/bridge-descriptors/statuses/" target="_blank" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> - <a href="https://collector.torproject.org/archive/bridge-descriptors/statuses/" target="_blank" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> + <td><a href="/collector/recent/bridge-descriptors/statuses/" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> + <a href="/collector/archive/bridge-descriptors/statuses/" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> </tr> <tr> <td><a href="#type-bridge-server-descriptor">Bridge Server Descriptors</a></td> <td><code>@type bridge-server-descriptor 1.2</code></td> - <td><a href="https://collector.torproject.org/recent/bridge-descriptors/server-descriptors/" target="_blank" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> - <a href="https://collector.torproject.org/archive/bridge-descriptors/server-descriptors/" target="_blank" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> + <td><a href="/collector/recent/bridge-descriptors/server-descriptors/" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> + <a href="/collector/archive/bridge-descriptors/server-descriptors/" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> </tr> <tr> <td><a href="#type-bridge-extra-info">Bridge Extra-info Descriptors</a></td> <td><code>@type bridge-extra-info 1.3</code></td> - <td><a href="https://collector.torproject.org/recent/bridge-descriptors/extra-infos/" target="_blank" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> - <a href="https://collector.torproject.org/archive/bridge-descriptors/extra-infos/" target="_blank" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> + <td><a href="/collector/recent/bridge-descriptors/extra-infos/" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> + <a href="/collector/archive/bridge-descriptors/extra-infos/" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> </tr> <tr class="tableHeadline"> <td colspan="3"><b><a href="#tor-hidden-service-descriptors">Tor Hidden Service Descriptors</a></b></td> @@ -148,7 +148,7 @@ <tr> <td><a href="#type-bridge-pool-assignment">Bridge Pool Assignments</a></td> <td><code>@type bridge-pool-assignment 1.0</code></td> - <td><a href="https://collector.torproject.org/archive/bridge-pool-assignments/" target="_blank" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> + <td><a href="/collector/archive/bridge-pool-assignments/" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> </tr> <tr class="tableHeadline"> <td colspan="3"><b><a href="#exit-lists">TorDNSEL's Exit Lists</a></b></td> @@ -156,8 +156,8 @@ <tr> <td><a href="#type-tordnsel">Exit Lists</a></td> <td><code>@type tordnsel 1.0</code></td> - <td><a href="https://collector.torproject.org/recent/exit-lists/" target="_blank" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> - <a href="https://collector.torproject.org/archive/exit-lists/" target="_blank" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> + <td><a href="/collector/recent/exit-lists/" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> + <a href="/collector/archive/exit-lists/" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> </tr> <tr class="tableHeadline"> <td colspan="3"><b><a href="#torperf">Torperf's and OnionPerf's Performance Data</a></b></td> @@ -165,8 +165,8 @@ <tr> <td><a href="#type-torperf">Torperf Measurement Results</a></td> <td><code>@type torperf 1.1</code></td> - <td><a href="https://collector.torproject.org/recent/torperf/" target="_blank" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> - <a href="https://collector.torproject.org/archive/torperf/" target="_blank" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> + <td><a href="/collector/recent/torperf/" class="btn btn-primary btn-xs pull-left"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> + <a href="/collector/archive/torperf/" class="btn btn-primary btn-xs pull-right"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a></td> </tr> </tbody> </table> @@ -213,8 +213,8 @@ earlier protocol
<h3 id="type-server-descriptor" class="hover">Relay Server Descriptors <small><code>@type server-descriptor 1.0</code></small> -<a href="https://collector.torproject.org/recent/relay-descriptors/server-descriptors/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> -<a href="https://collector.torproject.org/archive/relay-descriptors/server-descriptors/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> +<a href="/collector/recent/relay-descriptors/server-descriptors/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> +<a href="/collector/archive/relay-descriptors/server-descriptors/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> <a href="#type-server-descriptor" class="anchor">#</a> </h3>
@@ -231,8 +231,8 @@ file.
<h3 id="type-extra-info" class="hover">Relay Extra-info Descriptors <small><code>@type extra-info 1.0</code></small> -<a href="https://collector.torproject.org/recent/relay-descriptors/extra-infos/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> -<a href="https://collector.torproject.org/archive/relay-descriptors/extra-infos/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> +<a href="/collector/recent/relay-descriptors/extra-infos/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> +<a href="/collector/archive/relay-descriptors/extra-infos/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> <a href="#type-extra-info" class="anchor">#</a> </h3>
@@ -249,8 +249,8 @@ file.
<h3 id="type-network-status-consensus-3" class="hover">Network Status Consensuses <small><code>@type network-status-consensus-3 1.0</code></small> -<a href="https://collector.torproject.org/recent/relay-descriptors/consensuses/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> -<a href="https://collector.torproject.org/archive/relay-descriptors/consensuses/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> +<a href="/collector/recent/relay-descriptors/consensuses/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> +<a href="/collector/archive/relay-descriptors/consensuses/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> <a href="#type-network-status-consensus-3" class="anchor">#</a> </h3>
@@ -265,8 +265,8 @@ flags, heuristics used for relay selection, etc.
<h3 id="type-network-status-vote-3" class="hover">Network Status Votes <small><code>@type network-status-vote-3 1.0</code></small> -<a href="https://collector.torproject.org/recent/relay-descriptors/votes/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> -<a href="https://collector.torproject.org/archive/relay-descriptors/votes/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> +<a href="/collector/recent/relay-descriptors/votes/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> +<a href="/collector/archive/relay-descriptors/votes/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> <a href="#type-network-status-vote-3" class="anchor">#</a> </h3>
@@ -278,7 +278,7 @@ Vote documents are by far the largest documents provided here.
<h3 id="type-dir-key-certificate-3" class="hover">Directory Key Certificates <small><code>@type dir-key-certificate-3 1.0</code></small> -<a href="https://collector.torproject.org/archive/relay-descriptors/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> +<a href="/collector/archive/relay-descriptors/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> <a href="#type-dir-key-certificate-3" class="anchor">#</a> </h3>
@@ -291,8 +291,8 @@ available in a single descriptor archive tarball.
<h3 id="type-network-status-microdesc-consensus-3" class="hover">Microdescriptor Consensuses <small><code>@type network-status-microdesc-consensus-3 1.0</code></small> -<a href="https://collector.torproject.org/recent/relay-descriptors/microdescs/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> -<a href="https://collector.torproject.org/archive/relay-descriptors/microdescs/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> +<a href="/collector/recent/relay-descriptors/microdescs/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> +<a href="/collector/archive/relay-descriptors/microdescs/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> <a href="#type-network-status-microdesc-consensus-3" class="anchor">#</a> </h3>
@@ -309,8 +309,8 @@ together.
<h3 id="type-microdescriptor" class="hover">Microdescriptors <small><code>@type microdescriptor 1.0</code></small> -<a href="https://collector.torproject.org/recent/relay-descriptors/microdescs/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> -<a href="https://collector.torproject.org/archive/relay-descriptors/microdescs/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> +<a href="/collector/recent/relay-descriptors/microdescs/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> +<a href="/collector/archive/relay-descriptors/microdescs/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> <a href="#type-microdescriptor" class="anchor">#</a> </h3>
@@ -328,7 +328,7 @@ file.
<h3 id="type-network-status-2" class="hover">Version 2 Network Statuses <small><code>@type network-status-2 1.0</code></small> -<a href="https://collector.torproject.org/archive/relay-descriptors/statuses/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> +<a href="/collector/archive/relay-descriptors/statuses/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> <a href="#type-network-status-2" class="anchor">#</a> </h3>
@@ -343,7 +343,7 @@ We stopped archiving version 2 network statuses in 2012.
<h3 id="type-directory" class="hover">Version 1 Directories <small><code>@type directory 1.0</code></small> -<a href="https://collector.torproject.org/archive/relay-descriptors/tor/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> +<a href="/collector/archive/relay-descriptors/tor/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> <a href="#type-directory" class="anchor">#</a> </h3>
@@ -372,8 +372,8 @@ The sanitizing steps are specified in detail on a separate
<h3 id="type-bridge-network-status" class="hover">Bridge Network Statuses <small><code>@type bridge-network-status 1.2</code></small> -<a href="https://collector.torproject.org/recent/bridge-descriptors/statuses/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> -<a href="https://collector.torproject.org/archive/bridge-descriptors/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> +<a href="/collector/recent/bridge-descriptors/statuses/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> +<a href="/collector/archive/bridge-descriptors/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> <a href="#type-bridge-network-status" class="anchor">#</a> </h3>
@@ -397,8 +397,8 @@ authority which produced the document, to the header.</li>
<h3 id="type-bridge-server-descriptor" class="hover">Bridge Server descriptors <small><code>@type bridge-server-descriptor 1.2</code></small> -<a href="https://collector.torproject.org/recent/bridge-descriptors/server-descriptors/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> -<a href="https://collector.torproject.org/archive/bridge-descriptors/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> +<a href="/collector/recent/bridge-descriptors/server-descriptors/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> +<a href="/collector/archive/bridge-descriptors/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> <a href="#type-bridge-server-descriptor" class="anchor">#</a> </h3>
@@ -431,8 +431,8 @@ ports.</li>
<h3 id="type-bridge-extra-info" class="hover">Bridge Extra-info Descriptors <small><code>@type bridge-extra-info 1.3</code></small> -<a href="https://collector.torproject.org/recent/bridge-descriptors/extra-infos/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> -<a href="https://collector.torproject.org/archive/bridge-descriptors/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> +<a href="/collector/recent/bridge-descriptors/extra-infos/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> +<a href="/collector/archive/bridge-descriptors/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> <a href="#type-bridge-extra-info" class="anchor">#</a> </h3>
@@ -514,7 +514,7 @@ statistical analysis.
<h3 id="type-bridge-pool-assignment" class="hover">Bridge Pool Assignments <small><code>@type bridge-pool-assignment 1.0</code></small> -<a href="https://collector.torproject.org/archive/bridge-pool-assignments/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> +<a href="/collector/archive/bridge-pool-assignments/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> <a href="#type-bridge-pool-assignment" class="anchor">#</a> </h3>
@@ -573,8 +573,8 @@ when exiting through them.
<h3 id="type-tordnsel" class="hover">Exit Lists <small><code>@type tordnsel 1.0</code></small> -<a href="https://collector.torproject.org/recent/exit-lists/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> -<a href="https://collector.torproject.org/archive/exit-lists/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> +<a href="/collector/recent/exit-lists/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> +<a href="/collector/archive/exit-lists/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> <a href="#type-tordnsel" class="anchor">#</a> </h3>
@@ -617,8 +617,8 @@ over the Tor network and notes how long substeps take.
<h3 id="type-torperf" class="hover">Torperf and OnionPerf Measurement Results <small><code>@type torperf 1.1</code></small> -<a href="https://collector.torproject.org/recent/torperf/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> -<a href="https://collector.torproject.org/archive/torperf/" target="_blank" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> +<a href="/collector/recent/torperf/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> recent</a> +<a href="/collector/archive/torperf/" class="btn btn-primary btn-xs"><i class="fa fa-chevron-right" aria-hidden="true"></i> archive</a> <a href="#type-torperf" class="anchor">#</a> </h3>
diff --git a/website/src/main/resources/web/WEB-INF/top.jsp b/website/src/main/resources/web/WEB-INF/top.jsp index c013780..e5e95eb 100644 --- a/website/src/main/resources/web/WEB-INF/top.jsp +++ b/website/src/main/resources/web/WEB-INF/top.jsp @@ -7,7 +7,7 @@ <title>${param.pageTitle}</title>
<meta charset="utf-8"> - <link href="images/favicon.ico" type="image/x-icon" rel="shortcut icon"> + <link href="/images/favicon.ico" type="image/x-icon" rel="shortcut icon">
<!-- yes, we are handheld friendly :) --> <meta name="HandheldFriendly" content="True"> @@ -15,31 +15,31 @@ <meta name="apple-mobile-web-app-capable" content="yes">
<!-- icons for mobile devices --> - <link rel="apple-touch-icon" href="images/apple-touch-icon-152x152.png"> - <link rel="shortcut icon" href="images/android-icon.png" sizes="196x196"> - <meta name="msapplication-square70x70logo" content="images/smalltile.png"> - <meta name="msapplication-square150x150logo" content="images/mediumtile.png"> - <meta name="msapplication-wide310x150logo" content="images/widetile.png"> - <meta name="msapplication-square310x310logo" content="images/largetile.png"> + <link rel="apple-touch-icon" href="/images/apple-touch-icon-152x152.png"> + <link rel="shortcut icon" href="/images/android-icon.png" sizes="196x196"> + <meta name="msapplication-square70x70logo" content="/images/smalltile.png"> + <meta name="msapplication-square150x150logo" content="/images/mediumtile.png"> + <meta name="msapplication-wide310x150logo" content="/images/widetile.png"> + <meta name="msapplication-square310x310logo" content="/images/largetile.png">
<!-- jQuery --> - <script src="js/jquery-3.2.1.min.js"></script> + <script src="/js/jquery-3.2.1.min.js"></script>
<!-- Bootstrap --> - <link rel="stylesheet" href="css/bootstrap.min.css"> - <script src="js/bootstrap.min.js"></script> + <link rel="stylesheet" href="/css/bootstrap.min.css"> + <script src="/js/bootstrap.min.js"></script>
<!-- Fonts --> - <link rel="stylesheet" href="css/font-awesome.min.css"> - <link rel="stylesheet" href="fonts/source-sans-pro.css"> + <link rel="stylesheet" href="/css/font-awesome.min.css"> + <link rel="stylesheet" href="/fonts/source-sans-pro.css">
<!-- Prism --> - <link rel="stylesheet" href="css/prism.css"> - <script src="js/prism.js"></script> + <link rel="stylesheet" href="/css/prism.css"> + <script src="/js/prism.js"></script>
<!-- custom styles and javascript --> - <link rel="stylesheet" href="css/style.css"> - <script src="js/script.js"></script> + <link rel="stylesheet" href="/css/style.css"> + <script src="/js/script.js"></script>
</head>
@@ -69,7 +69,7 @@ document.write('<div class="topButton" style="display:none;"><a href="#top"><i c <span class="icon-bar"></span> <span class="icon-bar"></span> </label> - <a class="navbar-brand visible-xs" href="/"><img src="images/tor-metrics-white.png" width="232" height="50" alt="Tor Metrics"></a> + <a class="navbar-brand visible-xs" href="/"><img src="/images/tor-metrics-white.png" width="232" height="50" alt="Tor Metrics"></a> </div>
<!-- Collect the nav links, forms, and other content for toggling --> @@ -80,18 +80,18 @@ document.write('<div class="topButton" style="display:none;"><a href="#top"><i c <li class="visible-xs section-header">Metrics</li> <li class="visible-xs<c:if test="${'Home'.equals(param.navActive)}"> active</c:if>"><a href="/"><i class="fa fa-home fa-fw" aria-hidden="true"></i> Home</a></li> <c:forEach var="category" items="${categories}"> - <li class="visible-xs<c:if test="${category[1].equals(param.navActive)}"> active</c:if><c:if test="${fn:length(category[0]) == 0}"> disabled</c:if>"><a<c:if test="${fn:length(category[0]) > 0}"> href="${category[0]}.html"</c:if>><i class="fa ${category[3]} fa-fw" aria-hidden="true"></i> ${category[1]}</a></li> + <li class="visible-xs<c:if test="${category[1].equals(param.navActive)}"> active</c:if><c:if test="${fn:length(category[0]) == 0}"> disabled</c:if>"><a<c:if test="${fn:length(category[0]) > 0}"> href="/${category[0]}.html"</c:if>><i class="fa ${category[3]} fa-fw" aria-hidden="true"></i> ${category[1]}</a></li> </c:forEach> <!-- /end of primary copy -->
<!-- secondary navigation items --> <li class="visible-xs section-header">More</li> - <li <c:if test="${'News'.equals(param.navActive)}"> class="active"</c:if>><a href="news.html"><i class="fa fa-newspaper-o fa-fw hidden-sm" aria-hidden="true"></i> News</a></li> - <li <c:if test="${'Sources'.equals(param.navActive)}"> class="active"</c:if>><a href="sources.html"><i class="fa fa-archive fa-fw hidden-sm" aria-hidden="true"></i> Sources</a></li> - <li <c:if test="${'Operation'.equals(param.navActive)}"> class="active"</c:if>><a href="operation.html"><i class="fa fa-cogs fa-fw hidden-sm" aria-hidden="true"></i> Operation</a></li> - <li <c:if test="${'Development'.equals(param.navActive)}"> class="active"</c:if>><a href="development.html"><i class="fa fa-code fa-fw hidden-sm" aria-hidden="true"></i> Development</a></li> - <li <c:if test="${'Research'.equals(param.navActive)}"> class="active"</c:if>><a href="research.html"><i class="fa fa-university fa-fw hidden-sm" aria-hidden="true"></i> Research</a></li> - <li <c:if test="${'About'.equals(param.navActive)}"> class="active"</c:if>><a href="about.html"><i class="fa fa-lightbulb-o fa-fw hidden-sm" aria-hidden="true"></i> About</a></li> + <li <c:if test="${'News'.equals(param.navActive)}"> class="active"</c:if>><a href="/news.html"><i class="fa fa-newspaper-o fa-fw hidden-sm" aria-hidden="true"></i> News</a></li> + <li <c:if test="${'Sources'.equals(param.navActive)}"> class="active"</c:if>><a href="/sources.html"><i class="fa fa-archive fa-fw hidden-sm" aria-hidden="true"></i> Sources</a></li> + <li <c:if test="${'Operation'.equals(param.navActive)}"> class="active"</c:if>><a href="/operation.html"><i class="fa fa-cogs fa-fw hidden-sm" aria-hidden="true"></i> Operation</a></li> + <li <c:if test="${'Development'.equals(param.navActive)}"> class="active"</c:if>><a href="/development.html"><i class="fa fa-code fa-fw hidden-sm" aria-hidden="true"></i> Development</a></li> + <li <c:if test="${'Research'.equals(param.navActive)}"> class="active"</c:if>><a href="/research.html"><i class="fa fa-university fa-fw hidden-sm" aria-hidden="true"></i> Research</a></li> + <li <c:if test="${'About'.equals(param.navActive)}"> class="active"</c:if>><a href="/about.html"><i class="fa fa-lightbulb-o fa-fw hidden-sm" aria-hidden="true"></i> About</a></li> <!-- /secondary navigation items -->
</ul> @@ -102,7 +102,7 @@ document.write('<div class="topButton" style="display:none;"><a href="#top"><i c
<!-- page header for every single page --> <div class="page-header hidden-xs"> - <a href="/"><img src="images/tor-metrics-white@2x.png" width="232" height="50" alt="Tor Metrics" id="metrics-wordmark"></a> + <a href="/"><img src="/images/tor-metrics-white@2x.png" width="232" height="50" alt="Tor Metrics" id="metrics-wordmark"></a> <div> <p> <i>“Tor metrics are the ammunition that lets Tor and other security advocates argue for a more private and secure Internet from a position of data, rather than just dogma or perspective.”<br><small>— Bruce Schneier (June 1, 2016)</small></i> @@ -119,7 +119,7 @@ document.write('<div class="topButton" style="display:none;"><a href="#top"><i c <ul class="nav navbar-nav"> <li <c:if test="${'Home'.equals(param.navActive)}"> class="active"</c:if>><a href="/"><i class="fa fa-home fa-fw hidden-sm" aria-hidden="true"></i> Home</a></li> <c:forEach var="category" items="${categories}"> - <li class="<c:if test="${category[1].equals(param.navActive)}"> active</c:if><c:if test="${fn:length(category[0]) == 0}"> disabled</c:if>"><a<c:if test="${fn:length(category[0]) > 0}"> href="${category[0]}.html"</c:if>><i class="fa ${category[3]} fa-fw hidden-sm" aria-hidden="true"></i> ${category[1]}</a></li> + <li class="<c:if test="${category[1].equals(param.navActive)}"> active</c:if><c:if test="${fn:length(category[0]) == 0}"> disabled</c:if>"><a<c:if test="${fn:length(category[0]) > 0}"> href="/${category[0]}.html"</c:if>><i class="fa ${category[3]} fa-fw hidden-sm" aria-hidden="true"></i> ${category[1]}</a></li> </c:forEach> </ul> </div><!-- /.navbar-collapse --> diff --git a/website/src/test/java/org/torproject/metrics/web/DirectoryListingTest.java b/website/src/test/java/org/torproject/metrics/web/DirectoryListingTest.java new file mode 100644 index 0000000..5c6b37a --- /dev/null +++ b/website/src/test/java/org/torproject/metrics/web/DirectoryListingTest.java @@ -0,0 +1,81 @@ +/* Copyright 2017 The Tor Project + * See LICENSE for licensing information */ + +package org.torproject.metrics.web; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.torproject.descriptor.index.IndexNode; + +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class DirectoryListingTest { + + @Test + public void testFormatBytes() { + long[] input = new long[] { -1024L, -1L, 0L, 1L, 1023L, // B + 1024L, 1025L, 1048575L, // KiB + 1048576L, 1048577L, 1073741823L, // MiB + 1073741824L, 1073741825L, 1099511627775L, // GiB + 32099511627776L, 1099511627777L, 1125899906842623L, // TiB + 1125899906842624L, 1125899906842625L }; // PiB + String[] expectedOutput = new String[] { "-1024 B", "-1 B", "0 B", "1 B", + "1023 B", "1.0 KiB", "1.0 KiB", "1024.0 KiB", "1.0 MiB", "1.0 MiB", + "1024.0 MiB", "1.0 GiB", "1.0 GiB", "1024.0 GiB", "29.2 TiB", "1.0 TiB", + "1.0 PiB", // <- Would have expected 1024.0 TiB, but who cares? + "1.0 PiB", "1.0 PiB" }; + assertEquals(expectedOutput.length, input.length); + for (int i = 0; i < input.length; i++) { + assertEquals("Mismatch for input " + input[i], expectedOutput[i], + DirectoryListing.formatBytes(input[i])); + } + } + + private static final String jsonIndex + = "{"index_created":"2016-02-02 00:02"," + + ""path":"https://some.collector.url%5C"," + + ""directories":[{"path":"a1"," + + ""directories":[{"path":"p1"," + + ""files":[{"path":"file1","size":624156," + + ""last_modified":"2012-01-01 13:13"},{"path":"file2"," + + ""size":1010648," + + ""last_modified":"2012-02-02 14:14"}]},{"path":"p2"," + + ""files":[{"path":"file3","size":624156," + + ""last_modified":"2012-03-03 15:15"}]}]}]}"; + + @Test + public void testListing() throws Exception { + DirectoryListing dl = new DirectoryListing(IndexNode + .fetchIndex(new ByteArrayInputStream(jsonIndex.getBytes()))); + assertEquals(4, dl.size()); + for (String key : new String[]{"/collector/a1/", "/collector/", + "/collector/a1/p2/", "/collector/a1/p1/"}) { + assertTrue("Missing: " + key, dl.keySet().contains(key)); + } + assertEquals("[Parent Directory, /collector.html, , ]", + Arrays.toString(dl.get("/collector/").get(0))); + assertEquals(3, dl.get("/collector/a1/").size()); + assertEquals("[Parent Directory, /collector/, , ]", + Arrays.toString(dl.get("/collector/a1/").get(0))); + assertEquals("[p1, /collector/a1/p1/, , ]", + Arrays.toString(dl.get("/collector/a1/").get(1))); + assertEquals("[p2, /collector/a1/p2/, , ]", + Arrays.toString(dl.get("/collector/a1/").get(2))); + assertEquals("[Parent Directory, /collector/a1/, , ]", + Arrays.toString(dl.get("/collector/a1/p1/").get(0))); + assertEquals(2, dl.get("/collector/a1/p2/").size()); + assertEquals("[file3, https://some.collector.url/a1/p2/file3, " + + "2012-03-03 15:15, 609.5 KiB]", + Arrays.toString(dl.get("/collector/a1/p2/").get(1))); + } +} +
tor-commits@lists.torproject.org