1 16 package org.apache.cocoon.servlet.multipart; 17 18 import java.io.BufferedInputStream ; 19 import java.io.ByteArrayInputStream ; 20 import java.io.ByteArrayOutputStream ; 21 import java.io.File ; 22 import java.io.FileOutputStream ; 23 import java.io.IOException ; 24 import java.io.InputStream ; 25 import java.io.OutputStream ; 26 import java.io.PushbackInputStream ; 27 import java.util.Enumeration ; 28 import java.util.Hashtable ; 29 import java.util.StringTokenizer ; 30 import java.util.Vector ; 31 32 import javax.servlet.http.HttpServletRequest ; 33 34 import org.apache.cocoon.util.NullOutputStream; 35 36 47 public class MultipartParser { 48 49 private final static int FILE_BUFFER_SIZE = 4096; 50 51 private static final int MAX_BOUNDARY_SIZE = 128; 52 53 private boolean saveUploadedFilesToDisk; 54 55 private File uploadDirectory = null; 56 57 private boolean allowOverwrite; 58 59 private boolean silentlyRename; 60 61 private int maxUploadSize; 62 63 private String characterEncoding; 64 65 private Hashtable parts; 66 67 private boolean oversized = false; 68 69 private int contentLength; 70 71 82 public MultipartParser(boolean saveUploadedFilesToDisk, 83 File uploadDirectory, 84 boolean allowOverwrite, 85 boolean silentlyRename, 86 int maxUploadSize, 87 String characterEncoding) 88 { 89 this.saveUploadedFilesToDisk = saveUploadedFilesToDisk; 90 this.uploadDirectory = uploadDirectory; 91 this.allowOverwrite = allowOverwrite; 92 this.silentlyRename = silentlyRename; 93 this.maxUploadSize = maxUploadSize; 94 this.characterEncoding = characterEncoding; 95 } 96 97 private void parseParts(int contentLength, String contentType, InputStream requestStream) 98 throws IOException , MultipartException { 99 this.contentLength = contentLength; 100 if (contentLength > this.maxUploadSize) { 101 this.oversized = true; 102 } 103 104 BufferedInputStream bufferedStream = new BufferedInputStream (requestStream); 105 PushbackInputStream pushbackStream = new PushbackInputStream (bufferedStream, MAX_BOUNDARY_SIZE); 106 TokenStream stream = new TokenStream(pushbackStream); 107 108 parseMultiPart(stream, getBoundary(contentType)); 109 110 } 111 112 public Hashtable getParts(int contentLength, String contentType, InputStream requestStream) 113 throws IOException , MultipartException { 114 this.parts = new Hashtable (); 115 parseParts(contentLength, contentType, requestStream); 116 return this.parts; 117 } 118 119 public Hashtable getParts(HttpServletRequest request) throws IOException , MultipartException { 120 this.parts = new Hashtable (); 121 122 Enumeration names = request.getParameterNames(); 125 while(names.hasMoreElements()) { 126 String name = (String )names.nextElement(); 127 String [] values = request.getParameterValues(name); 128 Vector v = new Vector (values.length); 129 for (int i = 0; i < values.length; i++) { 130 v.add(values[i]); 131 } 132 this.parts.put(name, v); 133 } 134 parseParts(request.getContentLength(), request.getContentType(), request.getInputStream()); 135 return this.parts; 136 } 137 138 147 private void parseMultiPart(TokenStream ts, String boundary) 148 throws IOException , MultipartException { 149 150 ts.setBoundary(boundary.getBytes()); 151 ts.read(); ts.setBoundary(("\r\n" + boundary).getBytes()); 153 154 while (ts.getState() == TokenStream.STATE_NEXTPART) { 155 ts.nextPart(); 156 parsePart(ts); 157 } 158 159 if (ts.getState() != TokenStream.STATE_ENDMULTIPART) { throw new MultipartException("Malformed stream"); 161 } 162 } 163 164 172 private void parsePart(TokenStream ts) 173 throws IOException , MultipartException { 174 175 Hashtable headers = new Hashtable (); 176 headers = readHeaders(ts); 177 try { 178 if (headers.containsKey("filename")) { 179 if (!"".equals(headers.get("filename"))) { 180 parseFilePart(ts, headers); 181 } else { 182 byte[] buf = new byte[32]; 185 while(ts.getState() == TokenStream.STATE_READING) 186 ts.read(buf); 187 } 188 } else if (((String ) headers.get("content-disposition")) 189 .toLowerCase().equals("form-data")) { 190 parseInlinePart(ts, headers); 191 } 192 193 else if (((String ) headers.get("content-disposition")).toLowerCase() 195 .indexOf("multipart") > -1) { 196 parseMultiPart(new TokenStream(ts, MAX_BOUNDARY_SIZE), 197 "--" + (String ) headers.get("boundary")); 198 ts.read(); } else { 200 throw new MultipartException("Unknown part type"); 201 } 202 } catch (IOException e) { 203 throw new MultipartException("Malformed stream: " + e.getMessage()); 204 } catch (NullPointerException e) { 205 e.printStackTrace(); 206 throw new MultipartException("Malformed header"); 207 } 208 } 209 210 219 private void parseFilePart(TokenStream in, Hashtable headers) 220 throws IOException , MultipartException { 221 222 byte[] buf = new byte[FILE_BUFFER_SIZE]; 223 OutputStream out; 224 File file = null; 225 226 if (oversized) { 227 out = new NullOutputStream(); 228 } else if (!saveUploadedFilesToDisk) { 229 out = new ByteArrayOutputStream (); 230 } else { 231 String fileName = (String ) headers.get("filename"); 232 if(File.separatorChar == '\\') 233 fileName = fileName.replace('/','\\'); 234 else 235 fileName = fileName.replace('\\','/'); 236 237 String filePath = uploadDirectory.getPath() + File.separator; 238 fileName = new File (fileName).getName(); 239 file = new File (filePath + fileName); 240 241 if (!allowOverwrite && !file.createNewFile()) { 242 if (silentlyRename) { 243 int c = 0; 244 do { 245 file = new File (filePath + c++ + "_" + fileName); 246 } while (!file.createNewFile()); 247 } else { 248 throw new MultipartException("Duplicate file '" + file.getName() 249 + "' in '" + file.getParent() + "'"); 250 } 251 } 252 253 out = new FileOutputStream (file); 254 } 255 256 int length = 0; try { 258 int read = 0; 259 while (in.getState() == TokenStream.STATE_READING) { read = in.read(buf); 261 length += read; 262 out.write(buf, 0, read); 263 } 264 } catch (IOException ioe) { 265 out.close(); 268 out = null; 269 if ( file!=null ) file.delete(); 270 throw ioe; 271 } finally { 272 if ( out!=null ) out.close(); 273 } 274 275 String name = (String )headers.get("name"); 276 if (oversized) { 277 this.parts.put(name, new RejectedPart(headers, length, this.contentLength, this.maxUploadSize)); 278 } else if (file == null) { 279 byte[] bytes = ((ByteArrayOutputStream ) out).toByteArray(); 280 this.parts.put(name, new PartInMemory(headers, new ByteArrayInputStream (bytes), bytes.length)); 281 } else { 282 this.parts.put(name, new PartOnDisk(headers, file)); 283 } 284 } 285 286 294 private void parseInlinePart(TokenStream in, Hashtable headers) 295 throws IOException { 296 297 ByteArrayOutputStream bos = new ByteArrayOutputStream (); 299 300 while (in.getState() == TokenStream.STATE_READING) { 301 int c = in.read(); 302 if (c != -1) bos.write(c); 303 } 304 305 String field = (String ) headers.get("name"); 306 Vector v = (Vector ) this.parts.get(field); 307 308 if (v == null) { 309 v = new Vector (); 310 this.parts.put(field, v); 311 } 312 313 v.add(new String (bos.toByteArray(), this.characterEncoding)); 314 } 315 316 325 private Hashtable readHeaders(TokenStream in) throws IOException { 326 327 Hashtable headers = new Hashtable (); 328 String hdrline = readln(in); 329 330 while (!"".equals(hdrline)) { 331 StringTokenizer tokenizer = new StringTokenizer (hdrline); 332 333 headers.put(tokenizer.nextToken(" :").toLowerCase(), 334 tokenizer.nextToken(" :;")); 335 336 while (tokenizer.hasMoreTokens()) { 340 headers.put(tokenizer.nextToken(" ;=\""), 341 tokenizer.hasMoreTokens()?tokenizer.nextToken("=\""):""); 342 } 343 344 hdrline = readln(in); 345 } 346 347 return headers; 348 } 349 350 357 private String getBoundary(String hdr) { 358 359 int start = hdr.toLowerCase().indexOf("boundary="); 360 if (start > -1) { 361 return "--" + hdr.substring(start + 9); 362 } else { 363 return null; 364 } 365 } 366 367 376 private String readln(TokenStream in) throws IOException { 377 378 ByteArrayOutputStream bos = new ByteArrayOutputStream (); 379 380 int b = in.read(); 381 382 while ((b != -1) && (b != '\r')) { 383 bos.write(b); 384 b = in.read(); 385 } 386 387 if (b == '\r') { 388 in.read(); } 390 391 return new String (bos.toByteArray(), this.characterEncoding); 392 } 393 } 394 | Popular Tags |