Upload Component: restricting file size

Hi there,

I’d like to limit the size of the files that users upload on BlackBeltFactory. Currently there are 6GB of pictures, just for the user’s tiny pictures (we keep the originals).

This is my current file upload code:


public abstract class UploadComponent extends Upload
                        implements Upload.SucceededListener,
                                   Upload.FailedListener,
                                   Upload.Receiver {
    
	protected String directory;
	protected File file;
	
    public UploadComponent(String fieldCaption, String buttonCaption, String directoryParam) {
        super(fieldCaption, null);
        setReceiver( this); 
        this.directory = directoryParam;
        this.setButtonCaption(buttonCaption);
        this.addListener((Upload.SucceededListener) this);
        this.addListener((Upload.FailedListener) this);
    }

    @Override
    public OutputStream receiveUpload(String filename,  String MIMEType) {
        FileOutputStream fos = null;
        FileUtils.ensureFolderExists(directory);
        file = new File(directory, filename);
 
        try {
            fos = new FileOutputStream(file);
        } catch (final java.io.FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        return fos; // Return the output stream to write to
    }

	public String getDirectory() {
		return directory;
	}

	public File getFile() {
		return file;
	}
    
    
}

My receiveUpload method sends an OuputStream back to Vaadin.
I’d like to limit files to 100Kb max.

How would you recommend me to do that?

Many thanks.
John.

Hi John,

as far as i understand, you’ve got the following possibilities:

  • Post-process your upload, deleting files bigger than 100K
  • Use a progress listener and abort the upload process (for an example see the
    sampler
    )
  • Extend OutputStream

I’d prefer the progress listener.

Hope that helps :wink:

Markus

It works great, thanks you Markus.

Here is my code (for others) of reusable upload component with a progress bar and a cancel button:


public abstract class UploadComponent extends VerticalLayout
                        implements Upload.SucceededListener,
                                   Upload.FailedListener,
                                   Upload.Receiver,
                                   Upload.ProgressListener,
                                   Upload.FinishedListener {
    
    protected Upload upload;
    protected String directory;
    protected File file;
	protected long maxSize;  // In bytes. 100Kb = 100000
	protected ProgressIndicator progressIndicator;  // May be null
	protected boolean cancelled = false;
    protected Long contentLength;
	protected Button cancelProcessing;
	protected HorizontalLayout processingLayout;
    
    public UploadComponent(String fieldCaption, String buttonCaption, String directoryParam, int maxSize) {
        upload = new Upload(fieldCaption, null);
        this.addComponent(upload);
        this.maxSize = maxSize;
        upload.setReceiver( this); 
        this.directory = directoryParam;
        upload.setButtonCaption(buttonCaption);
        upload.addListener((Upload.SucceededListener) this);
        upload.addListener((Upload.FailedListener) this);
        upload.addListener((Upload.ProgressListener) this);
        upload.addListener((Upload.FinishedListener) this);

        processingLayout = new HorizontalLayout();
        processingLayout.setSpacing(true);
        processingLayout.setVisible(false);
        this.addComponent(processingLayout);

        progressIndicator = new ProgressIndicator();
        progressIndicator.setWidth("100%");
        processingLayout.addComponent(progressIndicator);
        
        cancelProcessing = new Button("cancel", new Button.ClickListener() {
            public void buttonClick(ClickEvent event) {
                cancelled = true;
                upload.interruptUpload();
            }
        });
        cancelProcessing.setStyleName("small");
        processingLayout.addComponent(cancelProcessing);
    }

    @Override
    public OutputStream receiveUpload(String filename,  String MIMEType) {
        FileOutputStream fos = null;
        FileUtils.ensureFolderExists(directory);
        file = new File(directory, filename);
 
        try {
            fos = new FileOutputStream(file);
        } catch (final java.io.FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        return fos; // Return the output stream to write to
    }

    @Override
    public void updateProgress(long readBytes, long contentLength) {
        this.contentLength = contentLength;
        if (maxSize < contentLength) {
            upload.interruptUpload();
            return;
        }
        
        processingLayout.setVisible(true);
        progressIndicator.setValue(new Float(readBytes / (float) contentLength));
    }
    
    @Override
    public void uploadFinished(FinishedEvent event) {
        processingLayout.setVisible(false);
    }
    
    
    @Override
    public void uploadFailed(FailedEvent event) {
        processingLayout.setVisible(false);
        if (contentLength != null && maxSize < contentLength) {
            showNotification("File too large", 
                    "Your file "+contentLength/1000+"Kb long. Please select an file smaller than " + maxSize / 1000 + "Kb");
        } else if (cancelled) {
            // Nothing to do...
        } else {
            showNotification("There was a problem uploading your file.",
                    "<pre>"+event.getReason().getStackTrace().toString()+"</pre>");
        }
        
        try{
            file.delete();
        } catch (Exception e) {
            // Silent exception. If we can't delete the file, it's not big problem. May the file did not even exist.
        }
        
        afterUploadFailed(event);
    }

    /** Override me to do something more than displaying the notification */
    public void afterUploadFailed(FailedEvent event) {
    }
    
    
    /** File upload is a special case because the Nav7 is not initialized, because the file upload requests don't go through the Vaadin servlet. */ 
    protected void showNotification(String message, String detail) {
        BlackBeltAppLevelWindow mainWin = (BlackBeltAppLevelWindow)(this.getWindow().getParent());
        NotificationUtil.showNotification(mainWin, message, detail);
    }
    
	public String getDirectory() {
		return directory;
	}

	public File getFile() {
		return file;
	}
    
    
}

I have the same question for the use of “easyuploads” add-on. Is there a possibility to stop or not even start the upload when the file size is too large?

Your code there would probably bug if the browser doesn’t report the content length properly, in which case it will be -1. It can also create a security problem if a user agent fabricates the content length. You should be able to prevent these issues by doing it like this:

@Override
public void updateProgress(long readBytes, long contentLength) {
    if (maxSize < readBytes || (contentLength != -1 && maxSize < contentLength)) {
        upload.interruptUpload();

Not sure what your change (checking that the contentLength is not -1) is doing…

If contentLength is -1 in the code above, under what circumstance would “maxSize < -1” be true? Presumably the maxSize is not also negative as it would surely trigger the “maxSize < readBytes” anyway. I don’t want any security issues, but not sure I understand the change.

:blink: I was probably writing while sleeping again. I guess this is what I meant what happens easily when you use reverse comparison order…

Thanks! To put it real-ly simple:

@Override
public void updateProgress(long readBytes, long contentLength) {
    if (readBytes > maxSize || contentLength > maxSize) {
        upload.interruptUpload();

The possible value -1 for the contentLength would cause also other problems in the code.

Also, there’s nowadays a Upload.StartListener, where you can do the contentLength check, and there’s probably no point in doing it again in the ProgressListener.

Note that the GWT Uploader project also supports file size restrictions on the client side, so that’s another option you could consider:


http://www.moxiegroup.com/moxieapps/gwt-uploader/

Good luck!

 -Shawn