diff options
-rw-r--r-- | server/src/com/vaadin/server/communication/FileUploadHandler.java | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/server/src/com/vaadin/server/communication/FileUploadHandler.java b/server/src/com/vaadin/server/communication/FileUploadHandler.java index 3f6bfd9267..88f2e4b120 100644 --- a/server/src/com/vaadin/server/communication/FileUploadHandler.java +++ b/server/src/com/vaadin/server/communication/FileUploadHandler.java @@ -227,6 +227,9 @@ public class FileUploadHandler implements RequestHandler { /* Same as in apache commons file upload library that was previously used. */ private static final int MAX_UPLOAD_BUFFER_SIZE = 4 * 1024; + /* Minimum interval which will be used for streaming progress events. */ + public static final int DEFAULT_STREAMING_PROGRESS_EVENT_INTERVAL_MS = 500; + @Override public boolean handleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException { @@ -537,26 +540,35 @@ public class FileUploadHandler implements RequestHandler { } final byte buffer[] = new byte[MAX_UPLOAD_BUFFER_SIZE]; + long lastStreamingEvent = 0; int bytesReadToBuffer = 0; - while ((bytesReadToBuffer = in.read(buffer)) > 0) { - out.write(buffer, 0, bytesReadToBuffer); - totalBytes += bytesReadToBuffer; + do { + bytesReadToBuffer = in.read(buffer); + if (bytesReadToBuffer > 0) { + out.write(buffer, 0, bytesReadToBuffer); + totalBytes += bytesReadToBuffer; + } if (listenProgress) { - // update progress if listener set and contentLength - // received - session.lock(); - try { - StreamingProgressEventImpl progressEvent = new StreamingProgressEventImpl( - filename, type, contentLength, totalBytes); - streamVariable.onProgress(progressEvent); - } finally { - session.unlock(); + long now = System.currentTimeMillis(); + // to avoid excessive session locking and event storms, + // events are sent in intervals, or at the end of the file. + if (lastStreamingEvent + getProgressEventInterval() <= now + || bytesReadToBuffer <= 0) { + lastStreamingEvent = now; + session.lock(); + try { + StreamingProgressEventImpl progressEvent = new StreamingProgressEventImpl( + filename, type, contentLength, totalBytes); + streamVariable.onProgress(progressEvent); + } finally { + session.unlock(); + } } } if (streamVariable.isInterrupted()) { throw new UploadInterruptedException(); } - } + } while (bytesReadToBuffer > 0); // upload successful out.close(); @@ -599,6 +611,17 @@ public class FileUploadHandler implements RequestHandler { return startedEvent.isDisposed(); } + /** + * To prevent event storming, streaming progress events are sent in this + * interval rather than every time the buffer is filled. This fixes #13155. + * To adjust this value override the method, and register your own handler + * in VaadinService.createRequestHandlers(). The default is 500ms, and + * setting it to 0 effectively restores the old behavior. + */ + protected int getProgressEventInterval() { + return DEFAULT_STREAMING_PROGRESS_EVENT_INTERVAL_MS; + } + static void tryToCloseStream(OutputStream out) { try { // try to close output stream (e.g. file handle) |