SPONSORED BY VSLive! San Francisco 2003

Send Files to Browser Clients the Right Way
You want a browser client to download a file, so just link to it, right? Wrong.
by Budi Kurniawan

Posted March 13, 2002

Web programmers often ask how to send a file to the browser and force the browser to display the Save dialog box. Of course, the simplest solution is to provide a link to the file. However, this solution has two disadvantages.

First, if the browser recognizes the extension of the downloaded file, it will try to activate the application that can open the downloaded file. For example, if the user is using Windows and the downloaded file is a .doc file, chances are the browser will fire up Microsoft Word and open the file inside Word.

Second, anyone who knows the URL can download it. You can restrict access to the file using the security configuration of the Web container or the Web server, but in some cases, this is not sufficient. You want more flexibility in controlling who can have access to it.

There is a reliable technique to send a file to the browser and force the browser to display the Save dialog, regardless of the file extension. Before we jump into coding, however, here is the thing you should remember when sending a file to the browser: Unauthorized users should not be able to download a file by typing its URL. This means, the file should be stored in a directory outside the virtual directory. For example, if your virtual directory is C:\Tomcat4\webapps\MyApp, storing the file in this directory or in a subdirectory under this directory will make your file visible by anyone on the Internet.

With that out of the way, here's what you have to do in your code. First, set the response's content type to APPLICATION/OCTET-STREAM. This value is not case-sensitive. Then, add an HTTP response header named Content-Disposition and give it this value:

attachment; filename=theFileName

Where "theFileName" is the default name for the file that appears on the File Download dialog box. This is normally the same name as the file, but does not need to be.

Finally, this JSP page demonstrates how to send a file to the user's browser:

<%
	// fetch the file
	String filename = "companySecret.txt";
	String filepath = "C:\\";
	response.setContentType(
		"APPLICATION/OCTET-STREAM");
	response.setHeader("Content-Disposition",
		"attachment; filename=\""
		     + filename + "\"");

	java.io.FileInputStream fileInputStream =
		new java.io.FileInputStream(filepath
		     + filename);
	int i;
	while ((i=fileInputStream.read()) != -1) {
		out.write(i);
	}
	fileInputStream.close();
	out.close();
%>

There is a catch. You must not send any characters other than the file content. This could happen without you realizing it. For example, if you need to write some page directives in your file download JSP page, you might write the directives in a normal way:

<%@ page import="java.io.*"
%> <jsp:useBean id="MyBeanId" scope="page"
class="com.brainysoftware.DownloadBean" />

Without you realizing it, the carriage return at the end of the first page directive will be sent to the browser. Instead, write those directives like this:

<%@ page import="java.io.*"
%><jsp:useBean id="MyBeanId" scope="page"
class="com.brainysoftware.DownloadBean" />

This looks weird, but it gives you the correct result.

About the Author
Budi Kurniawan is an independent consultant in Sydney, Australia, and the author of Java Scalability with Servlet, JSP and EJB, to be published by New Riders in April 2002. He is also one of the developers at BrainySoftware. You can reach him at budi@brainysoftware.com.

Close Window