Reputation: 1327
I am implementing an upload functionality in my Vaadin web application that uses drag & drop, like in this Vaadin sampler example.
My code is almost identical to the example code there. When trying my code and the linked example however, there is one important difference: When dropping a folder, my code starts to show the progress spinner, but never finishes. None of the StreamVariable
callback methods are ever called. No bytes are ever actually uploaded.
The sample application simply does nothing (user visible at least).
I actually don't even want the user to be able to upload folders, but i need to be able to detect whether the dropped "file" is a folder.
Unfortunately, neither the WrapperTransferable
nor the Html5File
objects i get give me any indication. I've only come up with heuristics to determine whether i have a file or folder: Check that the MIME type is empty, check that the filesisze is small, check that there are no dots in the filename. None of these is very safe though.
How can i detect and prevent an attempted upload of a folder?
Here is my code (again, almost a straight copy of the linked Vaadin example).
public class AttachmentDropBox extends DragAndDropWrapper implements DropHandler {
private final ProgressBar progress;
public AttachmentDropBox(Component root, ProgressBar progress) {
super(root);
this.progress = progress;
progress.setIndeterminate(true);
setDropHandler(this);
}
@Override
public void drop(DragAndDropEvent dropEvent) {
// expecting this to be an html5 drag
if (!(dropEvent.getTransferable() instanceof WrapperTransferable)) {
return;
}
final WrapperTransferable tr = (WrapperTransferable) dropEvent.getTransferable();
final Html5File[] files = tr.getFiles();
if (files == null) {
return;
}
if (files.length != 1) {
Notification.show("Please upload single files only", Notification.Type.WARNING_MESSAGE);
return;
}
Html5File file = files[0];
if (file.getFileSize() > settings.getClientMaxAttachmentSize()) {
Notification.show(
MessageFormat.format("File rejected. Attachments may not exceed {0} in size.",
FileUtils.byteCountToDisplaySize(settings.getClientMaxAttachmentSize())),
Notification.Type.WARNING_MESSAGE);
return;
}
final ByteArrayOutputStream bas = new ByteArrayOutputStream();
final StreamVariable streamVariable = new StreamVariable() {
@Override
public OutputStream getOutputStream() {
return bas;
}
@Override
public boolean listenProgress() {
return false;
}
@Override
public void onProgress(final StreamingProgressEvent event) {
// not called
}
@Override
public void streamingStarted(final StreamingStartEvent event) {
LOG.info("Upload started: " + event.getFileName());
}
@Override
public void streamingFinished(final StreamingEndEvent event) {
progress.setVisible(false);
LOG.info("Upload finished: " + event.getFileName());
}
@Override
public void streamingFailed(final StreamingErrorEvent event) {
Notification.show(
MessageFormat.format("Failed to upload file: {0}",
StringUtils.abbreviate(event.getException().getMessage(), 100)),
Notification.Type.ERROR_MESSAGE);
LOG.error("Failed to upload file '{}'", event.getFileName(), event.getException());
progress.setVisible(false);
}
@Override
public boolean isInterrupted() {
return false;
}
};
file.setStreamVariable(streamVariable);
progress.setVisible(true);
}
@Override
public AcceptCriterion getAcceptCriterion() {
return AcceptAll.get();
}
}
Upvotes: 2
Views: 481
Reputation: 1327
This problem has been fixed in Vaadin 7.7.0
This is the corresponding change note:
Folder upload is not supported by most of the browsers and can cause StreamVariable methods not fire on some configurations. This fix tries to detect and prevent uploading of folders.
Upvotes: 1