Skip to content

Commit 14cbb20

Browse files
authored
Merge pull request #918 from conveyal/freeform-guardrails
Fix freeform guardrails
2 parents f349656 + 6a6ab47 commit 14cbb20

File tree

5 files changed

+39
-30
lines changed

5 files changed

+39
-30
lines changed

src/main/java/com/conveyal/analysis/components/HttpApi.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ private void respondToException(Exception e, Request request, Response response,
179179
// Include a stack trace except when the error is known to be about unauthenticated or unauthorized access,
180180
// in which case we don't want to leak information about the server to people scanning it for weaknesses.
181181
if (type != UNAUTHORIZED && type != FORBIDDEN) {
182-
body.put("stackTrace", errorEvent.stackTrace);
182+
body.put("stackTrace", errorEvent.filteredStackTrace);
183183
}
184184
response.status(code);
185185
response.type("application/json");

src/main/java/com/conveyal/analysis/components/eventbus/ErrorEvent.java

+9-4
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
*/
1212
public class ErrorEvent extends Event {
1313

14-
// We may serialize this object, so we convert the Throwable to two strings to control its representation.
14+
// All Events are intended to be eligible for serialization into a log or database, so we convert the Throwable to
15+
// some Strings to determine its representation in a simple way.
1516
// For flexibility in event handlers, it is tempting to hold on to the original Throwable instead of derived
1617
// Strings. Exceptions are famously slow, but it's the initial creation and filling in the stack trace that are
17-
// slow. Once the instace exists, repeatedly examining its stack trace should not be prohibitively costly. Still,
18-
// we do probably gain some efficiency by converting the stack trace to a String once and reusing that.
18+
// slow. Once the instance exists, repeatedly examining its stack trace should not be prohibitively costly.
1919

2020
public final String summary;
2121

@@ -25,11 +25,16 @@ public class ErrorEvent extends Event {
2525
*/
2626
public final String httpPath;
2727

28+
/** The full stack trace of the exception that occurred. */
2829
public final String stackTrace;
2930

31+
/** A minimal stack trace showing the immediate cause within Conveyal code. */
32+
public final String filteredStackTrace;
33+
3034
public ErrorEvent (Throwable throwable, String httpPath) {
3135
this.summary = ExceptionUtils.shortCauseString(throwable);
3236
this.stackTrace = ExceptionUtils.stackTraceString(throwable);
37+
this.filteredStackTrace = ExceptionUtils.filterStackTrace(throwable);
3338
this.httpPath = httpPath;
3439
}
3540

@@ -56,7 +61,7 @@ public String traceWithContext (boolean verbose) {
5661
if (verbose) {
5762
builder.append(stackTrace);
5863
} else {
59-
builder.append(filterStackTrace(stackTrace));
64+
builder.append(filteredStackTrace);
6065
}
6166
return builder.toString();
6267
}

src/main/java/com/conveyal/analysis/results/MultiOriginAssembler.java

+23-15
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import com.conveyal.file.FileStorage;
88
import com.conveyal.file.FileStorageFormat;
99
import com.conveyal.r5.analyst.PointSet;
10+
import com.conveyal.r5.analyst.cluster.PathResult;
11+
import com.conveyal.r5.analyst.cluster.RegionalTask;
1012
import com.conveyal.r5.analyst.cluster.RegionalWorkResult;
1113
import com.conveyal.r5.util.ExceptionUtils;
1214
import org.slf4j.Logger;
@@ -89,21 +91,27 @@ public MultiOriginAssembler (RegionalAnalysis regionalAnalysis, Job job, FileSto
8991
this.job = job;
9092
this.nOriginsTotal = job.nTasksTotal;
9193
this.originsReceived = new BitSet(job.nTasksTotal);
92-
// Check that origin and destination sets are not too big for generating CSV files.
93-
if (!job.templateTask.makeTauiSite &&
94-
job.templateTask.destinationPointSetKeys[0].endsWith(FileStorageFormat.FREEFORM.extension)
95-
) {
96-
// This requires us to have already loaded this destination pointset instance into the transient field.
97-
PointSet destinationPointSet = job.templateTask.destinationPointSets[0];
98-
if ((job.templateTask.recordTimes || job.templateTask.includePathResults) && !job.templateTask.oneToOne) {
99-
if (nOriginsTotal * destinationPointSet.featureCount() > MAX_FREEFORM_OD_PAIRS ||
100-
destinationPointSet.featureCount() > MAX_FREEFORM_DESTINATIONS
101-
) {
102-
throw new AnalysisServerException(String.format(
103-
"Freeform requests limited to %d destinations and %d origin-destination pairs.",
104-
MAX_FREEFORM_DESTINATIONS, MAX_FREEFORM_OD_PAIRS
105-
));
106-
}
94+
// If results have been requested for freeform origins, check that the origin and
95+
// destination pointsets are not too big for generating CSV files.
96+
RegionalTask task = job.templateTask;
97+
if (!task.makeTauiSite && task.destinationPointSetKeys[0].endsWith(FileStorageFormat.FREEFORM.extension)) {
98+
// This requires us to have already loaded this destination pointset instance into the transient field.
99+
PointSet destinationPointSet = task.destinationPointSets[0];
100+
int nDestinations = destinationPointSet.featureCount();
101+
int nODPairs = task.oneToOne ? nOriginsTotal : nOriginsTotal * nDestinations;
102+
if (task.recordTimes &&
103+
(nDestinations > MAX_FREEFORM_DESTINATIONS || nODPairs > MAX_FREEFORM_OD_PAIRS)) {
104+
throw AnalysisServerException.badRequest(String.format(
105+
"Travel time results limited to %d destinations and %d origin-destination pairs.",
106+
MAX_FREEFORM_DESTINATIONS, MAX_FREEFORM_OD_PAIRS
107+
));
108+
}
109+
if (task.includePathResults &&
110+
(nDestinations > PathResult.MAX_PATH_DESTINATIONS || nODPairs > MAX_FREEFORM_OD_PAIRS)) {
111+
throw AnalysisServerException.badRequest(String.format(
112+
"Path results limited to %d destinations and %d origin-destination pairs.",
113+
PathResult.MAX_PATH_DESTINATIONS, MAX_FREEFORM_OD_PAIRS
114+
));
107115
}
108116
}
109117

src/main/java/com/conveyal/r5/analyst/cluster/PathResult.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public class PathResult {
3838
* These results are returned to the backend over an HTTP API so we don't want to risk making them too huge.
3939
* This could be set to a higher number in cases where you know the result return channel can handle the size.
4040
*/
41-
public static int maxDestinations = 5000;
41+
public static final int MAX_PATH_DESTINATIONS = 5_000;
4242

4343
private final int nDestinations;
4444
/**
@@ -49,7 +49,7 @@ public class PathResult {
4949
public final Multimap<RouteSequence, Iteration>[] iterationsForPathTemplates;
5050
private final TransitLayer transitLayer;
5151

52-
public static String[] DATA_COLUMNS = new String[]{
52+
public static final String[] DATA_COLUMNS = new String[]{
5353
"routes",
5454
"boardStops",
5555
"alightStops",
@@ -70,8 +70,8 @@ public PathResult(AnalysisWorkerTask task, TransitLayer transitLayer) {
7070
// In regional analyses, return paths to all destinations
7171
nDestinations = task.nTargetsPerOrigin();
7272
// This limitation reflects the initial design, for use with freeform pointset destinations
73-
if (nDestinations > maxDestinations) {
74-
throw new UnsupportedOperationException("Number of detailed path destinations exceeds limit of " + maxDestinations);
73+
if (nDestinations > MAX_PATH_DESTINATIONS) {
74+
throw new UnsupportedOperationException("Number of detailed path destinations exceeds limit of " + MAX_PATH_DESTINATIONS);
7575
}
7676
}
7777
iterationsForPathTemplates = new Multimap[nDestinations];

src/main/java/com/conveyal/r5/util/ExceptionUtils.java

+2-6
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ public static String shortAndLongString (Throwable throwable) {
5555
* and all additional frames that come from Conveyal packages. This yields a much shorter stack trace that still
5656
* shows where the exception was thrown and where the problem originates in our own code.
5757
*/
58-
public static String filterStackTrace (String stackTrace) {
59-
if (stackTrace == null) return null;
58+
public static String filterStackTrace (Throwable throwable) {
59+
String stackTrace = stackTraceString(throwable);
6060
final String unknownFrame = "Unknown stack frame, probably optimized out by JVM.";
6161
String error = stackTrace.lines().findFirst().get();
6262
String frame = stackTrace.lines()
@@ -71,8 +71,4 @@ public static String filterStackTrace (String stackTrace) {
7171
return String.join("\n", error, frame, conveyalFrame);
7272
}
7373

74-
public static String filterStackTrace (Throwable throwable) {
75-
return filterStackTrace(stackTraceString(throwable));
76-
}
77-
7874
}

0 commit comments

Comments
 (0)