Commit 75981fe7 authored by Karsten Loesing's avatar Karsten Loesing
Browse files

Support quoted qualified search terms.

With this patch, the "search" parameter does not only accept unquoted
qualified search terms like `search=contact:John Doe` where "John"
would be looked up in the contact line and "Doe" in the nickname or
base64-encoded fingerprint. It also accepts quoted qualified search
terms like `search=contact:"John Doe"` where "John Doe" would be
looked up in the contact line. It further accepts escaped double
quotes (\") within quoted qualified search terms.

Implements #21366.
parent 0cb09d1e
# Changes in version 4.2-1.6.1 - 2017-10-2?
# Changes in version 4.3-1.7.0 - 2017-1?-??
* Medium changes
- Support quoted qualified search terms.
# Changes in version 4.2-1.6.1 - 2017-10-26
* Medium changes
- Fix two NullPointerExceptions caused by accessing optional parts
......
......@@ -3,6 +3,8 @@
package org.torproject.onionoo.server;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
......@@ -169,6 +171,12 @@ public class ResourceServlet extends HttpServlet {
}
if (!parameterMap.containsKey(parameterKey)) {
String parameterValue = parts[1];
if (parameterValue.startsWith("\"")
&& parameterValue.endsWith("\"")) {
parameterValue = parameterValue
.substring(1, parameterValue.length() - 1)
.replaceAll("\\\\\"", "\"");
}
parameterMap.put(parameterKey, parameterValue);
}
} else {
......@@ -388,7 +396,7 @@ public class ResourceServlet extends HttpServlet {
+ "^[0-9a-zA-Z+/]{1,27}$|" /* Base64 fingerprint. */
+ "^[0-9a-zA-Z\\.]{1,19}$|" /* Nickname or IPv4 address. */
+ ipv6AddressPatternString + "|" /* IPv6 address. */
+ "^[a-zA-Z_]+:\\p{Graph}+$" /* Qualified search term. */);
+ "^[a-zA-Z_]+:\"?[\\p{Graph} ]+\"?$"); /* Qualified search term. */
protected static String[] parseSearchParameters(String queryString) {
Matcher searchQueryStringMatcher = searchQueryStringPattern.matcher(
......@@ -398,15 +406,39 @@ public class ResourceServlet extends HttpServlet {
return null;
}
String parameter = searchQueryStringMatcher.group(1);
String[] searchParameters =
String[] spaceSeparatedParts =
parameter.replaceAll("%20", " ").split(" ");
List<String> searchParameters = new ArrayList<>();
StringBuilder doubleQuotedSearchTerm = null;
for (String spaceSeparatedPart : spaceSeparatedParts) {
if ((StringUtils.countMatches(spaceSeparatedPart, '"')
- StringUtils.countMatches(spaceSeparatedPart, "\\\"")) % 2 == 0) {
if (null == doubleQuotedSearchTerm) {
searchParameters.add(spaceSeparatedPart);
} else {
doubleQuotedSearchTerm.append(' ').append(spaceSeparatedPart);
}
} else {
if (null == doubleQuotedSearchTerm) {
doubleQuotedSearchTerm = new StringBuilder(spaceSeparatedPart);
} else {
doubleQuotedSearchTerm.append(' ').append(spaceSeparatedPart);
searchParameters.add(doubleQuotedSearchTerm.toString());
doubleQuotedSearchTerm = null;
}
}
}
if (null != doubleQuotedSearchTerm) {
/* Opening double quote is not followed by closing double quote. */
return null;
}
for (String searchParameter : searchParameters) {
if (!searchParameterPattern.matcher(searchParameter).matches()) {
/* Illegal search term. */
return null;
}
}
return searchParameters;
return searchParameters.toArray(new String[0]);
}
private static Pattern fingerprintParameterPattern =
......
......@@ -169,7 +169,7 @@ public class ResourceServletTest {
new TreeSet<>(Arrays.asList(new String[] { "Fast",
"Running", "Unnamed", "V2Dir", "Valid" })), 63L, "a1",
DateTimeHelper.parse("2013-04-16 18:00:00"), "AS6830",
"1024D/51E2A1C7 steven j. murdoch "
"1024d/51e2a1c7 \"steven j. murdoch\" "
+ "<tor+steven.murdoch@cl.cam.ac.uk> <fb-token:5sr_k_zs2wm=>",
new TreeSet<String>(), new TreeSet<String>(), "0.2.3.25");
this.relays.put("0025C136C1F3A9EEFE2AE3F918F03BFA21B5070B",
......@@ -932,6 +932,40 @@ public class ResourceServletTest {
new String[] { "TimMayTribute" }, 0, null);
}
@Test(timeout = 100)
public void testSearchDoubleQuotedEmailAddress() {
this.assertSummaryDocument(
"/summary?search=contact:\"klaus dot zufall at gmx dot de\"", 1,
new String[] { "TorkaZ" }, 0, null);
}
@Test(timeout = 100)
public void testSearchDoubleQuotedContactAndNickname() {
this.assertSummaryDocument(
"/summary?search=contact:\"dot de\" TorkaZ", 1,
new String[] { "TorkaZ" }, 0, null);
}
@Test(timeout = 100)
public void testSearchMissingEndingDoubleQuote() {
this.assertErrorStatusCode(
"/summary?search=contact:\"klaus dot zufall at gmx dot de", 400);
}
@Test(timeout = 100)
public void testSearchEvenNumberOfDoubleQuotes() {
this.assertSummaryDocument(
"/summary?search=contact:\"\"\" \"\"\"", 0,
null, 0, null);
}
@Test(timeout = 100)
public void testSearchContactEscapedDoubleQuotes() {
this.assertSummaryDocument(
"/summary?search=contact:\"1024D/51E2A1C7 \\\"Steven J. Murdoch\\\"\"",
1, new String[] { "TimMayTribute" }, 0, null);
}
@Test(timeout = 100)
public void testLookupFingerprint() {
this.assertSummaryDocument(
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment