From 68be95e48405be0e5d54b3d8ddb66de454fcbfed Mon Sep 17 00:00:00 2001 From: Fabian Lange Date: Wed, 12 Jun 2013 21:21:31 +0200 Subject: [PATCH] Support uploading files larger 2GB via drag and drop and file input (#11947). Vaadin mostly just passes through the value from the Javascript File object on drag and drop. As per specification (http://www.w3.org/TR/file-upload/#blob) the size value can be "long". The size attribute of Html5File was already long, but this patch makes sure long values actually are transported correctly from the client side Transferable. Additionally, the file upload handling in FileUploadHandler was determining the length of the upload via the Servlet Spec getContentLength method of the request. However the spec was written at a time where 2GB were unthinkable. Luckily containers return this value by querying the Content-Length header, which can transport values of "long". So instead of using the Servlet Spec method, FileUploadHandler evaluates the header itself. AbstractStreamingEvent already was supporting "long" values. For Drag&Drop, the file size needs to be serialized as double, because long is not supported in JSNI. Change-Id: I606fca7430c65c20144793fa011cb2f6ee3a0415 --- .../com/vaadin/client/ui/dd/VHtml5File.java | 8 +++++- .../communication/FileUploadHandler.java | 25 ++++++++++++++----- .../src/com/vaadin/ui/DragAndDropWrapper.java | 2 +- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/client/src/com/vaadin/client/ui/dd/VHtml5File.java b/client/src/com/vaadin/client/ui/dd/VHtml5File.java index 4b36e7fd1b..c4ad615fbd 100644 --- a/client/src/com/vaadin/client/ui/dd/VHtml5File.java +++ b/client/src/com/vaadin/client/ui/dd/VHtml5File.java @@ -35,7 +35,13 @@ public class VHtml5File extends JavaScriptObject { return this.type; }-*/; - public native final int getSize() + /* + * Browser implementations support files >2GB dropped and report the value + * as long. Due to JSNI limitations this value needs to be sent as double + * and then cast back to a long value. + * www.gwtproject.org/doc/latest/DevGuideCodingBasicsJSNI.html#important + */ + public native final double getSize() /*-{ return this.size ? this.size : 0; }-*/; diff --git a/server/src/com/vaadin/server/communication/FileUploadHandler.java b/server/src/com/vaadin/server/communication/FileUploadHandler.java index e9569d45a1..8014dba12d 100644 --- a/server/src/com/vaadin/server/communication/FileUploadHandler.java +++ b/server/src/com/vaadin/server/communication/FileUploadHandler.java @@ -271,7 +271,7 @@ public class FileUploadHandler implements RequestHandler { // if boundary string does not exist, the posted file is from // XHR2.post(File) doHandleXhrFilePost(session, request, response, streamVariable, - variableName, source, request.getContentLength()); + variableName, source, getContentLength(request)); } return true; } @@ -323,7 +323,7 @@ public class FileUploadHandler implements RequestHandler { final InputStream inputStream = request.getInputStream(); - int contentLength = request.getContentLength(); + long contentLength = getContentLength(request); boolean atStart = false; boolean firstFileFieldFound = false; @@ -390,9 +390,22 @@ public class FileUploadHandler implements RequestHandler { } + /* + * request.getContentLength() is limited to "int" by the Servlet + * specification. To support larger file uploads manually evaluate the + * Content-Length header which can contain long values. + */ + private long getContentLength(VaadinRequest request) { + try { + return Long.parseLong(request.getHeader("Content-Length")); + } catch (NumberFormatException e) { + return -1l; + } + } + private void handleFileUploadValidationAndData(VaadinSession session, InputStream inputStream, StreamVariable streamVariable, - String filename, String mimeType, int contentLength, + String filename, String mimeType, long contentLength, ClientConnector connector, String variableName) throws UploadException { session.lock(); @@ -461,7 +474,7 @@ public class FileUploadHandler implements RequestHandler { protected void doHandleXhrFilePost(VaadinSession session, VaadinRequest request, VaadinResponse response, StreamVariable streamVariable, String variableName, - ClientConnector owner, int contentLength) throws IOException { + ClientConnector owner, long contentLength) throws IOException { // These are unknown in filexhr ATM, maybe add to Accept header that // is accessible in portlets @@ -491,7 +504,7 @@ public class FileUploadHandler implements RequestHandler { */ protected final boolean streamToReceiver(VaadinSession session, final InputStream in, StreamVariable streamVariable, - String filename, String type, int contentLength) + String filename, String type, long contentLength) throws UploadException { if (streamVariable == null) { throw new IllegalStateException( @@ -499,7 +512,7 @@ public class FileUploadHandler implements RequestHandler { } OutputStream out = null; - int totalBytes = 0; + long totalBytes = 0; StreamingStartEventImpl startedEvent = new StreamingStartEventImpl( filename, type, contentLength); try { diff --git a/server/src/com/vaadin/ui/DragAndDropWrapper.java b/server/src/com/vaadin/ui/DragAndDropWrapper.java index 6c6aa3c3f4..7a2cfb82e4 100644 --- a/server/src/com/vaadin/ui/DragAndDropWrapper.java +++ b/server/src/com/vaadin/ui/DragAndDropWrapper.java @@ -54,7 +54,7 @@ public class DragAndDropWrapper extends CustomComponent implements DropTarget, for (int i = 0; i < fc; i++) { Html5File file = new Html5File( (String) rawVariables.get("fn" + i), // name - (Integer) rawVariables.get("fs" + i), // size + ((Double) rawVariables.get("fs" + i)).longValue(), // size (String) rawVariables.get("ft" + i)); // mime String id = (String) rawVariables.get("fi" + i); files[i] = file; -- 2.39.5