commit cfa54b8f076eced634d484e2cdaa4af84ab477fc Author: Karsten Loesing karsten.loesing@gmx.net Date: Thu Jul 21 15:17:03 2011 +0200
Enable downloading all descriptors referenced by a consensus. --- .../ernie/web/ServerDescriptorServlet.java | 138 +++++++++++++++----- 1 files changed, 104 insertions(+), 34 deletions(-)
diff --git a/src/org/torproject/ernie/web/ServerDescriptorServlet.java b/src/org/torproject/ernie/web/ServerDescriptorServlet.java index 960bd75..1db68c4 100644 --- a/src/org/torproject/ernie/web/ServerDescriptorServlet.java +++ b/src/org/torproject/ernie/web/ServerDescriptorServlet.java @@ -2,6 +2,8 @@ package org.torproject.ernie.web;
import java.io.*; import java.sql.*; +import java.text.*; +import java.util.*; import java.util.logging.*; import java.util.regex.*;
@@ -36,56 +38,124 @@ public class ServerDescriptorServlet extends HttpServlet { HttpServletResponse response) throws IOException, ServletException {
- /* Check desc-id parameter. */ + /* Read desc-id and/or valid-after parameters. */ + String validAfterParameter = request.getParameter("valid-after"); String descIdParameter = request.getParameter("desc-id"); - if (descIdParameter == null || descIdParameter.length() < 8 || - descIdParameter.length() > 40) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - return; - } - String descId = descIdParameter.toLowerCase(); - Pattern descIdPattern = Pattern.compile("^[0-9a-f]+$"); - Matcher descIdMatcher = descIdPattern.matcher(descId); - if (!descIdMatcher.matches()) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - return; - }
- /* Look up descriptor in the database. */ - String descriptor = null; - byte[] rawDescriptor = null; - try { - Connection conn = ds.getConnection(); - Statement statement = conn.createStatement(); - String query = "SELECT descriptor, rawdesc FROM descriptor " - + "WHERE descriptor LIKE '" + descId + "%'"; - ResultSet rs = statement.executeQuery(query); - if (rs.next()) { - descriptor = rs.getString(1); - rawDescriptor = rs.getBytes(2); + /* See if we were given a desc-id parameter. If so, look up this + * descriptor and return it. */ + List<byte[]> rawDescriptors = new ArrayList<byte[]>(); + String filename = null; + if (descIdParameter != null && validAfterParameter == null) { + if (descIdParameter.length() < 8 || + descIdParameter.length() > 40) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + String descId = descIdParameter.toLowerCase(); + Pattern descIdPattern = Pattern.compile("^[0-9a-f]+$"); + Matcher descIdMatcher = descIdPattern.matcher(descId); + if (!descIdMatcher.matches()) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + /* Look up descriptor in the database. */ + try { + Connection conn = ds.getConnection(); + Statement statement = conn.createStatement(); + String query = "SELECT descriptor, rawdesc FROM descriptor " + + "WHERE descriptor LIKE '" + descId + "%'"; + ResultSet rs = statement.executeQuery(query); + if (rs.next()) { + filename = rs.getString(1); + rawDescriptors.add(rs.getBytes(2)); + } + rs.close(); + statement.close(); + conn.close(); + } catch (SQLException e) { + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + return; } - rs.close(); - statement.close(); - conn.close(); - } catch (SQLException e) { - response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + + /* See if we were given a valid-after parameter. If so, return all + * descriptors referenced from the consensus published at that + * time. */ + } else if (descIdParameter == null && validAfterParameter != null) { + if (validAfterParameter.length() != + "yyyy-MM-dd-HH-mm-ss".length()) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + SimpleDateFormat parameterFormat = new SimpleDateFormat( + "yyyy-MM-dd-HH-mm-ss"); + parameterFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + long parsedTimestamp = -1L; + try { + parsedTimestamp = parameterFormat.parse(validAfterParameter). + getTime(); + } catch (ParseException e) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + if (parsedTimestamp < 0L) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + filename = validAfterParameter + "-descriptors"; + + /* Look up descriptors in the database. */ + SimpleDateFormat databaseFormat = new SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss"); + databaseFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + String databaseParameter = databaseFormat.format(parsedTimestamp); + try { + Connection conn = this.ds.getConnection(); + Statement statement = conn.createStatement(); + String query = "SELECT descriptor.rawdesc FROM statusentry " + + "JOIN descriptor ON statusentry.descriptor = " + + "descriptor.descriptor WHERE validafter = '" + + databaseParameter + "'"; + ResultSet rs = statement.executeQuery(query); + while (rs.next()) { + rawDescriptors.add(rs.getBytes(1)); + } + rs.close(); + statement.close(); + conn.close(); + } catch (SQLException e) { + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + return; + } + + /* Return an error if neither desc-id nor valid-after parameter was + * given (or both of them). */ + } else { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); return; }
/* Write response. */ - if (rawDescriptor == null) { + if (rawDescriptors.size() == 0) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } try { response.setContentType("text/plain"); + int responseLength = 0; + for (byte[] rawDescriptor : rawDescriptors) { + responseLength += rawDescriptor.length; + } response.setHeader("Content-Length", String.valueOf( - rawDescriptor.length)); + responseLength)); response.setHeader("Content-Disposition", "inline; filename="" - + descriptor + """); + + filename + """); BufferedOutputStream output = new BufferedOutputStream( response.getOutputStream()); - output.write(rawDescriptor); + for (byte[] rawDescriptor : rawDescriptors) { + output.write(rawDescriptor); + } output.flush(); output.close(); } finally {