1 16 package org.mortbay.servlet; 17 18 import java.io.ByteArrayInputStream ; 19 import java.io.ByteArrayOutputStream ; 20 import java.io.IOException ; 21 import java.io.InputStream ; 22 import java.io.UnsupportedEncodingException ; 23 import java.util.Hashtable ; 24 import java.util.List ; 25 import java.util.Set ; 26 import java.util.StringTokenizer ; 27 28 import javax.servlet.http.HttpServletRequest ; 29 30 import org.apache.commons.logging.Log; 31 import org.mortbay.log.LogFactory; 32 import org.mortbay.http.HttpFields; 33 import org.mortbay.util.LineInput; 34 import org.mortbay.util.MultiMap; 35 import org.mortbay.util.StringUtil; 36 37 38 55 public class MultiPartRequest 56 { 57 private static Log log = LogFactory.getLog(MultiPartRequest.class); 58 59 60 HttpServletRequest _request; 61 LineInput _in; 62 String _boundary; 63 String _encoding; 64 byte[] _byteBoundary; 65 MultiMap _partMap = new MultiMap(10); 66 int _char=-2; 67 boolean _lastPart=false; 68 69 70 75 public MultiPartRequest(HttpServletRequest request) 76 throws IOException 77 { 78 _request=request; 79 String content_type = request.getHeader(HttpFields.__ContentType); 80 if (!content_type.startsWith("multipart/form-data")) 81 throw new IOException ("Not multipart/form-data request"); 82 83 if(log.isDebugEnabled())log.debug("Multipart content type = "+content_type); 84 _encoding = request.getCharacterEncoding(); 85 if (_encoding != null) 86 _in = new LineInput(request.getInputStream(), 2048, _encoding); 87 else 88 _in = new LineInput(request.getInputStream()); 89 90 _boundary="--"+ 92 value(content_type.substring(content_type.indexOf("boundary="))); 93 94 if(log.isDebugEnabled())log.debug("Boundary="+_boundary); 95 _byteBoundary= (_boundary+"--").getBytes(StringUtil.__ISO_8859_1); 96 97 loadAllParts(); 98 } 99 100 101 104 public String [] getPartNames() 105 { 106 Set s = _partMap.keySet(); 107 return (String []) s.toArray(new String [s.size()]); 108 } 109 110 111 115 public boolean contains(String name) 116 { 117 Part part = (Part)_partMap.get(name); 118 return (part!=null); 119 } 120 121 122 126 public String getString(String name) 127 { 128 List part = _partMap.getValues(name); 129 if (part==null) 130 return null; 131 if (_encoding != null) 132 { 133 try 134 { 135 return new String (((Part)part.get(0))._data, _encoding); 136 } 137 catch (UnsupportedEncodingException uee) 138 { 139 if (log.isDebugEnabled())log.debug("Invalid character set: " + uee); 140 return null; 141 } 142 } 143 else 144 return new String (((Part)part.get(0))._data); 145 } 146 147 148 152 public String [] getStrings(String name) 153 { 154 List parts = _partMap.getValues(name); 155 if (parts==null) 156 return null; 157 String [] strings = new String [parts.size()]; 158 159 if (_encoding == null) 160 { 161 for (int i=0; i<strings.length; i++) 162 strings[i] = new String (((Part)parts.get(i))._data); 163 } 164 else 165 { 166 try 167 { 168 for (int i=0; i<strings.length; i++) 169 strings[i] = new String (((Part)parts.get(i))._data, _encoding); 170 } 171 catch (UnsupportedEncodingException uee) 172 { 173 if (log.isDebugEnabled())log.debug("Invalid character set: " + uee); 174 return null; 175 } 176 } 177 178 return strings; 179 } 180 181 182 186 public InputStream getInputStream(String name) 187 { 188 List part = (List )_partMap.getValues(name); 189 if (part==null) 190 return null; 191 return new ByteArrayInputStream (((Part)part.get(0))._data); 192 } 193 194 195 public InputStream [] getInputStreams(String name) 196 { 197 List parts = (List )_partMap.getValues(name); 198 if (parts==null) 199 return null; 200 InputStream [] streams = new InputStream [parts.size()]; 201 for (int i=0; i<streams.length; i++) { 202 streams[i] = new ByteArrayInputStream (((Part)parts.get(i))._data); 203 } 204 return streams; 205 } 206 207 208 212 public Hashtable getParams(String name) 213 { 214 List part = (List )_partMap.getValues(name); 215 if (part==null) 216 return null; 217 return ((Part)part.get(0))._headers; 218 } 219 220 221 public Hashtable [] getMultipleParams(String name) 222 { 223 List parts = (List )_partMap.getValues(name); 224 if (parts==null) 225 return null; 226 Hashtable [] params = new Hashtable [parts.size()]; 227 for (int i=0; i<params.length; i++) { 228 params[i] = ((Part)parts.get(i))._headers; 229 } 230 return params; 231 } 232 233 234 238 public String getFilename(String name) 239 { 240 List part = (List )_partMap.getValues(name); 241 if (part==null) 242 return null; 243 return ((Part)part.get(0))._filename; 244 } 245 246 247 public String [] getFilenames(String name) 248 { 249 List parts = (List )_partMap.getValues(name); 250 if (parts==null) 251 return null; 252 String [] filenames = new String [parts.size()]; 253 for (int i=0; i<filenames.length; i++) { 254 filenames[i] = ((Part)parts.get(i))._filename; 255 } 256 return filenames; 257 } 258 259 260 private void loadAllParts() 261 throws IOException 262 { 263 String line = _in.readLine(); 265 if (!line.equals(_boundary)) 266 { 267 log.warn(line); 268 throw new IOException ("Missing initial multi part boundary"); 269 } 270 271 while (!_lastPart) 273 { 274 Part part = new Part(); 276 277 String content_disposition=null; 278 while ((line=_in.readLine())!=null) 279 { 280 if (line.length()==0) 282 break; 283 284 if(log.isDebugEnabled())log.debug("LINE="+line); 285 286 int c = line.indexOf(':',0); 288 if (c>0) 289 { 290 String key = line.substring(0,c).trim().toLowerCase(); 291 String value = line.substring(c+1,line.length()).trim(); 292 String ev = (String ) part._headers.get(key); 293 part._headers.put(key,(ev!=null)?(ev+';'+value):value); 294 if(log.isDebugEnabled())log.debug(key+": "+value); 295 if (key.equals("content-disposition")) 296 content_disposition=value; 297 } 298 } 299 300 boolean form_data=false; 302 if (content_disposition==null) 303 { 304 throw new IOException ("Missing content-disposition"); 305 } 306 307 StringTokenizer tok = 308 new StringTokenizer (content_disposition,";"); 309 while (tok.hasMoreTokens()) 310 { 311 String t = tok.nextToken().trim(); 312 String tl = t.toLowerCase(); 313 if (t.startsWith("form-data")) 314 form_data=true; 315 else if (tl.startsWith("name=")) 316 part._name=value(t); 317 else if (tl.startsWith("filename=")) 318 part._filename=value(t); 319 } 320 321 if (!form_data) 323 { 324 log.warn("Non form-data part in multipart/form-data"); 325 continue; 326 } 327 if (part._name==null || part._name.length()==0) 328 { 329 log.warn("Part with no name in multipart/form-data"); 330 continue; 331 } 332 if(log.isDebugEnabled())log.debug("name="+part._name); 333 if(log.isDebugEnabled())log.debug("filename="+part._filename); 334 _partMap.add(part._name,part); 335 part._data=readBytes(); 336 } 337 } 338 339 340 private byte[] readBytes() 341 throws IOException 342 { 343 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 344 345 int c; 346 boolean cr=false; 347 boolean lf=false; 348 349 while (true) 351 { 352 int b=0; 353 while ((c=(_char!=-2)?_char:_in.read())!=-1) 354 { 355 _char=-2; 356 357 if (c==13 || c==10) 359 { 360 if (c==13) _char=_in.read(); 361 break; 362 } 363 364 if (b>=0 && b<_byteBoundary.length && c==_byteBoundary[b]) 366 b++; 367 else 368 { 369 if (cr) baos.write(13); 371 if (lf) baos.write(10); 372 cr=lf=false; 373 374 if (b>0) 375 baos.write(_byteBoundary,0,b); 376 b=-1; 377 378 baos.write(c); 379 } 380 } 381 382 if ((b>0 && b<_byteBoundary.length-2) || 384 (b==_byteBoundary.length-1)) 385 { 386 if (cr) baos.write(13); 387 if (lf) baos.write(10); 388 cr=lf=false; 389 baos.write(_byteBoundary,0,b); 390 b=-1; 391 } 392 393 if (b>0 || c==-1) 395 { 396 if (b==_byteBoundary.length) 397 _lastPart=true; 398 if (_char==10) _char=-2; 399 break; 400 } 401 402 if (cr) baos.write(13); 404 if (lf) baos.write(10); 405 cr=(c==13); 406 lf=(c==10 || _char==10); 407 if (_char==10) _char=-2; 408 } 409 if(log.isTraceEnabled())log.trace(baos.toString()); 410 return baos.toByteArray(); 411 } 412 413 414 415 private String value(String nameEqualsValue) 416 { 417 String value = 418 nameEqualsValue.substring(nameEqualsValue.indexOf('=')+1).trim(); 419 420 int i=value.indexOf(';'); 421 if (i>0) 422 value=value.substring(0,i); 423 if (value.startsWith("\"")) 424 { 425 value=value.substring(1,value.indexOf('"',1)); 426 } 427 428 else 429 { 430 i=value.indexOf(' '); 431 if (i>0) 432 value=value.substring(0,i); 433 } 434 return value; 435 } 436 437 438 private class Part 439 { 440 String _name=null; 441 String _filename=null; 442 Hashtable _headers= new Hashtable (10); 443 byte[] _data=null; 444 } 445 }; 446 | Popular Tags |