1 23 24 package org.netbeans.lib.uihandler; 25 33 34 import java.io.BufferedOutputStream ; 35 import java.io.ByteArrayOutputStream ; 36 import java.io.File ; 37 import java.io.FileOutputStream ; 38 import java.io.FilterInputStream ; 39 import java.io.IOException ; 40 import java.io.InputStream ; 41 import java.io.OutputStream ; 42 import java.util.Enumeration ; 43 import java.util.Hashtable ; 44 import java.util.HashMap ; 45 import java.util.Vector ; 46 import java.util.zip.GZIPInputStream ; 47 48 public class MultiPartHandler { 49 public interface InputFacade { 50 public int readLine(byte[] arr, int off, int len) throws IOException ; 51 public InputStream getInputStream(); 52 } 53 54 public interface RequestFacade { 55 public int getContentLength(); 56 public String getContentType(); 57 public InputFacade getInput() throws IOException ; 58 } 59 60 private static final int DEFAULT_MAX_UPLOAD_SIZE = 1024 * 1024; 62 protected Hashtable <String ,Vector <String >> formFields = new Hashtable <String ,Vector <String >>(); 63 protected Hashtable <String ,OneUpload> uploadFiles = new Hashtable <String ,OneUpload>(); 64 65 66 private RequestFacade req; 67 68 69 private InputFacade in; 70 71 72 private String boundary; 73 74 75 private byte[] buf = new byte[8 * 1024]; 76 77 78 private File uploadDir; 79 80 81 private String fieldEncoding = "ISO-8859-1"; 82 83 86 87 90 public MultiPartHandler(RequestFacade request, 91 String tmpDirectory) throws IOException { 92 this(request, tmpDirectory, DEFAULT_MAX_UPLOAD_SIZE, "ISO-8859-1"); 93 } 94 95 public MultiPartHandler(RequestFacade request, 96 String tmpDirectory, 97 int maxUploadSize) throws IOException { 98 this(request, tmpDirectory, maxUploadSize, "ISO-8859-1"); 99 } 100 101 114 public MultiPartHandler(RequestFacade request, 115 String tmpDirectory, 116 int maxUploadSize, 117 String fieldEncoding) throws IOException { 118 119 if (request == null) { 121 throw new IllegalArgumentException ( "request is null" ); 123 } 124 if (tmpDirectory == null) { 125 throw new IllegalArgumentException ( "tmp Dir is null" ); 127 } 128 if (maxUploadSize <= 0) { 129 throw new IllegalArgumentException ( "Max size is < 0" ); 131 } 132 133 uploadDir = new File (tmpDirectory); 135 if (!uploadDir.isDirectory()) { 136 throw new IllegalArgumentException ( "Not a Directory" ); 138 } 139 if (!uploadDir.canWrite()) { 140 throw new IllegalArgumentException ("write protected" ); 142 } 143 int length = request.getContentLength(); 144 149 String type = request.getContentType(); 151 if (type == null || 152 !type.toLowerCase().startsWith("multipart/form-data")) { 153 throw new IOException ( "type null" ); 155 } 156 157 this.fieldEncoding = fieldEncoding; 159 this.req = request; 160 } 161 162 168 public void parseMultipartUpload() 169 throws IOException { 170 startMultipartParse(); 173 174 HashMap partHeaders = parsePartHeaders(); 175 while (partHeaders != null) { 176 177 String fieldName = (String )partHeaders.get("fieldName"); 178 String fileName = (String )partHeaders.get("fileName"); 179 180 if (fileName != null) { 181 if (fileName.equals("")) { 183 fileName = null; } 185 186 if (fileName != null) { 187 String content = (String )partHeaders.get("content-type"); 189 fileName = saveUploadFile(fileName, content); 190 191 uploadFiles.put(fieldName, 192 new OneUpload( 193 uploadDir.toString(), 194 fileName, 195 content 196 ) 197 ); 198 } 199 else { 200 uploadFiles.put(fieldName, new OneUpload(null, null, null)); 202 } 203 } 204 else { 205 byte[] valueBytes = parseFormFieldBytes(); 207 String value = new String (valueBytes, fieldEncoding); 208 209 Vector <String > existingValues = formFields.get(fieldName); 210 if (existingValues == null) { 211 existingValues = new Vector <String >(); 212 formFields.put(fieldName, existingValues); 213 } 214 existingValues.addElement(value); 215 } 216 217 partHeaders.clear(); 218 partHeaders = parsePartHeaders(); 219 } 220 } 221 222 private void startMultipartParse() 223 throws IOException { 224 String boundary = parseBoundary(req.getContentType()); 227 if (boundary == null) { 228 throw new IOException ( "boundary is nul" ); 230 } 231 232 this.in = req.getInput(); 233 this.boundary = boundary; 234 235 String line = readLine(); 237 if (line == null) { 238 throw new IOException ( "line is null" ); 240 } 241 242 if (!line.startsWith(boundary)) { 244 throw new IOException ( "not start with boundary" ); 246 } 247 } 248 249 255 private HashMap parsePartHeaders() throws IOException { 256 HashMap <String ,String > partHeaders = new HashMap <String ,String >(); 257 258 Vector <String > headers = new Vector <String >(); 259 String line = readLine(); 260 if (line == null) { 261 return null; 263 } 264 else if (line.length() == 0) { 265 return null; 267 } 268 headers.addElement(line); 269 270 while ((line = readLine()) != null && (line.length() > 0)) { 272 headers.addElement(line); 273 } 274 275 if (line == null) { 277 return null; 278 } 279 280 partHeaders.put("content-type", "text/plain"); 282 283 Enumeration ee = headers.elements(); 284 while (ee.hasMoreElements()) { 285 String headerline = (String ) ee.nextElement(); 286 287 if (headerline.toLowerCase().startsWith("content-disposition:")) { 288 parseContentDisposition(headerline, partHeaders); 290 } 291 else if (headerline.toLowerCase().startsWith("content-type:")) { 292 parseContentType(headerline, partHeaders); 294 } 295 } 296 297 return partHeaders; 298 } 299 300 303 private String parseBoundary(String line) { 304 int index = line.lastIndexOf("boundary="); 307 if (index == -1) { 308 return null; 309 } 310 String boundary = line.substring(index + 9); if (boundary.charAt(0) == '"') { 312 index = boundary.lastIndexOf('"'); 314 boundary = boundary.substring(1, index); 315 } 316 317 boundary = "--" + boundary; 319 320 return boundary; 321 } 322 323 329 private void parseContentDisposition(String line, HashMap <String ,String > partHeaders) 330 throws IOException { 331 332 String origline = line; 335 line = origline.toLowerCase(); 336 337 int start = line.indexOf("content-disposition: "); 339 int end = line.indexOf(";"); 340 if (start == -1 || end == -1) { 341 throw new IOException ( "end reached" ); 343 } 344 String disposition = line.substring(start + 21, end); 345 if (!disposition.equals("form-data")) { 346 throw new IOException ( "fome-data not match" ); 348 } 349 350 start = line.indexOf("name=\"", end); end = line.indexOf("\"", start + 7); if (start == -1 || end == -1) { 354 throw new IOException ( "data corrupt" ); 356 } 357 358 String name = origline.substring(start + 6, end); 359 360 String fileName = null; 362 String origFileName = null; 363 start = line.indexOf("filename=\"", end + 2); end = line.indexOf("\"", start + 10); 366 if (start != -1 && end != -1) { fileName = origline.substring(start + 10, end); 368 origFileName = fileName; 369 int slash = 371 Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\')); 372 if (slash > -1) { 373 fileName = fileName.substring(slash + 1); } 375 } 376 377 partHeaders.put("disposition", disposition); 380 partHeaders.put("fieldName", name); 381 partHeaders.put("fileName", fileName); 382 partHeaders.put("filePath", origFileName); 383 } 384 385 389 private void parseContentType(String line, HashMap <String ,String > partHeaders) 390 throws IOException { 391 String contentType = null; 392 393 String origline = line; 395 line = origline.toLowerCase(); 396 397 if (line.startsWith("content-type")) { 399 int start = line.indexOf(" "); 400 401 if (start == -1) { 402 throw new IOException ( "no start" ); 404 } 405 contentType = line.substring(start + 1); 406 407 partHeaders.put("content-type", contentType); 408 } 409 else if (line.length() != 0) { throw new IOException ( "length 0" ); 412 } 413 } 414 415 417 private byte[] parseFormFieldBytes() throws IOException { 418 419 MultipartInputStream pis = new MultipartInputStream(in, boundary); 421 422 ByteArrayOutputStream baos = new ByteArrayOutputStream (512); 423 byte[] buf = new byte[128]; 424 int read; 425 while ((read = pis.read(buf)) != -1) { 426 baos.write(buf, 0, read); 427 } 428 pis.close(); 429 baos.close(); 430 431 return baos.toByteArray(); 433 } 434 435 442 private String readLine() throws IOException { 443 StringBuffer sbuf = new StringBuffer (); 444 int result; 445 String line; 446 447 do { 448 result = in.readLine(buf, 0, buf.length); if (result != -1) { 450 sbuf.append(new String (buf, 0, result, "ISO-8859-1")); 451 } 452 } while (result == buf.length); 454 if (sbuf.length() == 0) { 455 return null; } 457 458 int len = sbuf.length(); 461 if (len >= 2 && sbuf.charAt(len - 2) == '\r') { 462 sbuf.setLength(len - 2); } 464 else { 465 sbuf.setLength(len - 1); } 467 return sbuf.toString(); 468 } 469 470 473 private String saveUploadFile(String fileName, String content) 474 throws IOException { 475 476 long written = 0; 477 OutputStream fileOut = null; 478 479 try { 480 File file = new File (uploadDir, fileName); 482 for (int i = 0; file.exists(); i++) { 483 if (!file.exists()) { 484 break; 485 } 486 file = new File (uploadDir, fileName + "." + i); 487 } 488 fileName = file.getName(); 489 490 fileOut = new BufferedOutputStream (new FileOutputStream (file)); 491 int numBytes; 492 byte[] buf = new byte[8 * 1024]; 493 494 InputStream partInput; 495 if (content.equals("x-application/gzip")) { partInput = new GZIPInputStream (in.getInputStream()); 498 } else { 499 500 partInput = new MultipartInputStream(in, boundary); 501 } 502 while((numBytes = partInput.read(buf)) != -1) { 503 fileOut.write(buf, 0, numBytes); 504 written += numBytes; 505 } 506 partInput.close(); 507 } 508 finally { 509 if (fileOut != null) fileOut.close(); 510 } 511 512 return fileName; 513 } 514 515 516 521 public Enumeration getParameterNames() { 522 return formFields.keys(); 523 } 524 525 532 public Enumeration getFileNames() { 533 return uploadFiles.keys(); 534 } 535 536 545 public String getParameter(String name) { 546 try { 547 Vector values = (Vector )formFields.get(name); 548 if (values == null || values.size() == 0) { 549 return null; 550 } 551 String value = (String )values.elementAt(values.size() - 1); 552 return value; 553 } 554 catch (Exception e) { 555 return null; 556 } 557 } 558 559 567 public String [] getParameterValues(String name) { 568 try { 569 Vector values = (Vector )formFields.get(name); 570 if (values == null || values.size() == 0) { 571 return null; 572 } 573 String [] valuesArray = new String [values.size()]; 574 values.copyInto(valuesArray); 575 return valuesArray; 576 } 577 catch (Exception e) { 578 return null; 579 } 580 } 581 582 589 public String getFileName(String name) { 590 try { 591 OneUpload file = uploadFiles.get(name); 592 return file.getFileName(); } 594 catch (Exception e) { 595 return null; 596 } 597 } 598 599 604 public String getFileType(String name) { 605 try { 606 OneUpload file = uploadFiles.get(name); 607 return file.getFileType(); } 609 catch (Exception e) { 610 return null; 611 } 612 } 613 614 619 public File getFile(String name) { 620 try { 621 OneUpload file = uploadFiles.get(name); 622 return file.getFile(); } 624 catch (Exception e) { 625 return null; 626 } 627 } 628 629 632 public void close() throws IOException { 633 req = null; 634 in = null; 635 boundary = null; 636 buf = null; 637 uploadDir = null; 638 } 639 640 641 642 private static class OneUpload { 643 644 private String dir; 645 private String filename; 646 private String type; 647 648 OneUpload(String dir, String filename, String type) { 649 this.dir = dir; 650 this.filename = filename; 651 this.type = type; 652 } 653 654 public String getFileType() { 655 return type; 656 } 657 658 public String getFileName() { 659 return filename; 660 } 661 662 public File getFile() { 663 if (dir == null || filename == null) { 664 return null; 665 } else { 666 return new File (dir + File.separator + filename); 667 } 668 } 669 } 670 671 676 private static class MultipartInputStream extends FilterInputStream { 677 678 private String boundary; 679 680 681 private byte [] buf = new byte[64*1024]; 683 684 private int count; 685 686 687 private int pos; 688 689 690 private boolean eof; 691 692 693 private MultiPartHandler.InputFacade facade; 694 695 698 699 704 MultipartInputStream(MultiPartHandler.InputFacade in, 705 String boundary) throws IOException { 706 super(in.getInputStream()); 707 this.boundary = boundary; 708 this.facade = in; 709 } 710 711 720 private void fill() throws IOException 721 { 722 if (eof) 723 return; 724 725 if (count > 0) 727 { 728 if (count - pos == 2) { 730 System.arraycopy(buf, pos, buf, 0, count - pos); 732 count -= pos; 733 pos = 0; 734 } else { 735 throw new IllegalStateException ( "should never happen" ); 738 } 739 } 740 741 int read = 0; 744 int maxRead = buf.length - boundary.length(); 745 while (count < maxRead) { 746 read = facade.readLine(buf, count, buf.length - count); 748 if (read == -1) { 750 throw new IOException ( "read is -1" ); 752 } else { 753 if (read >= boundary.length()) { 754 eof = true; 755 for (int i=0; i < boundary.length(); i++) { 756 if (boundary.charAt(i) != buf[count + i]) { 757 eof = false; 759 break; 760 } 761 } 762 if (eof) { 763 break; 764 } 765 } 766 } 767 count += read; 769 } 770 } 771 772 778 public int read() throws IOException { 779 if (count - pos <= 2) { 780 fill(); 781 if (count - pos <= 2) { 782 return -1; 783 } 784 } 785 return buf[pos++] & 0xff; 786 } 787 788 796 public int read(byte b[]) throws IOException { 797 return read(b, 0, b.length); 798 } 799 800 807 public int read(byte b[], int off, int len) throws IOException 808 { 809 int total = 0; 810 if (len == 0) { 811 return 0; 812 } 813 814 int avail = count - pos - 2; 815 if (avail <= 0) { 816 fill(); 817 avail = count - pos - 2; 818 if(avail <= 0) { 819 return -1; 820 } 821 } 822 int copy = Math.min(len, avail); 823 System.arraycopy(buf, pos, b, off, copy); 824 pos += copy; 825 total += copy; 826 827 while (total < len) { 828 fill(); 829 avail = count - pos - 2; 830 if(avail <= 0) { 831 return total; 832 } 833 copy = Math.min(len - total, avail); 834 System.arraycopy(buf, pos, b, off + total, copy); 835 pos += copy; 836 total += copy; 837 } 838 return total; 839 } 840 841 849 public int available() throws IOException { 850 int avail = (count - pos - 2) + in.available(); 851 return (avail < 0 ? 0 : avail); 853 } 854 855 863 public void close() throws IOException { 864 if (!eof) { 865 while (read(buf, 0, buf.length) != -1) 866 ; } 868 } 869 } 870 871 } 872 873 | Popular Tags |