001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.fileupload;
018
019 import java.io.ByteArrayInputStream;
020 import java.io.ByteArrayOutputStream;
021 import java.io.FilterInputStream;
022 import java.io.IOException;
023 import java.io.InputStream;
024 import java.io.OutputStreamWriter;
025 import java.util.Iterator;
026 import java.util.List;
027 import javax.servlet.http.HttpServletRequest;
028
029 import org.apache.commons.fileupload.FileUploadBase.IOFileUploadException;
030 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
031 import org.apache.commons.fileupload.servlet.ServletFileUpload;
032 import org.apache.commons.fileupload.servlet.ServletRequestContext;
033
034 import junit.framework.TestCase;
035
036 /**
037 * Unit test for items with varying sizes.
038 *
039 * @version $Id: StreamingTest.java 1454693 2013-03-09 12:30:27Z simonetripodi $
040 */
041 public class StreamingTest extends TestCase {
042
043 /**
044 * Tests a file upload with varying file sizes.
045 */
046 public void testFileUpload()
047 throws IOException, FileUploadException {
048 byte[] request = newRequest();
049 List<FileItem> fileItems = parseUpload(request);
050 Iterator<FileItem> fileIter = fileItems.iterator();
051 int add = 16;
052 int num = 0;
053 for (int i = 0; i < 16384; i += add) {
054 if (++add == 32) {
055 add = 16;
056 }
057 FileItem item = fileIter.next();
058 assertEquals("field" + (num++), item.getFieldName());
059 byte[] bytes = item.get();
060 assertEquals(i, bytes.length);
061 for (int j = 0; j < i; j++) {
062 assertEquals((byte) j, bytes[j]);
063 }
064 }
065 assertTrue(!fileIter.hasNext());
066 }
067
068 /**
069 * Tests, whether an invalid request throws a proper
070 * exception.
071 */
072 public void testFileUploadException()
073 throws IOException, FileUploadException {
074 byte[] request = newRequest();
075 byte[] invalidRequest = new byte[request.length-11];
076 System.arraycopy(request, 0, invalidRequest, 0, request.length-11);
077 try {
078 parseUpload(invalidRequest);
079 fail("Expected EndOfStreamException");
080 } catch (IOFileUploadException e) {
081 assertTrue(e.getCause() instanceof MultipartStream.MalformedStreamException);
082 }
083 }
084
085 /**
086 * Tests, whether an IOException is properly delegated.
087 */
088 public void testIOException()
089 throws IOException {
090 byte[] request = newRequest();
091 InputStream stream = new FilterInputStream(new ByteArrayInputStream(request)){
092 private int num;
093 @Override
094 public int read() throws IOException {
095 if (++num > 123) {
096 throw new IOException("123");
097 }
098 return super.read();
099 }
100 @Override
101 public int read(byte[] pB, int pOff, int pLen)
102 throws IOException {
103 for (int i = 0; i < pLen; i++) {
104 int res = read();
105 if (res == -1) {
106 return i == 0 ? -1 : i;
107 }
108 pB[pOff+i] = (byte) res;
109 }
110 return pLen;
111 }
112 };
113 try {
114 parseUpload(stream, request.length);
115 fail("Expected IOException");
116 } catch (FileUploadException e) {
117 assertTrue(e.getCause() instanceof IOException);
118 assertEquals("123", e.getCause().getMessage());
119 }
120 }
121
122 /**
123 * Test for FILEUPLOAD-135
124 */
125 public void testFILEUPLOAD135()
126 throws IOException, FileUploadException {
127 byte[] request = newShortRequest();
128 final ByteArrayInputStream bais = new ByteArrayInputStream(request);
129 List<FileItem> fileItems = parseUpload(new InputStream() {
130 @Override
131 public int read()
132 throws IOException
133 {
134 return bais.read();
135 }
136 @Override
137 public int read(byte b[], int off, int len) throws IOException
138 {
139 return bais.read(b, off, Math.min(len, 3));
140 }
141
142 }, request.length);
143 Iterator<FileItem> fileIter = fileItems.iterator();
144 assertTrue(fileIter.hasNext());
145 FileItem item = fileIter.next();
146 assertEquals("field", item.getFieldName());
147 byte[] bytes = item.get();
148 assertEquals(3, bytes.length);
149 assertEquals((byte)'1', bytes[0]);
150 assertEquals((byte)'2', bytes[1]);
151 assertEquals((byte)'3', bytes[2]);
152 assertTrue(!fileIter.hasNext());
153 }
154
155 private List<FileItem> parseUpload(byte[] bytes) throws FileUploadException {
156 return parseUpload(new ByteArrayInputStream(bytes), bytes.length);
157 }
158
159 private FileItemIterator parseUpload(int pLength, InputStream pStream)
160 throws FileUploadException, IOException {
161 String contentType = "multipart/form-data; boundary=---1234";
162
163 FileUploadBase upload = new ServletFileUpload();
164 upload.setFileItemFactory(new DiskFileItemFactory());
165 HttpServletRequest request = new MockHttpServletRequest(pStream,
166 pLength, contentType);
167
168 return upload.getItemIterator(new ServletRequestContext(request));
169 }
170
171 private List<FileItem> parseUpload(InputStream pStream, int pLength)
172 throws FileUploadException {
173 String contentType = "multipart/form-data; boundary=---1234";
174
175 FileUploadBase upload = new ServletFileUpload();
176 upload.setFileItemFactory(new DiskFileItemFactory());
177 HttpServletRequest request = new MockHttpServletRequest(pStream,
178 pLength, contentType);
179
180 List<FileItem> fileItems = upload.parseRequest(new ServletRequestContext(request));
181 return fileItems;
182 }
183
184 private String getHeader(String pField) {
185 return "-----1234\r\n"
186 + "Content-Disposition: form-data; name=\"" + pField + "\"\r\n"
187 + "\r\n";
188
189 }
190
191 private String getFooter() {
192 return "-----1234--\r\n";
193 }
194
195 private byte[] newShortRequest() throws IOException {
196 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
197 final OutputStreamWriter osw = new OutputStreamWriter(baos, "US-ASCII");
198 osw.write(getHeader("field"));
199 osw.write("123");
200 osw.write("\r\n");
201 osw.write(getFooter());
202 osw.close();
203 return baos.toByteArray();
204 }
205
206 private byte[] newRequest() throws IOException {
207 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
208 final OutputStreamWriter osw = new OutputStreamWriter(baos, "US-ASCII");
209 int add = 16;
210 int num = 0;
211 for (int i = 0; i < 16384; i += add) {
212 if (++add == 32) {
213 add = 16;
214 }
215 osw.write(getHeader("field" + (num++)));
216 osw.flush();
217 for (int j = 0; j < i; j++) {
218 baos.write((byte) j);
219 }
220 osw.write("\r\n");
221 }
222 osw.write(getFooter());
223 osw.close();
224 return baos.toByteArray();
225 }
226
227 /**
228 * Tests, whether an {@link InvalidFileNameException} is thrown.
229 */
230 public void testInvalidFileNameException() throws Exception {
231 final String fileName = "foo.exe\u0000.png";
232 final String request =
233 "-----1234\r\n" +
234 "Content-Disposition: form-data; name=\"file\"; filename=\"" + fileName + "\"\r\n" +
235 "Content-Type: text/whatever\r\n" +
236 "\r\n" +
237 "This is the content of the file\n" +
238 "\r\n" +
239 "-----1234\r\n" +
240 "Content-Disposition: form-data; name=\"field\"\r\n" +
241 "\r\n" +
242 "fieldValue\r\n" +
243 "-----1234\r\n" +
244 "Content-Disposition: form-data; name=\"multi\"\r\n" +
245 "\r\n" +
246 "value1\r\n" +
247 "-----1234\r\n" +
248 "Content-Disposition: form-data; name=\"multi\"\r\n" +
249 "\r\n" +
250 "value2\r\n" +
251 "-----1234--\r\n";
252 final byte[] reqBytes = request.getBytes("US-ASCII");
253
254 FileItemIterator fileItemIter = parseUpload(reqBytes.length, new ByteArrayInputStream(reqBytes));
255 final FileItemStream fileItemStream = fileItemIter.next();
256 try {
257 fileItemStream.getName();
258 fail("Expected exception");
259 } catch (InvalidFileNameException e) {
260 assertEquals(fileName, e.getName());
261 assertTrue(e.getMessage().indexOf(fileName) == -1);
262 assertTrue(e.getMessage().indexOf("foo.exe\\0.png") != -1);
263 }
264
265 List<FileItem> fileItems = parseUpload(reqBytes);
266 final FileItem fileItem = fileItems.get(0);
267 try {
268 fileItem.getName();
269 fail("Expected exception");
270 } catch (InvalidFileNameException e) {
271 assertEquals(fileName, e.getName());
272 assertTrue(e.getMessage().indexOf(fileName) == -1);
273 assertTrue(e.getMessage().indexOf("foo.exe\\0.png") != -1);
274 }
275 }
276
277 }