View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  
21  package org.waarp.http.protocol.servlet;
22  
23  import org.waarp.common.database.exception.WaarpDatabaseException;
24  import org.waarp.common.guid.LongUuid;
25  import org.waarp.common.logging.WaarpLogger;
26  import org.waarp.common.logging.WaarpLoggerFactory;
27  import org.waarp.common.utility.WaarpSystemUtil;
28  import org.waarp.http.protocol.HttpDownloadSession;
29  
30  import javax.servlet.ServletException;
31  import javax.servlet.http.Cookie;
32  import javax.servlet.http.HttpServletRequest;
33  import javax.servlet.http.HttpServletResponse;
34  import java.io.IOException;
35  import java.lang.reflect.InvocationTargetException;
36  import java.util.Enumeration;
37  import java.util.HashMap;
38  import java.util.Map;
39  import java.util.concurrent.Callable;
40  import java.util.concurrent.ExecutionException;
41  import java.util.concurrent.ExecutorService;
42  import java.util.concurrent.Executors;
43  import java.util.concurrent.Future;
44  
45  /**
46   * Download Servlet: enables downloading file from Web Browser to final user
47   */
48  public class DownloadServlet extends AbstractServlet {
49    private static final long serialVersionUID = 2002L;
50    public static final String FILENAME = "filename";
51    public static final String IDENTIFIER = "identifier";
52    private static final WaarpLogger logger =
53        WaarpLoggerFactory.getLogger(DownloadServlet.class);
54    public static final String X_HASH_SHA_256 = "X-Hash-Sha-256";
55  
56    @Override
57    protected final void doPost(final HttpServletRequest request,
58                                final HttpServletResponse response) {
59      doGet(request, response);
60    }
61  
62    @Override
63    protected final void doHead(final HttpServletRequest request,
64                                final HttpServletResponse response) {
65      final Map<String, String> arguments = new HashMap<String, String>();
66      final Enumeration<String> names = request.getParameterNames();
67      while (names.hasMoreElements()) {
68        final String name = names.nextElement();
69        arguments.put(name, request.getParameter(name));
70      }
71      final String filename = getFilename(arguments);
72      logger.debug("RECVHEAD: {}", filename);
73      try {
74        final HttpDownloadSession session =
75            getDownloadSession(arguments, filename, true);//NOSONAR
76        logger.debug("RECVHEAD SESSION: {}", session);
77        logger.debug("Check on going");
78        response.setHeader("Expires", "0");
79        response.setHeader("Cache-Control",
80                           "must-revalidate, post-check=0, " + "pre-check=0");
81        if (session == null) {
82          logger.debug("Not found");
83          response.setStatus(404);
84        } else if (session.isTransmitting()) {
85          logger.debug("On going");
86          response.setStatus(202);
87        } else if (session.isFinished()) {
88          logger.debug("Done");
89          response.setHeader(X_HASH_SHA_256, session.getComputedHadh());
90          response.setStatus(200);
91        }
92      } catch (final ServletException e) {
93        logger.error(e.getMessage());
94        response.setStatus(400);
95      }
96    }
97  
98    @Override
99    protected final void doGet(final HttpServletRequest request,
100                              final HttpServletResponse response) {
101     final ExecutorService executor = Executors.newSingleThreadExecutor();
102     try {
103       final Map<String, String> arguments = new HashMap<String, String>();
104       final Enumeration<String> names = request.getParameterNames();
105       while (names.hasMoreElements()) {
106         final String name = names.nextElement();
107         arguments.put(name, request.getParameter(name));
108       }
109       final String filename = getFilename(arguments);
110       logger.debug("RECVGET: {}", filename);
111       try {
112         final HttpDownloadSession session =
113             getDownloadSession(arguments, filename, false);
114         logger.debug("SESSION: {}", session);
115         final Callable<String> hashCompute = new Callable<String>() {
116           @Override
117           public final String call() {
118             return session.getHash();
119           }
120         };
121         final Future<String> future = executor.submit(hashCompute);
122         response.setHeader("Content-Disposition",
123                            "attachment; filename=\"" + session.getFinalName() +
124                            "\"");
125         response.setHeader("Content-Description", "File Transfer");
126         response.setHeader("Content-Type", "application/octet-stream");
127         response.setHeader("Content-Transfer-Encoding", "binary");
128         response.setHeader("Expires", "0");
129         response.setHeader("Cache-Control",
130                            "must-revalidate, post-check=0, " + "pre-check=0");
131         // Used by javascript downloader
132         final Cookie cookie = new Cookie("fileDownload", "true");
133         cookie.setHttpOnly(true);
134         cookie.setSecure(true);
135         response.addCookie(cookie);
136         response.setHeader("Content-Length",
137                            Long.toString(session.getFileSize()));
138         String hash = null;
139         try {
140           hash = future.get();
141         } catch (final InterruptedException e) {//NOSONAR
142           logger.debug(e);
143         } catch (final ExecutionException e) {
144           logger.debug(e);
145         }
146         if (hash != null) {
147           response.setHeader(X_HASH_SHA_256, hash);
148 
149         }
150         try {
151           if (session.tryWrite(response.getOutputStream())) {
152             session.downloadFinished();
153             logger.info("Download OK: {}", session);
154             response.setStatus(HttpServletResponse.SC_OK);
155           } else {
156             logger.info("NOT FOUND: {}", session);
157             response.setStatus(HttpServletResponse.SC_NOT_FOUND);
158           }
159         } catch (final IOException e) {
160           logger.error("Error: {} {}", session, e.getMessage());
161           response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
162         }
163       } catch (final ServletException e) {
164         logger.error(e.getMessage());
165         response.setStatus(400);
166       }
167     } finally {
168       executor.shutdown();
169     }
170   }
171 
172   private String getFilename(final Map<String, String> arguments) {
173     return arguments.get(FILENAME);
174   }
175 
176   private HttpDownloadSession getDownloadSession(
177       final Map<String, String> arguments, final String filename,
178       final boolean check) throws ServletException {
179     final String rulename = arguments.get(RULENAME);
180     if (rulename == null) {
181       throw new ServletException(INVALID_REQUEST_PARAMS);
182     }
183     String identifier = arguments.get(IDENTIFIER);
184     if (identifier == null) {
185       identifier = Long.toString(LongUuid.getLongUuid());
186     }
187     String comment = arguments.get(COMMENT);
188     if (comment == null) {
189       comment = "Web Download " + identifier;
190     }
191 
192     try {
193       final HttpAuthent authent =
194           (HttpAuthent) WaarpSystemUtil.newInstance(authentClass);
195       authent.initializeAuthent(arguments);
196       if (check) {
197         try {
198           return new HttpDownloadSession(identifier, authent);
199         } catch (final WaarpDatabaseException e) {
200           logger.debug(e);
201           return null;
202         }
203       }
204       return new HttpDownloadSession(filename, rulename, identifier, comment,
205                                      authent);
206     } catch (final IllegalArgumentException e) {
207       throw new ServletException(
208           INVALID_REQUEST_PARAMS + ": " + e.getMessage());
209     } catch (final InvocationTargetException e) {
210       throw new ServletException(
211           INVALID_REQUEST_PARAMS + ": " + e.getMessage());
212     }
213   }
214 }