• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 10245
  • Last Modified:

Force download not working for MS Office files

I have created a JSP page to force the download of different types of files.  PDF, TXT and ZIP files download perfectly, however DOC, XLS PPT and TIFF files do not - they download but then are not correctly interpreted by the application.  A Word doc, for example, looks like:

ÐÏ à¡± á                >   þÿ                      !           #       þÿÿÿ        ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿì¥Á          ð ¿               0

For the XLS, DOC and PPT files, I get the same result if I set the MIME Type to APPLICATION/OCTET-STREAM, APPLICATION/STREAM, and APPLICATION/UNKNOWN.  I've confirmed that there is nothing wrong with the files themselves.  Interestingly, if I zip the file it downloads AND opens correctly!

Here's my code (The code comes largely from a number of answers on this site - thanks especially to cheekyci):

<%@ page import="java.util.*,java.io.*"%>
<%
  String filePath = this.getServletContext().getRealPath("/") + "/doc/";
  String fileName = request.getParameter("file");

  //determine MIME type based on fileName extension
  String extension = fileName.substring(fileName.indexOf(".")+1);
  String mimeType;
  if (extension.equals("xls")) {
    mimeType="APPLICATION/VND.MS-EXCEL";
  }
  else if (extension.equals("doc")) {
    mimeType="APPLICATION/MSWORD";
  }
  else if (extension.equals("ppt")) {
    mimeType="APPLICATION/VND.MS-POWERPOINT";
  }
  else if (extension.equals("tiff")) {
    mimeType="IMAGE/TIFF";
  }
  else {
    mimeType="APPLICATION/STREAM";    
  }
  File downloadFile = new File(filePath+fileName);
  try {
      if (downloadFile.exists()) {
        //set response headers to force download
        response.setContentType(mimeType);
        response.setHeader("Content-Disposition","attachment; filename=\""+ fileName + "\"");
         
        //stream out file
        FileInputStream fInputStream =new FileInputStream(filePath+fileName);
        ServletOutputStream fOutputStream = response.getOutputStream();
        int i;
        while ((i=fInputStream.read()) != -1) {
            fOutputStream.write(i);
        }
        fInputStream.close();
        fOutputStream.close();
      }
      else {
            System.out.println("File not found @"+filePath+fileName);
      }
  } catch (Exception exp){
     System.out.println("Exception: "+exp.getMessage());
  }
%>
0
lordparma
Asked:
lordparma
  • 5
  • 3
  • 2
  • +1
1 Solution
 
kennethxuCommented:
1. I'm not sure upper case of mimetype works, but I never used it and never seen it. so you might want to try lower case: e.g. application/vnd.ms-excel

2. just to be sure the fileName with out any path in it, use
response.setHeader("Content-Disposition","attachment; filename=\""+ downloadFile.getName() + "\"");

3. try it on another PC, it might be the IE/Office installation problem in a particular PC
0
 
cheekycjCommented:
interesting situation.

when you transfer the file onto your server are you using FTP?  Make sure the FTP mode is set to binary not ascii.

CJ
0
 
lordparmaAuthor Commented:
I'm working on my development PC, so all files are local. That's what's so weird - I'm 'downloading' from my PC to my PC - it's the input stream and/or output stream that is corrupting or converting the Office files.

I'm running BEA Weblogic on a W2K PC, Java SKD 1.4.
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
lordparmaAuthor Commented:
kennethxu, I just tried your suggestions and unfortunately none of them made a difference.  Lowercase mimetype - no change, using downloadFile.getName() gives the same name as before, and the downloaded files appear corrupted on other PCs as well.  Thanks for the suggestions though!
0
 
damonfCommented:
just to make sure, change Content-Disposition to Content-disposition.  Also, I don't think you're supposed to have "" around the filename for the Content-disposition header.  

so instead of:

response.setHeader("Content-Disposition","attachment; filename=\""+ downloadFile.getName() + "\"");

Use

response.setHeader("Content-Disposition","attachment; filename=" + downloadFile.getName());

0
 
lordparmaAuthor Commented:
I changed Content-Disposition to Content-disposition, and got rid of the quotes around the filename; still the same result.  
I'm thinking now that this has more to do with the way java's FileInputStream and/or ServletOutputStream handle the binary data that makes up a Word, Excel or Powerpoint file.  I've read that the MS uses a proprietary binary format for their documents - perhaps this is the cause of the problem.
0
 
damonfCommented:
I don't think so ...  I have a servlet that does more or less exactly what you're doing.  I happen to wrap the InputStream and OutputStream with buffered streams for performance.  But I also tried your method (actually pasted your code into my servlet) and it works just fine.  Have you tried changing the content-disposition to "inline" just for testing purposes?

I'm using a servlet and you're using a JSP.  Can't think of a reason why, but could the JSP-generated servlet by hosing up the transfer somehow by putting something in the Outputstream before or after your stuff?  Check the generated source of your JSP ... or maybe just try this from a Servlet.

0
 
cheekycjCommented:
0
 
kennethxuCommented:
anyway, I always use servlet to download files, jsp is good for generate text information, but always have problem for binary data, I know somebody success, but I also heard a lot of problems. try this:
import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public final class DownloadServlet extends HttpServlet {
    private static final String basePath = "/doc";

    public void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, java.io.IOException
    {
        String filePath = request.getPathInfo();
        String filename = request.getParameter( "filename" );
     if( filePath == null && filename != null ) filePath = "/" + filename;
     if( filename == null ) filename = filePath;
     if( filename != null ) filename = (new File(filename)).getName();

        if( filePath != null ) {
          InputStream in = null;
          OutputStream out = null;
          try {
                 in = getServletContext().getResourceAsStream(basePath + filePath);
              if( in != null ) {
                        out = new BufferedOutputStream( response.getOutputStream() );
                        in = new BufferedInputStream( in );
                        String contentType = getServletConfig().getServletContext().getMimeType( filename );
                        if( contentType == null ) contentType = "application/unknow";
                        System.out.println( "contentType: " + contentType );
                        response.setHeader("Content-Disposition","attachment; filename=\"" + filename + "\"");
                        int c; while( ( c=in.read() ) != -1 ) out.write( c );
                        return;
                 }
          } finally {
               if( in != null ) try { in.close(); } catch( Exception e ) {}
               if( out != null ) try { out.close(); } catch( Exception e ) {}
          }
     }
     response.sendError( HttpServletResponse.SC_NOT_FOUND );
    }
}
0
 
kennethxuCommented:
this servlet can be mapped as
1. /download/*, the download file as /download/xxx.doc
2. /download, then download file as /download?filename=xxx.doc
or both.
0
 
lordparmaAuthor Commented:
For those of you who have responded recently - thank you - I am travelling on business and will be back in the office in a couple of days - I'll be able to test the different solutions proposed, and I'll let you know what works!  Thanks again.
0
 
lordparmaAuthor Commented:
kennethxu - after a really long delay, I have finally returned to accept this answer.  Thanks to all of you for your input - for some reason this code works in a java servlet and not in a jsp page.  Must be the way the jsp-->servlet conversion takes place.  In the end, we used a servlet/bean combination to retrieve the document from a database rather than a file server.
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 5
  • 3
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now