0

The program I am currently working on allows the user to browse files on the server and then download them. For the download I wrote a JSP to upload the content to the client. It is passed the name of the file and then sends back its contents. The code I have bellow currently works great for text files however when I try to download and then open a word document which is as I understand a binary file I get some text, some weird squares, and an error message from MS Word. I am not sure why it is incorrectly reading the binary data. Any help would be appreciated.

    <%@ page import="java.io.*" %>

<%
    final File APP_ROOT = new File(com.mdi.core.config.ProcessConfiguration.getInstance().getStringValue("APP_ROOT"));
    File f = new File(request.getParameter("path"));

    File parent = f;
    boolean valid = false;
    while(!valid && (parent = parent.getParentFile()) != null)
    {
        valid = parent.equals(APP_ROOT);
    }
    if(!valid)
    {
        response.sendError(403, "You can not download this file!");
        return;
    }

    response.addHeader("Content-Disposition","attachment; filename="+f.getName());

    response.setContentLength((int)f.length());
    OutputStream os = response.getOutputStream();
    response.setContentType(java.net.URLConnection.guessContentTypeFromName(f.getName()));
    InputStream fin = null;
    try
    {
        fin = new FileInputStream(f);
        byte[] buff = new byte[512];
        int read;
        while((read = fin.read(buff)) != -1)
            os.write(buff, 0, read);
    }
    catch(Exception ex)
    {
        ex.printStackTrace();
    }
    finally
    {
        if(fin != null) fin.close();
    }       
%>

Also I get this error in the standard output.

java.net.ProtocolException: Exceeded stated content-length of: '40220' bytes
    at weblogic.servlet.internal.ServletOutputStreamImpl.checkCL(ServletOutputStreamImpl.java:200)
    at weblogic.servlet.internal.ServletOutputStreamImpl.write(ServletOutputStreamImpl.java:146)
    at jsp_servlet._mdi._html._file_upload.__default_file_upload._jspService(__default_file_upload.java:101)
    at weblogic.servlet.jsp.JspBase.service(JspBase.java:34)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
    at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:300)
    at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
    at com.mdi.core.utils.http.SecurityFilter.doFilter(SecurityFilter.java:154)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
    at com.mdi.core.utils.http.ResponseHeaderFilter.doFilter(ResponseHeaderFilter.java:69)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3715)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3681)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
    at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
    at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2277)
    at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2183)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1454)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:209)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:178)
<Jun 27, 2014 10:46:07 AM EDT> <Error> <HTTP> <BEA-101083> <Connection failure.
java.net.ProtocolException: Didn't meet stated Content-Length, wrote: '39942' bytes instead of stated: '40220' bytes.
    at weblogic.servlet.internal.ServletOutputStreamImpl.ensureContentLength(ServletOutputStreamImpl.java:446)
    at weblogic.servlet.internal.ServletResponseImpl.ensureContentLength(ServletResponseImpl.java:1432)
    at weblogic.servlet.internal.ServletResponseImpl.send(ServletResponseImpl.java:1511)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1462)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:209)
    Truncated. see log file for complete stacktrace
> 
<Jun 27, 2014 10:46:07 AM EDT> <Error> <HTTP> <BEA-101104> <Servlet execution in servlet context "ServletContext@1188950474[app:Trade module:TA15 path:/TA15 spec-version:null]" failed, java.net.ProtocolException: Didn't meet stated Content-Length, wrote: '39942' bytes instead of stated: '40220' bytes..
java.net.ProtocolException: Didn't meet stated Content-Length, wrote: '39942' bytes instead of stated: '40220' bytes.
    at weblogic.servlet.internal.ServletOutputStreamImpl.ensureContentLength(ServletOutputStreamImpl.java:446)
    at weblogic.servlet.internal.ServletResponseImpl.ensureContentLength(ServletResponseImpl.java:1432)
    at weblogic.servlet.internal.ServletResponseImpl.send(ServletResponseImpl.java:1511)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1462)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:209)
    Truncated. see log file for complete stacktrace
chasep255
  • 11,745
  • 8
  • 58
  • 115
  • Nothing like massive code blocks in a JSP to make your eyes bleed. JSP is for _templating_. Java files are for business logic. Your issue is 100% due to character encoding as I see not one single explicit encoding in the whole block. – Boris the Spider Jun 27 '14 at 14:37
  • 1
    But why would the character encoding matter if I am just trying to upload binary data? – chasep255 Jun 27 '14 at 14:38
  • So how should I go about fixing this? – chasep255 Jun 27 '14 at 14:39
  • What type of character encoding should I use? – chasep255 Jun 27 '14 at 14:40
  • Your fundamental problem is that your are using a JSP. A JSP will write _directly to the HTTP response stream_ and it is designed to serve _HTML_. You can, of course, hack the JSP and try to get your output over the stream before the JSP sends anything but this approach is fundamentally flawed. – Boris the Spider Jun 27 '14 at 14:42

1 Answers1

1

Very important is to remove the JSP own whitespace output:

<%@ page contentType="application/octet" import="java.io.*" %><%
%>

No white space, and no newline on the last line. Tip: use a servlet.

Somehow an os.flush() still needs to be done.

After comment from @BoristheSpide: forget flushing. I think the spaces caused some problem, Added content type as binary data.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138