/* * Copyright 2000-2018 Vaadin Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.vaadin.server; import java.io.IOException; import com.vaadin.shared.extension.filedownloader.FileDownloaderState; import com.vaadin.ui.AbstractComponent; /** * Extension that starts a download when the extended component is clicked. This * is used to overcome two challenges: *
* Please note that the download will be started in an iframe, which means that
* care should be taken to avoid serving content types that might make the
* browser attempt to show the content using a plugin instead of downloading it.
* Connector resources (e.g. {@link FileResource} and {@link ClassResource})
* will automatically be served using a
* Content-Type: application/octet-stream
header unless
* {@link #setOverrideContentType(boolean)} has been set to false
* while files served in other ways, (e.g. {@link ExternalResource} or
* {@link ThemeResource}) will not automatically get this treatment.
*
application/octet-stream
to reduce the risk of a browser
* plugin choosing to display the resource instead of downloading it. This
* is by default set to true
.
* * 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}). *
* * @param overrideContentType *true
to override the content type if possible;
* false
to use the original content type.
*/
public void setOverrideContentType(boolean overrideContentType) {
this.overrideContentType = overrideContentType;
}
/**
* Checks whether the content type should be overridden.
*
* @return true
if the content type will be overridden when
* possible; false
if the original content type will be
* used.
* @see #setOverrideContentType(boolean)
*/
public boolean isOverrideContentType() {
return overrideContentType;
}
/**
* {@inheritDoc}
*
* @throws IOException
* if something goes wrong with the download or the user
* cancelled the file download process.
*/
@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();
String contentDisposition = stream
.getParameter(DownloadStream.CONTENT_DISPOSITION);
if (contentDisposition == null) {
contentDisposition = "attachment; " + DownloadStream
.getContentDispositionFilename(stream.getFileName());
}
stream.setParameter(DownloadStream.CONTENT_DISPOSITION,
contentDisposition);
// 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;
}
@Override
protected FileDownloaderState getState() {
return (FileDownloaderState) super.getState();
}
@Override
protected FileDownloaderState getState(boolean markAsDirty) {
return (FileDownloaderState) super.getState(markAsDirty);
}
}