1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package wjhk.jupload2.upload;
21
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.io.UnsupportedEncodingException;
25 import java.net.URL;
26 import java.net.URLDecoder;
27 import java.net.URLEncoder;
28 import java.util.HashMap;
29 import java.util.Iterator;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.concurrent.BlockingQueue;
33
34 import wjhk.jupload2.exception.JUploadException;
35 import wjhk.jupload2.exception.JUploadIOException;
36 import wjhk.jupload2.policies.UploadPolicy;
37 import wjhk.jupload2.upload.helper.ByteArrayEncoder;
38 import wjhk.jupload2.upload.helper.ByteArrayEncoderHTTP;
39 import wjhk.jupload2.upload.helper.HTTPConnectionHelper;
40
41
42
43
44
45
46
47 public class FileUploadThreadHTTP extends DefaultFileUploadThread {
48
49
50
51
52
53 private HTTPConnectionHelper connectionHelper = null;
54
55
56
57
58
59
60
61
62 private HashMap<UploadFileData, ByteArrayEncoder> heads = null;
63
64
65
66
67
68
69 private HashMap<UploadFileData, ByteArrayEncoder> tails = null;
70
71
72
73
74
75
76
77
78 public FileUploadThreadHTTP(UploadPolicy uploadPolicy,
79 BlockingQueue<UploadFilePacket> packetQueue,
80 FileUploadManagerThread fileUploadManagerThread) {
81 super("FileUploadThreadHTTP thread", packetQueue, uploadPolicy,
82 fileUploadManagerThread);
83 this.uploadPolicy.displayDebug(" Using " + this.getClass().getName(),
84 30);
85
86 uploadPolicy.displayDebug("Upload done by using the "
87 + getClass().getName() + " class", 30);
88
89 setName("FileUploadThreadHTTP");
90
91 this.connectionHelper = new HTTPConnectionHelper(uploadPolicy);
92 }
93
94
95 @Override
96 void beforeRequest(UploadFilePacket packet) throws JUploadException {
97 if (this.connectionHelper != null) {
98
99 this.connectionHelper.dispose();
100 }
101 this.connectionHelper = new HTTPConnectionHelper(uploadPolicy);
102 setAllHead(packet, this.connectionHelper.getBoundary());
103 setAllTail(packet, this.connectionHelper.getBoundary());
104 }
105
106
107 @Override
108 long getAdditionnalBytesForUpload(UploadFileData uploadFileData)
109 throws JUploadIOException {
110 return this.heads.get(uploadFileData).getEncodedLength()
111 + this.tails.get(uploadFileData).getEncodedLength();
112 }
113
114
115 @Override
116 void afterFile(UploadFileData uploadFileData) throws JUploadIOException {
117 this.connectionHelper.append(this.tails.get(uploadFileData));
118 this.uploadPolicy.displayDebug("--- filetail start (len="
119 + this.tails.get(uploadFileData).getEncodedLength() + "):", 70);
120 this.uploadPolicy.displayDebug(quoteCRLF(this.tails.get(uploadFileData)
121 .getString()), 70);
122 this.uploadPolicy.displayDebug("--- filetail end", 70);
123 }
124
125
126 @Override
127 void beforeFile(UploadFilePacket uploadFilePacket,
128 UploadFileData uploadFileData) throws JUploadException {
129
130
131
132
133 try {
134 this.connectionHelper.append(this.heads.get(uploadFileData)
135 .getEncodedByteArray());
136
137
138
139 this.uploadPolicy.displayDebug("--- fileheader start (len="
140 + this.heads.get(uploadFileData).getEncodedLength() + "):",
141 70);
142 this.uploadPolicy.displayDebug(quoteCRLF(this.heads.get(
143 uploadFileData).getString()), 70);
144 this.uploadPolicy.displayDebug("--- fileheader end", 70);
145 } catch (Exception e) {
146 throw new JUploadException(e);
147 }
148 }
149
150
151 @Override
152 void cleanAll() throws JUploadException {
153
154 }
155
156
157 @Override
158 void cleanRequest() throws JUploadException {
159 try {
160 this.connectionHelper.dispose();
161 } catch (JUploadIOException e) {
162 this.uploadPolicy.displayErr(this.uploadPolicy
163 .getLocalizedString("errDuringUpload"), e);
164 throw e;
165 }
166 }
167
168 @Override
169 int finishRequest() throws JUploadException {
170 if (this.uploadPolicy.getDebugLevel() > 100) {
171
172
173 try {
174 Thread.sleep(400);
175 } catch (InterruptedException e) {
176 }
177 }
178 int status = this.connectionHelper.readHttpResponse();
179 setResponseMsg(this.connectionHelper.getResponseMsg());
180 setResponseBody(this.connectionHelper.getResponseBody());
181 return status;
182 }
183
184
185
186
187 @Override
188 void interruptionReceived() {
189
190
191 try {
192 if (this.connectionHelper != null) {
193 this.connectionHelper.dispose();
194 this.connectionHelper = null;
195 }
196
197 if (this.heads != null) {
198 for (UploadFileData uploadFileData : this.heads.keySet()) {
199 ByteArrayEncoder bae = this.heads.get(uploadFileData);
200 if (bae != null) {
201 bae.close();
202 }
203 }
204 this.heads = null;
205 }
206 if (this.tails != null) {
207 for (UploadFileData uploadFileData : this.tails.keySet()) {
208 ByteArrayEncoder bae = this.tails.get(uploadFileData);
209 if (bae != null) {
210 bae.close();
211 }
212 }
213 this.tails = null;
214 }
215 } catch (Exception e) {
216 this.uploadPolicy.displayWarn("Exception in "
217 + getClass().getName() + ".interruptionReceived() ("
218 + e.getClass().getName() + "): " + e.getMessage());
219 }
220 }
221
222
223
224
225
226
227
228 @Override
229 OutputStream getOutputStream() throws JUploadException {
230 return this.connectionHelper.getOutputStream();
231 }
232
233
234 @Override
235 void startRequest(long contentLength, boolean bChunkEnabled, int chunkPart,
236 boolean bLastChunk) throws JUploadException {
237
238 try {
239 String chunkHttpParam = "jupart=" + chunkPart + "&jufinal="
240 + (bLastChunk ? "1" : "0");
241 this.uploadPolicy.displayDebug("chunkHttpParam: " + chunkHttpParam,
242 30);
243
244 URL url = new URL(this.uploadPolicy.getPostURL());
245
246
247 if (bChunkEnabled) {
248 if (null != url.getQuery() && !"".equals(url.getQuery())) {
249 url = new URL(url.toExternalForm() + "&" + chunkHttpParam);
250 } else {
251 url = new URL(url.toExternalForm() + "?" + chunkHttpParam);
252 }
253 }
254
255 this.connectionHelper.initRequest(url, "POST", bChunkEnabled,
256 bLastChunk);
257
258
259
260 ByteArrayEncoder formParams = getFormParamsForPostRequest(url);
261 contentLength += formParams.getEncodedLength();
262
263 this.connectionHelper.append(
264 "Content-Type: multipart/form-data; boundary=").append(
265 this.connectionHelper.getBoundary().substring(2)).append(
266 "\r\n");
267 this.connectionHelper.append("Content-Length: ").append(
268 String.valueOf(contentLength)).append("\r\n");
269
270
271 this.connectionHelper.append("\r\n");
272
273
274
275
276
277
278 this.connectionHelper.append(formParams);
279
280
281 this.connectionHelper.sendRequest();
282
283
284
285 this.uploadPolicy.displayDebug("=== main header (len="
286 + this.connectionHelper.getByteArrayEncoder()
287 .getEncodedLength()
288 + "):\n"
289 + quoteCRLF(this.connectionHelper.getByteArrayEncoder()
290 .getString()), 70);
291 this.uploadPolicy.displayDebug("=== main header end", 70);
292 } catch (IOException e) {
293 throw new JUploadIOException(e);
294 } catch (IllegalArgumentException e) {
295 throw new JUploadException(e);
296 }
297 }
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314 private final ByteArrayEncoder getFileHeader(UploadFileData uploadFileData,
315 int numInCurrentUpload, String bound, int chunkPart)
316 throws JUploadException {
317 String filenameEncoding = this.uploadPolicy.getFilenameEncoding();
318 String mimetype = uploadFileData.getMimeType();
319 String uploadFilename = uploadFileData
320 .getUploadFilename(numInCurrentUpload);
321 ByteArrayEncoder bae = new ByteArrayEncoderHTTP(this.uploadPolicy,
322 bound);
323
324 if (numInCurrentUpload == 0) {
325
326
327 String form = this.uploadPolicy.getFormdata();
328 if (null != form) {
329 bae.appendFormVariables(form);
330 }
331 }
332
333 uploadFileData.appendFileProperties(bae, numInCurrentUpload);
334
335
336 bae.append(bound).append("\r\n");
337
338
339 bae.append("Content-Disposition: form-data; name=\"");
340 bae.append(uploadFileData.getUploadName(numInCurrentUpload)).append(
341 "\"; filename=\"");
342 if (filenameEncoding == null) {
343 bae.append(uploadFilename);
344 } else {
345 try {
346 this.uploadPolicy.displayDebug("Encoded filename: "
347 + URLEncoder.encode(uploadFilename, filenameEncoding),
348 70);
349 bae.append(URLEncoder.encode(uploadFilename, filenameEncoding));
350 } catch (UnsupportedEncodingException e) {
351 this.uploadPolicy
352 .displayWarn(e.getClass().getName() + ": "
353 + e.getMessage()
354 + " (in UploadFileData.getFileHeader)");
355 bae.append(uploadFilename);
356 }
357 }
358 bae.append("\"\r\n");
359
360
361 bae.append("Content-Type: ").append(mimetype).append("\r\n");
362
363
364 bae.append("\r\n");
365
366
367 bae.close();
368 return bae;
369 }
370
371
372
373
374
375
376
377
378 private final void setAllHead(UploadFilePacket packet, String bound)
379 throws JUploadException {
380 this.heads = new HashMap<UploadFileData, ByteArrayEncoder>(packet
381 .size());
382 int numInCurrentUpload = 0;
383 for (UploadFileData uploadFileData : packet) {
384 this.heads.put(uploadFileData, getFileHeader(uploadFileData,
385 numInCurrentUpload++, bound, -1));
386 }
387 }
388
389
390
391
392
393
394 private final void setAllTail(UploadFilePacket packet, String bound)
395 throws JUploadException {
396 this.tails = new HashMap<UploadFileData, ByteArrayEncoder>(packet
397 .size());
398 for (int i = 0; i < packet.size(); i++) {
399
400 ByteArrayEncoder bae = new ByteArrayEncoderHTTP(this.uploadPolicy,
401 bound);
402
403 bae.append("\r\n");
404
405 if (this.uploadPolicy.getSendMD5Sum()) {
406 bae.appendTextProperty("md5sum", packet.get(i).getMD5(), i);
407 }
408
409
410
411 if (i == packet.size() - 1) {
412 bae.append(bound).append("--\r\n");
413 }
414
415
416 bae.close();
417
418 this.tails.put(packet.get(i), bae);
419 }
420
421 }
422
423
424
425
426
427
428
429
430 private final ByteArrayEncoder getFormParamsForPostRequest(final URL url)
431 throws JUploadIOException {
432
433
434
435 ByteArrayEncoder bae = new ByteArrayEncoderHTTP(this.uploadPolicy,
436 this.connectionHelper.getBoundary());
437
438
439 String query = url.getQuery();
440
441 if (null != query) {
442
443 HashMap<String, String> requestParameters = new HashMap<String, String>();
444 String[] paramPairs = query.split("&");
445 String[] oneParamArray;
446
447
448
449
450 for (String param : paramPairs) {
451 if (param.contains("=")) {
452 oneParamArray = param.split("=");
453 if (oneParamArray.length > 1) {
454
455 try {
456
457 requestParameters.put(oneParamArray[0], URLDecoder
458 .decode(oneParamArray[1], "UTF-8"));
459 } catch (UnsupportedEncodingException e) {
460 throw new JUploadIOException(e.getClass().getName()
461 + ": " + e.getMessage()
462 + " (when trying to decode "
463 + oneParamArray[1] + ")");
464 }
465 } else {
466
467 requestParameters.put(oneParamArray[0], "");
468 }
469 }
470 }
471
472
473 Set<Map.Entry<String, String>> entrySet = requestParameters
474 .entrySet();
475 Map.Entry<String, String> entry;
476 Iterator<Map.Entry<String, String>> i = entrySet.iterator();
477 while (i.hasNext()) {
478 entry = i.next();
479 bae.appendTextProperty(entry.getKey(), entry.getValue(), -1);
480 }
481 }
482
483 bae.close();
484
485 return bae;
486 }
487 }