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

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

There is a newer version: 8.27.1
Show newest version
/*
 * Copyright (C) 2000-2023 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 java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import com.vaadin.util.EncodeUtil;

/**
 * Downloadable stream.
 * 

* Note that the methods in a DownloadStream are called without locking the * session to prevent locking the session during long file downloads. If your * DownloadStream uses anything from the session, you must handle the locking. *

* * @author Vaadin Ltd. * @since 3.0 */ @SuppressWarnings("serial") public class DownloadStream implements Serializable { public static final String CONTENT_DISPOSITION = "Content-Disposition"; /** * Maximum cache time. */ public static final long MAX_CACHETIME = Long.MAX_VALUE; /** * Default cache time. */ public static final long DEFAULT_CACHETIME = 1000 * 60 * 60 * 24; private InputStream stream; private String contentType; private String fileName; private Map params; private long cacheTime = DEFAULT_CACHETIME; private int bufferSize = 0; /** * Creates a new instance of DownloadStream. */ public DownloadStream(InputStream stream, String contentType, String fileName) { setStream(stream); setContentType(contentType); setFileName(fileName); } /** * Gets downloadable stream. * * @return output stream. */ public InputStream getStream() { return stream; } /** * Sets the stream. * * @param stream * The stream to set */ public void setStream(InputStream stream) { this.stream = stream; } /** * Gets stream content type. * * @return type of the stream content. */ public String getContentType() { return contentType; } /** * Sets stream content type. * * @param contentType * the contentType to set */ public void setContentType(String contentType) { this.contentType = contentType; } /** * Returns the file name. * * @return the name of the file. */ public String getFileName() { return fileName; } /** * Sets the file name. * * @param fileName * the file name to set. */ public void setFileName(String fileName) { this.fileName = fileName; } /** * Sets a parameter for download stream. Parameters are optional information * about the downloadable stream and their meaning depends on the used * adapter. For example in WebAdapter they are interpreted as HTTP response * headers. * * If the parameters by this name exists, the old value is replaced. * * @param name * the Name of the parameter to set. * @param value * the Value of the parameter to set. */ public void setParameter(String name, String value) { if (params == null) { params = new HashMap<>(); } params.put(name, value); } /** * Gets a paramater for download stream. Parameters are optional information * about the downloadable stream and their meaning depends on the used * adapter. For example in WebAdapter they are interpreted as HTTP response * headers. * * @param name * the Name of the parameter to set. * @return Value of the parameter or null if the parameter does not exist. */ public String getParameter(String name) { if (params != null) { return params.get(name); } return null; } /** * Gets the names of the parameters. * * @return Iterator of names or null if no parameters are set. */ public Iterator getParameterNames() { if (params != null) { return params.keySet().iterator(); } return null; } /** * Gets length of cache expiration time. This gives the adapter the * possibility cache streams sent to the client. The caching may be made in * adapter or at the client if the client supports caching. Default is * DEFAULT_CACHETIME. * * @return Cache time in milliseconds */ public long getCacheTime() { return cacheTime; } /** * Sets length of cache expiration time. This gives the adapter the * possibility cache streams sent to the client. The caching may be made in * adapter or at the client if the client supports caching. Zero or negative * value disables the caching of this stream. * * @param cacheTime * the cache time in milliseconds. */ public void setCacheTime(long cacheTime) { this.cacheTime = cacheTime; } /** * Gets the size of the download buffer. * * @return The size of the buffer in bytes. */ public int getBufferSize() { return bufferSize; } /** * Sets the size of the download buffer. * * @param bufferSize * the size of the buffer in bytes. * * @since 7.0 */ public void setBufferSize(int bufferSize) { this.bufferSize = bufferSize; } /** * Writes this download stream to a Vaadin response. This takes care of * setting response headers according to what is defined in this download * stream ({@link #getContentType()}, {@link #getCacheTime()}, * {@link #getFileName()}) and transferring the data from the stream ( * {@link #getStream()}) to the response. Defined parameters ( * {@link #getParameterNames()}) are also included as headers in the * response. If there's is a parameter named Location, a * redirect (302 Moved temporarily) is sent instead of the contents of this * stream. * * @param request * the request for which the response should be written * @param response * the Vaadin response to write this download stream to * * @throws IOException * passed through from the Vaadin response * * @since 7.0 */ public void writeResponse(VaadinRequest request, VaadinResponse response) throws IOException { if (getParameter("Location") != null) { response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); response.setHeader("Location", getParameter("Location")); return; } // Download from given stream final InputStream data = getStream(); if (data == null) { response.setStatus(HttpServletResponse.SC_NOT_FOUND); return; } if (data != null) { OutputStream out = null; try { // Sets content type response.setContentType(getContentType()); // Sets cache headers response.setCacheTime(getCacheTime()); // Copy download stream parameters directly // to HTTP headers. final Iterator i = getParameterNames(); if (i != null) { while (i.hasNext()) { final String param = i.next(); response.setHeader(param, getParameter(param)); } } // Content-Disposition: attachment generally forces download String contentDisposition = getParameter(CONTENT_DISPOSITION); if (contentDisposition == null) { contentDisposition = getContentDispositionFilename( getFileName()); } response.setHeader(CONTENT_DISPOSITION, contentDisposition); int bufferSize = getBufferSize(); if (bufferSize <= 0 || bufferSize > Constants.MAX_BUFFER_SIZE) { bufferSize = Constants.DEFAULT_BUFFER_SIZE; } final byte[] buffer = new byte[bufferSize]; int bytesRead = 0; out = response.getOutputStream(); long totalWritten = 0; while ((bytesRead = data.read(buffer)) > 0) { out.write(buffer, 0, bytesRead); totalWritten += bytesRead; if (totalWritten >= buffer.length) { // Avoid chunked encoding for small resources out.flush(); } } } finally { tryToCloseStream(out); tryToCloseStream(data); } } } /** * Returns the filename formatted for inclusion in a Content-Disposition * header. Includes both a plain version of the name and a UTF-8 version * * @since 7.4.8 * @param filename * The filename to include * @return A value for inclusion in a Content-Disposition header */ public static String getContentDispositionFilename(String filename) { String encodedFilename = EncodeUtil.rfc5987Encode(filename); return String.format("filename=\"%s\"; filename*=utf-8''%s", encodedFilename, encodedFilename); } /** * Helper method that tries to close an output stream and ignores any * exceptions. * * @param out * the output stream to close, null is also * supported */ static void tryToCloseStream(OutputStream out) { try { // try to close output stream (e.g. file handle) if (out != null) { out.close(); } } catch (IOException e1) { // NOP } } /** * Helper method that tries to close an input stream and ignores any * exceptions. * * @param in * the input stream to close, null is also supported */ static void tryToCloseStream(InputStream in) { try { // try to close output stream (e.g. file handle) if (in != null) { in.close(); } } catch (IOException e1) { // NOP } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy