comparison src/org/eclipse/jetty/util/MultiPartInputStream.java @ 859:3dcc52e17535

simplify multipart
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 21 Sep 2016 16:15:19 -0600
parents 7fb7c1915788
children
comparison
equal deleted inserted replaced
858:dbbd9c3f14f8 859:3dcc52e17535
41 import java.util.Locale; 41 import java.util.Locale;
42 import java.util.Map; 42 import java.util.Map;
43 import java.util.StringTokenizer; 43 import java.util.StringTokenizer;
44 import java.util.Base64; 44 import java.util.Base64;
45 45
46 import javax.servlet.MultipartConfigElement;
47 import javax.servlet.ServletException; 46 import javax.servlet.ServletException;
48 import javax.servlet.http.Part; 47 import javax.servlet.http.Part;
49 48
50 import org.slf4j.Logger; 49 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory; 50 import org.slf4j.LoggerFactory;
59 */ 58 */
60 public class MultiPartInputStream 59 public class MultiPartInputStream
61 { 60 {
62 private static final Logger LOG = LoggerFactory.getLogger(MultiPartInputStream.class); 61 private static final Logger LOG = LoggerFactory.getLogger(MultiPartInputStream.class);
63 62
64 public static final MultipartConfigElement __DEFAULT_MULTIPART_CONFIG = new MultipartConfigElement(System.getProperty("java.io.tmpdir"));
65 protected InputStream _in; 63 protected InputStream _in;
66 protected MultipartConfigElement _config;
67 protected String _contentType; 64 protected String _contentType;
68 protected MultiMap<String> _parts; 65 protected MultiMap<String> _parts;
69 protected File _tmpDir; 66
70 protected File _contextTmpDir; 67
71 protected boolean _deleteOnExit; 68
72 69 public final class MultiPart implements Part
73
74
75 public class MultiPart implements Part
76 { 70 {
77 protected String _name; 71 protected String _name;
78 protected String _filename; 72 protected String _filename;
79 protected File _file; 73 protected File _file;
80 protected OutputStream _out; 74 protected OutputStream _out;
81 protected ByteArrayOutputStream2 _bout; 75 protected ByteArrayOutputStream2 _bout;
82 protected String _contentType; 76 protected String _contentType;
83 protected MultiMap<String> _headers; 77 protected MultiMap<String> _headers;
84 protected long _size = 0; 78 protected long _size = 0;
85 protected boolean _temporary = true;
86 79
87 public MultiPart (String name, String filename) 80 public MultiPart (String name, String filename)
88 throws IOException 81 throws IOException
89 { 82 {
90 _name = name; 83 _name = name;
123 116
124 117
125 protected void write (int b) 118 protected void write (int b)
126 throws IOException 119 throws IOException
127 { 120 {
128 if (MultiPartInputStream.this._config.getMaxFileSize() > 0 && _size + 1 > MultiPartInputStream.this._config.getMaxFileSize())
129 throw new IllegalStateException ("Multipart Mime part "+_name+" exceeds max filesize");
130
131 if (MultiPartInputStream.this._config.getFileSizeThreshold() > 0 && _size + 1 > MultiPartInputStream.this._config.getFileSizeThreshold() && _file==null)
132 createFile();
133 _out.write(b); 121 _out.write(b);
134 _size ++; 122 _size ++;
135 } 123 }
136 124
137 protected void write (byte[] bytes, int offset, int length) 125 protected void write (byte[] bytes, int offset, int length)
138 throws IOException 126 throws IOException
139 { 127 {
140 if (MultiPartInputStream.this._config.getMaxFileSize() > 0 && _size + length > MultiPartInputStream.this._config.getMaxFileSize())
141 throw new IllegalStateException ("Multipart Mime part "+_name+" exceeds max filesize");
142
143 if (MultiPartInputStream.this._config.getFileSizeThreshold() > 0 && _size + length > MultiPartInputStream.this._config.getFileSizeThreshold() && _file==null)
144 createFile();
145
146 _out.write(bytes, offset, length); 128 _out.write(bytes, offset, length);
147 _size += length; 129 _size += length;
148 } 130 }
149 131
150 protected void createFile () 132 protected void createFile ()
151 throws IOException 133 throws IOException
152 { 134 {
153 _file = File.createTempFile("MultiPart", "", MultiPartInputStream.this._tmpDir); 135 _file = File.createTempFile("MultiPart", null);
154 if (_deleteOnExit) 136 _file.deleteOnExit();
155 _file.deleteOnExit();
156 FileOutputStream fos = new FileOutputStream(_file); 137 FileOutputStream fos = new FileOutputStream(_file);
157 BufferedOutputStream bos = new BufferedOutputStream(fos); 138 BufferedOutputStream bos = new BufferedOutputStream(fos);
158 139
159 if (_size > 0 && _out != null) 140 if (_size > 0 && _out != null)
160 { 141 {
251 /** 232 /**
252 * @see javax.servlet.http.Part#write(java.lang.String) 233 * @see javax.servlet.http.Part#write(java.lang.String)
253 */ 234 */
254 public void write(String fileName) throws IOException 235 public void write(String fileName) throws IOException
255 { 236 {
256 if (_file == null) 237 throw new UnsupportedOperationException();
257 {
258 _temporary = false;
259
260 //part data is only in the ByteArrayOutputStream and never been written to disk
261 _file = new File (_tmpDir, fileName);
262
263 BufferedOutputStream bos = null;
264 try
265 {
266 bos = new BufferedOutputStream(new FileOutputStream(_file));
267 _bout.writeTo(bos);
268 bos.flush();
269 }
270 finally
271 {
272 if (bos != null)
273 bos.close();
274 _bout = null;
275 }
276 }
277 else
278 {
279 //the part data is already written to a temporary file, just rename it
280 _temporary = false;
281
282 File f = new File(_tmpDir, fileName);
283 if (_file.renameTo(f))
284 _file = f;
285 }
286 } 238 }
287 239
288 /** 240 /**
289 * Remove the file, whether or not Part.write() was called on it 241 * Remove the file, whether or not Part.write() was called on it
290 * (ie no longer temporary) 242 * (ie no longer temporary)
301 * 253 *
302 * @throws IOException 254 * @throws IOException
303 */ 255 */
304 public void cleanUp() throws IOException 256 public void cleanUp() throws IOException
305 { 257 {
306 if (_temporary && _file != null && _file.exists()) 258 if (_file != null && _file.exists())
307 _file.delete(); 259 _file.delete();
308 } 260 }
309 261
310 262
311 /** 263 /**
335 * @param in Request input stream 287 * @param in Request input stream
336 * @param contentType Content-Type header 288 * @param contentType Content-Type header
337 * @param config MultipartConfigElement 289 * @param config MultipartConfigElement
338 * @param contextTmpDir javax.servlet.context.tempdir 290 * @param contextTmpDir javax.servlet.context.tempdir
339 */ 291 */
340 public MultiPartInputStream (InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir) 292 public MultiPartInputStream (InputStream in, String contentType)
341 { 293 {
342 _in = new ReadLineInputStream(in); 294 _in = new ReadLineInputStream(in);
343 _contentType = contentType; 295 _contentType = contentType;
344 _config = config;
345 _contextTmpDir = contextTmpDir;
346 if (_contextTmpDir == null)
347 _contextTmpDir = new File (System.getProperty("java.io.tmpdir"));
348
349 if (_config == null)
350 _config = new MultipartConfigElement(_contextTmpDir.getAbsolutePath());
351 } 296 }
352 297
353 /** 298 /**
354 * Get the already parsed parts. 299 * Get the already parsed parts.
355 * 300 *
453 _parts = new MultiMap<String>(); 398 _parts = new MultiMap<String>();
454 399
455 //if its not a multipart request, don't parse it 400 //if its not a multipart request, don't parse it
456 if (_contentType == null || !_contentType.startsWith("multipart/form-data")) 401 if (_contentType == null || !_contentType.startsWith("multipart/form-data"))
457 return; 402 return;
458
459 //sort out the location to which to write the files
460
461 if (_config.getLocation() == null)
462 _tmpDir = _contextTmpDir;
463 else if ("".equals(_config.getLocation()))
464 _tmpDir = _contextTmpDir;
465 else
466 {
467 File f = new File (_config.getLocation());
468 if (f.isAbsolute())
469 _tmpDir = f;
470 else
471 _tmpDir = new File (_contextTmpDir, _config.getLocation());
472 }
473
474 if (!_tmpDir.exists())
475 _tmpDir.mkdirs();
476 403
477 String contentTypeBoundary = ""; 404 String contentTypeBoundary = "";
478 int bstart = _contentType.indexOf("boundary="); 405 int bstart = _contentType.indexOf("boundary=");
479 if (bstart >= 0) 406 if (bstart >= 0)
480 { 407 {
538 // If blank line, end of part headers 465 // If blank line, end of part headers
539 if("".equals(line)) 466 if("".equals(line))
540 break; 467 break;
541 468
542 total += line.length(); 469 total += line.length();
543 if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize())
544 throw new IllegalStateException ("Request exceeds maxRequestSize ("+_config.getMaxRequestSize()+")");
545 470
546 //get content-disposition and content-type 471 //get content-disposition and content-type
547 int c=line.indexOf(':',0); 472 int c=line.indexOf(':',0);
548 if(c>0) 473 if(c>0)
549 { 474 {
647 { 572 {
648 int b=0; 573 int b=0;
649 while((c=(state!=-2)?state:partInput.read())!=-1) 574 while((c=(state!=-2)?state:partInput.read())!=-1)
650 { 575 {
651 total ++; 576 total ++;
652 if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize())
653 throw new IllegalStateException("Request exceeds maxRequestSize ("+_config.getMaxRequestSize()+")");
654 577
655 state=-2; 578 state=-2;
656 579
657 // look for CR and/or LF 580 // look for CR and/or LF
658 if(c==13||c==10) 581 if(c==13||c==10)
738 } 661 }
739 if (!lastPart) 662 if (!lastPart)
740 throw new IOException("Incomplete parts"); 663 throw new IOException("Incomplete parts");
741 } 664 }
742 665
743 public void setDeleteOnExit(boolean deleteOnExit)
744 {
745 _deleteOnExit = deleteOnExit;
746 }
747
748
749 public boolean isDeleteOnExit()
750 {
751 return _deleteOnExit;
752 }
753
754 666
755 /* ------------------------------------------------------------ */ 667 /* ------------------------------------------------------------ */
756 private String value(String nameEqualsValue, boolean splitAfterSpace) 668 private String value(String nameEqualsValue, boolean splitAfterSpace)
757 { 669 {
758 /* 670 /*