All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vaadin.server.FileDownloader Maven / Gradle / Ivy

There is a newer version: 8.27.3
Show newest version
/*
 * Copyright (C) 2000-2024 Vaadin Ltd
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See  for the full
 * 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:
 * 
    *
  • Resource should be bound to a component to allow it to be garbage * collected when there are no longer any ways of reaching the resource.
  • *
  • Download should be started directly when the user clicks e.g. a Button * without going through a server-side click listener to avoid triggering * security warnings in some browsers.
  • *
*

* 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. *

* * @author Vaadin Ltd * @since 7.0.0 */ 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); } /** * Add this extension to the target component. * * @param target * the component to attach this extension to */ public void extend(AbstractComponent target) { super.extend(target); } /** * Add this extension to the {@code EventTrigger}. * * @param eventTrigger * the trigger to attach this extension to * @since 8.4 */ public void extend(EventTrigger eventTrigger) { super.extend(eventTrigger.getConnector()); getState().partInformation = eventTrigger.getPartInformation(); } /** * 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 overridden to * 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); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy