1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.waarp.http.protocol.servlet;
22
23 import com.google.common.io.ByteSource;
24 import org.waarp.common.logging.WaarpLogger;
25 import org.waarp.common.logging.WaarpLoggerFactory;
26 import org.waarp.common.utility.ParametersChecker;
27 import org.waarp.common.utility.WaarpStringUtils;
28 import org.waarp.common.utility.WaarpSystemUtil;
29 import org.waarp.http.protocol.HttpHelper;
30 import org.waarp.http.protocol.HttpResumableInfo;
31 import org.waarp.http.protocol.HttpResumableSession;
32 import org.waarp.http.protocol.HttpSessions;
33
34 import javax.servlet.MultipartConfigElement;
35 import javax.servlet.ServletException;
36 import javax.servlet.annotation.MultipartConfig;
37 import javax.servlet.http.HttpServletRequest;
38 import javax.servlet.http.HttpServletResponse;
39 import javax.servlet.http.Part;
40 import java.io.IOException;
41 import java.io.InputStream;
42 import java.lang.reflect.InvocationTargetException;
43 import java.util.Collection;
44 import java.util.Enumeration;
45 import java.util.HashMap;
46 import java.util.Map;
47
48
49
50
51 @MultipartConfig(fileSizeThreshold = 1024 * 1024)
52 public class UploadServlet extends AbstractServlet {
53 private static final long serialVersionUID = 2003L;
54 public static final String RESUMABLE_CHUNK_NUMBER = "resumableChunkNumber";
55 public static final String RESUMABLE_CHUNK_SIZE = "resumableChunkSize";
56 public static final String RESUMABLE_TOTAL_SIZE = "resumableTotalSize";
57 public static final String RESUMABLE_IDENTIFIER = "resumableIdentifier";
58 public static final String RESUMABLE_FILENAME = "resumableFilename";
59 public static final String RESUMABLE_RELATIVE_PATH = "resumableRelativePath";
60 public static final String FIELD_FILE = "file";
61 private static final WaarpLogger logger =
62 WaarpLoggerFactory.getLogger(UploadServlet.class);
63 private static final MultipartConfigElement MULTI_PART_CONFIG =
64 new MultipartConfigElement("/tmp");
65 private static final String __MULTIPART_CONFIG_ELEMENT =
66 "org.eclipse.jetty.multipartConfig";
67 protected static final String SHA_256 = "sha256";
68 protected static final String INVALID_BLOCK = "Invalid block.";
69
70
71 @Override
72 protected final void doPost(final HttpServletRequest request,
73 final HttpServletResponse response)
74 throws ServletException {
75
76 final boolean isMultipart =
77 request.getHeader("Content-Type").contains("multipart/");
78 InputStream inputStream = null;
79 final HttpResumableInfo resumableInfo;
80 final HttpResumableSession session;
81 final Map<String, String> arguments = new HashMap<String, String>();
82 logger.debug("MULTIPART MODE? {} {}", isMultipart,
83 request.getHeader("Content-Type"));
84 if (isMultipart) {
85 if (request.getAttribute(__MULTIPART_CONFIG_ELEMENT) == null) {
86 request.setAttribute(__MULTIPART_CONFIG_ELEMENT, MULTI_PART_CONFIG);
87 }
88 try {
89 final Collection<Part> parts = request.getParts();
90 if (parts.isEmpty()) {
91 logger.warn("MULTIPART MODE BUT EMPTY");
92 inputStream = request.getInputStream();
93 } else {
94 for (final Part part : parts) {
95
96 if (part.getName().equalsIgnoreCase(FIELD_FILE)) {
97 inputStream = part.getInputStream();
98 } else {
99 final InputStream finalInputStream = part.getInputStream();
100 final ByteSource byteSource = new ByteSource() {
101 @Override
102 public final InputStream openStream() {
103 return finalInputStream;
104 }
105 };
106
107 final String valueText =
108 byteSource.asCharSource(WaarpStringUtils.UTF8).read();
109 arguments.put(part.getName(), valueText);
110 }
111 }
112 }
113 } catch (final ServletException e) {
114 logger.warn("MULTIPART MODE BUT error {}", e.getMessage());
115 try {
116 inputStream = request.getInputStream();
117 } catch (final IOException e2) {
118 throw new ServletException(INVALID_BLOCK + ": " + e2.getMessage());
119 }
120 } catch (final IOException e) {
121 logger.warn("MULTIPART MODE BUT error {}", e.getMessage());
122 try {
123 inputStream = request.getInputStream();
124 } catch (final IOException e2) {
125 throw new ServletException(INVALID_BLOCK + ": " + e2.getMessage());
126 }
127 }
128 } else {
129 final Enumeration<String> names = request.getParameterNames();
130 while (names.hasMoreElements()) {
131 final String name = names.nextElement();
132 arguments.put(name, request.getParameter(name));
133 }
134 try {
135 inputStream = request.getInputStream();
136 } catch (final IOException e) {
137 throw new ServletException(INVALID_BLOCK + ": " + e.getMessage());
138 }
139 }
140 logger.warn("PARAMS: {}", arguments);
141 resumableInfo = getResumableInfo(arguments);
142 logger.debug("RECV: {}", resumableInfo);
143 try {
144 session = getResumableSession(arguments, resumableInfo);
145 } catch (final ServletException e) {
146 logger.error(e.getMessage());
147 response.setStatus(400);
148 return;
149 }
150 logger.debug("SESSION: {}", session);
151 try {
152 if (!session.tryWrite(resumableInfo, inputStream)) {
153 throw new ServletException(INVALID_BLOCK);
154 }
155 } catch (final IOException e) {
156 throw new ServletException(INVALID_BLOCK + ": " + e.getMessage());
157 }
158
159 String sha = arguments.get(SHA_256);
160 if (ParametersChecker.isNotEmpty(sha) &&
161 sha.equalsIgnoreCase("undefined")) {
162 sha = null;
163 }
164 try {
165 if (session.checkIfUploadFinished(sha)) {
166
167 logger.warn("ALL USER TRANSFER FINISHED: {}", session);
168 HttpSessions.getInstance().removeSession(session);
169 response.setStatus(200);
170 try {
171 response.getWriter().print("All finished.");
172 } catch (final IOException ignore) {
173 logger.debug(ignore);
174 }
175 } else {
176 logger.debug("PARTIAL UPLOAD: {}", session);
177 response.setStatus(201);
178 try {
179 response.getWriter().print("Upload");
180 } catch (final IOException ignore) {
181 logger.debug(ignore);
182 }
183 }
184 } catch (final IllegalArgumentException e) {
185 throw new ServletException(e);
186 }
187 }
188
189
190
191
192
193
194
195
196 private HttpResumableInfo getResumableInfo(
197 final Map<String, String> arguments) {
198 final int resumableChunkNumber =
199 HttpHelper.toInt(arguments.get(RESUMABLE_CHUNK_NUMBER), -1);
200 final int resumableChunkSize =
201 HttpHelper.toInt(arguments.get(RESUMABLE_CHUNK_SIZE), -1);
202 final long resumableTotalSize =
203 HttpHelper.toLong(arguments.get(RESUMABLE_TOTAL_SIZE), -1);
204 final String resumableIdentifier = arguments.get(RESUMABLE_IDENTIFIER);
205 final String resumableFilename = arguments.get(RESUMABLE_FILENAME);
206 final String resumableRelativePath = arguments.get(RESUMABLE_RELATIVE_PATH);
207 return new HttpResumableInfo(resumableChunkNumber, resumableChunkSize,
208 resumableTotalSize, resumableIdentifier,
209 resumableFilename, resumableRelativePath);
210 }
211
212
213
214
215
216
217
218
219
220
221
222
223 private HttpResumableSession getResumableSession(
224 final Map<String, String> arguments,
225 final HttpResumableInfo resumableInfo) throws ServletException {
226 final String rulename = arguments.get(RULENAME);
227 if (rulename == null) {
228 throw new ServletException(INVALID_REQUEST_PARAMS);
229 }
230 String comment = arguments.get(COMMENT);
231 if (comment == null) {
232 comment = "Web Upload " + resumableInfo.getIdentifier();
233 }
234 final HttpSessions sessions = HttpSessions.getInstance();
235
236 try {
237 final HttpAuthent authent =
238 (HttpAuthent) WaarpSystemUtil.newInstance(authentClass);
239 authent.initializeAuthent(arguments);
240 final HttpResumableSession session =
241 sessions.getOrCreateResumableSession(resumableInfo, rulename, comment,
242 authent);
243 if (!session.valid(resumableInfo)) {
244 sessions.removeSession(resumableInfo);
245 throw new ServletException(INVALID_REQUEST_PARAMS);
246 }
247 return session;
248 } catch (final IllegalArgumentException e) {
249 throw new ServletException(
250 INVALID_REQUEST_PARAMS + ": " + e.getMessage());
251 } catch (final InvocationTargetException e) {
252 throw new ServletException(
253 INVALID_REQUEST_PARAMS + ": " + e.getMessage());
254 }
255 }
256
257 @Override
258 protected final void doGet(final HttpServletRequest request,
259 final HttpServletResponse response)
260 throws ServletException {
261 final Map<String, String> arguments = new HashMap<String, String>();
262 final Enumeration<String> names = request.getParameterNames();
263 while (names.hasMoreElements()) {
264 final String name = names.nextElement();
265 arguments.put(name, request.getParameter(name));
266 }
267 final HttpResumableInfo resumableInfo = getResumableInfo(arguments);
268 logger.debug("RECVGET: {}", resumableInfo);
269 final HttpResumableSession session;
270 try {
271 session = getResumableSession(arguments, resumableInfo);
272 } catch (final ServletException e) {
273 logger.error(e.getMessage());
274 response.setStatus(400);
275 return;
276 }
277 logger.debug("SESSION: {}", session);
278 if (session.contains(resumableInfo)) {
279 logger.info("ALREADY: {}", session);
280 response.setStatus(200);
281 try {
282 response.getWriter().print("Uploaded.");
283 } catch (final IOException ignore) {
284 logger.debug(ignore);
285 }
286 } else {
287 logger.info("NOTDONE: {}", session);
288 response.setStatus(HttpServletResponse.SC_NOT_FOUND);
289 }
290 }
291 }