    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  package org.apache.commons.fileupload;
    18
    19  import java.io.ByteArrayInputStream;
    20  import java.io.ByteArrayOutputStream;
    21  import java.io.FilterInputStream;
    22  import java.io.IOException;
    23  import java.io.InputStream;
    24  import java.io.OutputStreamWriter;
    25  import java.util.Iterator;
    26  import java.util.List;
    27  import javax.servlet.http.HttpServletRequest;
    28
    29  import org.apache.commons.fileupload.FileUploadBase.IOFileUploadException;
    30  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
    31  import org.apache.commons.fileupload.servlet.ServletFileUpload;
    32  import org.apache.commons.fileupload.servlet.ServletRequestContext;
    33
    34  import junit.framework.TestCase;
    35
    36
    37  /**
    38   * Unit test for items with varying sizes.
    39   */
    40  public class StreamingTest extends TestCase
    41  {
    42      /**
    43       * Tests a file upload with varying file sizes.
    44       */
    45      public void testFileUpload()
    46              throws IOException, FileUploadException
    47      {
    48      	byte[] request = newRequest();
    49          List fileItems = parseUpload(request);
    50          Iterator fileIter = fileItems.iterator();
    51          int add = 16;
    52          int num = 0;
    53          for (int i = 0;  i < 16384;  i += add) {
    54              if (++add == 32) {
    55                  add = 16;
    56              }
    57              FileItem item = (FileItem) fileIter.next();
    58              assertEquals("field" + (num++), item.getFieldName());
    59              byte[] bytes = item.get();
    60              assertEquals(i, bytes.length);
    61              for (int j = 0;  j < i;  j++) {
    62                  assertEquals((byte) j, bytes[j]);
    63              }
    64          }
    65          assertTrue(!fileIter.hasNext());
    66      }
    67
    68
    69      /**
    70       * Tests, whether an invalid request throws a proper
    71       * exception.
    72       */
    73      public void testFileUploadException()
    74      		throws IOException, FileUploadException {
    75      	byte[] request = newRequest();
    76      	byte[] invalidRequest = new byte[request.length-11];
    77      	System.arraycopy(request, 0, invalidRequest, 0, request.length-11);
    78      	try {
    79      		parseUpload(invalidRequest);
    80  	        fail("Expected EndOfStreamException");
    81      	} catch (IOFileUploadException e) {
    82      		assertTrue(e.getCause() instanceof MultipartStream.MalformedStreamException);
    83      	}
    84      }
    85
    86      /**
    87       * Tests, whether an IOException is properly delegated.
    88       */
    89      public void testIOException()
    90      		throws IOException {
    91      	byte[] request = newRequest();
    92      	InputStream stream = new FilterInputStream(new ByteArrayInputStream(request)){
    93      		private int num;
    94      		public int read() throws IOException {
    95      			if (++num > 123) {
    96      				throw new IOException("123");
    97      			}
    98      			return super.read();
    99      		}
    100 			public int read(byte[] pB, int pOff, int pLen)
    101 					throws IOException {
    102 				for (int i = 0;  i < pLen;  i++) {
    103 					int res = read();
    104 					if (res == -1) {
    105 						return i == 0 ? -1 : i;
    106 					}
    107 					pB[pOff+i] = (byte) res;
    108 				}
    109 				return pLen;
    110 			}
    111     	};
    112     	try {
    113     		parseUpload(stream, request.length);
    114     		fail("Expected IOException");
    115     	} catch (FileUploadException e) {
    116     		assertTrue(e.getCause() instanceof IOException);
    117     		assertEquals("123", e.getCause().getMessage());
    118         }
    119     }
    120
    121     /**
    122      * Test for FILEUPLOAD-135
    123      */
    124     public void testFILEUPLOAD135()
    125             throws IOException, FileUploadException
    126     {
    127         byte[] request = newShortRequest();
    128         final ByteArrayInputStream bais = new ByteArrayInputStream(request);
    129         List fileItems = parseUpload(new InputStream() {
    130             public int read()
    131             throws IOException
    132             {
    133                 return bais.read();
    134             }
    135             public int read(byte b[], int off, int len) throws IOException
    136             {
    137                 return bais.read(b, off, Math.min(len, 3));
    138             }
    139
    140         }, request.length);
    141         Iterator fileIter = fileItems.iterator();
    142         assertTrue(fileIter.hasNext());
    143         FileItem item = (FileItem) fileIter.next();
    144         assertEquals("field", item.getFieldName());
    145         byte[] bytes = item.get();
    146         assertEquals(3, bytes.length);
    147         assertEquals((byte)'1', bytes[0]);
    148         assertEquals((byte)'2', bytes[1]);
    149         assertEquals((byte)'3', bytes[2]);
    150         assertTrue(!fileIter.hasNext());
    151     }
    152
    153     private List parseUpload(byte[] bytes) throws FileUploadException {
    154     	return parseUpload(new ByteArrayInputStream(bytes), bytes.length);
    155     }
    156
    157     private List parseUpload(InputStream pStream, int pLength)
    158     		throws FileUploadException {
    159         String contentType = "multipart/form-data; boundary=---1234";
    160
    161         FileUploadBase upload = new ServletFileUpload();
    162         upload.setFileItemFactory(new DiskFileItemFactory());
    163         HttpServletRequest request = new MockHttpServletRequest(pStream,
    164         		pLength, contentType);
    165
    166         List fileItems = upload.parseRequest(new ServletRequestContext(request));
    167         return fileItems;
    168     }
    169
    170     private String getHeader(String pField) {
    171         return "-----1234\r\n"
    172             + "Content-Disposition: form-data; name=\"" + pField + "\"\r\n"
    173             + "\r\n";
    174
    175     }
    176
    177     private String getFooter() {
    178         return "-----1234--\r\n";
    179     }
    180
    181     private byte[] newShortRequest() throws IOException {
    182         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    183         final OutputStreamWriter osw = new OutputStreamWriter(baos, "US-ASCII");
    184         osw.write(getHeader("field"));
    185         osw.write("123");
    186         osw.write("\r\n");
    187         osw.write(getFooter());
    188         osw.close();
    189         return baos.toByteArray();
    190     }
    191
    192     private byte[] newRequest() throws IOException {
    193         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    194         final OutputStreamWriter osw = new OutputStreamWriter(baos, "US-ASCII");
    195         int add = 16;
    196         int num = 0;
    197         for (int i = 0;  i < 16384;  i += add) {
    198             if (++add == 32) {
    199                 add = 16;
    200             }
    201             osw.write(getHeader("field" + (num++)));
    202             osw.flush();
    203             for (int j = 0;  j < i;  j++) {
    204                 baos.write((byte) j);
    205             }
    206             osw.write("\r\n");
    207         }
    208         osw.write(getFooter());
    209         osw.close();
    210         return baos.toByteArray();
    211     }
    212 }