3

I'm working on a web app (Java/JSP) and part of it, is to allow users to download the requested file only "Once". The problem that when they hit "Download" button, they will be asked to save/open or cancel the file and whatever they respond the file will be marked as downloaded and the user won't be able to download it again. I'm trying to figure out a way to not count the file as downloaded when the user respond with "Cancel" and to check if really the user downloaded the file completely.

Here is the Java Part:

@WebServlet("/download")
    public class download extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private static final int DEFAULT_BUFFER_SIZE = 10240;
/**
 * @see HttpServlet#HttpServlet()
 */
public download() {
    super();
    // TODO Auto-generated constructor stub
}

/**
 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
 *      response)
 */
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    try {

        Class.forName("org.sqlite.JDBC");
        Connection c = DriverManager.getConnection("jdbc:sqlite:C:\\sqlite\\mascapp.db");
        c.setAutoCommit(false);
        Cookie[] cookies = request.getCookies();
        if(request.getSession().getAttribute("aeid") == null || request.getSession().getAttribute("uid") == null)
        {
            response.sendRedirect("/index.jsp");
        }
        int ae_num = Integer.parseInt(request.getSession().getAttribute("aeid").toString());




        String sql = "SELECT file, filename FROM reports INNER JOIN download USING(tipid) WHERE reports.tipid = ?"+
                "AND download.ts_" + ae_num+ " = 0;";

        PreparedStatement stmt = c.prepareStatement(sql);
        String tipNum = request.getParameter("tipid");
        if (tipNum != null) {

            stmt.setString(1, tipNum);
            //stmt.setString(2, tipNum);
            ResultSet res = stmt.executeQuery();
            BufferedInputStream fileBlob = null;
            String filename = "";

            while (res.next()) {
                fileBlob = new BufferedInputStream(res.getBinaryStream("file"), DEFAULT_BUFFER_SIZE);

                filename = res.getString("filename");
            }
            if (fileBlob != null) {
                System.out.println(filename);
                response.setContentType("APPLICATION/OCTET-STREAM");
                response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");

                BufferedOutputStream output = new BufferedOutputStream(response.getOutputStream(),
                        DEFAULT_BUFFER_SIZE);

                byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
                int length;
                while ((length = fileBlob.read(buffer)) > 0) {
                    output.write(buffer, 0, length);
                }

                output.close();
                fileBlob.close();
                Date now = new Date();

                sql = "UPDATE download SET ts_" + ae_num + " = " + now.getTime() + " WHERE tipid = ?;";
                System.out.println(sql);
                stmt = c.prepareStatement(sql);
                stmt.setString(1, tipNum);

                stmt.executeUpdate();
                stmt.close();

                c.commit();
                c.close();
            }
            else
            {

                c.close();
                response.sendRedirect("/MASC/formdownloaded.jsp");

            }
        }
        else
        {
            response.getWriter().append("<html><body><h1>Error: no param</h1></body></html>");
            c.close();

        }
    } catch (SQLException | ClassNotFoundException e) {
        e.printStackTrace();

    }
}

/**
 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
 *      response)
 */
protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    // TODO Auto-generated method stub
    doGet(request, response);
}

}

Any solution or suggestion?! Thank you in advance.

Boann
  • 48,794
  • 16
  • 117
  • 146
  • I think your better bet is to try to detect and report successful downloads, and use those reports to inform whether the user has already downloaded the file. Else what if the user's download is interrupted? I'm afraid I don't have specific advice for how to make that happen, however. In any event, trying to *force* anything on your users is a bad plan. It is unlikely to be appreciated. – John Bollinger Sep 14 '15 at 19:34
  • I have updated the question, I agree with you. How can I track that the user pressed "Cancel" or "Download"?! – user4071915 Sep 14 '15 at 19:39
  • You can force download : http://stackoverflow.com/questions/11353425/force-a-browser-to-save-file-as-after-clicking-link – Deependra Patel Sep 14 '15 at 19:41
  • It might be easier, rather than allowing a download only once, to allow the download any number of times within a limited time period. Depending on your use case that might suffice. – Boann Sep 15 '15 at 09:50

3 Answers3

1

The answer is don't do that. Those dialogs are there for good reasons, some of them involving security.

What you want to do instead depends on why you only want the user to download the file once. Downloads can fail for all sorts of reasons, so what are you going to do if the user loses their connection in the middle of the download?

  • That's part of my question, how can I generally track a downloaded file from the database (Sqlite) using JAVA in a webapp to know whether the user really downloaded the file completely or not?! – user4071915 Sep 14 '15 at 19:51
1

Check this page: http://johnculviner.com/jquery-file-download-plugin-for-ajax-like-feature-rich-file-downloads/ (this link doesn't work sometimes, if you have some problems with it here is a link to github: https://github.com/johnculviner/jquery.fileDownload ).

It looks like the best you can do here is to make sure that download was started by checking on client side special cookie sent back from server with downloading file stream. For that you have to add Cookie into servlet response like in this thread: Set cookie only after file download complete.

So at the end of doGet method in your servlet you should have something like:

Cookie fileDwnld = new Cookie("fileDownload", "true");
fileDwnld.setPath("/");
response.addCookie(fileDwnld);

And here is client side code:

<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="jquery.fileDownload.js"></script>
<script>
$(document).ready(function() {
    $("#btnSubmit").click(function(){
        $.fileDownload('path/to/servlet')
            .done(function () { alert('File download a success!'); })
            .fail(function () { alert('File download failed!'); });
    }); 
});

Community
  • 1
  • 1
rsutormin
  • 1,629
  • 2
  • 17
  • 21
-5

I don't have a proper answer, but I do know that the "attachment;" in the header forces the browser to "download" the file, compared to "open it", if you understand what I mean. Try removing that header and see if you get the desired effect.

halfer
  • 19,824
  • 17
  • 99
  • 186
corgrath
  • 11,673
  • 15
  • 68
  • 99