View Javadoc
1 package org.apache.turbine.util.upload; 2 3 /* ==================================================================== 4 * The Apache Software License, Version 1.1 5 * 6 * Copyright (c) 2001 The Apache Software Foundation. All rights 7 * reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The end-user documentation included with the redistribution, 22 * if any, must include the following acknowledgment: 23 * "This product includes software developed by the 24 * Apache Software Foundation (http://www.apache.org/)." 25 * Alternately, this acknowledgment may appear in the software itself, 26 * if and wherever such third-party acknowledgments normally appear. 27 * 28 * 4. The names "Apache" and "Apache Software Foundation" and 29 * "Apache Turbine" must not be used to endorse or promote products 30 * derived from this software without prior written permission. For 31 * written permission, please contact apache@apache.org. 32 * 33 * 5. Products derived from this software may not be called "Apache", 34 * "Apache Turbine", nor may "Apache" appear in their name, without 35 * prior written permission of the Apache Software Foundation. 36 * 37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * ==================================================================== 50 * 51 * This software consists of voluntary contributions made by many 52 * individuals on behalf of the Apache Software Foundation. For more 53 * information on the Apache Software Foundation, please see 54 * <http://www.apache.org/>;. 55 */ 56 57 import java.io.BufferedInputStream; 58 import java.io.BufferedOutputStream; 59 import java.io.File; 60 import java.io.FileInputStream; 61 import java.io.FileOutputStream; 62 import java.io.IOException; 63 import java.io.InputStream; 64 import java.io.OutputStream; 65 import java.lang.reflect.Method; 66 import java.util.Date; 67 import javax.servlet.ServletException; 68 import javax.servlet.http.HttpServletRequest; 69 import javax.servlet.http.HttpServletResponse; 70 import org.apache.turbine.util.ParameterParser; 71 import org.apache.turbine.util.RunData; 72 73 /*** 74 * This class is used to upload files from a client to the server (any 75 * types and any number of fields is supported) and download files 76 * from the server to the client. 77 * 78 * @author <a href="mailto:oleg@one.lv">Oleg M. Podolsky</a> 79 * @author <a href="mailto:neeme@one.lv">Neeme Praks</a> 80 * 81 * @deprecated Use TurbineUploadService counterpart FileItem. 82 */ 83 public class FileHandler 84 { 85 public static String PARAMETER_NAME_FILENAME = "_fileuploader_filename"; 86 public static String PARAMETER_NAME_FILESIZE = "_fileuploader_filesize"; 87 public static String PARAMETER_NAME_FILENAME_SAVED = "_fileuploader_filename_saved"; 88 public static String PARAMETER_NAME_ENCODING = "_fileuploader_encoding"; 89 public static String PARAMETER_NAME_CONTENT_TYPE = "_fileuploader_content-type"; 90 91 /*** Carriage return - line feed two times. */ 92 private static final byte[] CRLF2 = { 0xD, 0xA, 0xD, 0xA }; 93 94 /*** 95 * Buffer for reading/writing data and buffer for storing all 96 * data. 97 */ 98 private static int readbuffersize = 4096; 99 private byte[] readbuffer = new byte[readbuffersize]; 100 private int storebuffersize; 101 private byte[] storebuffer = null; 102 103 /*** Buffer for sending data back to browser. */ 104 private static int writebuffersize = 4096; 105 private byte[] writebuffer = new byte[writebuffersize]; 106 107 /*** Maximum number of bytes accepted, if zero then no limit. */ 108 private long maxdata = 0; 109 110 /*** Place for boundary that separates field data. */ 111 private int boundarysize; 112 private byte[] boundary = null; 113 114 private String fieldname, filename, contenttype; 115 116 private HttpServletRequest req; 117 private HttpServletResponse res; 118 private ParameterParser pp; 119 private String root; 120 121 /*** 122 * If the form data is non-multipart (simple), it returns true, 123 * otherwise returns false. 124 * 125 * @param req An HttpServletRequest. 126 * @return True if the form data is non-multipart (simple). 127 * @deprecated Use TurbineUploadService counterpart FileItem. 128 */ 129 public static boolean isSimpleForm(HttpServletRequest req) 130 { 131 String header = req.getHeader("Content-Type"); 132 if (header != null && header.indexOf("multipart/form-data") >= 0) 133 { 134 return false; 135 } 136 return true; 137 } 138 139 /*** 140 * Copies stream ins to stream outs. 141 * 142 * @param ins An InputStream. 143 * @param outs An OutputStream. 144 * @exception IOException. 145 */ 146 private void copyStream(InputStream ins, 147 OutputStream outs) 148 throws IOException 149 { 150 BufferedInputStream bis = new BufferedInputStream(ins, writebuffersize); 151 BufferedOutputStream bos 152 = new BufferedOutputStream(outs, writebuffersize); 153 int bufread; 154 155 while ((bufread = bis.read(writebuffer)) != -1) 156 { 157 bos.write(writebuffer, 0, bufread); 158 } 159 bos.flush(); bos.close(); 160 bis.close(); 161 } 162 163 /*** 164 * Writes HTTP headers and the file data to the response. 165 * 166 * @param savedname A String. 167 * @param filename A String. 168 * @param contenttype A String. 169 * @exception Exception, a generic exception. 170 * @deprecated Use TurbineUploadService counterpart FileItem. 171 */ 172 public void writeFileToResponse(String savedname, 173 String filename, 174 String contenttype) 175 throws Exception 176 { 177 String fullPath = root + "/" + savedname; 178 File f = new File(fullPath); 179 180 // The following try block replaces: 181 // res.setBufferSize(writebuffersize); 182 try 183 { 184 Class[] sig = new Class[1]; 185 sig[0] = Integer.TYPE; 186 Object[] param = new Object[1]; 187 param[0] = new Integer(writebuffersize); 188 Method method = res.getClass() 189 .getDeclaredMethod("setBufferSize", sig); 190 method.invoke(res, param); 191 } 192 catch (Exception e) 193 { 194 // Ignore it. 195 } 196 res.setContentLength((int)f.length()); 197 res.setContentType(contenttype); 198 res.setHeader("Content-Disposition", 199 "attachment; filename=\"" + filename + "\""); 200 res.setDateHeader("Date", new Date().getTime()); 201 res.setDateHeader("Expires", new Date().getTime()); 202 res.setIntHeader("Age",0); 203 res.setIntHeader("Retry-After",60); 204 res.setHeader("Pragma","no-cache"); 205 res.setHeader("Connection","Keep-Alive"); 206 207 copyStream(new FileInputStream(fullPath), res.getOutputStream()); 208 } 209 210 /*** 211 * Finds random name in the ROOT directory. For example, if 212 * ROOT="c:/temp", name="c:/temp/upload23967879053.dat". ROOT 213 * cannot finish with '/' or '\'. 214 * 215 * @return A String with a random name in the given directory. 216 */ 217 private String getRandomName() 218 { 219 // TODO: if user is logged in, then put the file in user's 220 // folder. 221 String name = null; 222 String fullpath = null; 223 File f = null; 224 225 do 226 { 227 name = "upload" + System.currentTimeMillis() + "_"; 228 fullpath = root + "/" + name; 229 f = new File(fullpath); 230 } 231 while(f.exists()); 232 233 return name; 234 } 235 236 /*** 237 * Cuts short name of a file from its fully qualified name. For 238 * example, "c:\a\b\info.txt" -> "info.txt". 239 * 240 * @param fullname Full name of a file. 241 * @return A String with the short name. 242 */ 243 private String getShortName(String fullname) 244 { 245 int lastslash = fullname.lastIndexOf("/"); 246 int lastbackslash = fullname.lastIndexOf("//"); 247 int pos; 248 249 if (lastslash == lastbackslash) 250 { 251 pos = -1; 252 } 253 else if (lastslash > lastbackslash) 254 { 255 pos = lastslash + 1; 256 } 257 else 258 { 259 pos = lastbackslash + 1; 260 } 261 262 return fullname.substring(pos); 263 } 264 265 /*** 266 * Finds the first position of B in StoreBuffer beginning with 267 * position number Pos, or -1 if not found. 268 * 269 * @param b Byte to find. 270 * @param pos Position to start from. 271 * @return The first occurence of B from Pos. 272 */ 273 private int findByte(byte b, int pos) 274 { 275 if (pos < 0) 276 { 277 pos = 0; 278 } 279 else if (pos >= storebuffersize) 280 { 281 return -1; 282 } 283 284 for (int i = pos; i < storebuffersize ; i++) 285 { 286 if (storebuffer[i] == b) 287 { 288 return i; 289 } 290 } 291 return -1; 292 } 293 294 /*** 295 * Finds the first position of SubArray in StoreBuffer beginning 296 * with position number Pos, or -1 if not found. 297 * 298 * @param subarray Subarray to find. 299 * @param pos Position to start from. 300 * @return The first occurence of Subarray from Pos. 301 */ 302 private int findSubArray(byte[] subarray, int pos) 303 { 304 int sublen = subarray.length; 305 int maxpos, first, sp=0; 306 307 maxpos = storebuffersize - sublen; 308 309 for(first = pos ; (sp != sublen) && (first <= maxpos); first++) 310 { 311 first=findByte(subarray[0],first); 312 if ((first < 0) || (first > maxpos)) 313 { 314 return - 1; 315 } 316 317 for (sp = 1 ; sp < sublen ; sp++) 318 { 319 if (storebuffer[first+sp] != subarray[sp]) 320 { 321 sp = sublen; 322 } 323 } 324 } 325 326 if (sublen == 0) 327 { 328 return 0; 329 } 330 if (sp == sublen) 331 { 332 return (first - 1); 333 } 334 return -1; 335 } 336 337 /*** 338 * Reads the data from the given inputstream to StoreBuffer. 339 * 340 * @param instream InputStream to use. 341 * @exception IOException. 342 */ 343 private void readToStoreBuffer(InputStream instream) 344 throws IOException 345 { 346 int bufread; 347 int pos = 0; 348 BufferedInputStream bis = 349 new BufferedInputStream(instream, readbuffersize); 350 351 while ((bufread=bis.read(readbuffer)) != -1 && 352 (maxdata >= pos || maxdata==0) ) 353 { 354 System.arraycopy(readbuffer, 0, storebuffer, pos, bufread); 355 pos += bufread; 356 } 357 bis.close(); 358 } 359 360 /*** 361 * Finds values of Fieldname and Filename variables from the given 362 * chunk of StoreBuffer. 363 * 364 * @param start Starting position in StoreBuffer. 365 * @param end Ending position in StoreBuffer. 366 */ 367 private void getHeaderInfo(int start, int end) 368 { 369 String temp = new String(storebuffer, start, end - start + 1); 370 int namestart, nameend; 371 int filenamestart, filenameend; 372 int conttypestart, conttypeend; 373 374 contenttype = null; 375 filename = null; 376 377 conttypestart = temp.indexOf("Content-Type: "); 378 if(conttypestart >= 0) 379 { 380 conttypestart += 14; 381 conttypeend = temp.length() - 1; 382 contenttype = temp.substring(conttypestart, conttypeend); 383 } 384 385 namestart = temp.indexOf("; name=\"") + 8; 386 nameend = temp.indexOf("\"", namestart); 387 fieldname = temp.substring(namestart, nameend); 388 389 filenamestart = temp.indexOf("; filename=\"", nameend + 1); 390 if (filenamestart >= 0) 391 { 392 filenamestart += 12; 393 filenameend = temp.indexOf("\"", filenamestart); 394 filename = temp.substring(filenamestart, filenameend); 395 } 396 } 397 398 /*** 399 * Returns the given chunk of StoreBuffer as a String. 400 * 401 * @param start Starting position in StoreBuffer. 402 * @param end Ending position in StoreBuffer. 403 * @return Given chunk's representation as a String. 404 */ 405 private String getChunkAsText(int start, int end) 406 { 407 String text = new String(storebuffer, start, end - start + 1); 408 return text; 409 } 410 411 /*** 412 * Writes the given chunk of StoreBuffer to given OutputStream. 413 * 414 * @param start Starting position in StoreBuffer. 415 * @param end Ending position in StoreBuffer. 416 * @param outstream OutputStream to write to. 417 * @exception IOException. 418 */ 419 private void storeChunk(int start, 420 int end, 421 OutputStream outstream) 422 throws IOException 423 { 424 BufferedOutputStream bos = 425 new BufferedOutputStream(outstream, readbuffersize); 426 427 bos.write(storebuffer, start, end - start + 1); 428 bos.flush(); 429 bos.close(); 430 } 431 432 /*** 433 * Divides StoreBuffer into simple fields and binary fields 434 * (files) and writes them to files (simple fields - to a text 435 * file, files - to files with random names, providing name 436 * mappings in the file for simple fields). 437 * 438 * @exception IOException. 439 */ 440 private void writeChunks() 441 throws IOException 442 { 443 int a; 444 int b; 445 int c = 0; 446 String savename = null; 447 String param = null; 448 449 b = findSubArray(boundary, 0); 450 do 451 { 452 if ((a = findSubArray(CRLF2, b + boundarysize)) >= 0) 453 { 454 if ((b = findSubArray(boundary, a + 4)) >= 0); 455 { 456 getHeaderInfo(c, a); 457 c = b; 458 459 if (filename == null || filename.length() == 0) 460 { 461 param = getChunkAsText(a + 4, b - 5); 462 org.apache.turbine.util.Log.info("FileUploader: received field: " + fieldname + "=" + param); 463 pp.add(fieldname, param); 464 } 465 else 466 { 467 // TODO: implement also retrieving enconding 468 // and other header info. 469 470 // TODO: strip the path information from the 471 // original filename. 472 473 String shortname = getShortName(filename); 474 savename = getRandomName() + shortname + ".dat"; 475 String fullPath = root + "/" + savename; 476 org.apache.turbine.util.Log.info ("FileUploader: received file: field=" + fieldname + ", fullpath=" + filename + ", filename=" + shortname + ", saved to file: " + fullPath); 477 storeChunk(a + 4, b - 5, 478 new FileOutputStream(fullPath)); 479 File f = new File(fullPath); 480 pp.add(this.PARAMETER_NAME_FILESIZE, f.length()); 481 pp.add(this.PARAMETER_NAME_FILENAME, shortname); 482 pp.add(this.PARAMETER_NAME_FILENAME_SAVED, savename); 483 pp.add(this.PARAMETER_NAME_CONTENT_TYPE, contenttype); 484 } 485 } 486 } 487 } 488 while (a >= 0 && b >= 0); 489 } 490 491 /*** 492 * Stores all data. 493 * 494 * @exception ServletException. 495 * @exception IOException. 496 * @deprecated Use TurbineUploadService counterpart FileItem. 497 */ 498 public void saveStream() 499 throws ServletException, 500 IOException 501 { 502 readToStoreBuffer(req.getInputStream()); 503 writeChunks(); 504 } 505 506 /*** 507 * Performs initialization. 508 * 509 * @param req An HttpServletRequest. 510 * @param res An HttpServletResponse. 511 * @param pp A ParameterParser. 512 * @deprecated Use TurbineUploadService counterpart FileItem. 513 */ 514 public FileHandler(HttpServletRequest req, 515 HttpServletResponse res, 516 ParameterParser pp) 517 { 518 this.req = req; 519 this.res = res; 520 this.pp = pp; 521 this.root = "c:"; 522 523 String conttype = req.getHeader("Content-Type"); 524 if (conttype != null) 525 { 526 boundary = conttype.substring(conttype.indexOf("boundary") + 9).getBytes(); 527 boundarysize = boundary.length; 528 storebuffersize = Integer.parseInt(req.getHeader("Content-Length")); 529 storebuffer = new byte[storebuffersize]; 530 } 531 } 532 533 /*** 534 * Performs initialization. 535 * 536 * @param req An HttpServletRequest. 537 * @param res An HttpServletResponse. 538 * @param pp A ParameterParser. 539 * @param root A String. 540 * @deprecated Use TurbineUploadService counterpart FileItem. 541 */ 542 public FileHandler( HttpServletRequest req, 543 HttpServletResponse res, 544 ParameterParser pp, 545 String root ) 546 { 547 this( req, res, pp ); 548 this.setFileRepository(root); 549 } 550 551 /*** 552 * Performs initialization. 553 * 554 * @param req An HttpServletRequest. 555 * @param res An HttpServletResponse. 556 * @param root A String. 557 * @deprecated Use TurbineUploadService counterpart FileItem. 558 */ 559 public FileHandler( HttpServletRequest req, 560 ParameterParser pp, 561 String root ) 562 { 563 this( req, null, pp ); 564 this.setFileRepository(root); 565 } 566 567 /*** 568 * Performs initialization. 569 * 570 * @param data A Turbine RunData object. 571 * @param root A String. 572 * @deprecated Use TurbineUploadService counterpart FileItem. 573 */ 574 public FileHandler( RunData data, 575 String root ) 576 { 577 this( data.getRequest(), 578 data.getResponse(), 579 data.getParameters(), 580 root ); 581 } 582 583 /*** 584 * Performs initialization. 585 * 586 * @param data A Turbine RunData object. 587 * @deprecated Use TurbineUploadService counterpart FileItem. 588 */ 589 public FileHandler( RunData data ) 590 { 591 this( data.getRequest(), 592 data.getResponse(), 593 data.getParameters() ); 594 } 595 596 /*** 597 * Sets the root file repository. 598 * 599 * @param root A String. 600 * @deprecated Use TurbineUploadService counterpart FileItem. 601 */ 602 public void setFileRepository(String root) 603 { 604 this.root = root; 605 } 606 607 /*** 608 * Gets the root file repository. 609 * 610 * @return A String. 611 * @deprecated Use TurbineUploadService counterpart FileItem. 612 */ 613 public String getFileRepository() 614 { 615 return this.root; 616 } 617 618 /*** 619 * Sets the maximum size. 620 * 621 * @param size A long. 622 * @deprecated Use TurbineUploadService counterpart FileItem. 623 */ 624 public void setMaxSize(long size) 625 { 626 this.maxdata = size; 627 } 628 629 /*** 630 * Deletes the file. 631 * 632 * @param filename A String. 633 * @return True if file was deleted. 634 * @deprecated Use TurbineUploadService counterpart FileItem. 635 */ 636 public boolean deleteFile(String filename) 637 { 638 File f = new File(root + "/" + filename); 639 return f.delete(); 640 } 641 }

This page was automatically generated by Maven