Skip to content

Instantly share code, notes, and snippets.

@kungfoo
Created February 10, 2015 13:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kungfoo/8a507b1657c82ae51d7b to your computer and use it in GitHub Desktop.
Save kungfoo/8a507b1657c82ae51d7b to your computer and use it in GitHub Desktop.
FileDownloader
public class FileDownloader extends AbstractExtension {
private boolean overrideContentType = true;
/**
* Creates a new file downloader for the given resource. To use the
* downloader, you should also {@link #extend(AbstractClientConnector)} the
* component.
*
* @param resource
* the resource to download when the user clicks the extended
* component.
*/
public FileDownloader(Resource resource) {
if (resource == null) {
throw new IllegalArgumentException("resource may not be null");
}
setResource("dl", resource);
}
public void extend(AbstractComponent target) {
super.extend(target);
}
/**
* Gets the resource set for download.
*
* @return the resource that will be downloaded if clicking the extended
* component
*/
public Resource getFileDownloadResource() {
return getResource("dl");
}
/**
* Sets the resource that is downloaded when the extended component is
* clicked.
*
* @param resource
* the resource to download
*/
public void setFileDownloadResource(Resource resource) {
setResource("dl", resource);
}
/**
* Sets whether the content type of served resources should be overriden to
* <code>application/octet-stream</code> to reduce the risk of a browser
* plugin choosing to display the resource instead of downloading it. This
* is by default set to <code>true</code>.
* <p>
* Please note that this only affects Connector resources (e.g.
* {@link FileResource} and {@link ClassResource}) but not other resource
* types (e.g. {@link ExternalResource} or {@link ThemeResource}).
* </p>
*
* @param overrideContentType
* <code>true</code> to override the content type if possible;
* <code>false</code> to use the original content type.
*/
public void setOverrideContentType(boolean overrideContentType) {
this.overrideContentType = overrideContentType;
}
/**
* Checks whether the content type should be overridden.
*
* @see #setOverrideContentType(boolean)
*
* @return <code>true</code> if the content type will be overridden when
* possible; <code>false</code> if the original content type will be
* used.
*/
public boolean isOverrideContentType() {
return overrideContentType;
}
@Override
public boolean handleConnectorRequest(VaadinRequest request,
VaadinResponse response, String path) throws IOException {
if (!path.matches("dl(/.*)?")) {
// Ignore if it isn't for us
return false;
}
VaadinSession session = getSession();
session.lock();
DownloadStream stream;
try {
Resource resource = getFileDownloadResource();
if (!(resource instanceof ConnectorResource)) {
return false;
}
stream = ((ConnectorResource) resource).getStream();
if (stream.getParameter("Content-Disposition") == null) {
// Content-Disposition: attachment generally forces download
stream.setParameter("Content-Disposition",
"attachment; filename=\"" + stream.getFileName() + "\"");
}
// Content-Type to block eager browser plug-ins from hijacking
// the file
if (isOverrideContentType()) {
stream.setContentType("application/octet-stream;charset=UTF-8");
}
} finally {
session.unlock();
}
stream.writeResponse(request, response);
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment