2

I am trying to upload videos in tomcat server, but after uploading one video I got below error :

Error Log:

org.apache.jasper.JasperException: An exception occurred processing JSP page /SaveVideos.jsp at line 34

31:         pos = file.indexOf("\n", pos) + 1;
32:         int boundaryLocation = file.indexOf(boundary, pos) - 4;
33:         int startPos = ((file.substring(0, pos)).getBytes()).length;
34:         int endPos = ((file.substring(0, boundaryLocation)).getBytes()).length;
35:         
36:     //  String pathToFile = this.getServletContext().getRealPath(request.getPathInfo());
37:         File ff = new File(this.getServletContext().getRealPath("/")+"videos/"+ saveFile);


Stacktrace:
    org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:524)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:417)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)


root cause 

javax.servlet.ServletException: java.lang.OutOfMemoryError: Java heap space
    org.apache.jasper.runtime.PageContextImpl.doHandlePageException(PageContextImpl.java:850)
    org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:779)
    org.apache.jsp.SaveVideos_jsp._jspService(SaveVideos_jsp.java:138)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:393)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)


root cause 

java.lang.OutOfMemoryError: Java heap space
    java.lang.StringCoding$StringEncoder.encode(StringCoding.java:232)
    java.lang.StringCoding.encode(StringCoding.java:272)
    java.lang.StringCoding.encode(StringCoding.java:284)
    java.lang.String.getBytes(String.java:987)
    org.apache.jsp.SaveVideos_jsp._jspService(SaveVideos_jsp.java:90)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:393)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

SaveVideo.jsp :

<%@ page import="java.io.*,java.sql.*,java.util.zip.*"%>
<%@ page import="jdbc.DBConnection"%>
<%
    String saveFile = "";
    String contentType = request.getContentType();
    if ((contentType != null)
            && (contentType.indexOf("multipart/form-data") >= 0)) {
        DataInputStream in = new DataInputStream(request
        .getInputStream());
        int formDataLength = request.getContentLength();
        byte dataBytes[] = new byte[formDataLength];
        int byteRead = 0;
        int totalBytesRead = 0;
        while (totalBytesRead < formDataLength) {
            byteRead = in.read(dataBytes, totalBytesRead,
            formDataLength);
            totalBytesRead += byteRead;
        }
        String file = new String(dataBytes);
        saveFile = file.substring(file.indexOf("filename=\"") + 10);
        saveFile = saveFile.substring(0, saveFile.indexOf("\n"));
        saveFile = saveFile.substring(saveFile.lastIndexOf("\\") + 1,
        saveFile.indexOf("\""));
        int lastIndex = contentType.lastIndexOf("=");
        String boundary = contentType.substring(lastIndex + 1,
        contentType.length());
        int pos;
        pos = file.indexOf("filename=\"");
        pos = file.indexOf("\n", pos) + 1;
        pos = file.indexOf("\n", pos) + 1;
        pos = file.indexOf("\n", pos) + 1;
        int boundaryLocation = file.indexOf(boundary, pos) - 4;
        int startPos = ((file.substring(0, pos)).getBytes()).length;
        int endPos = ((file.substring(0, boundaryLocation)).getBytes()).length;

    //  String pathToFile = this.getServletContext().getRealPath(request.getPathInfo());
        File ff = new File(this.getServletContext().getRealPath("/")+"videos/"+ saveFile);

        FileOutputStream fileOut = new FileOutputStream(ff);
        fileOut.write(dataBytes, startPos, (endPos - startPos));
        fileOut.flush();
        fileOut.close();
%><br>
<table border="2">
    <tr>
        <td><b>You have successfully upload the file:</b> <%
        response.sendRedirect("HomePage.jsp");

 %>
        </td>
    </tr>
</table>
<%
DBConnection db_con = new DBConnection();
PreparedStatement psmnt = null;
        try {
            Connection con = db_con.getConnection();

                psmnt = con.prepareStatement("insert into video_tbl(Video_name  ) values(?)");

            psmnt.setString(1,saveFile);

            int s = psmnt.executeUpdate();
            if (s > 0) {
        System.out.println("Uploaded successfully !");
            } else {
        System.out.println("Error!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
%>

configuration

VM Arguments :
-Xms1024m -Xmx1024m
1
  • 4
    Why not stream the uploads to disk then rather than taking them all in memory? There's plenty of frameworks that'll do this for you. Or, in your case, don't read all of the data in while (totalBytesRead < formDataLength) at once: read a bit, process it, and then read some more. Commented May 31, 2013 at 9:42

3 Answers 3

7

There are two related problems with your code:

  1. You are buffering the entire uploaded document (video) in memory. This takes a lot of memory and is the most likely cause of your OOMEs.

  2. Related to the previous, if the fileContent is more than 2^32 - 1 bytes (i.e. a bit over 2Gb) your code will fail because the content length won't fit into an int, and you cannot allocate an array with more than 2^32 - 1 elements.

What you need to do is something like this:

  • Wrap the InputStream in a BufferedInputStream not a DataInputStream.
  • Read and accumulate the form-data "envelope" data a byte at a time using read() until you reach the newline characters. Then turn each line into a string to do the parsing.
  • Once you get to the start of the file content, read a byte at a time looking for the boundary sequence, and writing (non-boundary) data bytes to the output file via a BufferedOutputStream.

Better still, if you looked you should be able to find existing components for handling multiparts.


You've also got the problem that you have significant "business logic" embedded in your JSP as "scriptlet" code. This is Bad Practice. You should do the business logic (database queries and updates, file uploading, etc) in a Servlet and just use JSPs for rendering output.

Sign up to request clarification or add additional context in comments.

Comments

3

You could rewrite your code so that it directly streams from the input stream to a file. This only requires a small buffer.

Comments

0

You create the video in the memory twice: 1. byte dataBytes[] = new byte[formDataLength]; 2. String file = new String(dataBytes);

You might want to change that...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.