Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 6C905200CCA for ; Tue, 13 Jun 2017 14:48:55 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 6B3CD160BEB; Tue, 13 Jun 2017 12:48:55 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id C7B65160C06 for ; Tue, 13 Jun 2017 14:48:51 +0200 (CEST) Received: (qmail 62297 invoked by uid 500); 13 Jun 2017 12:48:51 -0000 Mailing-List: contact notifications-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@commons.apache.org Delivered-To: mailing list notifications@commons.apache.org Received: (qmail 61751 invoked by uid 99); 13 Jun 2017 12:48:49 -0000 Received: from Unknown (HELO svn01-us-west.apache.org) (209.188.14.144) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 13 Jun 2017 12:48:49 +0000 Received: from svn01-us-west.apache.org (localhost [127.0.0.1]) by svn01-us-west.apache.org (ASF Mail Server at svn01-us-west.apache.org) with ESMTP id 37A413A2656 for ; Tue, 13 Jun 2017 12:48:45 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1013974 [32/43] - in /websites/production/commons/content/proper/commons-fileupload/javadocs: ./ api-release/ api-release/org/ api-release/org/apache/ api-release/org/apache/commons/ api-release/org/apache/commons/fileupload/ api-release/o... Date: Tue, 13 Jun 2017 12:48:40 -0000 To: notifications@commons.apache.org From: chtompki@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20170613124845.37A413A2656@svn01-us-west.apache.org> archived-at: Tue, 13 Jun 2017 12:48:55 -0000 Added: websites/production/commons/content/proper/commons-fileupload/javadocs/api-release/src-html/org/apache/commons/fileupload/FileUploadBase.html ============================================================================== --- websites/production/commons/content/proper/commons-fileupload/javadocs/api-release/src-html/org/apache/commons/fileupload/FileUploadBase.html (added) +++ websites/production/commons/content/proper/commons-fileupload/javadocs/api-release/src-html/org/apache/commons/fileupload/FileUploadBase.html Tue Jun 13 12:48:38 2017 @@ -0,0 +1,1563 @@ + + + +Source code + + + +
+
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;
+018
+019import static java.lang.String.format;
+020
+021import java.io.IOException;
+022import java.io.InputStream;
+023import java.io.UnsupportedEncodingException;
+024import java.util.ArrayList;
+025import java.util.HashMap;
+026import java.util.Iterator;
+027import java.util.List;
+028import java.util.Locale;
+029import java.util.Map;
+030import java.util.NoSuchElementException;
+031
+032import javax.servlet.http.HttpServletRequest;
+033
+034import org.apache.commons.fileupload.MultipartStream.ItemInputStream;
+035import org.apache.commons.fileupload.servlet.ServletFileUpload;
+036import org.apache.commons.fileupload.servlet.ServletRequestContext;
+037import org.apache.commons.fileupload.util.Closeable;
+038import org.apache.commons.fileupload.util.FileItemHeadersImpl;
+039import org.apache.commons.fileupload.util.LimitedInputStream;
+040import org.apache.commons.fileupload.util.Streams;
+041
+042/**
+043 * <p>High level API for processing file uploads.</p>
+044 *
+045 * <p>This class handles multiple files per single HTML widget, sent using
+046 * <code>multipart/mixed</code> encoding type, as specified by
+047 * <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>.  Use {@link
+048 * #parseRequest(RequestContext)} to acquire a list of {@link
+049 * org.apache.commons.fileupload.FileItem}s associated with a given HTML
+050 * widget.</p>
+051 *
+052 * <p>How the data for individual parts is stored is determined by the factory
+053 * used to create them; a given part may be in memory, on disk, or somewhere
+054 * else.</p>
+055 *
+056 * @version $Id$
+057 */
+058public abstract class FileUploadBase {
+059
+060    // ---------------------------------------------------------- Class methods
+061
+062    /**
+063     * <p>Utility method that determines whether the request contains multipart
+064     * content.</p>
+065     *
+066     * <p><strong>NOTE:</strong>This method will be moved to the
+067     * <code>ServletFileUpload</code> class after the FileUpload 1.1 release.
+068     * Unfortunately, since this method is static, it is not possible to
+069     * provide its replacement until this method is removed.</p>
+070     *
+071     * @param ctx The request context to be evaluated. Must be non-null.
+072     *
+073     * @return <code>true</code> if the request is multipart;
+074     *         <code>false</code> otherwise.
+075     */
+076    public static final boolean isMultipartContent(RequestContext ctx) {
+077        String contentType = ctx.getContentType();
+078        if (contentType == null) {
+079            return false;
+080        }
+081        if (contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART)) {
+082            return true;
+083        }
+084        return false;
+085    }
+086
+087    /**
+088     * Utility method that determines whether the request contains multipart
+089     * content.
+090     *
+091     * @param req The servlet request to be evaluated. Must be non-null.
+092     *
+093     * @return <code>true</code> if the request is multipart;
+094     *         <code>false</code> otherwise.
+095     *
+096     * @deprecated 1.1 Use the method on <code>ServletFileUpload</code> instead.
+097     */
+098    @Deprecated
+099    public static boolean isMultipartContent(HttpServletRequest req) {
+100        return ServletFileUpload.isMultipartContent(req);
+101    }
+102
+103    // ----------------------------------------------------- Manifest constants
+104
+105    /**
+106     * HTTP content type header name.
+107     */
+108    public static final String CONTENT_TYPE = "Content-type";
+109
+110    /**
+111     * HTTP content disposition header name.
+112     */
+113    public static final String CONTENT_DISPOSITION = "Content-disposition";
+114
+115    /**
+116     * HTTP content length header name.
+117     */
+118    public static final String CONTENT_LENGTH = "Content-length";
+119
+120    /**
+121     * Content-disposition value for form data.
+122     */
+123    public static final String FORM_DATA = "form-data";
+124
+125    /**
+126     * Content-disposition value for file attachment.
+127     */
+128    public static final String ATTACHMENT = "attachment";
+129
+130    /**
+131     * Part of HTTP content type header.
+132     */
+133    public static final String MULTIPART = "multipart/";
+134
+135    /**
+136     * HTTP content type header for multipart forms.
+137     */
+138    public static final String MULTIPART_FORM_DATA = "multipart/form-data";
+139
+140    /**
+141     * HTTP content type header for multiple uploads.
+142     */
+143    public static final String MULTIPART_MIXED = "multipart/mixed";
+144
+145    /**
+146     * The maximum length of a single header line that will be parsed
+147     * (1024 bytes).
+148     * @deprecated This constant is no longer used. As of commons-fileupload
+149     *   1.2, the only applicable limit is the total size of a parts headers,
+150     *   {@link MultipartStream#HEADER_PART_SIZE_MAX}.
+151     */
+152    @Deprecated
+153    public static final int MAX_HEADER_SIZE = 1024;
+154
+155    // ----------------------------------------------------------- Data members
+156
+157    /**
+158     * The maximum size permitted for the complete request, as opposed to
+159     * {@link #fileSizeMax}. A value of -1 indicates no maximum.
+160     */
+161    private long sizeMax = -1;
+162
+163    /**
+164     * The maximum size permitted for a single uploaded file, as opposed
+165     * to {@link #sizeMax}. A value of -1 indicates no maximum.
+166     */
+167    private long fileSizeMax = -1;
+168
+169    /**
+170     * The content encoding to use when reading part headers.
+171     */
+172    private String headerEncoding;
+173
+174    /**
+175     * The progress listener.
+176     */
+177    private ProgressListener listener;
+178
+179    // ----------------------------------------------------- Property accessors
+180
+181    /**
+182     * Returns the factory class used when creating file items.
+183     *
+184     * @return The factory class for new file items.
+185     */
+186    public abstract FileItemFactory getFileItemFactory();
+187
+188    /**
+189     * Sets the factory class to use when creating file items.
+190     *
+191     * @param factory The factory class for new file items.
+192     */
+193    public abstract void setFileItemFactory(FileItemFactory factory);
+194
+195    /**
+196     * Returns the maximum allowed size of a complete request, as opposed
+197     * to {@link #getFileSizeMax()}.
+198     *
+199     * @return The maximum allowed size, in bytes. The default value of
+200     *   -1 indicates, that there is no limit.
+201     *
+202     * @see #setSizeMax(long)
+203     *
+204     */
+205    public long getSizeMax() {
+206        return sizeMax;
+207    }
+208
+209    /**
+210     * Sets the maximum allowed size of a complete request, as opposed
+211     * to {@link #setFileSizeMax(long)}.
+212     *
+213     * @param sizeMax The maximum allowed size, in bytes. The default value of
+214     *   -1 indicates, that there is no limit.
+215     *
+216     * @see #getSizeMax()
+217     *
+218     */
+219    public void setSizeMax(long sizeMax) {
+220        this.sizeMax = sizeMax;
+221    }
+222
+223    /**
+224     * Returns the maximum allowed size of a single uploaded file,
+225     * as opposed to {@link #getSizeMax()}.
+226     *
+227     * @see #setFileSizeMax(long)
+228     * @return Maximum size of a single uploaded file.
+229     */
+230    public long getFileSizeMax() {
+231        return fileSizeMax;
+232    }
+233
+234    /**
+235     * Sets the maximum allowed size of a single uploaded file,
+236     * as opposed to {@link #getSizeMax()}.
+237     *
+238     * @see #getFileSizeMax()
+239     * @param fileSizeMax Maximum size of a single uploaded file.
+240     */
+241    public void setFileSizeMax(long fileSizeMax) {
+242        this.fileSizeMax = fileSizeMax;
+243    }
+244
+245    /**
+246     * Retrieves the character encoding used when reading the headers of an
+247     * individual part. When not specified, or <code>null</code>, the request
+248     * encoding is used. If that is also not specified, or <code>null</code>,
+249     * the platform default encoding is used.
+250     *
+251     * @return The encoding used to read part headers.
+252     */
+253    public String getHeaderEncoding() {
+254        return headerEncoding;
+255    }
+256
+257    /**
+258     * Specifies the character encoding to be used when reading the headers of
+259     * individual part. When not specified, or <code>null</code>, the request
+260     * encoding is used. If that is also not specified, or <code>null</code>,
+261     * the platform default encoding is used.
+262     *
+263     * @param encoding The encoding used to read part headers.
+264     */
+265    public void setHeaderEncoding(String encoding) {
+266        headerEncoding = encoding;
+267    }
+268
+269    // --------------------------------------------------------- Public methods
+270
+271    /**
+272     * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
+273     * compliant <code>multipart/form-data</code> stream.
+274     *
+275     * @param req The servlet request to be parsed.
+276     *
+277     * @return A list of <code>FileItem</code> instances parsed from the
+278     *         request, in the order that they were transmitted.
+279     *
+280     * @throws FileUploadException if there are problems reading/parsing
+281     *                             the request or storing files.
+282     *
+283     * @deprecated 1.1 Use {@link ServletFileUpload#parseRequest(HttpServletRequest)} instead.
+284     */
+285    @Deprecated
+286    public List<FileItem> parseRequest(HttpServletRequest req)
+287    throws FileUploadException {
+288        return parseRequest(new ServletRequestContext(req));
+289    }
+290
+291    /**
+292     * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
+293     * compliant <code>multipart/form-data</code> stream.
+294     *
+295     * @param ctx The context for the request to be parsed.
+296     *
+297     * @return An iterator to instances of <code>FileItemStream</code>
+298     *         parsed from the request, in the order that they were
+299     *         transmitted.
+300     *
+301     * @throws FileUploadException if there are problems reading/parsing
+302     *                             the request or storing files.
+303     * @throws IOException An I/O error occurred. This may be a network
+304     *   error while communicating with the client or a problem while
+305     *   storing the uploaded content.
+306     */
+307    public FileItemIterator getItemIterator(RequestContext ctx)
+308    throws FileUploadException, IOException {
+309        try {
+310            return new FileItemIteratorImpl(ctx);
+311        } catch (FileUploadIOException e) {
+312            // unwrap encapsulated SizeException
+313            throw (FileUploadException) e.getCause();
+314        }
+315    }
+316
+317    /**
+318     * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
+319     * compliant <code>multipart/form-data</code> stream.
+320     *
+321     * @param ctx The context for the request to be parsed.
+322     *
+323     * @return A list of <code>FileItem</code> instances parsed from the
+324     *         request, in the order that they were transmitted.
+325     *
+326     * @throws FileUploadException if there are problems reading/parsing
+327     *                             the request or storing files.
+328     */
+329    public List<FileItem> parseRequest(RequestContext ctx)
+330            throws FileUploadException {
+331        List<FileItem> items = new ArrayList<FileItem>();
+332        boolean successful = false;
+333        try {
+334            FileItemIterator iter = getItemIterator(ctx);
+335            FileItemFactory fac = getFileItemFactory();
+336            if (fac == null) {
+337                throw new NullPointerException("No FileItemFactory has been set.");
+338            }
+339            while (iter.hasNext()) {
+340                final FileItemStream item = iter.next();
+341                // Don't use getName() here to prevent an InvalidFileNameException.
+342                final String fileName = ((FileItemIteratorImpl.FileItemStreamImpl) item).name;
+343                FileItem fileItem = fac.createItem(item.getFieldName(), item.getContentType(),
+344                                                   item.isFormField(), fileName);
+345                items.add(fileItem);
+346                try {
+347                    Streams.copy(item.openStream(), fileItem.getOutputStream(), true);
+348                } catch (FileUploadIOException e) {
+349                    throw (FileUploadException) e.getCause();
+350                } catch (IOException e) {
+351                    throw new IOFileUploadException(format("Processing of %s request failed. %s",
+352                                                           MULTIPART_FORM_DATA, e.getMessage()), e);
+353                }
+354                final FileItemHeaders fih = item.getHeaders();
+355                fileItem.setHeaders(fih);
+356            }
+357            successful = true;
+358            return items;
+359        } catch (FileUploadIOException e) {
+360            throw (FileUploadException) e.getCause();
+361        } catch (IOException e) {
+362            throw new FileUploadException(e.getMessage(), e);
+363        } finally {
+364            if (!successful) {
+365                for (FileItem fileItem : items) {
+366                    try {
+367                        fileItem.delete();
+368                    } catch (Throwable e) {
+369                        // ignore it
+370                    }
+371                }
+372            }
+373        }
+374    }
+375
+376    /**
+377     * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
+378     * compliant <code>multipart/form-data</code> stream.
+379     *
+380     * @param ctx The context for the request to be parsed.
+381     *
+382     * @return A map of <code>FileItem</code> instances parsed from the request.
+383     *
+384     * @throws FileUploadException if there are problems reading/parsing
+385     *                             the request or storing files.
+386     *
+387     * @since 1.3
+388     */
+389    public Map<String, List<FileItem>> parseParameterMap(RequestContext ctx)
+390            throws FileUploadException {
+391        final List<FileItem> items = parseRequest(ctx);
+392        final Map<String, List<FileItem>> itemsMap = new HashMap<String, List<FileItem>>(items.size());
+393
+394        for (FileItem fileItem : items) {
+395            String fieldName = fileItem.getFieldName();
+396            List<FileItem> mappedItems = itemsMap.get(fieldName);
+397
+398            if (mappedItems == null) {
+399                mappedItems = new ArrayList<FileItem>();
+400                itemsMap.put(fieldName, mappedItems);
+401            }
+402
+403            mappedItems.add(fileItem);
+404        }
+405
+406        return itemsMap;
+407    }
+408
+409    // ------------------------------------------------------ Protected methods
+410
+411    /**
+412     * Retrieves the boundary from the <code>Content-type</code> header.
+413     *
+414     * @param contentType The value of the content type header from which to
+415     *                    extract the boundary value.
+416     *
+417     * @return The boundary, as a byte array.
+418     */
+419    protected byte[] getBoundary(String contentType) {
+420        ParameterParser parser = new ParameterParser();
+421        parser.setLowerCaseNames(true);
+422        // Parameter parser can handle null input
+423        Map<String, String> params = parser.parse(contentType, new char[] {';', ','});
+424        String boundaryStr = params.get("boundary");
+425
+426        if (boundaryStr == null) {
+427            return null;
+428        }
+429        byte[] boundary;
+430        try {
+431            boundary = boundaryStr.getBytes("ISO-8859-1");
+432        } catch (UnsupportedEncodingException e) {
+433            boundary = boundaryStr.getBytes(); // Intentionally falls back to default charset
+434        }
+435        return boundary;
+436    }
+437
+438    /**
+439     * Retrieves the file name from the <code>Content-disposition</code>
+440     * header.
+441     *
+442     * @param headers A <code>Map</code> containing the HTTP request headers.
+443     *
+444     * @return The file name for the current <code>encapsulation</code>.
+445     * @deprecated 1.2.1 Use {@link #getFileName(FileItemHeaders)}.
+446     */
+447    @Deprecated
+448    protected String getFileName(Map<String, String> headers) {
+449        return getFileName(getHeader(headers, CONTENT_DISPOSITION));
+450    }
+451
+452    /**
+453     * Retrieves the file name from the <code>Content-disposition</code>
+454     * header.
+455     *
+456     * @param headers The HTTP headers object.
+457     *
+458     * @return The file name for the current <code>encapsulation</code>.
+459     */
+460    protected String getFileName(FileItemHeaders headers) {
+461        return getFileName(headers.getHeader(CONTENT_DISPOSITION));
+462    }
+463
+464    /**
+465     * Returns the given content-disposition headers file name.
+466     * @param pContentDisposition The content-disposition headers value.
+467     * @return The file name
+468     */
+469    private String getFileName(String pContentDisposition) {
+470        String fileName = null;
+471        if (pContentDisposition != null) {
+472            String cdl = pContentDisposition.toLowerCase(Locale.ENGLISH);
+473            if (cdl.startsWith(FORM_DATA) || cdl.startsWith(ATTACHMENT)) {
+474                ParameterParser parser = new ParameterParser();
+475                parser.setLowerCaseNames(true);
+476                // Parameter parser can handle null input
+477                Map<String, String> params = parser.parse(pContentDisposition, ';');
+478                if (params.containsKey("filename")) {
+479                    fileName = params.get("filename");
+480                    if (fileName != null) {
+481                        fileName = fileName.trim();
+482                    } else {
+483                        // Even if there is no value, the parameter is present,
+484                        // so we return an empty file name rather than no file
+485                        // name.
+486                        fileName = "";
+487                    }
+488                }
+489            }
+490        }
+491        return fileName;
+492    }
+493
+494    /**
+495     * Retrieves the field name from the <code>Content-disposition</code>
+496     * header.
+497     *
+498     * @param headers A <code>Map</code> containing the HTTP request headers.
+499     *
+500     * @return The field name for the current <code>encapsulation</code>.
+501     */
+502    protected String getFieldName(FileItemHeaders headers) {
+503        return getFieldName(headers.getHeader(CONTENT_DISPOSITION));
+504    }
+505
+506    /**
+507     * Returns the field name, which is given by the content-disposition
+508     * header.
+509     * @param pContentDisposition The content-dispositions header value.
+510     * @return The field jake
+511     */
+512    private String getFieldName(String pContentDisposition) {
+513        String fieldName = null;
+514        if (pContentDisposition != null
+515                && pContentDisposition.toLowerCase(Locale.ENGLISH).startsWith(FORM_DATA)) {
+516            ParameterParser parser = new ParameterParser();
+517            parser.setLowerCaseNames(true);
+518            // Parameter parser can handle null input
+519            Map<String, String> params = parser.parse(pContentDisposition, ';');
+520            fieldName = params.get("name");
+521            if (fieldName != null) {
+522                fieldName = fieldName.trim();
+523            }
+524        }
+525        return fieldName;
+526    }
+527
+528    /**
+529     * Retrieves the field name from the <code>Content-disposition</code>
+530     * header.
+531     *
+532     * @param headers A <code>Map</code> containing the HTTP request headers.
+533     *
+534     * @return The field name for the current <code>encapsulation</code>.
+535     * @deprecated 1.2.1 Use {@link #getFieldName(FileItemHeaders)}.
+536     */
+537    @Deprecated
+538    protected String getFieldName(Map<String, String> headers) {
+539        return getFieldName(getHeader(headers, CONTENT_DISPOSITION));
+540    }
+541
+542    /**
+543     * Creates a new {@link FileItem} instance.
+544     *
+545     * @param headers       A <code>Map</code> containing the HTTP request
+546     *                      headers.
+547     * @param isFormField   Whether or not this item is a form field, as
+548     *                      opposed to a file.
+549     *
+550     * @return A newly created <code>FileItem</code> instance.
+551     *
+552     * @throws FileUploadException if an error occurs.
+553     * @deprecated 1.2 This method is no longer used in favour of
+554     *   internally created instances of {@link FileItem}.
+555     */
+556    @Deprecated
+557    protected FileItem createItem(Map<String, String> headers,
+558                                  boolean isFormField)
+559        throws FileUploadException {
+560        return getFileItemFactory().createItem(getFieldName(headers),
+561                getHeader(headers, CONTENT_TYPE),
+562                isFormField,
+563                getFileName(headers));
+564    }
+565
+566    /**
+567     * <p> Parses the <code>header-part</code> and returns as key/value
+568     * pairs.
+569     *
+570     * <p> If there are multiple headers of the same names, the name
+571     * will map to a comma-separated list containing the values.
+572     *
+573     * @param headerPart The <code>header-part</code> of the current
+574     *                   <code>encapsulation</code>.
+575     *
+576     * @return A <code>Map</code> containing the parsed HTTP request headers.
+577     */
+578    protected FileItemHeaders getParsedHeaders(String headerPart) {
+579        final int len = headerPart.length();
+580        FileItemHeadersImpl headers = newFileItemHeaders();
+581        int start = 0;
+582        for (;;) {
+583            int end = parseEndOfLine(headerPart, start);
+584            if (start == end) {
+585                break;
+586            }
+587            StringBuilder header = new StringBuilder(headerPart.substring(start, end));
+588            start = end + 2;
+589            while (start < len) {
+590                int nonWs = start;
+591                while (nonWs < len) {
+592                    char c = headerPart.charAt(nonWs);
+593                    if (c != ' '  &&  c != '\t') {
+594                        break;
+595                    }
+596                    ++nonWs;
+597                }
+598                if (nonWs == start) {
+599                    break;
+600                }
+601                // Continuation line found
+602                end = parseEndOfLine(headerPart, nonWs);
+603                header.append(" ").append(headerPart.substring(nonWs, end));
+604                start = end + 2;
+605            }
+606            parseHeaderLine(headers, header.toString());
+607        }
+608        return headers;
+609    }
+610
+611    /**
+612     * Creates a new instance of {@link FileItemHeaders}.
+613     * @return The new instance.
+614     */
+615    protected FileItemHeadersImpl newFileItemHeaders() {
+616        return new FileItemHeadersImpl();
+617    }
+618
+619    /**
+620     * <p> Parses the <code>header-part</code> and returns as key/value
+621     * pairs.
+622     *
+623     * <p> If there are multiple headers of the same names, the name
+624     * will map to a comma-separated list containing the values.
+625     *
+626     * @param headerPart The <code>header-part</code> of the current
+627     *                   <code>encapsulation</code>.
+628     *
+629     * @return A <code>Map</code> containing the parsed HTTP request headers.
+630     * @deprecated 1.2.1 Use {@link #getParsedHeaders(String)}
+631     */
+632    @Deprecated
+633    protected Map<String, String> parseHeaders(String headerPart) {
+634        FileItemHeaders headers = getParsedHeaders(headerPart);
+635        Map<String, String> result = new HashMap<String, String>();
+636        for (Iterator<String> iter = headers.getHeaderNames();  iter.hasNext();) {
+637            String headerName = iter.next();
+638            Iterator<String> iter2 = headers.getHeaders(headerName);
+639            StringBuilder headerValue = new StringBuilder(iter2.next());
+640            while (iter2.hasNext()) {
+641                headerValue.append(",").append(iter2.next());
+642            }
+643            result.put(headerName, headerValue.toString());
+644        }
+645        return result;
+646    }
+647
+648    /**
+649     * Skips bytes until the end of the current line.
+650     * @param headerPart The headers, which are being parsed.
+651     * @param end Index of the last byte, which has yet been
+652     *   processed.
+653     * @return Index of the \r\n sequence, which indicates
+654     *   end of line.
+655     */
+656    private int parseEndOfLine(String headerPart, int end) {
+657        int index = end;
+658        for (;;) {
+659            int offset = headerPart.indexOf('\r', index);
+660            if (offset == -1  ||  offset + 1 >= headerPart.length()) {
+661                throw new IllegalStateException(
+662                    "Expected headers to be terminated by an empty line.");
+663            }
+664            if (headerPart.charAt(offset + 1) == '\n') {
+665                return offset;
+666            }
+667            index = offset + 1;
+668        }
+669    }
+670
+671    /**
+672     * Reads the next header line.
+673     * @param headers String with all headers.
+674     * @param header Map where to store the current header.
+675     */
+676    private void parseHeaderLine(FileItemHeadersImpl headers, String header) {
+677        final int colonOffset = header.indexOf(':');
+678        if (colonOffset == -1) {
+679            // This header line is malformed, skip it.
+680            return;
+681        }
+682        String headerName = header.substring(0, colonOffset).trim();
+683        String headerValue =
+684            header.substring(header.indexOf(':') + 1).trim();
+685        headers.addHeader(headerName, headerValue);
+686    }
+687
+688    /**
+689     * Returns the header with the specified name from the supplied map. The
+690     * header lookup is case-insensitive.
+691     *
+692     * @param headers A <code>Map</code> containing the HTTP request headers.
+693     * @param name    The name of the header to return.
+694     *
+695     * @return The value of specified header, or a comma-separated list if
+696     *         there were multiple headers of that name.
+697     * @deprecated 1.2.1 Use {@link FileItemHeaders#getHeader(String)}.
+698     */
+699    @Deprecated
+700    protected final String getHeader(Map<String, String> headers,
+701            String name) {
+702        return headers.get(name.toLowerCase(Locale.ENGLISH));
+703    }
+704
+705    /**
+706     * The iterator, which is returned by
+707     * {@link FileUploadBase#getItemIterator(RequestContext)}.
+708     */
+709    private class FileItemIteratorImpl implements FileItemIterator {
+710
+711        /**
+712         * Default implementation of {@link FileItemStream}.
+713         */
+714        class FileItemStreamImpl implements FileItemStream {
+715
+716            /**
+717             * The file items content type.
+718             */
+719            private final String contentType;
+720
+721            /**
+722             * The file items field name.
+723             */
+724            private final String fieldName;
+725
+726            /**
+727             * The file items file name.
+728             */
+729            private final String name;
+730
+731            /**
+732             * Whether the file item is a form field.
+733             */
+734            private final boolean formField;
+735
+736            /**
+737             * The file items input stream.
+738             */
+739            private final InputStream stream;
+740
+741            /**
+742             * Whether the file item was already opened.
+743             */
+744            private boolean opened;
+745
+746            /**
+747             * The headers, if any.
+748             */
+749            private FileItemHeaders headers;
+750
+751            /**
+752             * Creates a new instance.
+753             *
+754             * @param pName The items file name, or null.
+755             * @param pFieldName The items field name.
+756             * @param pContentType The items content type, or null.
+757             * @param pFormField Whether the item is a form field.
+758             * @param pContentLength The items content length, if known, or -1
+759             * @throws IOException Creating the file item failed.
+760             */
+761            FileItemStreamImpl(String pName, String pFieldName,
+762                    String pContentType, boolean pFormField,
+763                    long pContentLength) throws IOException {
+764                name = pName;
+765                fieldName = pFieldName;
+766                contentType = pContentType;
+767                formField = pFormField;
+768                final ItemInputStream itemStream = multi.newInputStream();
+769                InputStream istream = itemStream;
+770                if (fileSizeMax != -1) {
+771                    if (pContentLength != -1
+772                            &&  pContentLength > fileSizeMax) {
+773                        FileSizeLimitExceededException e =
+774                            new FileSizeLimitExceededException(
+775                                format("The field %s exceeds its maximum permitted size of %s bytes.",
+776                                       fieldName, Long.valueOf(fileSizeMax)),
+777                                pContentLength, fileSizeMax);
+778                        e.setFileName(pName);
+779                        e.setFieldName(pFieldName);
+780                        throw new FileUploadIOException(e);
+781                    }
+782                    istream = new LimitedInputStream(istream, fileSizeMax) {
+783                        @Override
+784                        protected void raiseError(long pSizeMax, long pCount)
+785                                throws IOException {
+786                            itemStream.close(true);
+787                            FileSizeLimitExceededException e =
+788                                new FileSizeLimitExceededException(
+789                                    format("The field %s exceeds its maximum permitted size of %s bytes.",
+790                                           fieldName, Long.valueOf(pSizeMax)),
+791                                    pCount, pSizeMax);
+792                            e.setFieldName(fieldName);
+793                            e.setFileName(name);
+794                            throw new FileUploadIOException(e);
+795                        }
+796                    };
+797                }
+798                stream = istream;
+799            }
+800
+801            /**
+802             * Returns the items content type, or null.
+803             *
+804             * @return Content type, if known, or null.
+805             */
+806            public String getContentType() {
+807                return contentType;
+808            }
+809
+810            /**
+811             * Returns the items field name.
+812             *
+813             * @return Field name.
+814             */
+815            public String getFieldName() {
+816                return fieldName;
+817            }
+818
+819            /**
+820             * Returns the items file name.
+821             *
+822             * @return File name, if known, or null.
+823             * @throws InvalidFileNameException The file name contains a NUL character,
+824             *   which might be an indicator of a security attack. If you intend to
+825             *   use the file name anyways, catch the exception and use
+826             *   InvalidFileNameException#getName().
+827             */
+828            public String getName() {
+829                return Streams.checkFileName(name);
+830            }
+831
+832            /**
+833             * Returns, whether this is a form field.
+834             *
+835             * @return True, if the item is a form field,
+836             *   otherwise false.
+837             */
+838            public boolean isFormField() {
+839                return formField;
+840            }
+841
+842            /**
+843             * Returns an input stream, which may be used to
+844             * read the items contents.
+845             *
+846             * @return Opened input stream.
+847             * @throws IOException An I/O error occurred.
+848             */
+849            public InputStream openStream() throws IOException {
+850                if (opened) {
+851                    throw new IllegalStateException(
+852                            "The stream was already opened.");
+853                }
+854                if (((Closeable) stream).isClosed()) {
+855                    throw new FileItemStream.ItemSkippedException();
+856                }
+857                return stream;
+858            }
+859
+860            /**
+861             * Closes the file item.
+862             *
+863             * @throws IOException An I/O error occurred.
+864             */
+865            void close() throws IOException {
+866                stream.close();
+867            }
+868
+869            /**
+870             * Returns the file item headers.
+871             *
+872             * @return The items header object
+873             */
+874            public FileItemHeaders getHeaders() {
+875                return headers;
+876            }
+877
+878            /**
+879             * Sets the file item headers.
+880             *
+881             * @param pHeaders The items header object
+882             */
+883            public void setHeaders(FileItemHeaders pHeaders) {
+884                headers = pHeaders;
+885            }
+886
+887        }
+888
+889        /**
+890         * The multi part stream to process.
+891         */
+892        private final MultipartStream multi;
+893
+894        /**
+895         * The notifier, which used for triggering the
+896         * {@link ProgressListener}.
+897         */
+898        private final MultipartStream.ProgressNotifier notifier;
+899
+900        /**
+901         * The boundary, which separates the various parts.
+902         */
+903        private final byte[] boundary;
+904
+905        /**
+906         * The item, which we currently process.
+907         */
+908        private FileItemStreamImpl currentItem;
+909
+910        /**
+911         * The current items field name.
+912         */

[... 644 lines stripped ...]