    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 */
    017package org.apache.commons.fileupload.disk;
    018
    019import java.io.File;
    020
    021import org.apache.commons.fileupload.FileItem;
    022import org.apache.commons.fileupload.FileItemFactory;
    023import org.apache.commons.io.FileCleaningTracker;
    024
    025/**
    026 * <p>The default {@link org.apache.commons.fileupload.FileItemFactory}
    027 * implementation. This implementation creates
    028 * {@link org.apache.commons.fileupload.FileItem} instances which keep their
    029 * content either in memory, for smaller items, or in a temporary file on disk,
    030 * for larger items. The size threshold, above which content will be stored on
    031 * disk, is configurable, as is the directory in which temporary files will be
    032 * created.</p>
    033 *
    034 * <p>If not otherwise configured, the default configuration values are as
    035 * follows:</p>
    036 * <ul>
    037 *   <li>Size threshold is 10KB.</li>
    038 *   <li>Repository is the system default temp directory, as returned by
    039 *       {@code System.getProperty("java.io.tmpdir")}.</li>
    040 * </ul>
    041 * <p>
    042 * <strong>NOTE</strong>: Files are created in the system default temp directory with
    043 * predictable names. This means that a local attacker with write access to that
    044 * directory can perform a TOUTOC attack to replace any uploaded file with a
    045 * file of the attackers choice. The implications of this will depend on how the
    046 * uploaded file is used but could be significant. When using this
    047 * implementation in an environment with local, untrusted users,
    048 * {@link #setRepository(File)} MUST be used to configure a repository location
    049 * that is not publicly writable. In a Servlet container the location identified
    050 * by the ServletContext attribute {@code javax.servlet.context.tempdir}
    051 * may be used.
    052 * </p>
    053 *
    054 * <p>Temporary files, which are created for file items, should be
    055 * deleted later on. The best way to do this is using a
    056 * {@link FileCleaningTracker}, which you can set on the
    057 * {@link DiskFileItemFactory}. However, if you do use such a tracker,
    058 * then you must consider the following: Temporary files are automatically
    059 * deleted as soon as they are no longer needed. (More precisely, when the
    060 * corresponding instance of {@link java.io.File} is garbage collected.)
    061 * This is done by the so-called reaper thread, which is started and stopped
    062 * automatically by the {@link FileCleaningTracker} when there are files to be
    063 * tracked.
    064 * It might make sense to terminate that thread, for example, if
    065 * your web application ends. See the section on "Resource cleanup"
    066 * in the users guide of commons-fileupload.</p>
    067 *
    068 * @since FileUpload 1.1
    069 */
    070public class DiskFileItemFactory implements FileItemFactory {
    071
    072    /**
    073     * The default threshold above which uploads will be stored on disk.
    074     */
    075    public static final int DEFAULT_SIZE_THRESHOLD = 10240;
    076
    077    /**
    078     * The directory in which uploaded files will be stored, if stored on disk.
    079     */
    080    private File repository;
    081
    082    /**
    083     * The threshold above which uploads will be stored on disk.
    084     */
    085    private int sizeThreshold = DEFAULT_SIZE_THRESHOLD;
    086
    087    /**
    088     * <p>The instance of {@link FileCleaningTracker}, which is responsible
    089     * for deleting temporary files.</p>
    090     * <p>May be null, if tracking files is not required.</p>
    091     */
    092    private FileCleaningTracker fileCleaningTracker;
    093
    094    /**
    095     * Default content charset to be used when no explicit charset
    096     * parameter is provided by the sender.
    097     */
    098    private String defaultCharset = DiskFileItem.DEFAULT_CHARSET;
    099
    100    /**
    101     * Constructs an unconfigured instance of this class. The resulting factory
    102     * may be configured by calling the appropriate setter methods.
    103     */
    104    public DiskFileItemFactory() {
    105        this(DEFAULT_SIZE_THRESHOLD, null);
    106    }
    107
    108    /**
    109     * Constructs a preconfigured instance of this class.
    110     *
    111     * @param sizeThreshold The threshold, in bytes, below which items will be
    112     *                      retained in memory and above which they will be
    113     *                      stored as a file.
    114     * @param repository    The data repository, which is the directory in
    115     *                      which files will be created, should the item size
    116     *                      exceed the threshold.
    117     */
    118    public DiskFileItemFactory(final int sizeThreshold, final File repository) {
    119        this.sizeThreshold = sizeThreshold;
    120        this.repository = repository;
    121    }
    122
    123    /**
    124     * Create a new {@link DiskFileItem}
    125     * instance from the supplied parameters and the local factory
    126     * configuration.
    127     *
    128     * @param fieldName   The name of the form field.
    129     * @param contentType The content type of the form field.
    130     * @param isFormField {@code true} if this is a plain form field;
    131     *                    {@code false} otherwise.
    132     * @param fileName    The name of the uploaded file, if any, as supplied
    133     *                    by the browser or other client.
    134     *
    135     * @return The newly created file item.
    136     */
    137    @Override
    138    public FileItem createItem(final String fieldName, final String contentType,
    139            final boolean isFormField, final String fileName) {
    140        final DiskFileItem result = new DiskFileItem(fieldName, contentType,
    141                isFormField, fileName, sizeThreshold, repository);
    142        result.setDefaultCharset(defaultCharset);
    143        final FileCleaningTracker tracker = getFileCleaningTracker();
    144        if (tracker != null) {
    145            tracker.track(result.getTempFile(), result);
    146        }
    147        return result;
    148    }
    149
    150    /**
    151     * Gets the default charset for use when no explicit charset
    152     * parameter is provided by the sender.
    153     * @return the default charset
    154     */
    155    public String getDefaultCharset() {
    156        return defaultCharset;
    157    }
    158
    159    /**
    160     * Gets the tracker, which is responsible for deleting temporary
    161     * files.
    162     *
    163     * @return An instance of {@link FileCleaningTracker}, or null
    164     *   (default), if temporary files aren't tracked.
    165     */
    166    public FileCleaningTracker getFileCleaningTracker() {
    167        return fileCleaningTracker;
    168    }
    169
    170    /**
    171     * Gets the directory used to temporarily store files that are larger
    172     * than the configured size threshold.
    173     *
    174     * @return The directory in which temporary files will be located.
    175     * @see #setRepository(java.io.File)
    176     *
    177     */
    178    public File getRepository() {
    179        return repository;
    180    }
    181
    182    /**
    183     * Gets the size threshold beyond which files are written directly to
    184     * disk. The default value is 10240 bytes.
    185     *
    186     * @return The size threshold, in bytes.
    187     * @see #setSizeThreshold(int)
    188     */
    189    public int getSizeThreshold() {
    190        return sizeThreshold;
    191    }
    192
    193    /**
    194     * Sets the default charset for use when no explicit charset
    195     * parameter is provided by the sender.
    196     *
    197     * @param charset the default charset
    198     */
    199    public void setDefaultCharset(final String charset) {
    200        this.defaultCharset = charset;
    201    }
    202
    203    /**
    204     * Sets the tracker, which is responsible for deleting temporary
    205     * files.
    206     *
    207     * @param fileCleaningTracker An instance of {@link FileCleaningTracker},
    208     *   which will from now on track the created files, or null
    209     *   (default), to disable tracking.
    210     */
    211    public void setFileCleaningTracker(final FileCleaningTracker fileCleaningTracker) {
    212        this.fileCleaningTracker = fileCleaningTracker;
    213    }
    214
    215    /**
    216     * Sets the directory used to temporarily store files that are larger
    217     * than the configured size threshold.
    218     *
    219     * @param repository The directory in which temporary files will be located.
    220     * @see #getRepository()
    221     *
    222     */
    223    public void setRepository(final File repository) {
    224        this.repository = repository;
    225    }
    226
    227    /**
    228     * Sets the size threshold beyond which files are written directly to disk.
    229     *
    230     * @param sizeThreshold The size threshold, in bytes.
    231     * @see #getSizeThreshold()
    232     *
    233     */
    234    public void setSizeThreshold(final int sizeThreshold) {
    235        this.sizeThreshold = sizeThreshold;
    236    }
    237}