Skip to content

Commit cf2ec17

Browse files
committed
fix(GTFS+): fix GTFS+ file upload
1 parent e4a007e commit cf2ec17

File tree

2 files changed

+25
-20
lines changed

2 files changed

+25
-20
lines changed

src/main/java/com/conveyal/datatools/manager/controllers/api/GtfsPlusController.java

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@
1111
import com.conveyal.gtfs.GTFSFeed;
1212
import com.fasterxml.jackson.databind.JsonNode;
1313
import com.fasterxml.jackson.databind.node.ArrayNode;
14+
import com.google.common.io.ByteStreams;
1415
import org.slf4j.Logger;
1516
import org.slf4j.LoggerFactory;
1617
import spark.Request;
1718
import spark.Response;
1819

1920
import javax.servlet.MultipartConfigElement;
2021
import javax.servlet.ServletException;
22+
import javax.servlet.ServletInputStream;
23+
import javax.servlet.ServletRequestWrapper;
2124
import javax.servlet.http.HttpServletResponse;
2225
import javax.servlet.http.Part;
2326
import java.io.BufferedInputStream;
@@ -55,28 +58,26 @@ public class GtfsPlusController {
5558
private static FeedStore gtfsPlusStore = new FeedStore("gtfsplus");
5659

5760

58-
public static Boolean uploadGtfsPlusFile (Request req, Response res) throws IOException, ServletException {
59-
60-
//FeedSource s = FeedSource.retrieveById(req.queryParams("feedSourceId"));
61-
String feedVersionId = req.params("versionid");
62-
63-
if (req.raw().getAttribute("org.eclipse.jetty.multipartConfig") == null) {
64-
MultipartConfigElement multipartConfigElement = new MultipartConfigElement(System.getProperty("java.io.tmpdir"));
65-
req.raw().setAttribute("org.eclipse.jetty.multipartConfig", multipartConfigElement);
66-
}
67-
68-
Part part = req.raw().getPart("file");
69-
70-
LOG.info("Saving GTFS+ feed {} from upload for version " + feedVersionId);
71-
72-
73-
InputStream uploadStream;
61+
private static Boolean uploadGtfsPlusFile (Request req, Response res) throws IOException, ServletException {
7462
try {
75-
uploadStream = part.getInputStream();
76-
gtfsPlusStore.newFeed(feedVersionId, uploadStream, null);
77-
} catch (IOException e) {
63+
String feedVersionId = req.params("versionid");
64+
File newGtfsFile = new File(gtfsPlusStore.getPathToFeed(feedVersionId));
65+
// Bypass Spark's request wrapper which always caches the request body in memory that may be a very large
66+
// GTFS file. Also, the body of the request is the GTFS file instead of using multipart form data because
67+
// multipart form handling code also caches the request body.
68+
ServletInputStream inputStream = ((ServletRequestWrapper) req.raw()).getRequest().getInputStream();
69+
FileOutputStream fileOutputStream = new FileOutputStream(newGtfsFile);
70+
// Guava's ByteStreams.copy uses a 4k buffer (no need to wrap output stream), but does not close streams.
71+
ByteStreams.copy(inputStream, fileOutputStream);
72+
fileOutputStream.close();
73+
inputStream.close();
74+
if (newGtfsFile.length() == 0) {
75+
throw new IOException("No file found in request body.");
76+
}
77+
LOG.info("Saving GTFS+ feed {} from upload for version " + feedVersionId);
78+
} catch (Exception e) {
7879
LOG.error("Unable to open input stream from upload");
79-
logMessageAndHalt(req, 400, "Unable to open input stream from upload", e);
80+
logMessageAndHalt(req, 500, "Unable to read uploaded GTFS+ file.", e);
8081
}
8182

8283
return true;

src/main/java/com/conveyal/datatools/manager/persistence/FeedStore.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ private static String getS3Key (String id) {
171171
return s3Prefix + id;
172172
}
173173

174+
public String getPathToFeed (String id) {
175+
return new File(path, id).getAbsolutePath();
176+
}
177+
174178
/**
175179
* Get the feed with the given ID.
176180
*/

0 commit comments

Comments
 (0)