@ -16,33 +16,28 @@
* /
* /
package com.fr.third.org.apache.commons.fileupload.disk ;
package com.fr.third.org.apache.commons.fileupload.disk ;
import static java.lang.String.format ;
import com.fr.third.org.apache.commons.fileupload.FileItem ;
import com.fr.third.org.apache.commons.fileupload.FileItemHeaders ;
import com.fr.third.org.apache.commons.fileupload.FileUploadException ;
import com.fr.third.org.apache.commons.fileupload.ParameterParser ;
import com.fr.third.org.apache.commons.fileupload.util.Streams ;
import com.fr.third.org.apache.commons.io.FileUtils ;
import com.fr.third.org.apache.commons.io.IOUtils ;
import com.fr.third.org.apache.commons.io.output.DeferredFileOutputStream ;
import java.io.BufferedInputStream ;
import java.io.BufferedOutputStream ;
import java.io.ByteArrayInputStream ;
import java.io.ByteArrayInputStream ;
import java.io.File ;
import java.io.File ;
import java.io.FileInputStream ;
import java.io.FileInputStream ;
import java.io.FileOutputStream ;
import java.io.FileOutputStream ;
import java.io.IOException ;
import java.io.IOException ;
import java.io.InputStream ;
import java.io.InputStream ;
import java.io.ObjectInputStream ;
import java.io.ObjectOutputStream ;
import java.io.OutputStream ;
import java.io.OutputStream ;
import java.io.UnsupportedEncodingException ;
import java.io.UnsupportedEncodingException ;
import java.util.Map ;
import java.util.Map ;
import java.util.UUID ;
import java.util.UUID ;
import java.util.concurrent.atomic.AtomicInteger ;
import java.util.concurrent.atomic.AtomicInteger ;
import com.fr.third.org.apache.commons.fileupload.FileItem ;
import static java.lang.String.format ;
import com.fr.third.org.apache.commons.fileupload.FileItemHeaders ;
import com.fr.third.org.apache.commons.fileupload.FileUploadException ;
import com.fr.third.org.apache.commons.fileupload.InvalidFileNameException ;
import com.fr.third.org.apache.commons.fileupload.ParameterParser ;
import com.fr.third.org.apache.commons.fileupload.servlet.ServletFileUpload ;
import com.fr.third.org.apache.commons.fileupload.util.Streams ;
import com.fr.third.org.apache.commons.io.IOUtils ;
import com.fr.third.org.apache.commons.io.output.DeferredFileOutputStream ;
/ * *
/ * *
* < p > The default implementation of the
* < p > The default implementation of the
@ -50,47 +45,34 @@ import com.fr.third.org.apache.commons.io.output.DeferredFileOutputStream;
*
*
* < p > After retrieving an instance of this class from a { @link
* < p > After retrieving an instance of this class from a { @link
* DiskFileItemFactory } instance ( see
* DiskFileItemFactory } instance ( see
* { @link ServletFileUpload
* { @link com . fr . third . org . apache . commons . fileupload . servlet . ServletFileUpload
* # parseRequest ( javax . servlet . http . HttpServletRequest ) } ) , you may
* # parseRequest ( javax . servlet . http . HttpServletRequest ) } ) , you may
* either request all contents of file at once using { @link # get ( ) } or
* either request all contents of file at once using { @link # get ( ) } or
* request an { @link java . io . InputStream InputStream } with
* request an { @link InputStream InputStream } with
* { @link # getInputStream ( ) } and process the file without attempting to load
* { @link # getInputStream ( ) } and process the file without attempting to load
* it into memory , which may come handy with large files .
* it into memory , which may come handy with large files .
*
*
* < p > Temporary files , which are created for file items , should be
* < p > Temporary files , which are created for file items , should be
* deleted later on . The best way to do this is using a
* deleted later on . The best way to do this is using a
* { @link org . apache . commons . io . FileCleaningTracker } , which you can set on the
* { @link com . fr . third . org . apache . commons . io . FileCleaningTracker } , which you can set on the
* { @link DiskFileItemFactory } . However , if you do use such a tracker ,
* { @link DiskFileItemFactory } . However , if you do use such a tracker ,
* then you must consider the following : Temporary files are automatically
* then you must consider the following : Temporary files are automatically
* deleted as soon as they are no longer needed . ( More precisely , when the
* deleted as soon as they are no longer needed . ( More precisely , when the
* corresponding instance of { @link java . io . File } is garbage collected . )
* corresponding instance of { @link File } is garbage collected . )
* This is done by the so - called reaper thread , which is started and stopped
* This is done by the so - called reaper thread , which is started and stopped
* automatically by the { @link org . apache . commons . io . FileCleaningTracker } when
* automatically by the { @link com . fr . third . org . apache . commons . io . FileCleaningTracker } when
* there are files to be tracked .
* there are files to be tracked .
* It might make sense to terminate that thread , for example , if
* It might make sense to terminate that thread , for example , if
* your web application ends . See the section on "Resource cleanup"
* your web application ends . See the section on "Resource cleanup"
* in the users guide of commons - fileupload . < / p >
* in the users guide of commons - fileupload . < / p >
*
*
* @since FileUpload 1 . 1
* @since FileUpload 1 . 1
*
* @version $Id$
* /
* /
public class DiskFileItem
public class DiskFileItem
implements FileItem {
implements FileItem {
/ * *
* Although it implements { @link java . io . Serializable } , a DiskFileItem can actually only be deserialized ,
* if this System property is true .
* /
public static final String SERIALIZABLE_PROPERTY = DiskFileItem . class . getName ( ) + ".serializable" ;
// ----------------------------------------------------- Manifest constants
// ----------------------------------------------------- Manifest constants
/ * *
* The UID to use when serializing this instance .
* /
private static final long serialVersionUID = 2237570099615271025L ;
/ * *
/ * *
* Default content charset to be used when no explicit charset
* Default content charset to be used when no explicit charset
* parameter is provided by the sender . Media subtypes of the
* parameter is provided by the sender . Media subtypes of the
@ -166,14 +148,15 @@ public class DiskFileItem
private transient File tempFile ;
private transient File tempFile ;
/ * *
/ * *
* File to allow for serialization of the content of this item .
* The file items headers .
* /
* /
private File dfosFile ;
private FileItemHeaders headers ;
/ * *
/ * *
* The file items headers .
* Default content charset to be used when no explicit charset
* parameter is provided by the sender .
* /
* /
private FileItemHeaders headers ;
private String defaultCharset = DEFAULT_CHARSET ;
// ----------------------------------------------------------- Constructors
// ----------------------------------------------------------- Constructors
@ -208,14 +191,15 @@ public class DiskFileItem
// ------------------------------- Methods from javax.activation.DataSource
// ------------------------------- Methods from javax.activation.DataSource
/ * *
/ * *
* Returns an { @link java . io . InputStream InputStream } that can be
* Returns an { @link InputStream InputStream } that can be
* used to retrieve the contents of the file .
* used to retrieve the contents of the file .
*
*
* @return An { @link java . io . InputStream InputStream } that can be
* @return An { @link InputStream InputStream } that can be
* used to retrieve the contents of the file .
* used to retrieve the contents of the file .
*
*
* @throws IOException if an error occurs .
* @throws IOException if an error occurs .
* /
* /
@Override
public InputStream getInputStream ( )
public InputStream getInputStream ( )
throws IOException {
throws IOException {
if ( ! isInMemory ( ) ) {
if ( ! isInMemory ( ) ) {
@ -235,6 +219,7 @@ public class DiskFileItem
* @return The content type passed by the agent or < code > null < / code > if
* @return The content type passed by the agent or < code > null < / code > if
* not defined .
* not defined .
* /
* /
@Override
public String getContentType ( ) {
public String getContentType ( ) {
return contentType ;
return contentType ;
}
}
@ -258,11 +243,12 @@ public class DiskFileItem
* Returns the original filename in the client ' s filesystem .
* Returns the original filename in the client ' s filesystem .
*
*
* @return The original filename in the client ' s filesystem .
* @return The original filename in the client ' s filesystem .
* @throws InvalidFileNameException The file name contains a NUL character ,
* @throws com . fr . third . org . apache . commons . fileupload . InvalidFileNameException The file name contains a NUL character ,
* which might be an indicator of a security attack . If you intend to
* which might be an indicator of a security attack . If you intend to
* use the file name anyways , catch the exception and use
* use the file name anyways , catch the exception and use
* { @link InvalidFileNameException # getName ( ) } .
* { @link com . fr . third . org . apache . commons . fileupload . InvalidFileNameException # getName ( ) } .
* /
* /
@Override
public String getName ( ) {
public String getName ( ) {
return Streams . checkFileName ( fileName ) ;
return Streams . checkFileName ( fileName ) ;
}
}
@ -276,6 +262,7 @@ public class DiskFileItem
* @return < code > true < / code > if the file contents will be read
* @return < code > true < / code > if the file contents will be read
* from memory ; < code > false < / code > otherwise .
* from memory ; < code > false < / code > otherwise .
* /
* /
@Override
public boolean isInMemory ( ) {
public boolean isInMemory ( ) {
if ( cachedContent ! = null ) {
if ( cachedContent ! = null ) {
return true ;
return true ;
@ -288,6 +275,7 @@ public class DiskFileItem
*
*
* @return The size of the file , in bytes .
* @return The size of the file , in bytes .
* /
* /
@Override
public long getSize ( ) {
public long getSize ( ) {
if ( size > = 0 ) {
if ( size > = 0 ) {
return size ;
return size ;
@ -305,11 +293,13 @@ public class DiskFileItem
* contents of the file were not yet cached in memory , they will be
* contents of the file were not yet cached in memory , they will be
* loaded from the disk storage and cached .
* loaded from the disk storage and cached .
*
*
* @return The contents of the file as an array of bytes .
* @return The contents of the file as an array of bytes
* or { @code null } if the data cannot be read
* /
* /
@Override
public byte [ ] get ( ) {
public byte [ ] get ( ) {
if ( isInMemory ( ) ) {
if ( isInMemory ( ) ) {
if ( cachedContent = = null ) {
if ( cachedContent = = null & & dfos ! = null ) {
cachedContent = dfos . getData ( ) ;
cachedContent = dfos . getData ( ) ;
}
}
return cachedContent ;
return cachedContent ;
@ -319,18 +309,12 @@ public class DiskFileItem
InputStream fis = null ;
InputStream fis = null ;
try {
try {
fis = new BufferedInputStream ( new FileInputStream ( dfos . getFile ( ) ) ) ;
fis = new FileInputStream ( dfos . getFile ( ) ) ;
fi s. read ( fileData ) ;
IOUtil s. readFully ( fis , fileData ) ;
} catch ( IOException e ) {
} catch ( IOException e ) {
fileData = null ;
fileData = null ;
} finally {
} finally {
if ( fis ! = null ) {
IOUtils . closeQuietly ( fis ) ;
try {
fis . close ( ) ;
} catch ( IOException e ) {
// ignore
}
}
}
}
return fileData ;
return fileData ;
@ -348,6 +332,7 @@ public class DiskFileItem
* @throws UnsupportedEncodingException if the requested character
* @throws UnsupportedEncodingException if the requested character
* encoding is not available .
* encoding is not available .
* /
* /
@Override
public String getString ( final String charset )
public String getString ( final String charset )
throws UnsupportedEncodingException {
throws UnsupportedEncodingException {
return new String ( get ( ) , charset ) ;
return new String ( get ( ) , charset ) ;
@ -362,11 +347,12 @@ public class DiskFileItem
*
*
* @return The contents of the file , as a string .
* @return The contents of the file , as a string .
* /
* /
@Override
public String getString ( ) {
public String getString ( ) {
byte [ ] rawdata = get ( ) ;
byte [ ] rawdata = get ( ) ;
String charset = getCharSet ( ) ;
String charset = getCharSet ( ) ;
if ( charset = = null ) {
if ( charset = = null ) {
charset = DEFAULT_CHARSET ;
charset = defaultCharset ;
}
}
try {
try {
return new String ( rawdata , charset ) ;
return new String ( rawdata , charset ) ;
@ -395,16 +381,16 @@ public class DiskFileItem
*
*
* @throws Exception if an error occurs .
* @throws Exception if an error occurs .
* /
* /
@Override
public void write ( File file ) throws Exception {
public void write ( File file ) throws Exception {
if ( isInMemory ( ) ) {
if ( isInMemory ( ) ) {
FileOutputStream fout = null ;
FileOutputStream fout = null ;
try {
try {
fout = new FileOutputStream ( file ) ;
fout = new FileOutputStream ( file ) ;
fout . write ( get ( ) ) ;
fout . write ( get ( ) ) ;
fout . close ( ) ;
} finally {
} finally {
if ( fout ! = null ) {
IOUtils . closeQuietly ( fout ) ;
fout . close ( ) ;
}
}
}
} else {
} else {
File outputFile = getStoreLocation ( ) ;
File outputFile = getStoreLocation ( ) ;
@ -416,32 +402,10 @@ public class DiskFileItem
* in a temporary location so move it to the
* in a temporary location so move it to the
* desired file .
* desired file .
* /
* /
if ( ! outputFile . renameTo ( file ) ) {
if ( file . exists ( ) ) {
BufferedInputStream in = null ;
file . delete ( ) ;
BufferedOutputStream out = null ;
try {
in = new BufferedInputStream (
new FileInputStream ( outputFile ) ) ;
out = new BufferedOutputStream (
new FileOutputStream ( file ) ) ;
IOUtils . copy ( in , out ) ;
} finally {
if ( in ! = null ) {
try {
in . close ( ) ;
} catch ( IOException e ) {
// ignore
}
}
if ( out ! = null ) {
try {
out . close ( ) ;
} catch ( IOException e ) {
// ignore
}
}
}
}
}
FileUtils . moveFile ( outputFile , file ) ;
} else {
} else {
/ *
/ *
* For whatever reason we cannot write the
* For whatever reason we cannot write the
@ -460,10 +424,11 @@ public class DiskFileItem
* collected , this method can be used to ensure that this is done at an
* collected , this method can be used to ensure that this is done at an
* earlier time , thus preserving system resources .
* earlier time , thus preserving system resources .
* /
* /
@Override
public void delete ( ) {
public void delete ( ) {
cachedContent = null ;
cachedContent = null ;
File outputFile = getStoreLocation ( ) ;
File outputFile = getStoreLocation ( ) ;
if ( outputFile ! = null & & outputFile . exists ( ) ) {
if ( outputFile ! = null & & ! isInMemory ( ) & & outputFile . exists ( ) ) {
outputFile . delete ( ) ;
outputFile . delete ( ) ;
}
}
}
}
@ -474,9 +439,10 @@ public class DiskFileItem
*
*
* @return The name of the form field .
* @return The name of the form field .
*
*
* @see # setFieldName ( java . lang . String )
* @see # setFieldName ( String )
*
*
* /
* /
@Override
public String getFieldName ( ) {
public String getFieldName ( ) {
return fieldName ;
return fieldName ;
}
}
@ -489,6 +455,7 @@ public class DiskFileItem
* @see # getFieldName ( )
* @see # getFieldName ( )
*
*
* /
* /
@Override
public void setFieldName ( String fieldName ) {
public void setFieldName ( String fieldName ) {
this . fieldName = fieldName ;
this . fieldName = fieldName ;
}
}
@ -503,6 +470,7 @@ public class DiskFileItem
* @see # setFormField ( boolean )
* @see # setFormField ( boolean )
*
*
* /
* /
@Override
public boolean isFormField ( ) {
public boolean isFormField ( ) {
return isFormField ;
return isFormField ;
}
}
@ -517,19 +485,21 @@ public class DiskFileItem
* @see # isFormField ( )
* @see # isFormField ( )
*
*
* /
* /
@Override
public void setFormField ( boolean state ) {
public void setFormField ( boolean state ) {
isFormField = state ;
isFormField = state ;
}
}
/ * *
/ * *
* Returns an { @link java . io . OutputStream OutputStream } that can
* Returns an { @link OutputStream OutputStream } that can
* be used for storing the contents of the file .
* be used for storing the contents of the file .
*
*
* @return An { @link java . io . OutputStream OutputStream } that can be used
* @return An { @link OutputStream OutputStream } that can be used
* for storing the contens ts of the file .
* for storing the contents of the file .
*
*
* @throws IOException if an error occurs .
* @throws IOException if an error occurs .
* /
* /
@Override
public OutputStream getOutputStream ( )
public OutputStream getOutputStream ( )
throws IOException {
throws IOException {
if ( dfos = = null ) {
if ( dfos = = null ) {
@ -542,11 +512,11 @@ public class DiskFileItem
// --------------------------------------------------------- Public methods
// --------------------------------------------------------- Public methods
/ * *
/ * *
* Returns the { @link java . io . File } object for the < code > FileItem < / code > ' s
* Returns the { @link File } object for the < code > FileItem < / code > ' s
* data ' s temporary location on the disk . Note that for
* data ' s temporary location on the disk . Note that for
* < code > FileItem < / code > s that have their data stored in memory ,
* < code > FileItem < / code > s that have their data stored in memory ,
* this method will return < code > null < / code > . When handling large
* this method will return < code > null < / code > . When handling large
* files , you can use { @link java . io . File # renameTo ( java . io . File ) } to
* files , you can use { @link File # renameTo ( File ) } to
* move the file to new location without copying the data , if the
* move the file to new location without copying the data , if the
* source and destination locations reside within the same logical
* source and destination locations reside within the same logical
* volume .
* volume .
@ -558,6 +528,9 @@ public class DiskFileItem
if ( dfos = = null ) {
if ( dfos = = null ) {
return null ;
return null ;
}
}
if ( isInMemory ( ) ) {
return null ;
}
return dfos . getFile ( ) ;
return dfos . getFile ( ) ;
}
}
@ -568,6 +541,9 @@ public class DiskFileItem
* /
* /
@Override
@Override
protected void finalize ( ) {
protected void finalize ( ) {
if ( dfos = = null | | dfos . isInMemory ( ) ) {
return ;
}
File outputFile = dfos . getFile ( ) ;
File outputFile = dfos . getFile ( ) ;
if ( outputFile ! = null & & outputFile . exists ( ) ) {
if ( outputFile ! = null & & outputFile . exists ( ) ) {
@ -576,12 +552,15 @@ public class DiskFileItem
}
}
/ * *
/ * *
* Creates and returns a { @link java . io . File File } representing a uniquely
* Creates and returns a { @link File File } representing a uniquely
* named temporary file in the configured repository path . The lifetime of
* named temporary file in the configured repository path . The lifetime of
* the file is tied to the lifetime of the < code > FileItem < / code > instance ;
* the file is tied to the lifetime of the < code > FileItem < / code > instance ;
* the file will be deleted when the instance is garbage collected .
* the file will be deleted when the instance is garbage collected .
* < p >
* < b > Note : Subclasses that override this method must ensure that they return the
* same File each time . < / b >
*
*
* @return The { @link java . io . File File } to be used for temporary storage .
* @return The { @link File File } to be used for temporary storage .
* /
* /
protected File getTempFile ( ) {
protected File getTempFile ( ) {
if ( tempFile = = null ) {
if ( tempFile = = null ) {
@ -601,7 +580,7 @@ public class DiskFileItem
/ * *
/ * *
* Returns an identifier that is unique within the class loader used to
* Returns an identifier that is unique within the class loader used to
* load this class , but does not have random - like apearance .
* load this class , but does not have random - like app earance .
*
*
* @return A String with the non - random looking instance identifier .
* @return A String with the non - random looking instance identifier .
* /
* /
@ -630,83 +609,11 @@ public class DiskFileItem
Boolean . valueOf ( isFormField ( ) ) , getFieldName ( ) ) ;
Boolean . valueOf ( isFormField ( ) ) , getFieldName ( ) ) ;
}
}
// -------------------------------------------------- Serialization methods
/ * *
* Writes the state of this object during serialization .
*
* @param out The stream to which the state should be written .
*
* @throws IOException if an error occurs .
* /
private void writeObject ( ObjectOutputStream out ) throws IOException {
// Read the data
if ( dfos . isInMemory ( ) ) {
cachedContent = get ( ) ;
} else {
cachedContent = null ;
dfosFile = dfos . getFile ( ) ;
}
// write out values
out . defaultWriteObject ( ) ;
}
/ * *
* Reads the state of this object during deserialization .
*
* @param in The stream from which the state should be read .
*
* @throws IOException if an error occurs .
* @throws ClassNotFoundException if class cannot be found .
* /
private void readObject ( ObjectInputStream in )
throws IOException , ClassNotFoundException {
if ( ! Boolean . getBoolean ( SERIALIZABLE_PROPERTY ) ) {
throw new IllegalStateException ( "Property " + SERIALIZABLE_PROPERTY
+ " is not true, rejecting to deserialize a DiskFileItem." ) ;
}
// read values
in . defaultReadObject ( ) ;
/ * One expected use of serialization is to migrate HTTP sessions
* containing a DiskFileItem between JVMs . Particularly if the JVMs are
* on different machines It is possible that the repository location is
* not valid so validate it .
* /
if ( repository ! = null ) {
if ( repository . isDirectory ( ) ) {
// Check path for nulls
if ( repository . getPath ( ) . contains ( "\0" ) ) {
throw new IOException ( format (
"The repository [%s] contains a null character" ,
repository . getPath ( ) ) ) ;
}
} else {
throw new IOException ( format (
"The repository [%s] is not a directory" ,
repository . getAbsolutePath ( ) ) ) ;
}
}
OutputStream output = getOutputStream ( ) ;
if ( cachedContent ! = null ) {
output . write ( cachedContent ) ;
} else {
FileInputStream input = new FileInputStream ( dfosFile ) ;
IOUtils . copy ( input , output ) ;
dfosFile . delete ( ) ;
dfosFile = null ;
}
output . close ( ) ;
cachedContent = null ;
}
/ * *
/ * *
* Returns the file item headers .
* Returns the file item headers .
* @return The file items headers .
* @return The file items headers .
* /
* /
@Override
public FileItemHeaders getHeaders ( ) {
public FileItemHeaders getHeaders ( ) {
return headers ;
return headers ;
}
}
@ -715,8 +622,26 @@ public class DiskFileItem
* Sets the file item headers .
* Sets the file item headers .
* @param pHeaders The file items headers .
* @param pHeaders The file items headers .
* /
* /
@Override
public void setHeaders ( FileItemHeaders pHeaders ) {
public void setHeaders ( FileItemHeaders pHeaders ) {
headers = pHeaders ;
headers = pHeaders ;
}
}
/ * *
* Returns the default charset for use when no explicit charset
* parameter is provided by the sender .
* @return the default charset
* /
public String getDefaultCharset ( ) {
return defaultCharset ;
}
/ * *
* Sets the default charset for use when no explicit charset
* parameter is provided by the sender .
* @param charset the default charset
* /
public void setDefaultCharset ( String charset ) {
defaultCharset = charset ;
}
}
}