From 7b49d6a8fbefd39623d24dad61f5511d3d2b7a5d Mon Sep 17 00:00:00 2001 From: Emmanuel Bourg <ebourg@apache.org> Date: Mon, 27 Jan 2020 12:45:39 +0100 Subject: [PATCH] New upstream version 1.4 --- .travis.yml | 25 ++ CONTRIBUTING.md | 97 +++++ NOTICE.txt | 2 +- README.md | 104 ++++++ RELEASE-NOTES.txt | 59 ++++ build-gump.xml | 51 --- build.properties | 93 ----- build.xml | 332 ------------------ gump.xml | 53 --- pom.xml | 207 ++++++++--- src/changes/changes.xml | 38 +- src/changes/release-notes.vm | 4 +- src/checkstyle/fileupload_checks.xml | 6 + src/checkstyle/license-header.txt | 16 + .../commons/fileupload/DefaultFileItem.java | 7 - .../fileupload/DefaultFileItemFactory.java | 4 +- .../commons/fileupload/DiskFileUpload.java | 2 - .../apache/commons/fileupload/FileItem.java | 4 +- .../commons/fileupload/FileItemFactory.java | 2 - .../commons/fileupload/FileItemHeaders.java | 2 - .../fileupload/FileItemHeadersSupport.java | 2 - .../commons/fileupload/FileItemIterator.java | 2 - .../commons/fileupload/FileItemStream.java | 2 - .../apache/commons/fileupload/FileUpload.java | 2 - .../commons/fileupload/FileUploadBase.java | 48 ++- .../fileupload/FileUploadException.java | 2 - .../fileupload/InvalidFileNameException.java | 2 - .../commons/fileupload/MultipartStream.java | 71 ++-- .../commons/fileupload/ParameterParser.java | 24 +- .../commons/fileupload/ProgressListener.java | 2 - .../commons/fileupload/RequestContext.java | 2 - .../commons/fileupload/disk/DiskFileItem.java | 200 ++++------- .../fileupload/disk/DiskFileItemFactory.java | 27 +- .../fileupload/portlet/PortletFileUpload.java | 2 - .../portlet/PortletRequestContext.java | 7 +- .../fileupload/portlet/package-info.java | 2 +- .../servlet/FileCleanerCleanup.java | 4 +- .../fileupload/servlet/ServletFileUpload.java | 2 - .../servlet/ServletRequestContext.java | 7 +- .../commons/fileupload/util/Closeable.java | 2 - .../fileupload/util/FileItemHeadersImpl.java | 5 +- .../fileupload/util/LimitedInputStream.java | 13 +- .../commons/fileupload/util/Streams.java | 2 - .../fileupload/util/mime/MimeUtility.java | 2 +- .../util/mime/QuotedPrintableDecoder.java | 2 +- src/site/fml/faq.fml | 72 ++-- src/site/resources/profile.cobertura | 2 + src/site/site.xml | 5 +- src/site/xdoc/download_fileupload.xml | 60 ++-- src/site/xdoc/index.xml | 22 +- src/site/xdoc/security-reports.xml | 137 ++++++++ src/site/xdoc/streaming.xml | 10 +- src/site/xdoc/using.xml | 6 +- .../apache/commons/fileupload/Constants.java | 32 ++ .../fileupload/DefaultFileItemTest.java | 7 +- .../fileupload/DiskFileItemSerializeTest.java | 129 +++---- .../fileupload/DiskFileUploadTest.java | 67 ++++ .../fileupload/FileItemHeadersTest.java | 2 - ...ileUploadTest.java => FileUploadTest.java} | 158 ++++----- .../fileupload/HttpServletRequestFactory.java | 3 - .../fileupload/MockHttpServletRequest.java | 61 +++- .../fileupload/MultipartStreamTest.java | 3 - .../fileupload/ParameterParserTest.java | 2 - .../fileupload/ProgressListenerTest.java | 12 +- .../apache/commons/fileupload/SizesTest.java | 35 +- .../commons/fileupload/StreamingTest.java | 2 - .../{FileUploadTestCase.java => Util.java} | 36 +- .../portlet/MockPortletActionRequest.java | 271 ++++++++++++++ .../portlet/PortletFileUploadTest.java | 85 +++++ .../servlet/ServletFileUploadTest.java | 103 ++++++ 70 files changed, 1713 insertions(+), 1153 deletions(-) create mode 100644 .travis.yml create mode 100644 CONTRIBUTING.md create mode 100644 README.md delete mode 100644 build-gump.xml delete mode 100644 build.properties delete mode 100644 build.xml delete mode 100644 gump.xml create mode 100644 src/checkstyle/license-header.txt create mode 100644 src/site/resources/profile.cobertura create mode 100644 src/site/xdoc/security-reports.xml create mode 100644 src/test/java/org/apache/commons/fileupload/Constants.java create mode 100644 src/test/java/org/apache/commons/fileupload/DiskFileUploadTest.java rename src/test/java/org/apache/commons/fileupload/{ServletFileUploadTest.java => FileUploadTest.java} (78%) rename src/test/java/org/apache/commons/fileupload/{FileUploadTestCase.java => Util.java} (50%) create mode 100644 src/test/java/org/apache/commons/fileupload/portlet/MockPortletActionRequest.java create mode 100644 src/test/java/org/apache/commons/fileupload/portlet/PortletFileUploadTest.java create mode 100644 src/test/java/org/apache/commons/fileupload/servlet/ServletFileUploadTest.java diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2e8e6b9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,25 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +language: java +sudo: false + +jdk: + - openjdk7 + - oraclejdk8 + - oraclejdk9 + +after_success: + - mvn clean test jacoco:report coveralls:report -Ptravis-jacoco \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..34d8904 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,97 @@ +<!--- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<!--- + +======================================================================+ + |**** ****| + |**** THIS FILE IS GENERATED BY THE COMMONS BUILD PLUGIN ****| + |**** DO NOT EDIT DIRECTLY ****| + |**** ****| + +======================================================================+ + | TEMPLATE FILE: contributing-md-template.md | + | commons-build-plugin/trunk/src/main/resources/commons-xdoc-templates | + +======================================================================+ + | | + | 1) Re-generate using: mvn commons:contributing-md | + | | + | 2) Set the following properties in the component's pom: | + | - commons.jira.id (required, alphabetic, upper case) | + | | + | 3) Example Properties | + | | + | <properties> | + | <commons.jira.id>MATH</commons.jira.id> | + | </properties> | + | | + +======================================================================+ +---> +Contributing to Apache Commons FileUpload +====================== + +You have found a bug or you have an idea for a cool new feature? Contributing code is a great way to give something back to +the open source community. Before you dig right into the code there are a few guidelines that we need contributors to +follow so that we can have a chance of keeping on top of things. + +Getting Started +--------------- + ++ Make sure you have a [JIRA account](https://issues.apache.org/jira/). ++ Make sure you have a [GitHub account](https://github.com/signup/free). ++ If you're planning to implement a new feature it makes sense to discuss you're changes on the [dev list](https://commons.apache.org/mail-lists.html) first. This way you can make sure you're not wasting your time on something that isn't considered to be in Apache Commons FileUpload's scope. ++ Submit a ticket for your issue, assuming one does not already exist. + + Clearly describe the issue including steps to reproduce when it is a bug. + + Make sure you fill in the earliest version that you know has the issue. ++ Fork the repository on GitHub. + +Making Changes +-------------- + ++ Create a topic branch from where you want to base your work (this is usually the master/trunk branch). ++ Make commits of logical units. ++ Respect the original code style: + + Only use spaces for indentation. + + Create minimal diffs - disable on save actions like reformat source code or organize imports. If you feel the source code should be reformatted create a separate PR for this change. + + Check for unnecessary whitespace with git diff --check before committing. ++ Make sure your commit messages are in the proper format. Your commit message should contain the key of the JIRA issue. ++ Make sure you have added the necessary tests for your changes. ++ Run all the tests with `mvn clean verify` to assure nothing else was accidentally broken. + +Making Trivial Changes +---------------------- + +For changes of a trivial nature to comments and documentation, it is not always necessary to create a new ticket in JIRA. +In this case, it is appropriate to start the first line of a commit with '(doc)' instead of a ticket number. + +Submitting Changes +------------------ + ++ Sign the [Contributor License Agreement][cla] if you haven't already. ++ Push your changes to a topic branch in your fork of the repository. ++ Submit a pull request to the repository in the apache organization. ++ Update your JIRA ticket and include a link to the pull request in the ticket. + +Additional Resources +-------------------- + ++ [Contributing patches](https://commons.apache.org/patches.html) ++ [Apache Commons FileUpload JIRA project page](https://issues.apache.org/jira/browse/FILEUPLOAD) ++ [Contributor License Agreement][cla] ++ [General GitHub documentation](https://help.github.com/) ++ [GitHub pull request documentation](https://help.github.com/send-pull-requests/) ++ [Apache Commons Twitter Account](https://twitter.com/ApacheCommons) ++ #apachecommons IRC channel on freenode.org + +[cla]:https://www.apache.org/licenses/#clas diff --git a/NOTICE.txt b/NOTICE.txt index 5038a44..eb6f2fc 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,5 +1,5 @@ Apache Commons FileUpload -Copyright 2002-2017 The Apache Software Foundation +Copyright 2002-2018 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). diff --git a/README.md b/README.md new file mode 100644 index 0000000..0ef3cf6 --- /dev/null +++ b/README.md @@ -0,0 +1,104 @@ +<!--- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<!--- + +======================================================================+ + |**** ****| + |**** THIS FILE IS GENERATED BY THE COMMONS BUILD PLUGIN ****| + |**** DO NOT EDIT DIRECTLY ****| + |**** ****| + +======================================================================+ + | TEMPLATE FILE: readme-md-template.md | + | commons-build-plugin/trunk/src/main/resources/commons-xdoc-templates | + +======================================================================+ + | | + | 1) Re-generate using: mvn commons:readme-md | + | | + | 2) Set the following properties in the component's pom: | + | - commons.componentid (required, alphabetic, lower case) | + | - commons.release.version (required) | + | | + | 3) Example Properties | + | | + | <properties> | + | <commons.componentid>math</commons.componentid> | + | <commons.release.version>1.2</commons.release.version> | + | </properties> | + | | + +======================================================================+ +---> +Apache Commons FileUpload +=================== + +[](https://travis-ci.org/apache/commons-fileupload) +[](https://maven-badges.herokuapp.com/maven-central/commons-fileupload/commons-fileupload/) + +The Apache Commons FileUpload component provides a simple yet flexible means of adding support for multipart + file upload functionality to servlets and web applications. + +Documentation +------------- + +More information can be found on the [Apache Commons FileUpload homepage](https://commons.apache.org/proper/commons-fileupload). +The [Javadoc](https://commons.apache.org/proper/commons-fileupload/javadocs/api-release) can be browsed. +Questions related to the usage of Apache Commons FileUpload should be posted to the [user mailing list][ml]. + +Where can I get the latest release? +----------------------------------- +You can download source and binaries from our [download page](https://commons.apache.org/proper/commons-fileupload/download_fileupload.cgi). + +Alternatively you can pull it from the central Maven repositories: + +```xml +<dependency> + <groupId>commons-fileupload</groupId> + <artifactId>commons-fileupload</artifactId> + <version>1.4</version> +</dependency> +``` + +Contributing +------------ + +We accept Pull Requests via GitHub. The [developer mailing list][ml] is the main channel of communication for contributors. +There are some guidelines which will make applying PRs easier for us: ++ No tabs! Please use spaces for indentation. ++ Respect the code style. ++ Create minimal diffs - disable on save actions like reformat source code or organize imports. If you feel the source code should be reformatted create a separate PR for this change. ++ Provide JUnit tests for your changes and make sure your changes don't break any existing tests by running ```mvn clean test```. + +If you plan to contribute on a regular basis, please consider filing a [contributor license agreement](https://www.apache.org/licenses/#clas). +You can learn more about contributing via GitHub in our [contribution guidelines](CONTRIBUTING.md). + +License +------- +This code is under the [Apache Licence v2](https://www.apache.org/licenses/LICENSE-2.0). + +See the `NOTICE.txt` file for required notices and attributions. + +Donations +--------- +You like Apache Commons FileUpload? Then [donate back to the ASF](https://www.apache.org/foundation/contributing.html) to support the development. + +Additional Resources +-------------------- + ++ [Apache Commons Homepage](https://commons.apache.org/) ++ [Apache Issue Tracker (JIRA)](https://issues.apache.org/jira/browse/FILEUPLOAD) ++ [Apache Commons Twitter Account](https://twitter.com/ApacheCommons) ++ `#apache-commons` IRC channel on `irc.freenode.org` + +[ml]:https://commons.apache.org/mail-lists.html diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index ac7e3c1..3d7495e 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,3 +1,48 @@ + Apache Commons FileUpload 1.4 RELEASE NOTES + +The Apache Commons FileUpload team is pleased to announce the release of Apache Commons FileUpload 1.4. + +The Apache Commons FileUpload component provides a simple yet flexible means of +adding support for multipart file upload functionality to servlets and web +applications. Version 1.3 onwards requires Java 6 or later. + +No client code changes are required to migrate from version 1.3.0 to 1.3.1. + + +1.4 Release + +Changes in version 1.4 include: + +New features: +o Site: added security report + +Fixed Bugs: +o FILEUPLOAD-252: DiskFileItem#write() could lose original IO exception +o FILEUPLOAD-258: DiskFileItem#getStoreLocation() wrongly returned a File object for items stored in memory +o FILEUPLOAD-242: FileUploadBase - should not silently catch and ignore all Throwables +o FILEUPLOAD-257: Fix Javadoc 1.8.0 errors +o FILEUPLOAD-234: Fix section "Resource cleanup" of the user guide +o FILEUPLOAD-237: Fix streaming example: use FileItem.getInputStream() instead of openStream() +o FILEUPLOAD-248: DiskFileItem might suppress critical IOExceptions on rename - use FileUtil.move instead +o FILEUPLOAD-251: DiskFileItem#getTempFile() is broken +o FILEUPLOAD-250: FileUploadBase - potential resource leak - InputStream not closed on exception +o FILEUPLOAD-244: DiskFileItem.readObject fails to close FileInputStream +o FILEUPLOAD-245: DiskFileItem.get() may not fully read the data + +Changes: +o FILEUPLOAD-292: Don't create un-needed resources in FileUploadBase.java +o FILEUPLOAD-282: Upversion complier.source, compiler.target to 1.6 +o FILEUPLOAD-246: FileUpload should use IOUtils.closeQuietly where relevant +o FILEUPLOAD-243: Make some MultipartStream private fields final Thanks to Ville Skytt�. + + +For complete information on Apache Commons FileUpload, including instructions on how to submit bug reports, +patches, or suggestions for improvement, see the Apache Apache Commons FileUpload website: + +http://commons.apache.org/proper/commons-fileupload/ + +------------------------------------------------------------------------------ + Apache Commons FileUpload 1.3.3 RELEASE NOTES The Apache Commons FileUpload team is pleased to announce the release of Apache Commons FileUpload 1.3.3. @@ -13,6 +58,20 @@ Changes in version 1.3.3 include: o FILEUPLOAD-279: DiskFileItem can no longer be deserialized, unless a particular system property is set. +For complete information on Apache Commons FileUpload, including instructions on how to submit bug reports, +patches, or suggestions for improvement, see the Apache Apache Commons FileUpload website: + +http://commons.apache.org/proper/commons-fileupload/ + +------------------------------------------------------------------------------ + +No client code changes are required to migrate from version 1.3.1 to 1.3.2. + +Changes in version 1.3.2 include: + +o FILEUPLOAD-272: Performance Improvement in MultipartStream. Prevents a DoS (CVE-2016-3092) + + For complete information on Apache Commons FileUpload, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Apache Commons FileUpload website: diff --git a/build-gump.xml b/build-gump.xml deleted file mode 100644 index 8b355d4..0000000 --- a/build-gump.xml +++ /dev/null @@ -1,51 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<!-- - - WARNING: This file is generated! Do not edit by hand! - ---> -<project name="maven" default="jar" basedir="."> - - <target name="jar"> - - <property name="maven.build.dir" value="target" /> - <property name="maven.build.dest" value="${maven.build.dir}/classes" /> - - <mkdir dir="${maven.build.dest}" /> - - <javac - destdir="${maven.build.dest}" - excludes="**/package.html" - debug="false" - deprecation="false" - optimize="false"> - <src> - <pathelement location="src/java" /> - </src> - </javac> - - <jar - jarfile="${maven.build.dir}/${maven.final.name}.jar" - basedir="${maven.build.dest}" - excludes="**/package.html" - /> - - </target> - -</project> diff --git a/build.properties b/build.properties deleted file mode 100644 index 6325561..0000000 --- a/build.properties +++ /dev/null @@ -1,93 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -#Generated by Maven Ant Plugin - DO NOT EDIT THIS FILE! -#Fri Mar 08 12:53:27 CET 2013 -commons.compiler.compilerVersion= -maven.compile.source=1.5 -commons.release.2.name=commons-fileupload-${commons.release.2.version} -commons.release.desc= -maven.build.srcDir.0=src/main/java -commons.binary.suffix=-bin -commons.manifestfile=${maven.build.outputDir}/osgi/MANIFEST.MF -maven.build.timestamp.format=yyyy-MM-dd HH\:mm\:ssZ -commons.project-info.version=2.6 -maven.build.resourceDir.1=. -maven.build.resourceDir.0=src/main/resources -project.build.sourceEncoding=iso-8859-1 -sourceReleaseAssemblyDescriptor=source-release -commons.release.3.name=commons-fileupload-${commons.release.3.version} -maven.build.outputDir=${maven.build.dir}/classes -commons.componentid=fileupload -commons.site.path=commons-fileupload -maven.repo.local=${user.home}/.m2/repository -maven.build.finalName=commons-fileupload-1.3-SNAPSHOT -commons.osgi.private= -maven.build.testDir.0=src/test/java -commons.javadoc.javaee.link=http\://download.oracle.com/javaee/6/api/ -commons.osgi.export=org.apache.commons.*;version\=1.3-SNAPSHOT;-noimport\:\=true -commons.release.2.binary.suffix=-bin -maven.reporting.outputDirectory=${maven.build.dir}/site -commons.compiler.javac= -commons.encoding=iso-8859-1 -organization.logo=http\://www.apache.org/images/asf_logo_wide.gif -commons.scmPubUrl=https\://svn.apache.org/repos/infra/websites/production/commons/content/proper/commons-fileupload -sonar.host.url=https\://analysis.apache.org/ -commons.rc.version=RC1 -commons.cobertura.version=2.5.2 -commons.release.name=commons-fileupload-1.3 -minSeverity=info -maven.build.testOutputDir=${maven.build.dir}/test-classes -project.reporting.outputEncoding=iso-8859-1 -maven.build.dir=target -maven.test.reports=${maven.build.dir}/test-reports -gpg.useagent=true -commons.javadoc.version=2.9 -commons.surefire.version=2.13 -commons.changes.version=2.8 -commons.release.version=1.3 -commons.jxr.version=2.3 -commons.surefire-report.version=2.13 -commons.rat.version=0.8 -commons.site.cache=/Users/stripodi/commons-sites -project.build.outputDirectory=${maven.build.outputDir} -commons.docEncoding=iso-8859-1 -commons.javadoc.java.link=http\://download.oracle.com/javase/6/docs/api/ -commons.deployment.protocol=scp -maven.settings.offline=false -distMgmtSnapshotsName=Apache Development Snapshot Repository -maven.settings.interactiveMode=true -maven.compile.target=1.5 -commons.release.2.desc= -commons.jira.pid=12310476 -project.build.directory=${maven.build.dir} -arguments= -commons.surefire-report.aggregate=false -commons.release.3.binary.suffix=-bin -commons.wagon-ssh.version=2.3 -distMgmtSnapshotsUrl=https\://repository.apache.org/content/repositories/snapshots -maven.build.testResourceDir.1=. -maven.build.testResourceDir.0=src/test/resources -commons.osgi.dynamicImport=javax.portlet -commons.compiler.fork=false -commons.jdepend.version=2.0-beta-2 -commons.release.3.desc= -implementation.build=${scmBranch}@r${buildNumber}; 2013-03-08 12\:53\:21+0100 -commons.site-plugin.version=3.2 -commons.osgi.symbolicName=org.apache.commons.fileupload -commons.surefire.java= -commons.osgi.import=\!javax.portlet,* -commons.jira.id=FILEUPLOAD -commons.clirr.version=2.5 diff --git a/build.xml b/build.xml deleted file mode 100644 index b207f76..0000000 --- a/build.xml +++ /dev/null @@ -1,332 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<!-- ====================================================================== --> -<!-- Ant build file (http://ant.apache.org/) for Ant 1.6.2 or above. --> -<!-- ====================================================================== --> - -<!-- ====================================================================== --> -<!-- ===================== - DO NOT EDIT THIS FILE! - ===================== --> -<!-- ====================================================================== --> -<!-- --> -<!-- Any modifications will be overwritten. --> -<!-- --> -<!-- Generated by Maven Ant Plugin on 3/8/13 12:53 PM --> -<!-- See: http://maven.apache.org/plugins/maven-ant-plugin/ --> -<!-- --> -<!-- ====================================================================== --> - -<project name="commons-fileupload-from-maven" default="package" basedir="."> - - <!-- ====================================================================== --> - <!-- Build environment properties --> - <!-- ====================================================================== --> - - <property file="${user.home}/.m2/maven.properties"/> - <property file="build.properties"/> - - <property name="maven.build.finalName" value="commons-fileupload-1.3-SNAPSHOT"/> - <property name="maven.build.dir" value="target"/> - <property name="maven.build.outputDir" value="${maven.build.dir}/classes"/> - <property name="maven.build.srcDir.0" value="src/main/java"/> - <property name="maven.build.resourceDir.0" value="src/main/resources"/> - <property name="maven.build.resourceDir.1" value="."/> - <property name="maven.build.testOutputDir" value="${maven.build.dir}/test-classes"/> - <property name="maven.build.testDir.0" value="src/test/java"/> - <property name="maven.build.testResourceDir.0" value="src/test/resources"/> - <property name="maven.build.testResourceDir.1" value="."/> - <property name="maven.test.reports" value="${maven.build.dir}/test-reports"/> - <property name="maven.reporting.outputDirectory" value="${maven.build.dir}/site"/> - - <property name="maven.repo.local" value="${user.home}/.m2/repository"/> - <property name="maven.settings.offline" value="false"/> - <property name="maven.settings.interactiveMode" value="true"/> - - <!-- ====================================================================== --> - <!-- Defining classpaths --> - <!-- ====================================================================== --> - - <path id="build.classpath"> - <pathelement location="${maven.repo.local}/javax/servlet/servlet-api/2.4/servlet-api-2.4.jar"/> - <pathelement location="${maven.repo.local}/portlet-api/portlet-api/1.0/portlet-api-1.0.jar"/> - <pathelement location="${maven.repo.local}/commons-io/commons-io/2.2/commons-io-2.2.jar"/> - </path> - <path id="build.test.classpath"> - <pathelement location="${maven.repo.local}/junit/junit/4.11/junit-4.11.jar"/> - <pathelement location="${maven.repo.local}/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar"/> - <pathelement location="${maven.repo.local}/javax/servlet/servlet-api/2.4/servlet-api-2.4.jar"/> - <pathelement location="${maven.repo.local}/portlet-api/portlet-api/1.0/portlet-api-1.0.jar"/> - <pathelement location="${maven.repo.local}/commons-io/commons-io/2.2/commons-io-2.2.jar"/> - </path> - - <!-- ====================================================================== --> - <!-- Cleaning up target --> - <!-- ====================================================================== --> - - <target name="clean" description="Clean the output directory"> - <delete dir="${maven.build.dir}"/> - </target> - - <!-- ====================================================================== --> - <!-- Compilation target --> - <!-- ====================================================================== --> - - <target name="compile" depends="get-deps" description="Compile the code"> - <mkdir dir="${maven.build.outputDir}"/> - <javac destdir="${maven.build.outputDir}" - encoding="iso-8859-1" - nowarn="false" - debug="true" - optimize="false" - deprecation="true" - target="1.5" - verbose="false" - fork="false" - source="1.5"> - <src> - <pathelement location="${maven.build.srcDir.0}"/> - </src> - <classpath refid="build.classpath"/> - </javac> - <mkdir dir="${maven.build.outputDir}/META-INF"/> - <copy todir="${maven.build.outputDir}/META-INF"> - <fileset dir="${maven.build.resourceDir.1}"> - <include name="NOTICE.txt"/> - <include name="LICENSE.txt"/> - </fileset> - </copy> - </target> - - <!-- ====================================================================== --> - <!-- Test-compilation target --> - <!-- ====================================================================== --> - - <target name="compile-tests" - depends="compile" - description="Compile the test code" - unless="maven.test.skip"> - <mkdir dir="${maven.build.testOutputDir}"/> - <javac destdir="${maven.build.testOutputDir}" - encoding="iso-8859-1" - nowarn="false" - debug="true" - optimize="false" - deprecation="true" - target="1.5" - verbose="false" - fork="false" - source="1.5"> - <src> - <pathelement location="${maven.build.testDir.0}"/> - </src> - <classpath> - <path refid="build.test.classpath"/> - <pathelement location="${maven.build.outputDir}"/> - </classpath> - </javac> - <mkdir dir="${maven.build.testOutputDir}/META-INF"/> - <copy todir="${maven.build.testOutputDir}/META-INF"> - <fileset dir="${maven.build.testResourceDir.1}"> - <include name="NOTICE.txt"/> - <include name="LICENSE.txt"/> - </fileset> - </copy> - </target> - - <!-- ====================================================================== --> - <!-- Run all tests --> - <!-- ====================================================================== --> - - <target name="test" - depends="compile-tests, junit-missing" - unless="junit.skipped" - description="Run the test cases"> - <mkdir dir="${maven.test.reports}"/> - <junit printSummary="yes" haltonerror="true" haltonfailure="true" fork="true" dir="."> - <sysproperty key="basedir" value="."/> - <formatter type="xml"/> - <formatter type="plain" usefile="false"/> - <classpath> - <path refid="build.test.classpath"/> - <pathelement location="${maven.build.outputDir}"/> - <pathelement location="${maven.build.testOutputDir}"/> - </classpath> - <batchtest todir="${maven.test.reports}" unless="test"> - <fileset dir="${maven.build.testDir.0}"> - <include name="**/Test*.java"/> - <include name="**/*Test.java"/> - <include name="**/*TestCase.java"/> - <exclude name="**/*Abstract*Test.java"/> - </fileset> - </batchtest> - <batchtest todir="${maven.test.reports}" if="test"> - <fileset dir="${maven.build.testDir.0}"> - <include name="**/${test}.java"/> - <exclude name="**/*Abstract*Test.java"/> - </fileset> - </batchtest> - </junit> - </target> - - <target name="test-junit-present"> - <available classname="junit.framework.Test" property="junit.present"/> - </target> - - <target name="test-junit-status" - depends="test-junit-present"> - <condition property="junit.missing"> - <and> - <isfalse value="${junit.present}"/> - <isfalse value="${maven.test.skip}"/> - </and> - </condition> - <condition property="junit.skipped"> - <or> - <isfalse value="${junit.present}"/> - <istrue value="${maven.test.skip}"/> - </or> - </condition> - </target> - - <target name="junit-missing" - depends="test-junit-status" - if="junit.missing"> - <echo>=================================== WARNING ===================================</echo> - <echo> JUnit is not present in your $ANT_HOME/lib directory. Tests not executed.</echo> - <echo>===============================================================================</echo> - </target> - - <!-- ====================================================================== --> - <!-- Javadoc target --> - <!-- ====================================================================== --> - - <target name="javadoc" description="Generates the Javadoc of the application"> - <javadoc sourcepath="${maven.build.srcDir.0}" - packagenames="*" - destdir="${maven.reporting.outputDirectory}/apidocs" - access="protected" - old="false" - verbose="false" - encoding="iso-8859-1" - version="true" - use="true" - author="true" - splitindex="false" - nodeprecated="false" - nodeprecatedlist="false" - notree="false" - noindex="false" - nohelp="false" - nonavbar="false" - serialwarn="false" - charset="ISO-8859-1" - docencoding="iso-8859-1" - source="1.5" - linksource="true" - breakiterator="false"> - <link href="http://download.oracle.com/javase/6/docs/api/"/> - <link href="http://download.oracle.com/javaee/6/api/"/> - </javadoc> - </target> - - <!-- ====================================================================== --> - <!-- Package target --> - <!-- ====================================================================== --> - - <target name="package" depends="compile,test" description="Package the application"> - <jar jarfile="${maven.build.dir}/${maven.build.finalName}.jar" - compress="true" - index="false" - manifest="${commons.manifestfile}" - basedir="${maven.build.outputDir}" - excludes="**/package.html"> - <manifest> - <attribute name="Main-Class"/> - </manifest> - </jar> - </target> - - <!-- ====================================================================== --> - <!-- A dummy target for the package named after the type it creates --> - <!-- ====================================================================== --> - - <target name="jar" depends="package" description="Builds the jar for the application"/> - - <!-- ====================================================================== --> - <!-- Download dependencies target --> - <!-- ====================================================================== --> - - <target name="test-offline"> - <condition property="maven.mode.offline"> - <equals arg1="${maven.settings.offline}" arg2="true"/> - </condition> - </target> - - <target name="get-deps" - depends="test-offline" - description="Download all dependencies" - unless="maven.mode.offline"> - <mkdir dir="${maven.repo.local}"/> - <mkdir dir="${maven.repo.local}/junit/junit/4.11"/> - <get src="http://repository.apache.org/snapshots/junit/junit/4.11/junit-4.11.jar" - dest="${maven.repo.local}/junit/junit/4.11/junit-4.11.jar" - usetimestamp="false" - ignoreerrors="true"/> - <get src="http://repo.maven.apache.org/maven2/junit/junit/4.11/junit-4.11.jar" - dest="${maven.repo.local}/junit/junit/4.11/junit-4.11.jar" - usetimestamp="false" - ignoreerrors="true"/> - <mkdir dir="${maven.repo.local}/org/hamcrest/hamcrest-core/1.3"/> - <get src="http://repository.apache.org/snapshots/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" - dest="${maven.repo.local}/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" - usetimestamp="false" - ignoreerrors="true"/> - <get src="http://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" - dest="${maven.repo.local}/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" - usetimestamp="false" - ignoreerrors="true"/> - <mkdir dir="${maven.repo.local}/javax/servlet/servlet-api/2.4"/> - <get src="http://repository.apache.org/snapshots/javax/servlet/servlet-api/2.4/servlet-api-2.4.jar" - dest="${maven.repo.local}/javax/servlet/servlet-api/2.4/servlet-api-2.4.jar" - usetimestamp="false" - ignoreerrors="true"/> - <get src="http://repo.maven.apache.org/maven2/javax/servlet/servlet-api/2.4/servlet-api-2.4.jar" - dest="${maven.repo.local}/javax/servlet/servlet-api/2.4/servlet-api-2.4.jar" - usetimestamp="false" - ignoreerrors="true"/> - <mkdir dir="${maven.repo.local}/portlet-api/portlet-api/1.0"/> - <get src="http://repository.apache.org/snapshots/portlet-api/portlet-api/1.0/portlet-api-1.0.jar" - dest="${maven.repo.local}/portlet-api/portlet-api/1.0/portlet-api-1.0.jar" - usetimestamp="false" - ignoreerrors="true"/> - <get src="http://repo.maven.apache.org/maven2/portlet-api/portlet-api/1.0/portlet-api-1.0.jar" - dest="${maven.repo.local}/portlet-api/portlet-api/1.0/portlet-api-1.0.jar" - usetimestamp="false" - ignoreerrors="true"/> - <mkdir dir="${maven.repo.local}/commons-io/commons-io/2.2"/> - <get src="http://repository.apache.org/snapshots/commons-io/commons-io/2.2/commons-io-2.2.jar" - dest="${maven.repo.local}/commons-io/commons-io/2.2/commons-io-2.2.jar" - usetimestamp="false" - ignoreerrors="true"/> - <get src="http://repo.maven.apache.org/maven2/commons-io/commons-io/2.2/commons-io-2.2.jar" - dest="${maven.repo.local}/commons-io/commons-io/2.2/commons-io-2.2.jar" - usetimestamp="false" - ignoreerrors="true"/> - </target> - -</project> diff --git a/gump.xml b/gump.xml deleted file mode 100644 index 172c0ce..0000000 --- a/gump.xml +++ /dev/null @@ -1,53 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<module name="commons-fileupload"> - - <description>File upload component.</description> - <url href="http://commons.apache.org/fileupload/" /> - - <cvs repository="jakarta" /> - - <!-- This is really the cvs module. We need to change this but --> - <!-- I will leave this for now until everything works. --> - - <project name="commons-fileupload"> - <!-- Standard Maven target to produce Javadocs, source --> - <!-- and binary distributions. --> - <ant buildfile="build-gump.xml" target="jar"> - <property name="maven.final.name" value="commons-fileupload-@@DATE@@" /> - </ant> - - <package>org.apache.commons.fileupload</package> - - <!-- All Maven projects need Ant and Xerces to build. --> - <depend project="jakarta-ant" inherit="runtime" /> - <depend project="xml-xerces" /> - - <depend project="jaf" /> - <depend project="servletapi" /> - - <work nested="target/classes" /> - <home nested="target" /> - <jar name="commons-fileupload-@@DATE@@.jar" /> - <javadoc nested="docs/apidocs" /> - - <nag from="Maven Developers <turbine-maven-dev@jakarta.apache.org>" - to="dev@commons.apache.org" /> - </project> - -</module> diff --git a/pom.xml b/pom.xml index 154f19c..d883abd 100644 --- a/pom.xml +++ b/pom.xml @@ -21,12 +21,12 @@ <parent> <groupId>org.apache.commons</groupId> <artifactId>commons-parent</artifactId> - <version>41</version> + <version>47</version> </parent> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> - <version>1.3.3</version> + <version>1.4</version> <name>Apache Commons FileUpload</name> <description> @@ -101,7 +101,6 @@ <name>Rob Tompkins</name> <id>chtompki</id> <email>chtompki@apache.org</email> - <organization /> </developer> </developers> @@ -154,6 +153,10 @@ <name>frank</name> <email>mailsurfie@gmail.com</email> </contributor> + <contributor> + <name>maxxedev</name> + <email>maxxedev@gmail.com</email> + </contributor> <contributor> <name>Rafal Krzewski</name> <email>Rafal.Krzewski@e-point.pl</email> @@ -170,32 +173,55 @@ <name>David Sean Taylor</name> <email>taylor@apache.org</email> </contributor> + <contributor> + <name>fangwentong</name> + <email>fangwentong2012@gmail.com</email> + </contributor> </contributors> <scm> <connection>scm:git:http://git-wip-us.apache.org/repos/asf/commons-fileupload.git</connection> <developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/commons-fileupload.git</developerConnection> <url>https://git-wip-us.apache.org/repos/asf?p=commons-fileupload.git</url> - <tag>commons-fileupload-1.3.3-RC6</tag> </scm> <issueManagement> <system>jira</system> <url>http://issues.apache.org/jira/browse/FILEUPLOAD</url> </issueManagement> + <distributionManagement> + <site> + <id>apache.website</id> + <name>Apache Commons Site</name> + <url>scm:svn:https://svn.apache.org/repos/infra/websites/production/commons/content/proper/commons-fileupload/</url> + </site> + </distributionManagement> + <properties> - <maven.compiler.source>1.5</maven.compiler.source> - <maven.compiler.target>1.5</maven.compiler.target> - <maven.compile.encoding>ISO-8859-1</maven.compile.encoding> + <maven.compiler.source>1.6</maven.compiler.source> + <maven.compiler.target>1.6</maven.compiler.target> <commons.componentid>fileupload</commons.componentid> - <commons.release.version>1.3.3</commons.release.version> - <commons.rc.version>RC1</commons.rc.version> + <commons.module.name>org.apache.commons.fileupload</commons.module.name> + <commons.release.desc>(requires Java ${maven.compiler.target} or later)</commons.release.desc> <commons.jira.id>FILEUPLOAD</commons.jira.id> <commons.jira.pid>12310476</commons.jira.pid> + <commons.site.path>fileupload</commons.site.path> + <commons.scmPubUrl>https://svn.apache.org/repos/infra/websites/production/commons/content/proper/commons-fileupload</commons.scmPubUrl> + <commons.scmPubCheckoutDirectory>site-content</commons.scmPubCheckoutDirectory> <commons.osgi.export>!org.apache.commons.fileupload.util.mime,org.apache.commons.*;version=${project.version};-noimport:=true</commons.osgi.export> <commons.osgi.import>!javax.portlet,*</commons.osgi.import> <commons.osgi.dynamicImport>javax.portlet</commons.osgi.dynamicImport> - <project.scm.id>git-wip-us.apache.org</project.scm.id> + <commons.japicmp.version>0.13.0</commons.japicmp.version> + <japicmp.skip>true</japicmp.skip> + + <!-- Commons Release Plugin --> + <commons.release.version>1.4</commons.release.version> + <commons.bc.version>1.3.3</commons.bc.version> + <commons.rc.version>RC2</commons.rc.version> + <commons.release.isDistModule>true</commons.release.isDistModule> + <commons.distSvnStagingUrl>scm:svn:https://dist.apache.org/repos/dist/dev/commons/${commons.componentid}</commons.distSvnStagingUrl> + <commons.releaseManagerName>Rob Tompkins</commons.releaseManagerName> + <commons.releaseManagerKey>B6E73D84EA4FCC47166087253FAAD2CD5ECBB314</commons.releaseManagerKey> </properties> <dependencies> @@ -245,44 +271,64 @@ </plugin> </plugins> <pluginManagement> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-release-plugin</artifactId> - <configuration> - <tagBase>https://svn.apache.org/repos/asf/commons/proper/fileupload/tags</tagBase> - </configuration> - </plugin> - <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.--> - <plugin> - <groupId>org.eclipse.m2e</groupId> - <artifactId>lifecycle-mapping</artifactId> - <version>1.0.0</version> - <configuration> - <lifecycleMappingMetadata> - <pluginExecutions> - <pluginExecution> - <pluginExecutionFilter> - <groupId> - org.apache.maven.plugins - </groupId> - <artifactId> - maven-antrun-plugin - </artifactId> - <versionRange>[1.7,)</versionRange> - <goals> - <goal>run</goal> - </goals> - </pluginExecutionFilter> - <action> - <ignore /> - </action> - </pluginExecution> - </pluginExecutions> - </lifecycleMappingMetadata> - </configuration> - </plugin> - </plugins> + <plugins> + <plugin> + <groupId>org.apache.rat</groupId> + <artifactId>apache-rat-plugin</artifactId> + <configuration> + <excludes> + <exclude>site-content/**</exclude> + <exclude>src/site/resources/download_lang.cgi</exclude> + <exclude>src/checkstyle/license-header.txt</exclude> + </excludes> + </configuration> + </plugin><!-- override skip property of parent pom --> + <plugin> + <groupId>com.github.siom79.japicmp</groupId> + <artifactId>japicmp-maven-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.--> + <plugin> + <groupId>org.eclipse.m2e</groupId> + <artifactId>lifecycle-mapping</artifactId> + <version>1.0.0</version> + <configuration> + <lifecycleMappingMetadata> + <pluginExecutions> + <pluginExecution> + <pluginExecutionFilter> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-antrun-plugin</artifactId> + <versionRange>[1.8,)</versionRange> + <goals> + <goal>run</goal> + </goals> + </pluginExecutionFilter> + <action> + <execute/> + </action> + </pluginExecution> + <pluginExecution> + <pluginExecutionFilter> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <versionRange>[1.10,)</versionRange> + <goals> + <goal>parse-version</goal> + </goals> + </pluginExecutionFilter> + <action> + <execute/> + </action> + </pluginExecution> + </pluginExecutions> + </lifecycleMappingMetadata> + </configuration> + </plugin> + </plugins> </pluginManagement> </build> @@ -312,6 +358,7 @@ <configLocation>${basedir}/src/checkstyle/fileupload_checks.xml</configLocation> <suppressionsLocation>${basedir}/src/checkstyle/checkstyle-suppressions.xml</suppressionsLocation> <enableRulesSummary>false</enableRulesSummary> + <headerLocation>${basedir}/src/checkstyle/license-header.txt</headerLocation> </configuration> </plugin> <plugin> @@ -330,9 +377,71 @@ <artifactId>clirr-maven-plugin</artifactId> <version>${commons.clirr.version}</version> <configuration> - <comparisonVersion>1.3</comparisonVersion> + <comparisonArtifacts> + <comparisonArtifact> + <groupId>commons-fileupload</groupId> + <artifactId>commons-fileupload</artifactId> + <version>1.3</version> + </comparisonArtifact> + </comparisonArtifacts> </configuration> </plugin> </plugins> </reporting> + + <profiles> + <profile> + <id>setup-checkout</id> + <activation> + <file> + <missing>site-content</missing> + </file> + </activation> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-antrun-plugin</artifactId> + <executions> + <execution> + <id>prepare-checkout</id> + <phase>pre-site</phase> + <goals> + <goal>run</goal> + </goals> + <configuration> + <tasks> + <exec executable="svn"> + <arg line="checkout --depth immediates ${commons.scmPubUrl} ${commons.scmPubCheckoutDirectory}"/> + </exec> + + <exec executable="svn"> + <arg line="update --set-depth exclude ${commons.scmPubCheckoutDirectory}/javadocs"/> + </exec> + + <pathconvert pathsep=" " property="dirs"> + <dirset dir="${commons.scmPubCheckoutDirectory}" includes="*"/> + </pathconvert> + <exec executable="svn"> + <arg line="update --set-depth infinity ${dirs}"/> + </exec> + </tasks> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>java9</id> + <activation> + <jdk>9</jdk> + </activation> + <properties> + <!-- coverall version 4.3.0 does not work with java 9, see https://github.com/trautonen/coveralls-maven-plugin/issues/112 --> + <coveralls.skip>true</coveralls.skip> + </properties> + </profile> + </profiles> </project> diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 73f2613..4522eee 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -39,11 +39,34 @@ The <action> type attribute can be add,update,fix,remove. <properties> <title>Release Notes</title> - <author email="martinc@apache.org">Martin Cooper</author> + <author email="dev@commons.apache.org">Apache Commons Developers</author> </properties> <body> - <release version="1.3.3" description="Bugfix release for 1.3.2" date="tba"> + <release version="1.4" date="2018-12-23" description="1.4 Release"> + <action issue="FILEUPLOAD-292" dev="chtompki" type="update">Don't create un-needed resources in FileUploadBase.java</action> + <action issue="FILEUPLOAD-282" dev="chtompki" type="update">Upversion complier.source, compiler.target to 1.6</action> + <action issue="FILEUPLOAD-252" dev="tn" type="fix">DiskFileItem#write() could lose original IO exception</action> + <action issue="FILEUPLOAD-258" dev="tn" type="fix">DiskFileItem#getStoreLocation() wrongly returned a File object for items stored in memory</action> + <action issue="FILEUPLOAD-242" dev="tn" type="fix">FileUploadBase - should not silently catch and ignore all Throwables</action> + <action issue="FILEUPLOAD-257" dev="tn" type="fix">Fix Javadoc 1.8.0 errors</action> + <action issue="FILEUPLOAD-234" dev="tn" type="fix">Fix section "Resource cleanup" of the user guide</action> + <action issue="FILEUPLOAD-237" dev="tn" type="fix">Fix streaming example: use FileItem.getInputStream() instead of openStream()</action> + <action issue="FILEUPLOAD-248" dev="ecki" type="fix">DiskFileItem might suppress critical IOExceptions on rename - use FileUtil.move instead</action> + <action issue="FILEUPLOAD-251" dev="sebb" type="fix">DiskFileItem#getTempFile() is broken</action> + <action issue="FILEUPLOAD-250" dev="sebb" type="fix">FileUploadBase - potential resource leak - InputStream not closed on exception</action> + <action issue="FILEUPLOAD-244" dev="sebb" type="fix">DiskFileItem.readObject fails to close FileInputStream</action> + <action issue="FILEUPLOAD-246" dev="sebb" type="update">FileUpload should use IOUtils.closeQuietly where relevant</action> + <action issue="FILEUPLOAD-245" dev="sebb" type="fix">DiskFileItem.get() may not fully read the data</action> + <action issue="FILEUPLOAD-243" dev="sebb" type="update" due-to="Ville Skyttä">Make some MultipartStream private fields final</action> + <action dev="ecki" type="add">Site: added security report</action> + <action dev="markt" due-to="Felix Schumacher">Improve performance for large multi-part boundaries</action> + <action issue="FILEUPLOAD-286" dev="jochen" due-to="maxxedev" due-to-email="maxxedev@gmail.com">Added the default character set to the DiskFileItem.</action> + <action issue="FILEUPLOAD-288" dev="jochen" due-to="fangwentong" due-to-email="fangwentong2012@gmail.com">Avoid using File.exists() on temporary files, if we know that the file has been created.</action> + <action dev="jochen" due-to="Pascal Schumacher">Added .travis.yml, to fix build issues on Github.</action> + </release> + + <release version="1.3.3" description="Bugfix release for 1.3.3" date="2017-06-13"> <action issue="FILEUPLOAD-279" dev="jochen" type="fix"> DiskDileItem can actually no longer be deserialized, unless a system property is set to true. </action> @@ -51,10 +74,19 @@ The <action> type attribute can be add,update,fix,remove. <release version="1.3.2" description="Bugfix release for 1.3.1" date="2016.05-26"> <action issue="FILEUPLOAD-272" dev="jochen" type="update"> - Performance Improvement in MultipartStream + SECURITY - CVE-2016-3092. Performance Improvement in MultipartStream. </action> </release> + <release version="1.3.2" description= +"This is a security and maintenance release that includes an important security +fix as well. Compared to 1.3.1, no other changes have been made." date="2014-02-07"> + <action dev="jochen" type="fix"> + SECURITY - CVE-2016-3092. Specially crafted input can trigger a DoS, if the + size of the MIME boundard is close to the size of the buffer in MultipartStream. + (Similar to CVE-2014-0050.) + </action> + </release> <release version="1.3.1" description= "This is a security and maintenance release that includes an important security fix as well as a small number of bugfixes." date="2014-02-07"> diff --git a/src/changes/release-notes.vm b/src/changes/release-notes.vm index 5b2f547..32157c4 100644 --- a/src/changes/release-notes.vm +++ b/src/changes/release-notes.vm @@ -20,9 +20,9 @@ The ${developmentTeam} is pleased to announce the release of ${project.name} ${v The Apache Commons FileUpload component provides a simple yet flexible means of adding support for multipart file upload functionality to servlets and web -applications. Version 1.3 onwards requires Java 5 or later. +applications. Version 1.3 onwards requires Java 6 or later. -No client code changes are required to migrate from version 1.3.0, 1.3.1, or 1.3.2 to 1.3.3. +No client code changes are required to migrate from version 1.3.0 to 1.3.1. ## N.B. the available variables are described here: diff --git a/src/checkstyle/fileupload_checks.xml b/src/checkstyle/fileupload_checks.xml index 77699c3..b49a4f4 100644 --- a/src/checkstyle/fileupload_checks.xml +++ b/src/checkstyle/fileupload_checks.xml @@ -74,6 +74,12 @@ <!-- See http://checkstyle.sf.net/config_misc.html#Translation --> <module name="Translation"/> + <!-- Following interprets the header file as regular expressions. --> + <!-- <module name="RegexpHeader"/> --> + <module name="RegexpHeader"> + <property name="headerFile" value="${checkstyle.header.file}"/> + </module> + <!-- Checks for Size Violations. --> <!-- See http://checkstyle.sf.net/config_sizes.html --> <module name="FileLength"/> diff --git a/src/checkstyle/license-header.txt b/src/checkstyle/license-header.txt new file mode 100644 index 0000000..290c957 --- /dev/null +++ b/src/checkstyle/license-header.txt @@ -0,0 +1,16 @@ +/\*\s* + \*\s*Licensed to the Apache Software Foundation \(ASF\) under one or more + \*\s*contributor license agreements. See the NOTICE file distributed with + \*\s*this work for additional information regarding copyright ownership\. + \*\s*The ASF licenses this file to You under the Apache License, Version 2\.0 + \*\s*\(the "License"\); you may not use this file except in compliance with + \*\s*the License\. You may obtain a copy of the License at + \*\s* + \*\s*http://www\.apache\.org/licenses/LICENSE\-2\.0 + \*\s* + \*\s*Unless required by applicable law or agreed to in writing, software + \*\s*distributed under the License is distributed on an "AS IS" BASIS, + \*\s*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\. + \*\s*See the License for the specific language governing permissions and + \*\s*limitations under the License\. + \*/\s* diff --git a/src/main/java/org/apache/commons/fileupload/DefaultFileItem.java b/src/main/java/org/apache/commons/fileupload/DefaultFileItem.java index c5e4c8c..a7eb617 100644 --- a/src/main/java/org/apache/commons/fileupload/DefaultFileItem.java +++ b/src/main/java/org/apache/commons/fileupload/DefaultFileItem.java @@ -32,8 +32,6 @@ import org.apache.commons.fileupload.disk.DiskFileItem; * {@link #getInputStream()} and process the file without attempting to load * it into memory, which may come handy with large files. * - * @version $Id$ - * * @deprecated 1.1 Use <code>DiskFileItem</code> instead. */ @Deprecated @@ -42,11 +40,6 @@ public class DefaultFileItem // ----------------------------------------------------------- Constructors - /** - * The UID to use when serializing this instance. - */ - private static final long serialVersionUID = 4088572813833518255L; - /** * Constructs a new <code>DefaultFileItem</code> instance. * diff --git a/src/main/java/org/apache/commons/fileupload/DefaultFileItemFactory.java b/src/main/java/org/apache/commons/fileupload/DefaultFileItemFactory.java index 6fecb37..46bc7a3 100644 --- a/src/main/java/org/apache/commons/fileupload/DefaultFileItemFactory.java +++ b/src/main/java/org/apache/commons/fileupload/DefaultFileItemFactory.java @@ -28,7 +28,7 @@ import org.apache.commons.fileupload.disk.DiskFileItemFactory; * disk, is configurable, as is the directory in which temporary files will be * created.</p> * - * If not otherwise configured, the default configuration values are as + * <p>If not otherwise configured, the default configuration values are as * follows: * <ul> * <li>Size threshold is 10KB.</li> @@ -36,8 +36,6 @@ import org.apache.commons.fileupload.disk.DiskFileItemFactory; * <code>System.getProperty("java.io.tmpdir")</code>.</li> * </ul> * - * @version $Id$ - * * @deprecated 1.1 Use <code>DiskFileItemFactory</code> instead. */ @Deprecated diff --git a/src/main/java/org/apache/commons/fileupload/DiskFileUpload.java b/src/main/java/org/apache/commons/fileupload/DiskFileUpload.java index 3b4c212..3fad4f1 100644 --- a/src/main/java/org/apache/commons/fileupload/DiskFileUpload.java +++ b/src/main/java/org/apache/commons/fileupload/DiskFileUpload.java @@ -34,8 +34,6 @@ import javax.servlet.http.HttpServletRequest; * depending on their size, and will be available as {@link * org.apache.commons.fileupload.FileItem}s.</p> * - * @version $Id$ - * * @deprecated 1.1 Use <code>ServletFileUpload</code> together with * <code>DiskFileItemFactory</code> instead. */ diff --git a/src/main/java/org/apache/commons/fileupload/FileItem.java b/src/main/java/org/apache/commons/fileupload/FileItem.java index 484719f..f2a6f5f 100644 --- a/src/main/java/org/apache/commons/fileupload/FileItem.java +++ b/src/main/java/org/apache/commons/fileupload/FileItem.java @@ -20,7 +20,6 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.Serializable; import java.io.UnsupportedEncodingException; /** @@ -43,10 +42,9 @@ import java.io.UnsupportedEncodingException; * implementation of this interface to also implement * <code>javax.activation.DataSource</code> with minimal additional work. * - * @version $Id$ * @since 1.3 additionally implements FileItemHeadersSupport */ -public interface FileItem extends Serializable, FileItemHeadersSupport { +public interface FileItem extends FileItemHeadersSupport { // ------------------------------- Methods from javax.activation.DataSource diff --git a/src/main/java/org/apache/commons/fileupload/FileItemFactory.java b/src/main/java/org/apache/commons/fileupload/FileItemFactory.java index a576a33..f450a04 100644 --- a/src/main/java/org/apache/commons/fileupload/FileItemFactory.java +++ b/src/main/java/org/apache/commons/fileupload/FileItemFactory.java @@ -20,8 +20,6 @@ package org.apache.commons.fileupload; * <p>A factory interface for creating {@link FileItem} instances. Factories * can provide their own custom configuration, over and above that provided * by the default file upload implementation.</p> - * - * @version $Id$ */ public interface FileItemFactory { diff --git a/src/main/java/org/apache/commons/fileupload/FileItemHeaders.java b/src/main/java/org/apache/commons/fileupload/FileItemHeaders.java index 5f1533d..3fbda6d 100644 --- a/src/main/java/org/apache/commons/fileupload/FileItemHeaders.java +++ b/src/main/java/org/apache/commons/fileupload/FileItemHeaders.java @@ -24,8 +24,6 @@ import java.util.Iterator; * request.</p> * * @since 1.2.1 - * - * @version $Id$ */ public interface FileItemHeaders { diff --git a/src/main/java/org/apache/commons/fileupload/FileItemHeadersSupport.java b/src/main/java/org/apache/commons/fileupload/FileItemHeadersSupport.java index 4b372f6..dfba3df 100644 --- a/src/main/java/org/apache/commons/fileupload/FileItemHeadersSupport.java +++ b/src/main/java/org/apache/commons/fileupload/FileItemHeadersSupport.java @@ -24,8 +24,6 @@ package org.apache.commons.fileupload; * * @see FileItem * @see FileItemStream - * - * @version $Id$ */ public interface FileItemHeadersSupport { diff --git a/src/main/java/org/apache/commons/fileupload/FileItemIterator.java b/src/main/java/org/apache/commons/fileupload/FileItemIterator.java index 6c4e628..63e36eb 100644 --- a/src/main/java/org/apache/commons/fileupload/FileItemIterator.java +++ b/src/main/java/org/apache/commons/fileupload/FileItemIterator.java @@ -21,8 +21,6 @@ import java.io.IOException; /** * An iterator, as returned by * {@link FileUploadBase#getItemIterator(RequestContext)}. - * - * @version $Id$ */ public interface FileItemIterator { diff --git a/src/main/java/org/apache/commons/fileupload/FileItemStream.java b/src/main/java/org/apache/commons/fileupload/FileItemStream.java index fbb4abc..1154945 100644 --- a/src/main/java/org/apache/commons/fileupload/FileItemStream.java +++ b/src/main/java/org/apache/commons/fileupload/FileItemStream.java @@ -30,8 +30,6 @@ import java.io.InputStream; * its associated instances of {@link FileItemStream}: By invoking * {@link java.util.Iterator#hasNext()} on the iterator, you discard all data, * which hasn't been read so far from the previous data.</p> - * - * @version $Id$ */ public interface FileItemStream extends FileItemHeadersSupport { diff --git a/src/main/java/org/apache/commons/fileupload/FileUpload.java b/src/main/java/org/apache/commons/fileupload/FileUpload.java index d70cef5..4a48a49 100644 --- a/src/main/java/org/apache/commons/fileupload/FileUpload.java +++ b/src/main/java/org/apache/commons/fileupload/FileUpload.java @@ -29,8 +29,6 @@ package org.apache.commons.fileupload; * <p>How the data for individual parts is stored is determined by the factory * used to create them; a given part may be in memory, on disk, or somewhere * else.</p> - * - * @version $Id$ */ public class FileUpload extends FileUploadBase { diff --git a/src/main/java/org/apache/commons/fileupload/FileUploadBase.java b/src/main/java/org/apache/commons/fileupload/FileUploadBase.java index b567bd9..aaad4d2 100644 --- a/src/main/java/org/apache/commons/fileupload/FileUploadBase.java +++ b/src/main/java/org/apache/commons/fileupload/FileUploadBase.java @@ -38,6 +38,7 @@ import org.apache.commons.fileupload.util.Closeable; import org.apache.commons.fileupload.util.FileItemHeadersImpl; import org.apache.commons.fileupload.util.LimitedInputStream; import org.apache.commons.fileupload.util.Streams; +import org.apache.commons.io.IOUtils; /** * <p>High level API for processing file uploads.</p> @@ -52,8 +53,6 @@ import org.apache.commons.fileupload.util.Streams; * <p>How the data for individual parts is stored is determined by the factory * used to create them; a given part may be in memory, on disk, or somewhere * else.</p> - * - * @version $Id$ */ public abstract class FileUploadBase { @@ -365,8 +364,8 @@ public abstract class FileUploadBase { for (FileItem fileItem : items) { try { fileItem.delete(); - } catch (Throwable e) { - // ignore it + } catch (Exception ignored) { + // ignored TODO perhaps add to tracker delete failure list somehow? } } } @@ -765,20 +764,23 @@ public abstract class FileUploadBase { fieldName = pFieldName; contentType = pContentType; formField = pFormField; - final ItemInputStream itemStream = multi.newInputStream(); - InputStream istream = itemStream; - if (fileSizeMax != -1) { + if (fileSizeMax != -1) { // Check if limit is already exceeded if (pContentLength != -1 - && pContentLength > fileSizeMax) { + && pContentLength > fileSizeMax) { FileSizeLimitExceededException e = - new FileSizeLimitExceededException( - format("The field %s exceeds its maximum permitted size of %s bytes.", - fieldName, Long.valueOf(fileSizeMax)), - pContentLength, fileSizeMax); + new FileSizeLimitExceededException( + format("The field %s exceeds its maximum permitted size of %s bytes.", + fieldName, Long.valueOf(fileSizeMax)), + pContentLength, fileSizeMax); e.setFileName(pName); e.setFieldName(pFieldName); throw new FileUploadIOException(e); } + } + // OK to construct stream now + final ItemInputStream itemStream = multi.newInputStream(); + InputStream istream = itemStream; + if (fileSizeMax != -1) { istream = new LimitedInputStream(istream, fileSizeMax) { @Override protected void raiseError(long pSizeMax, long pCount) @@ -803,6 +805,7 @@ public abstract class FileUploadBase { * * @return Content type, if known, or null. */ + @Override public String getContentType() { return contentType; } @@ -812,6 +815,7 @@ public abstract class FileUploadBase { * * @return Field name. */ + @Override public String getFieldName() { return fieldName; } @@ -825,6 +829,7 @@ public abstract class FileUploadBase { * use the file name anyways, catch the exception and use * InvalidFileNameException#getName(). */ + @Override public String getName() { return Streams.checkFileName(name); } @@ -835,6 +840,7 @@ public abstract class FileUploadBase { * @return True, if the item is a form field, * otherwise false. */ + @Override public boolean isFormField() { return formField; } @@ -846,6 +852,7 @@ public abstract class FileUploadBase { * @return Opened input stream. * @throws IOException An I/O error occurred. */ + @Override public InputStream openStream() throws IOException { if (opened) { throw new IllegalStateException( @@ -871,6 +878,7 @@ public abstract class FileUploadBase { * * @return The items header object */ + @Override public FileItemHeaders getHeaders() { return headers; } @@ -880,6 +888,7 @@ public abstract class FileUploadBase { * * @param pHeaders The items header object */ + @Override public void setHeaders(FileItemHeaders pHeaders) { headers = pHeaders; } @@ -949,7 +958,6 @@ public abstract class FileUploadBase { MULTIPART_FORM_DATA, MULTIPART_MIXED, contentType)); } - InputStream input = ctx.getInputStream(); @SuppressWarnings("deprecation") // still has to be backward compatible final int contentLengthInt = ctx.getContentLength(); @@ -960,6 +968,7 @@ public abstract class FileUploadBase { : contentLengthInt; // CHECKSTYLE:ON + InputStream input; // N.B. this is eventually closed in MultipartStream processing if (sizeMax >= 0) { if (requestSize != -1 && requestSize > sizeMax) { throw new SizeLimitExceededException( @@ -967,7 +976,8 @@ public abstract class FileUploadBase { Long.valueOf(requestSize), Long.valueOf(sizeMax)), requestSize, sizeMax); } - input = new LimitedInputStream(input, sizeMax) { + // N.B. this is eventually closed in MultipartStream processing + input = new LimitedInputStream(ctx.getInputStream(), sizeMax) { @Override protected void raiseError(long pSizeMax, long pCount) throws IOException { @@ -978,6 +988,8 @@ public abstract class FileUploadBase { throw new FileUploadIOException(ex); } }; + } else { + input = ctx.getInputStream(); } String charEncoding = headerEncoding; @@ -987,6 +999,7 @@ public abstract class FileUploadBase { boundary = getBoundary(contentType); if (boundary == null) { + IOUtils.closeQuietly(input); // avoid possible resource leak throw new FileUploadException("the request was rejected because no multipart boundary was found"); } @@ -994,6 +1007,7 @@ public abstract class FileUploadBase { try { multi = new MultipartStream(input, boundary, notifier); } catch (IllegalArgumentException iae) { + IOUtils.closeQuietly(input); // avoid possible resource leak throw new InvalidContentTypeException( format("The boundary specified in the %s header is too long", CONTENT_TYPE), iae); } @@ -1095,6 +1109,7 @@ public abstract class FileUploadBase { * @return True, if one or more additional file items * are available, otherwise false. */ + @Override public boolean hasNext() throws FileUploadException, IOException { if (eof) { return false; @@ -1121,6 +1136,7 @@ public abstract class FileUploadBase { * @return FileItemStream instance, which provides * access to the next file item. */ + @Override public FileItemStream next() throws FileUploadException, IOException { if (eof || (!itemValid && !hasNext())) { throw new NoSuchElementException(); @@ -1361,7 +1377,7 @@ public abstract class FileUploadBase { /** * @deprecated 1.2 Replaced by - * {@code SizeLimitExceededException(String, long, long)} + * {@link #SizeLimitExceededException(String, long, long)} */ @Deprecated public SizeLimitExceededException() { @@ -1370,7 +1386,7 @@ public abstract class FileUploadBase { /** * @deprecated 1.2 Replaced by - * {@code #SizeLimitExceededException(String, long, long)} + * {@link #SizeLimitExceededException(String, long, long)} * @param message The exceptions detail message. */ @Deprecated diff --git a/src/main/java/org/apache/commons/fileupload/FileUploadException.java b/src/main/java/org/apache/commons/fileupload/FileUploadException.java index 1c66cb8..3c39fe1 100644 --- a/src/main/java/org/apache/commons/fileupload/FileUploadException.java +++ b/src/main/java/org/apache/commons/fileupload/FileUploadException.java @@ -21,8 +21,6 @@ import java.io.PrintWriter; /** * Exception for errors encountered while processing the request. - * - * @version $Id$ */ public class FileUploadException extends Exception { diff --git a/src/main/java/org/apache/commons/fileupload/InvalidFileNameException.java b/src/main/java/org/apache/commons/fileupload/InvalidFileNameException.java index e58f6e8..8bdee38 100644 --- a/src/main/java/org/apache/commons/fileupload/InvalidFileNameException.java +++ b/src/main/java/org/apache/commons/fileupload/InvalidFileNameException.java @@ -25,8 +25,6 @@ package org.apache.commons.fileupload; * checks for the extension ".png"), while, depending on the underlying * C library, it might create a file named "foo.exe", as the NUL * character is the string terminator in C. - * - * @version $Id$ */ public class InvalidFileNameException extends RuntimeException { diff --git a/src/main/java/org/apache/commons/fileupload/MultipartStream.java b/src/main/java/org/apache/commons/fileupload/MultipartStream.java index 045dac3..2c58e7e 100644 --- a/src/main/java/org/apache/commons/fileupload/MultipartStream.java +++ b/src/main/java/org/apache/commons/fileupload/MultipartStream.java @@ -80,8 +80,6 @@ import org.apache.commons.fileupload.util.Streams; * // a read or write error occurred * } * </pre> - * - * @version $Id$ */ public class MultipartStream { @@ -222,12 +220,17 @@ public class MultipartStream { * The amount of data, in bytes, that must be kept in the buffer in order * to detect delimiters reliably. */ - private int keepRegion; + private final int keepRegion; /** * The byte sequence that partitions the stream. */ - private byte[] boundary; + private final byte[] boundary; + + /** + * The table for Knuth-Morris-Pratt search algorithm. + */ + private final int[] boundaryTable; /** * The length of the buffer used for processing the request. @@ -339,12 +342,14 @@ public class MultipartStream { this.notifier = pNotifier; this.boundary = new byte[this.boundaryLength]; + this.boundaryTable = new int[this.boundaryLength + 1]; this.keepRegion = this.boundary.length; System.arraycopy(BOUNDARY_PREFIX, 0, this.boundary, 0, BOUNDARY_PREFIX.length); System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length, boundary.length); + computeBoundaryTable(); head = 0; tail = 0; @@ -502,10 +507,35 @@ public class MultipartStream { throws IllegalBoundaryException { if (boundary.length != boundaryLength - BOUNDARY_PREFIX.length) { throw new IllegalBoundaryException( - "The length of a boundary token can not be changed"); + "The length of a boundary token cannot be changed"); } System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length, boundary.length); + computeBoundaryTable(); + } + + /** + * Compute the table used for Knuth-Morris-Pratt search algorithm. + */ + private void computeBoundaryTable() { + int position = 2; + int candidate = 0; + + boundaryTable[0] = -1; + boundaryTable[1] = 0; + + while (position <= boundaryLength) { + if (boundary[position - 1] == boundary[candidate]) { + boundaryTable[position] = candidate + 1; + candidate++; + position++; + } else if (candidate > 0) { + candidate = boundaryTable[candidate]; + } else { + boundaryTable[position] = 0; + position++; + } + } } /** @@ -589,8 +619,7 @@ public class MultipartStream { */ public int readBodyData(OutputStream output) throws MalformedStreamException, IOException { - final InputStream istream = newInputStream(); - return (int) Streams.copy(istream, output, false); + return (int) Streams.copy(newInputStream(), output, false); // N.B. Streams.copy closes the input stream } /** @@ -629,6 +658,7 @@ public class MultipartStream { // First delimiter may be not preceeded with a CRLF. System.arraycopy(boundary, 2, boundary, 0, boundary.length - 2); boundaryLength = boundary.length - 2; + computeBoundaryTable(); try { // Discard all data up to the delimiter. discardBodyData(); @@ -644,6 +674,7 @@ public class MultipartStream { boundaryLength = boundary.length; boundary[0] = CR; boundary[1] = LF; + computeBoundaryTable(); } } @@ -699,23 +730,20 @@ public class MultipartStream { * not found. */ protected int findSeparator() { - int first; - int match = 0; - int maxpos = tail - boundaryLength; - for (first = head; first <= maxpos && match != boundaryLength; first++) { - first = findByte(boundary[0], first); - if (first == -1 || first > maxpos) { - return -1; + + int bufferPos = this.head; + int tablePos = 0; + + while (bufferPos < this.tail) { + while (tablePos >= 0 && buffer[bufferPos] != boundary[tablePos]) { + tablePos = boundaryTable[tablePos]; } - for (match = 1; match < boundaryLength; match++) { - if (buffer[first + match] != boundary[match]) { - break; - } + bufferPos++; + tablePos++; + if (tablePos == boundaryLength) { + return bufferPos - boundaryLength; } } - if (match == boundaryLength) { - return first - 1; - } return -1; } @@ -1023,6 +1051,7 @@ public class MultipartStream { * * @return True, if the stream is closed, otherwise false. */ + @Override public boolean isClosed() { return closed; } diff --git a/src/main/java/org/apache/commons/fileupload/ParameterParser.java b/src/main/java/org/apache/commons/fileupload/ParameterParser.java index 3db521a..e645458 100644 --- a/src/main/java/org/apache/commons/fileupload/ParameterParser.java +++ b/src/main/java/org/apache/commons/fileupload/ParameterParser.java @@ -33,8 +33,6 @@ import org.apache.commons.fileupload.util.mime.MimeUtility; * <p> * <code>param1 = value; param2 = "anything goes; really"; param3</code> * </p> - * - * @version $Id$ */ public class ParameterParser { @@ -78,8 +76,8 @@ public class ParameterParser { /** * Are there any characters left to parse? * - * @return <tt>true</tt> if there are unparsed characters, - * <tt>false</tt> otherwise. + * @return {@code true} if there are unparsed characters, + * {@code false} otherwise. */ private boolean hasChar() { return this.pos < this.len; @@ -90,8 +88,8 @@ public class ParameterParser { * leading and trailing blanks as well as enclosing quotation marks, * when necessary. * - * @param quoted <tt>true</tt> if quotation marks are expected, - * <tt>false</tt> otherwise. + * @param quoted {@code true} if quotation marks are expected, + * {@code false} otherwise. * @return the token */ private String getToken(boolean quoted) { @@ -124,8 +122,8 @@ public class ParameterParser { * @param ch the character to test for presense in the array of characters * @param charray the array of characters to test against * - * @return <tt>true</tt> if the character is present in the array of - * characters, <tt>false</tt> otherwise. + * @return {@code true} if the character is present in the array of + * characters, {@code false} otherwise. */ private boolean isOneOf(char ch, final char[] charray) { boolean result = false; @@ -195,12 +193,12 @@ public class ParameterParser { } /** - * Returns <tt>true</tt> if parameter names are to be converted to lower + * Returns {@code true} if parameter names are to be converted to lower * case when name/value pairs are parsed. * - * @return <tt>true</tt> if parameter names are to be + * @return {@code true} if parameter names are to be * converted to lower case when name/value pairs are parsed. - * Otherwise returns <tt>false</tt> + * Otherwise returns {@code false} */ public boolean isLowerCaseNames() { return this.lowerCaseNames; @@ -210,9 +208,9 @@ public class ParameterParser { * Sets the flag if parameter names are to be converted to lower case when * name/value pairs are parsed. * - * @param b <tt>true</tt> if parameter names are to be + * @param b {@code true} if parameter names are to be * converted to lower case when name/value pairs are parsed. - * <tt>false</tt> otherwise. + * {@code false} otherwise. */ public void setLowerCaseNames(boolean b) { this.lowerCaseNames = b; diff --git a/src/main/java/org/apache/commons/fileupload/ProgressListener.java b/src/main/java/org/apache/commons/fileupload/ProgressListener.java index 30d7209..5a869ef 100644 --- a/src/main/java/org/apache/commons/fileupload/ProgressListener.java +++ b/src/main/java/org/apache/commons/fileupload/ProgressListener.java @@ -19,8 +19,6 @@ package org.apache.commons.fileupload; /** * The {@link ProgressListener} may be used to display a progress bar * or do stuff like that. - * - * @version $Id$ */ public interface ProgressListener { diff --git a/src/main/java/org/apache/commons/fileupload/RequestContext.java b/src/main/java/org/apache/commons/fileupload/RequestContext.java index bd2b83c..b0d329e 100644 --- a/src/main/java/org/apache/commons/fileupload/RequestContext.java +++ b/src/main/java/org/apache/commons/fileupload/RequestContext.java @@ -25,8 +25,6 @@ import java.io.IOException; * handled by FileUpload, such as servlets and portlets.</p> * * @since FileUpload 1.1 - * - * @version $Id$ */ public interface RequestContext { diff --git a/src/main/java/org/apache/commons/fileupload/disk/DiskFileItem.java b/src/main/java/org/apache/commons/fileupload/disk/DiskFileItem.java index 00eda95..e5e3bf9 100644 --- a/src/main/java/org/apache/commons/fileupload/disk/DiskFileItem.java +++ b/src/main/java/org/apache/commons/fileupload/disk/DiskFileItem.java @@ -18,16 +18,12 @@ package org.apache.commons.fileupload.disk; import static java.lang.String.format; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.Map; @@ -39,6 +35,7 @@ import org.apache.commons.fileupload.FileItemHeaders; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.ParameterParser; import org.apache.commons.fileupload.util.Streams; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.DeferredFileOutputStream; @@ -70,25 +67,12 @@ import org.apache.commons.io.output.DeferredFileOutputStream; * in the users guide of commons-fileupload.</p> * * @since FileUpload 1.1 - * - * @version $Id$ */ public class DiskFileItem 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 - /** - * The UID to use when serializing this instance. - */ - private static final long serialVersionUID = 2237570099615271025L; - /** * Default content charset to be used when no explicit charset * parameter is provided by the sender. Media subtypes of the @@ -164,14 +148,15 @@ public class DiskFileItem 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 @@ -214,6 +199,7 @@ public class DiskFileItem * * @throws IOException if an error occurs. */ + @Override public InputStream getInputStream() throws IOException { if (!isInMemory()) { @@ -233,6 +219,7 @@ public class DiskFileItem * @return The content type passed by the agent or <code>null</code> if * not defined. */ + @Override public String getContentType() { return contentType; } @@ -261,6 +248,7 @@ public class DiskFileItem * use the file name anyways, catch the exception and use * {@link org.apache.commons.fileupload.InvalidFileNameException#getName()}. */ + @Override public String getName() { return Streams.checkFileName(fileName); } @@ -274,6 +262,7 @@ public class DiskFileItem * @return <code>true</code> if the file contents will be read * from memory; <code>false</code> otherwise. */ + @Override public boolean isInMemory() { if (cachedContent != null) { return true; @@ -286,6 +275,7 @@ public class DiskFileItem * * @return The size of the file, in bytes. */ + @Override public long getSize() { if (size >= 0) { return size; @@ -303,11 +293,13 @@ public class DiskFileItem * contents of the file were not yet cached in memory, they will be * 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() { if (isInMemory()) { - if (cachedContent == null) { + if (cachedContent == null && dfos != null) { cachedContent = dfos.getData(); } return cachedContent; @@ -317,18 +309,12 @@ public class DiskFileItem InputStream fis = null; try { - fis = new BufferedInputStream(new FileInputStream(dfos.getFile())); - fis.read(fileData); + fis = new FileInputStream(dfos.getFile()); + IOUtils.readFully(fis, fileData); } catch (IOException e) { fileData = null; } finally { - if (fis != null) { - try { - fis.close(); - } catch (IOException e) { - // ignore - } - } + IOUtils.closeQuietly(fis); } return fileData; @@ -346,6 +332,7 @@ public class DiskFileItem * @throws UnsupportedEncodingException if the requested character * encoding is not available. */ + @Override public String getString(final String charset) throws UnsupportedEncodingException { return new String(get(), charset); @@ -360,11 +347,12 @@ public class DiskFileItem * * @return The contents of the file, as a string. */ + @Override public String getString() { byte[] rawdata = get(); String charset = getCharSet(); if (charset == null) { - charset = DEFAULT_CHARSET; + charset = defaultCharset; } try { return new String(rawdata, charset); @@ -393,16 +381,16 @@ public class DiskFileItem * * @throws Exception if an error occurs. */ + @Override public void write(File file) throws Exception { if (isInMemory()) { FileOutputStream fout = null; try { fout = new FileOutputStream(file); fout.write(get()); + fout.close(); } finally { - if (fout != null) { - fout.close(); - } + IOUtils.closeQuietly(fout); } } else { File outputFile = getStoreLocation(); @@ -414,32 +402,7 @@ public class DiskFileItem * in a temporary location so move it to the * desired file. */ - if (!outputFile.renameTo(file)) { - BufferedInputStream in = null; - 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 { /* * For whatever reason we cannot write the @@ -458,10 +421,11 @@ public class DiskFileItem * collected, this method can be used to ensure that this is done at an * earlier time, thus preserving system resources. */ + @Override public void delete() { cachedContent = null; File outputFile = getStoreLocation(); - if (outputFile != null && outputFile.exists()) { + if (outputFile != null && !isInMemory() && outputFile.exists()) { outputFile.delete(); } } @@ -475,6 +439,7 @@ public class DiskFileItem * @see #setFieldName(java.lang.String) * */ + @Override public String getFieldName() { return fieldName; } @@ -487,6 +452,7 @@ public class DiskFileItem * @see #getFieldName() * */ + @Override public void setFieldName(String fieldName) { this.fieldName = fieldName; } @@ -501,6 +467,7 @@ public class DiskFileItem * @see #setFormField(boolean) * */ + @Override public boolean isFormField() { return isFormField; } @@ -515,6 +482,7 @@ public class DiskFileItem * @see #isFormField() * */ + @Override public void setFormField(boolean state) { isFormField = state; } @@ -524,10 +492,11 @@ public class DiskFileItem * be used for storing the contents of the file. * * @return An {@link java.io.OutputStream OutputStream} that can be used - * for storing the contensts of the file. + * for storing the contents of the file. * * @throws IOException if an error occurs. */ + @Override public OutputStream getOutputStream() throws IOException { if (dfos == null) { @@ -556,6 +525,9 @@ public class DiskFileItem if (dfos == null) { return null; } + if (isInMemory()) { + return null; + } return dfos.getFile(); } @@ -566,6 +538,9 @@ public class DiskFileItem */ @Override protected void finalize() { + if (dfos == null || dfos.isInMemory()) { + return; + } File outputFile = dfos.getFile(); if (outputFile != null && outputFile.exists()) { @@ -578,6 +553,9 @@ public class DiskFileItem * 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 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. */ @@ -599,7 +577,7 @@ public class DiskFileItem /** * 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 appearance. * * @return A String with the non-random looking instance identifier. */ @@ -628,83 +606,11 @@ public class DiskFileItem 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. * @return The file items headers. */ + @Override public FileItemHeaders getHeaders() { return headers; } @@ -713,8 +619,26 @@ public class DiskFileItem * Sets the file item headers. * @param pHeaders The file items headers. */ + @Override public void setHeaders(FileItemHeaders 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; + } } diff --git a/src/main/java/org/apache/commons/fileupload/disk/DiskFileItemFactory.java b/src/main/java/org/apache/commons/fileupload/disk/DiskFileItemFactory.java index 7f31ff7..edcaec1 100644 --- a/src/main/java/org/apache/commons/fileupload/disk/DiskFileItemFactory.java +++ b/src/main/java/org/apache/commons/fileupload/disk/DiskFileItemFactory.java @@ -66,8 +66,6 @@ import org.apache.commons.io.FileCleaningTracker; * in the users guide of commons-fileupload.</p> * * @since FileUpload 1.1 - * - * @version $Id$ */ public class DiskFileItemFactory implements FileItemFactory { @@ -97,6 +95,12 @@ public class DiskFileItemFactory implements FileItemFactory { */ private FileCleaningTracker fileCleaningTracker; + /** + * Default content charset to be used when no explicit charset + * parameter is provided by the sender. + */ + private String defaultCharset = DiskFileItem.DEFAULT_CHARSET; + // ----------------------------------------------------------- Constructors /** @@ -190,10 +194,12 @@ public class DiskFileItemFactory implements FileItemFactory { * * @return The newly created file item. */ + @Override public FileItem createItem(String fieldName, String contentType, boolean isFormField, String fileName) { DiskFileItem result = new DiskFileItem(fieldName, contentType, isFormField, fileName, sizeThreshold, repository); + result.setDefaultCharset(defaultCharset); FileCleaningTracker tracker = getFileCleaningTracker(); if (tracker != null) { tracker.track(result.getTempFile(), result); @@ -224,4 +230,21 @@ public class DiskFileItemFactory implements FileItemFactory { fileCleaningTracker = pTracker; } + /** + * 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 pCharset the default charset + */ + public void setDefaultCharset(String pCharset) { + defaultCharset = pCharset; + } } diff --git a/src/main/java/org/apache/commons/fileupload/portlet/PortletFileUpload.java b/src/main/java/org/apache/commons/fileupload/portlet/PortletFileUpload.java index 3564f3f..8192304 100644 --- a/src/main/java/org/apache/commons/fileupload/portlet/PortletFileUpload.java +++ b/src/main/java/org/apache/commons/fileupload/portlet/PortletFileUpload.java @@ -45,8 +45,6 @@ import org.apache.commons.fileupload.FileUploadException; * else.</p> * * @since FileUpload 1.1 - * - * @version $Id$ */ public class PortletFileUpload extends FileUpload { diff --git a/src/main/java/org/apache/commons/fileupload/portlet/PortletRequestContext.java b/src/main/java/org/apache/commons/fileupload/portlet/PortletRequestContext.java index 66a2e5c..f10c72e 100644 --- a/src/main/java/org/apache/commons/fileupload/portlet/PortletRequestContext.java +++ b/src/main/java/org/apache/commons/fileupload/portlet/PortletRequestContext.java @@ -31,8 +31,6 @@ import org.apache.commons.fileupload.UploadContext; * a portlet.</p> * * @since FileUpload 1.1 - * - * @version $Id$ */ public class PortletRequestContext implements UploadContext { @@ -63,6 +61,7 @@ public class PortletRequestContext implements UploadContext { * * @return The character encoding for the request. */ + @Override public String getCharacterEncoding() { return request.getCharacterEncoding(); } @@ -72,6 +71,7 @@ public class PortletRequestContext implements UploadContext { * * @return The content type of the request. */ + @Override public String getContentType() { return request.getContentType(); } @@ -82,6 +82,7 @@ public class PortletRequestContext implements UploadContext { * @return The content length of the request. * @deprecated 1.3 Use {@link #contentLength()} instead */ + @Override @Deprecated public int getContentLength() { return request.getContentLength(); @@ -93,6 +94,7 @@ public class PortletRequestContext implements UploadContext { * @return The content length of the request. * @since 1.3 */ + @Override public long contentLength() { long size; try { @@ -110,6 +112,7 @@ public class PortletRequestContext implements UploadContext { * * @throws IOException if a problem occurs. */ + @Override public InputStream getInputStream() throws IOException { return request.getPortletInputStream(); } diff --git a/src/main/java/org/apache/commons/fileupload/portlet/package-info.java b/src/main/java/org/apache/commons/fileupload/portlet/package-info.java index 7251b60..e39b6ca 100644 --- a/src/main/java/org/apache/commons/fileupload/portlet/package-info.java +++ b/src/main/java/org/apache/commons/fileupload/portlet/package-info.java @@ -30,7 +30,7 @@ * The following code fragment demonstrates typical usage. * </p> * <pre> - * DiskFileItemFactory factory = new DiskFileItemFactory(); + * DiskFileItemFactory factory = new DiskFileItemFactory(); * // Configure the factory here, if desired. * PortletFileUpload upload = new PortletFileUpload(factory); * // Configure the uploader here, if desired. diff --git a/src/main/java/org/apache/commons/fileupload/servlet/FileCleanerCleanup.java b/src/main/java/org/apache/commons/fileupload/servlet/FileCleanerCleanup.java index e0aa5e1..cb8b30d 100644 --- a/src/main/java/org/apache/commons/fileupload/servlet/FileCleanerCleanup.java +++ b/src/main/java/org/apache/commons/fileupload/servlet/FileCleanerCleanup.java @@ -26,8 +26,6 @@ import org.apache.commons.io.FileCleaningTracker; * A servlet context listener, which ensures that the * {@link FileCleaningTracker}'s reaper thread is terminated, * when the web application is destroyed. - * - * @version $Id$ */ public class FileCleanerCleanup implements ServletContextListener { @@ -70,6 +68,7 @@ public class FileCleanerCleanup implements ServletContextListener { * @param sce The servlet context, used for calling * {@link #setFileCleaningTracker(ServletContext, FileCleaningTracker)}. */ + @Override public void contextInitialized(ServletContextEvent sce) { setFileCleaningTracker(sce.getServletContext(), new FileCleaningTracker()); @@ -82,6 +81,7 @@ public class FileCleanerCleanup implements ServletContextListener { * @param sce The servlet context, used for calling * {@link #getFileCleaningTracker(ServletContext)}. */ + @Override public void contextDestroyed(ServletContextEvent sce) { getFileCleaningTracker(sce.getServletContext()).exitWhenFinished(); } diff --git a/src/main/java/org/apache/commons/fileupload/servlet/ServletFileUpload.java b/src/main/java/org/apache/commons/fileupload/servlet/ServletFileUpload.java index a7beb63..c0e2b5e 100644 --- a/src/main/java/org/apache/commons/fileupload/servlet/ServletFileUpload.java +++ b/src/main/java/org/apache/commons/fileupload/servlet/ServletFileUpload.java @@ -42,8 +42,6 @@ import org.apache.commons.fileupload.FileUploadException; * <p>How the data for individual parts is stored is determined by the factory * used to create them; a given part may be in memory, on disk, or somewhere * else.</p> - * - * @version $Id$ */ public class ServletFileUpload extends FileUpload { diff --git a/src/main/java/org/apache/commons/fileupload/servlet/ServletRequestContext.java b/src/main/java/org/apache/commons/fileupload/servlet/ServletRequestContext.java index 4b93846..b962734 100644 --- a/src/main/java/org/apache/commons/fileupload/servlet/ServletRequestContext.java +++ b/src/main/java/org/apache/commons/fileupload/servlet/ServletRequestContext.java @@ -31,8 +31,6 @@ import org.apache.commons.fileupload.UploadContext; * an HTTP servlet.</p> * * @since FileUpload 1.1 - * - * @version $Id$ */ public class ServletRequestContext implements UploadContext { @@ -61,6 +59,7 @@ public class ServletRequestContext implements UploadContext { * * @return The character encoding for the request. */ + @Override public String getCharacterEncoding() { return request.getCharacterEncoding(); } @@ -70,6 +69,7 @@ public class ServletRequestContext implements UploadContext { * * @return The content type of the request. */ + @Override public String getContentType() { return request.getContentType(); } @@ -80,6 +80,7 @@ public class ServletRequestContext implements UploadContext { * @return The content length of the request. * @deprecated 1.3 Use {@link #contentLength()} instead */ + @Override @Deprecated public int getContentLength() { return request.getContentLength(); @@ -91,6 +92,7 @@ public class ServletRequestContext implements UploadContext { * @return The content length of the request. * @since 1.3 */ + @Override public long contentLength() { long size; try { @@ -108,6 +110,7 @@ public class ServletRequestContext implements UploadContext { * * @throws IOException if a problem occurs. */ + @Override public InputStream getInputStream() throws IOException { return request.getInputStream(); } diff --git a/src/main/java/org/apache/commons/fileupload/util/Closeable.java b/src/main/java/org/apache/commons/fileupload/util/Closeable.java index dcef1ca..741ccea 100644 --- a/src/main/java/org/apache/commons/fileupload/util/Closeable.java +++ b/src/main/java/org/apache/commons/fileupload/util/Closeable.java @@ -20,8 +20,6 @@ import java.io.IOException; /** * Interface of an object, which may be closed. - * - * @version $Id$ */ public interface Closeable { diff --git a/src/main/java/org/apache/commons/fileupload/util/FileItemHeadersImpl.java b/src/main/java/org/apache/commons/fileupload/util/FileItemHeadersImpl.java index c593b9d..2845e32 100644 --- a/src/main/java/org/apache/commons/fileupload/util/FileItemHeadersImpl.java +++ b/src/main/java/org/apache/commons/fileupload/util/FileItemHeadersImpl.java @@ -31,8 +31,6 @@ import org.apache.commons.fileupload.FileItemHeaders; * Default implementation of the {@link FileItemHeaders} interface. * * @since 1.2.1 - * - * @version $Id$ */ public class FileItemHeadersImpl implements FileItemHeaders, Serializable { @@ -50,6 +48,7 @@ public class FileItemHeadersImpl implements FileItemHeaders, Serializable { /** * {@inheritDoc} */ + @Override public String getHeader(String name) { String nameLower = name.toLowerCase(Locale.ENGLISH); List<String> headerValueList = headerNameToValueListMap.get(nameLower); @@ -62,6 +61,7 @@ public class FileItemHeadersImpl implements FileItemHeaders, Serializable { /** * {@inheritDoc} */ + @Override public Iterator<String> getHeaderNames() { return headerNameToValueListMap.keySet().iterator(); } @@ -69,6 +69,7 @@ public class FileItemHeadersImpl implements FileItemHeaders, Serializable { /** * {@inheritDoc} */ + @Override public Iterator<String> getHeaders(String name) { String nameLower = name.toLowerCase(Locale.ENGLISH); List<String> headerValueList = headerNameToValueListMap.get(nameLower); diff --git a/src/main/java/org/apache/commons/fileupload/util/LimitedInputStream.java b/src/main/java/org/apache/commons/fileupload/util/LimitedInputStream.java index 002d7da..5946653 100644 --- a/src/main/java/org/apache/commons/fileupload/util/LimitedInputStream.java +++ b/src/main/java/org/apache/commons/fileupload/util/LimitedInputStream.java @@ -23,8 +23,6 @@ import java.io.InputStream; /** * An input stream, which limits its data size. This stream is * used, if the content length is unknown. - * - * @version $Id$ */ public abstract class LimitedInputStream extends FilterInputStream implements Closeable { @@ -93,7 +91,7 @@ public abstract class LimitedInputStream extends FilterInputStream implements Cl * * @return the next byte of data, or <code>-1</code> if the end of the * stream is reached. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @see java.io.FilterInputStream#in */ @Override @@ -122,11 +120,11 @@ public abstract class LimitedInputStream extends FilterInputStream implements Cl * @return the total number of bytes read into the buffer, or * <code>-1</code> if there is no more data because the end of * the stream has been reached. - * @exception NullPointerException If <code>b</code> is <code>null</code>. - * @exception IndexOutOfBoundsException If <code>off</code> is negative, + * @throws NullPointerException If <code>b</code> is <code>null</code>. + * @throws IndexOutOfBoundsException If <code>off</code> is negative, * <code>len</code> is negative, or <code>len</code> is greater than * <code>b.length - off</code> - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @see java.io.FilterInputStream#in */ @Override @@ -145,6 +143,7 @@ public abstract class LimitedInputStream extends FilterInputStream implements Cl * @return True, if the stream is closed, otherwise false. * @throws IOException An I/O error occurred. */ + @Override public boolean isClosed() throws IOException { return closed; } @@ -155,7 +154,7 @@ public abstract class LimitedInputStream extends FilterInputStream implements Cl * This * method simply performs <code>in.close()</code>. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @see java.io.FilterInputStream#in */ @Override diff --git a/src/main/java/org/apache/commons/fileupload/util/Streams.java b/src/main/java/org/apache/commons/fileupload/util/Streams.java index 9e9d58b..17d1fb9 100644 --- a/src/main/java/org/apache/commons/fileupload/util/Streams.java +++ b/src/main/java/org/apache/commons/fileupload/util/Streams.java @@ -26,8 +26,6 @@ import org.apache.commons.io.IOUtils; /** * Utility class for working with streams. - * - * @version $Id$ */ public final class Streams { diff --git a/src/main/java/org/apache/commons/fileupload/util/mime/MimeUtility.java b/src/main/java/org/apache/commons/fileupload/util/mime/MimeUtility.java index e92f719..b8a7e46 100644 --- a/src/main/java/org/apache/commons/fileupload/util/mime/MimeUtility.java +++ b/src/main/java/org/apache/commons/fileupload/util/mime/MimeUtility.java @@ -212,7 +212,7 @@ public final class MimeUtility { } // pull out the character set information (this is the MIME name at this point). - String charset = word.substring(2, charsetPos).toLowerCase(); + String charset = word.substring(2, charsetPos).toLowerCase(Locale.ENGLISH); // now pull out the encoding token the same way. int encodingPos = word.indexOf('?', charsetPos + 1); diff --git a/src/main/java/org/apache/commons/fileupload/util/mime/QuotedPrintableDecoder.java b/src/main/java/org/apache/commons/fileupload/util/mime/QuotedPrintableDecoder.java index f071532..7bdf588 100644 --- a/src/main/java/org/apache/commons/fileupload/util/mime/QuotedPrintableDecoder.java +++ b/src/main/java/org/apache/commons/fileupload/util/mime/QuotedPrintableDecoder.java @@ -44,7 +44,7 @@ final class QuotedPrintableDecoder { * @param out The output stream used to return the decoded data. * * @return the number of bytes produced. - * @exception IOException + * @throws IOException */ public static int decode(byte[] data, OutputStream out) throws IOException { int off = 0; diff --git a/src/site/fml/faq.fml b/src/site/fml/faq.fml index 44ed791..3b80c77 100644 --- a/src/site/fml/faq.fml +++ b/src/site/fml/faq.fml @@ -175,41 +175,41 @@ try { </part> <part id="security"> - <title>FileUpload and Flash</title> - - <faq id="diskfileitem-serializable"> - <question> I have read, that there is a security problem in Commons FileUpload, because there is a class called - DiskFileItem, which can be used for malicious attacks. - </question> - <answer> - <p> - It is true, that this class exists, and can be serialized/deserialized in FileUpload versions, up to, and - including 1.3.2. It is also true, that a malicious attacker can abuse this possibility to create abitraryly - located files (assuming the required permissions) with arbitrary contents, if he gets the opportunity to - provide specially crafted data, which is being deserialized by a Java application, which has either of the - above versions of Commons FileUpload in the classpath, and which puts no limitations on the classes being - deserialized. - </p> - <p> - That being said, we (the Apache Commons team) hold the view, that the actual problem is not the DiskFileItem - class, but the "if" in the previous sentence. A Java application should carefully consider, which classes - can be deserialized. A typical approach would be, for example, to provide a blacklist, or whitelist of - packages, and/or classes, which may, or may not be deserialized. - </p> - <p> - On the other hand, we acknowledge, that the likelyhood of application container vendors taking such a - simple security measure is extremely low. So, in order to support the Commons Fileupload users, we have - decided to choose a different approach: - </p> - <p> - Beginning with 1.3.3, the class DiskFileItem is still implementing the interface java.io.Serializable. - In other words, it still declares itself as serializable, and deserializable to the JVM. In practice, - however, an attempt to deserialize an instance of DiskFileItem will trigger an Exception. In the unlikely - case, that your application depends on the deserialization of DiskFileItems, you can revert to the - previous behaviour by setting the system property "org.apache.commons.fileupload.disk.DiskFileItem.serializable" - to "true". - </p> - </answer> - </faq> + <title>FileUpload and Flash</title> + + <faq id="diskfileitem-serializable"> + <question> I have read, that there is a security problem in Commons FileUpload, because there is a class called + DiskFileItem, which can be used for malicious attacks. + </question> + <answer> + <p> + It is true, that this class exists, and can be serialized/deserialized in FileUpload versions, up to, and + including 1.3.2. It is also true, that a malicious attacker can abuse this possibility to create abitraryly + located files (assuming the required permissions) with arbitrary contents, if he gets the opportunity to + provide specially crafted data, which is being deserialized by a Java application, which has either of the + above versions of Commons FileUpload in the classpath, and which puts no limitations on the classes being + deserialized. + </p> + <p> + That being said, we (the Apache Commons team) hold the view, that the actual problem is not the DiskFileItem + class, but the "if" in the previous sentence. A Java application should carefully consider, which classes + can be deserialized. A typical approach would be, for example, to provide a blacklist, or whitelist of + packages, and/or classes, which may, or may not be deserialized. + </p> + <p> + On the other hand, we acknowledge, that the likelyhood of application container vendors taking such a + simple security measure is extremely low. So, in order to support the Commons Fileupload users, we have + decided to choose a different approach: + </p> + <p> + Beginning with 1.3.3, the class DiskFileItem is still implementing the interface java.io.Serializable. + In other words, it still declares itself as serializable, and deserializable to the JVM. In practice, + however, an attempt to deserialize an instance of DiskFileItem will trigger an Exception. In the unlikely + case, that your application depends on the deserialization of DiskFileItems, you can revert to the + previous behaviour by setting the system property "org.apache.commons.fileupload.disk.DiskFileItem.serializable" + to "true". + </p> + </answer> + </faq> </part> </faqs> diff --git a/src/site/resources/profile.cobertura b/src/site/resources/profile.cobertura new file mode 100644 index 0000000..f2074df --- /dev/null +++ b/src/site/resources/profile.cobertura @@ -0,0 +1,2 @@ +# This file is intentionally empty. It is only used, because its +# presence activates the generation of a Coberturta report. diff --git a/src/site/site.xml b/src/site/site.xml index a54b55a..7c0b3ce 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -30,12 +30,13 @@ <item name="User guide" href="/using.html" /> <item name="Streaming API" href="/streaming.html" /> <item name="FAQ" href="/faq.html" /> - <item name="Javadoc" href="apidocs/index.html" /> + <item name="Javadoc (Latest release)" href="/javadocs/api-release/index.html" /> <item name="Download" href="/download_fileupload.cgi" /> + <item name="Security Reports" href="/security-reports.html"/> <item name="Mailing lists" href="/mail-lists.html" /> <item name="Issue Tracking" href="/issue-tracking.html" /> <item name="Team" href="/team-list.html" /> - <item name="SVN repository" href="/source-repository.html" /> + <item name="Source repository" href="/source-repository.html" /> </menu> </body> diff --git a/src/site/xdoc/download_fileupload.xml b/src/site/xdoc/download_fileupload.xml index ec57a1f..05f9b69 100644 --- a/src/site/xdoc/download_fileupload.xml +++ b/src/site/xdoc/download_fileupload.xml @@ -31,21 +31,10 @@ limitations under the License. | 2) Set the following properties in the component's pom: | | - commons.componentid (required, alphabetic, lower case) | | - commons.release.version (required) | - | - commons.release.name (required) | - | - commons.binary.suffix (optional) | + | - commons.binary.suffix (optional) | | (defaults to "-bin", set to "" for pre-maven2 releases) | - | - commons.release.desc (optional) | - | - commons.release.subdir (optional) | - | | - | - commons.release.2/3.version (conditional) | - | - commons.release.2/3.name (conditional) | - | - commons.release.2/3.binary.suffix (optional) | - | - commons.release.2/3.desc (optional) | - | - commons.release.2/3.subdir (optional) | | | | 3) Example Properties | - | (commons.release.name inherited by parent: | - | ${project.artifactId}-${commons.release.version} | | | | <properties> | | <commons.componentid>math</commons.componentid> | @@ -57,17 +46,17 @@ limitations under the License. <document> <properties> <title>Download Apache Commons FileUpload</title> - <author email="dev@commons.apache.org">Apache Commons Documentation Team</author> + <author email="dev@commons.apache.org">Commons Documentation Team</author> </properties> <body> <section name="Download Apache Commons FileUpload"> <subsection name="Using a Mirror"> <p> We recommend you use a mirror to download our release - builds, but you <strong>must</strong> <a href="http://www.apache.org/info/verification.html">verify the integrity</a> of + builds, but you <strong>must</strong> verify the integrity of the downloaded files using signatures downloaded from our main distribution directories. Recent releases (48 hours) may not yet - be available from all the mirrors. + be available from the mirrors. </p> <p> @@ -99,44 +88,39 @@ limitations under the License. </form> <p> - It is essential that you - <a href="https://www.apache.org/info/verification.html">verify the integrity</a> - of downloaded files, preferably using the <code>PGP</code> signature (<code>*.asc</code> files); - failing that using the <code>MD5</code> hash (<code>*.md5</code> checksum files). - </p> - <p> - The <a href="https://www.apache.org/dist/commons/KEYS">KEYS</a> - file contains the public PGP keys used by Apache Commons developers - to sign releases. + The <a href="http://www.apache.org/dist/commons/KEYS">KEYS</a> + link links to the code signing keys used to sign the product. + The <code>PGP</code> link downloads the OpenPGP compatible signature from our main site. + The <code>SHA256</code> link downloads the checksum from the main site. </p> </subsection> </section> - <section name="Apache Commons FileUpload 1.3.3 "> + <section name="Apache Commons FileUpload 1.4 (requires Java 1.6 or later)"> <subsection name="Binaries"> <table> <tr> - <td><a href="[preferred]/commons/fileupload/binaries/commons-fileupload-1.3.3-bin.tar.gz">commons-fileupload-1.3.3-bin.tar.gz</a></td> - <td><a href="https://www.apache.org/dist/commons/fileupload/binaries/commons-fileupload-1.3.3-bin.tar.gz.md5">md5</a></td> - <td><a href="https://www.apache.org/dist/commons/fileupload/binaries/commons-fileupload-1.3.3-bin.tar.gz.asc">pgp</a></td> + <td><a href="[preferred]/commons/fileupload/binaries/commons-fileupload-1.4-bin.tar.gz">commons-fileupload-1.4-bin.tar.gz</a></td> + <td><a href="http://www.apache.org/dist/commons/fileupload/binaries/commons-fileupload-1.4-bin.tar.gz.sha256">sha256</a></td> + <td><a href="http://www.apache.org/dist/commons/fileupload/binaries/commons-fileupload-1.4-bin.tar.gz.asc">pgp</a></td> </tr> <tr> - <td><a href="[preferred]/commons/fileupload/binaries/commons-fileupload-1.3.3-bin.zip">commons-fileupload-1.3.3-bin.zip</a></td> - <td><a href="https://www.apache.org/dist/commons/fileupload/binaries/commons-fileupload-1.3.3-bin.zip.md5">md5</a></td> - <td><a href="https://www.apache.org/dist/commons/fileupload/binaries/commons-fileupload-1.3.3-bin.zip.asc">pgp</a></td> + <td><a href="[preferred]/commons/fileupload/binaries/commons-fileupload-1.4-bin.zip">commons-fileupload-1.4-bin.zip</a></td> + <td><a href="http://www.apache.org/dist/commons/fileupload/binaries/commons-fileupload-1.4-bin.zip.sha256">sha256</a></td> + <td><a href="http://www.apache.org/dist/commons/fileupload/binaries/commons-fileupload-1.4-bin.zip.asc">pgp</a></td> </tr> </table> </subsection> <subsection name="Source"> <table> <tr> - <td><a href="[preferred]/commons/fileupload/source/commons-fileupload-1.3.3-src.tar.gz">commons-fileupload-1.3.3-src.tar.gz</a></td> - <td><a href="https://www.apache.org/dist/commons/fileupload/source/commons-fileupload-1.3.3-src.tar.gz.md5">md5</a></td> - <td><a href="https://www.apache.org/dist/commons/fileupload/source/commons-fileupload-1.3.3-src.tar.gz.asc">pgp</a></td> + <td><a href="[preferred]/commons/fileupload/source/commons-fileupload-1.4-src.tar.gz">commons-fileupload-1.4-src.tar.gz</a></td> + <td><a href="http://www.apache.org/dist/commons/fileupload/source/commons-fileupload-1.4-src.tar.gz.sha256">sha256</a></td> + <td><a href="http://www.apache.org/dist/commons/fileupload/source/commons-fileupload-1.4-src.tar.gz.asc">pgp</a></td> </tr> <tr> - <td><a href="[preferred]/commons/fileupload/source/commons-fileupload-1.3.3-src.zip">commons-fileupload-1.3.3-src.zip</a></td> - <td><a href="https://www.apache.org/dist/commons/fileupload/source/commons-fileupload-1.3.3-src.zip.md5">md5</a></td> - <td><a href="https://www.apache.org/dist/commons/fileupload/source/commons-fileupload-1.3.3-src.zip.asc">pgp</a></td> + <td><a href="[preferred]/commons/fileupload/source/commons-fileupload-1.4-src.zip">commons-fileupload-1.4-src.zip</a></td> + <td><a href="http://www.apache.org/dist/commons/fileupload/source/commons-fileupload-1.4-src.zip.sha256">sha256</a></td> + <td><a href="http://www.apache.org/dist/commons/fileupload/source/commons-fileupload-1.4-src.zip.asc">pgp</a></td> </tr> </table> </subsection> @@ -147,7 +131,7 @@ limitations under the License. </p> <ul> <li class="download"><a href="[preferred]/commons/fileupload/">browse download area</a></li> - <li><a href="https://archive.apache.org/dist/commons/fileupload/">archives...</a></li> + <li><a href="http://archive.apache.org/dist/commons/fileupload/">archives...</a></li> </ul> </section> </body> diff --git a/src/site/xdoc/index.xml b/src/site/xdoc/index.xml index c9c0148..2b17343 100644 --- a/src/site/xdoc/index.xml +++ b/src/site/xdoc/index.xml @@ -59,20 +59,34 @@ <li><a href="./using.html">User Guide</a></li> <li><a href="./streaming.html">Streaming API</a></li> <li><a href="./faq.html">Frequently Asked Questions</a></li> - <li><a href="./apidocs/index.html">JavaDoc API</a></li> + <li><a href="./javadocs/api-release/index.html">Javadoc API (Latest release)</a></li> + <li><a href="./apidocs/index.html">Javadoc API (Latest development)</a></li> <li><a href="./project-reports.html">Project Reports</a></li> + <li><a href="https://dist.apache.org/repos/dist/release/commons/fileupload/RELEASE-NOTES.txt">Release Notes</a></li> </ul> <p>You can also <a href="./source-repository.html">browse</a> the Subversion repository.</p> </section> <section name="Downloading"> <subsection name="Full Releases"> - <p><strong>FileUpload 1.3.2</strong> - 26 May 2016</p> + <p><strong>FileUpload 1.4</strong> - 23 December 2018</p> <ul> <li>Download the binary and source distributions from a mirror site <a href="http://commons.apache.org/fileupload/download_fileupload.cgi">here</a> </li> </ul> + <p><strong>FileUpload 1.3.3</strong> - 13 June 2017</p> + <ul> + <li>Download the binary and source distributions from a mirror site + <a href="http://archive.apache.org/dist/commons/fileupload/">here</a> + </li> + </ul> + <p><strong>FileUpload 1.3.2</strong> - 26 May 2016</p> + <ul> + <li>Download the binary and source distributions from the archive site + <a href="http://archive.apache.org/dist/commons/fileupload/">here</a> + </li> + </ul> <p><strong>FileUpload 1.3.1</strong> - 7 February 2014</p> <ul> <li>Download the binary and source distributions from the archive site @@ -81,13 +95,13 @@ </ul> <p><strong>FileUpload 1.3</strong> - 27 March 2013</p> <ul> - <li>Download the binary and source distributions from a mirror site + <li>Download the binary and source distributions from the archive site <a href="http://archive.apache.org/dist/commons/fileupload/">here</a> </li> </ul> <p><strong>FileUpload 1.2.2</strong> - 29 July 2010</p> <ul> - <li>Download the binary and source distributions from a mirror site + <li>Download the binary and source distributions from the archive site <a href="http://archive.apache.org/dist/commons/fileupload/">here</a> </li> </ul> diff --git a/src/site/xdoc/security-reports.xml b/src/site/xdoc/security-reports.xml new file mode 100644 index 0000000..558410a --- /dev/null +++ b/src/site/xdoc/security-reports.xml @@ -0,0 +1,137 @@ +<?xml version="1.0"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<document> + <properties> + <title>Commons FileUpload Security Reports</title> + <author email="dev@commons.apache.org">Commons Documentation Team</author> + </properties> + <body> + <section name="Apache Commons FileUpload Security Vulnerabilities"> + <p>This page lists all security vulnerabilities fixed in + released versions of Apache Commons FileUpload. Each + vulnerability is given a security impact rating by the + development team - please note that this rating may vary from + platform to platform. We also list the versions of Commons + FileUpload the flaw is known to affect, and where a flaw has not + been verified list the version with a question mark.</p> + + <p>Please note that binary patches are never provided. If you + need to apply a source code patch, use the building + instructions for the Commons FileUpload version that you are + using.</p> + + <p>If you need help on building Commons FileUpload or other help + on following the instructions to mitigate the known + vulnerabilities listed here, please send your questions to the + public <a href="mail-lists.html">Commons Users mailing + list</a>.</p> + + <p>If you have encountered an unlisted security vulnerability + or other unexpected behaviour that has security impact, or if + the descriptions here are incomplete, please report them + privately to the Apache Security Team. Thank you.</p> + + <p>For information about reporting or asking questions about + security problems, please see the <a + href="http://commons.apache.org/security.html">security page + of the Apache Commons project</a>.</p> + + <subsection name="Notes on Apache Commons FileUpload 1.3.3"> + <p> + Regarding potential security problems with the class called DiskFileItem, + it is true, that this class exists, and can be serialized/deserialized in FileUpload versions, up to, and + including 1.3.2. It is also true, that a malicious attacker can abuse this possibility to create abitraryly + located files (assuming the required permissions) with arbitrary contents, if he gets the opportunity to + provide specially crafted data, which is being deserialized by a Java application, which has either of the + above versions of Commons FileUpload in the classpath, and which puts no limitations on the classes being + deserialized. + </p> + <p> + That being said, we (the Apache Commons team) hold the view, that the actual problem is not the DiskFileItem + class, but the "if" in the previous sentence. A Java application should carefully consider, which classes + can be deserialized. A typical approach would be, for example, to provide a blacklist, or whitelist of + packages, and/or classes, which may, or may not be deserialized. + </p> + <p> + On the other hand, we acknowledge, that the likelyhood of application container vendors taking such a + simple security measure is extremely low. So, in order to support the Commons Fileupload users, we have + decided to choose a different approach: + </p> + <p> + Beginning with 1.3.3, the class DiskFileItem is still implementing the interface java.io.Serializable. + In other words, it still declares itself as serializable, and deserializable to the JVM. In practice, + however, an attempt to deserialize an instance of DiskFileItem will trigger an Exception. In the unlikely + case, that your application depends on the deserialization of DiskFileItems, you can revert to the + previous behaviour by setting the system property "org.apache.commons.fileupload.disk.DiskFileItem.serializable" + to "true". + </p> + </subsection> + + <subsection name="Fixed in Apache Commons FileUpload 1.3.2"> + <p><b>Low: Denial of Service</b> <a + href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-3092">CVE-2016-3092</a></p> + + <p>Specially crafted input can trigger a DoS (slow uploads), if the size of the MIME + boundary is close to the size of the buffer in MultipartStream. This is also fixed + for <a href="https://tomcat.apache.org/security.html">Apache Tomcat</a>.</p> + + <p>This was fixed in revisions + <a href="http://svn.apache.org/viewvc?view=revision&revision=1743480">1743480</a>.</p> + + <p>Affects: 1.0? - 1.3.1</p> + </subsection> + + <subsection name="Fixed in Apache Commons FileUpload 1.3.1"> + <p><b>Low: Denial of Service</b> <a + href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=2014-0050">CVE-2014-0050</a></p> + + <p>MultipartStream.java in Apache Commons FileUpload before 1.3.1, as used in + <a href="https://tomcat.apache.org/security.html">Apache Tomcat</a>, + JBoss Web, and other products, allows remote attackers to cause a denial of service (infinite + loop and CPU consumption) via a crafted Content-Type header that bypasses a loop's intended + exit conditions.</p> + + <p>This was fixed in revisions + <a href="http://svn.apache.org/viewvc?view=revision&revision=1565143">1565143</a>.</p> + + <p>Affects: 1.0? - 1.3</p> + </subsection> + + <subsection name="Fixed in Apache Commons FileUpload 1.3"> + + <p><b>Low: Improved Documentation for Multitenancy</b> <a + href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=2013-0248">CVE-2013-0248</a></p> + + <p>Update the Javadoc and documentation to make it clear that setting a repository + is required for a secure configuration if there are local, untrusted users.</p> + + <p>This was fixed in revisions + <a href="http://svn.apache.org/viewvc?view=revision&revision=1453273">1453273</a>.</p> + + <p>Affects: 1.0 - 1.2.2</p> + </subsection> + + </section> + + <section name="Errors and Ommissions"> + <p>Please report any errors or omissions to <a + href="mail-lists.html">the dev mailing list</a>.</p> + </section> + </body> +</document> diff --git a/src/site/xdoc/streaming.xml b/src/site/xdoc/streaming.xml index 2c2cd10..a765975 100644 --- a/src/site/xdoc/streaming.xml +++ b/src/site/xdoc/streaming.xml @@ -27,14 +27,14 @@ <section name="Why Streaming?"> <p> The traditional API, which is described in the <a href="using.html">User - Guide</a>, assumes, that file items must be stored somewhere, before + Guide</a>, assumes that file items must be stored somewhere before they are actually accessable by the user. This approach is convenient, because it allows easy access to an items contents. On the other hand, it is memory and time consuming. </p> <p> The streaming API allows you to trade a little bit of convenience for - optimal performance and and a low memory profile. Additionally, the + optimal performance and a low memory profile. Additionally, the API is more lightweight, thus easier to understand. </p> </section> @@ -42,7 +42,7 @@ <section name="How it works"> <p> Again, the <code>FileUpload</code> class is used for accessing the - form fields and fields in the order, in which they have been sent + form fields and fields in the order in which they have been sent by the client. However, the <code>FileItemFactory</code> is completely ignored. </p> @@ -50,7 +50,7 @@ <section name="Parsing the request"> <p> - First of all, do not forget to ensure, that a request actually is a + First of all, do not forget to ensure that a request actually is a a file upload request. This is typically done using the same static method, which you already know from the traditional API. </p> @@ -68,7 +68,7 @@ FileItemIterator iter = upload.getItemIterator(request); while (iter.hasNext()) { FileItemStream item = iter.next(); String name = item.getFieldName(); - InputStream stream = item.openStream(); + InputStream stream = item.getInputStream(); if (item.isFormField()) { System.out.println("Form field " + name + " with value " + Streams.asString(stream) + " detected."); diff --git a/src/site/xdoc/using.xml b/src/site/xdoc/using.xml index 8e2113b..8b2dfd5 100644 --- a/src/site/xdoc/using.xml +++ b/src/site/xdoc/using.xml @@ -284,8 +284,8 @@ byte[] data = item.get(); </p> <p> Such temporary files are deleted automatically, if they are no longer - used (more precisely, if the corresponding instance of <code>java.io.File</code> - is garbage collected. This is done silently by the <code>org.apache.commons.io.FileCleaner</code> + used (more precisely, if the corresponding instance of <code>DiskFileItem</code> + is garbage collected. This is done silently by the <code>org.apache.commons.io.FileCleanerTracker</code> class, which starts a reaper thread. </p> <p> @@ -426,7 +426,7 @@ ProgressListener progressListener = new ProgressListener(){ Hopefully this page has provided you with a good idea of how to use FileUpload in your own applications. For more detail on the methods introduced here, as well as other available methods, you should refer - to the <a href="./apidocs/index.html">JavaDocs</a>. + to the <a href="./apidocs/index.html">Javadocs</a>. </p> <p> The usage described here should satisfy a large majority of file upload diff --git a/src/test/java/org/apache/commons/fileupload/Constants.java b/src/test/java/org/apache/commons/fileupload/Constants.java new file mode 100644 index 0000000..69eaa53 --- /dev/null +++ b/src/test/java/org/apache/commons/fileupload/Constants.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.fileupload; + +/** + * Constants used for testing. + * + * @since 1.4 + */ +public final class Constants { + + /** + * The content type used in several tests. + */ + public static final String CONTENT_TYPE = "multipart/form-data; boundary=---1234"; + + private Constants() {} +} diff --git a/src/test/java/org/apache/commons/fileupload/DefaultFileItemTest.java b/src/test/java/org/apache/commons/fileupload/DefaultFileItemTest.java index cf27803..0855cb5 100644 --- a/src/test/java/org/apache/commons/fileupload/DefaultFileItemTest.java +++ b/src/test/java/org/apache/commons/fileupload/DefaultFileItemTest.java @@ -27,13 +27,12 @@ import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.util.Arrays; +import org.apache.commons.io.FileUtils; import org.junit.Test; /** * Unit tests for {@link org.apache.commons.fileupload.DefaultFileItem}. - * - * @version $Id$ */ @SuppressWarnings({"deprecation", "javadoc"}) // unit tests for deprecated class public class DefaultFileItemTest { @@ -142,11 +141,11 @@ public class DefaultFileItemTest { * configured threshold, where a specific repository is configured. */ @Test - public void testAboveThresholdSpecifiedRepository() { + public void testAboveThresholdSpecifiedRepository() throws IOException { String tempPath = System.getProperty("java.io.tmpdir"); String tempDirName = "testAboveThresholdSpecifiedRepository"; File tempDir = new File(tempPath, tempDirName); - tempDir.mkdir(); + FileUtils.forceMkdir(tempDir); doTestAboveThreshold(tempDir); assertTrue(tempDir.delete()); } diff --git a/src/test/java/org/apache/commons/fileupload/DiskFileItemSerializeTest.java b/src/test/java/org/apache/commons/fileupload/DiskFileItemSerializeTest.java index fb8e6e1..4507d58 100644 --- a/src/test/java/org/apache/commons/fileupload/DiskFileItemSerializeTest.java +++ b/src/test/java/org/apache/commons/fileupload/DiskFileItemSerializeTest.java @@ -30,22 +30,38 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; -import org.apache.commons.fileupload.disk.DiskFileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.io.FileUtils; +import org.junit.After; +import org.junit.Before; import org.junit.Test; - /** * Serialization Unit tests for * {@link org.apache.commons.fileupload.disk.DiskFileItem}. - * - * @version $Id$ */ public class DiskFileItemSerializeTest { - private static final String ERRMSG_DISKFILEITEM_DESERIALIZED = "Property org.apache.commons.fileupload.disk.DiskFileItem.serializable is not true, rejecting to deserialize a DiskFileItem."; + // Use a private repo to catch any files left over by tests + private static final File REPO = new File(System.getProperty("java.io.tmpdir"), "diskfileitemrepo"); + + @Before + public void setUp() throws Exception { + if (REPO.exists()) { + FileUtils.deleteDirectory(REPO); + } + FileUtils.forceMkdir(REPO); + } - /** + @After + public void tearDown() throws IOException { + for(File file : FileUtils.listFiles(REPO, null, true)) { + System.out.println("Found leftover file " + file); + } + FileUtils.deleteDirectory(REPO); + } + + /** * Content type for regular form items. */ private static final String textContentType = "text/plain"; @@ -65,31 +81,22 @@ public class DiskFileItemSerializeTest { assertTrue("Initial: in memory", item.isInMemory()); assertEquals("Initial: size", item.getSize(), testFieldValueBytes.length); compareBytes("Initial", item.get(), testFieldValueBytes); - - // Serialize & Deserialize - FileItem newItem = (FileItem)serializeDeserialize(item); - - // Test deserialized content is as expected - assertTrue("Check in memory", newItem.isInMemory()); - compareBytes("Check", testFieldValueBytes, newItem.get()); - - // Compare FileItem's (except byte[]) - compareFileItems(item, newItem); + item.delete(); } - + /** * Helper method to test creation of a field. */ private void testInMemoryObject(byte[] testFieldValueBytes) { - testInMemoryObject(testFieldValueBytes, null); + testInMemoryObject(testFieldValueBytes, REPO); } - + /** * Test creation of a field for which the amount of data falls below the * configured threshold. */ @Test - public void testBelowThreshold() throws Exception { + public void testBelowThreshold() { // Create the FileItem byte[] testFieldValueBytes = createContentBytes(threshold - 1); testInMemoryObject(testFieldValueBytes); @@ -100,7 +107,7 @@ public class DiskFileItemSerializeTest { * configured threshold. */ @Test - public void testThreshold() throws Exception { + public void testThreshold() { // Create the FileItem byte[] testFieldValueBytes = createContentBytes(threshold); testInMemoryObject(testFieldValueBytes); @@ -111,7 +118,7 @@ public class DiskFileItemSerializeTest { * configured threshold. */ @Test - public void testAboveThreshold() throws Exception { + public void testAboveThreshold() { // Create the FileItem byte[] testFieldValueBytes = createContentBytes(threshold + 1); FileItem item = createFileItem(testFieldValueBytes); @@ -121,28 +128,19 @@ public class DiskFileItemSerializeTest { assertEquals("Initial: size", item.getSize(), testFieldValueBytes.length); compareBytes("Initial", item.get(), testFieldValueBytes); - // Serialize & Deserialize - FileItem newItem = (FileItem)serializeDeserialize(item); - - // Test deserialized content is as expected - assertFalse("Check in memory", newItem.isInMemory()); - compareBytes("Check", testFieldValueBytes, newItem.get()); - - // Compare FileItem's (except byte[]) - compareFileItems(item, newItem); + item.delete(); } - + /** * Test serialization and deserialization when repository is not null. */ @Test - public void testValidRepository() throws Exception { + public void testValidRepository() { // Create the FileItem byte[] testFieldValueBytes = createContentBytes(threshold); - File repository = new File(System.getProperty("java.io.tmpdir")); - testInMemoryObject(testFieldValueBytes, repository); + testInMemoryObject(testFieldValueBytes, REPO); } - + /** * Test deserialization fails when repository is not valid. */ @@ -150,38 +148,21 @@ public class DiskFileItemSerializeTest { public void testInvalidRepository() throws Exception { // Create the FileItem byte[] testFieldValueBytes = createContentBytes(threshold); - File repository = new File(System.getProperty("java.io.tmpdir") + "file"); + File repository = new File(System.getProperty("java.io.tmpdir"), "file"); FileItem item = createFileItem(testFieldValueBytes, repository); deserialize(serialize(item)); } - + /** * Test deserialization fails when repository contains a null character. */ - @Test + @Test(expected=IOException.class) public void testInvalidRepositoryWithNullChar() throws Exception { // Create the FileItem byte[] testFieldValueBytes = createContentBytes(threshold); - File repository = new File(System.getProperty("java.io.tmpdir") + "\0"); + File repository = new File(System.getProperty("java.io.tmpdir"), "\0"); FileItem item = createFileItem(testFieldValueBytes, repository); - try { - deserialize(serialize(item)); - fail("Expected Exception"); - } catch (IllegalStateException e) { - assertEquals(ERRMSG_DISKFILEITEM_DESERIALIZED, e.getMessage()); - } - System.setProperty(DiskFileItem.SERIALIZABLE_PROPERTY, "true"); - } - - /** - * Compare FileItem's (except the byte[] content) - */ - private void compareFileItems(FileItem origItem, FileItem newItem) { - assertTrue("Compare: is in Memory", origItem.isInMemory() == newItem.isInMemory()); - assertTrue("Compare: is Form Field", origItem.isFormField() == newItem.isFormField()); - assertEquals("Compare: Field Name", origItem.getFieldName(), newItem.getFieldName()); - assertEquals("Compare: Content Type", origItem.getContentType(), newItem.getContentType()); - assertEquals("Compare: File Name", origItem.getName(), newItem.getName()); + deserialize(serialize(item)); } /** @@ -236,14 +217,14 @@ public class DiskFileItemSerializeTest { return item; } - + /** * Create a FileItem with the specfied content bytes. */ private FileItem createFileItem(byte[] contentBytes) { - return createFileItem(contentBytes, null); + return createFileItem(contentBytes, REPO); } - + /** * Do serialization */ @@ -255,7 +236,7 @@ public class DiskFileItemSerializeTest { oos.close(); return baos; } - + /** * Do deserialization */ @@ -269,28 +250,4 @@ public class DiskFileItemSerializeTest { return result; } - - /** - * Do serialization and deserialization. - */ - private Object serializeDeserialize(Object target) { - // Serialize the test object - ByteArrayOutputStream baos = null; - try { - baos = serialize(target); - } catch (Exception e) { - fail("Exception during serialization: " + e); - } - - // Deserialize the test object - Object result = null; - try { - result = deserialize(baos); - } catch (Exception e) { - fail("Exception during deserialization: " + e); - } - - return result; - } - } diff --git a/src/test/java/org/apache/commons/fileupload/DiskFileUploadTest.java b/src/test/java/org/apache/commons/fileupload/DiskFileUploadTest.java new file mode 100644 index 0000000..49f65f0 --- /dev/null +++ b/src/test/java/org/apache/commons/fileupload/DiskFileUploadTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.fileupload; + +import static org.junit.Assert.fail; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.Before; +import org.junit.Test; + +/** + * Test for {@link DiskFileUpload}. Remove when deprecated class is removed. + * + * @since 1.4 + */ +@SuppressWarnings({"deprecation"}) // unit tests for deprecated class +public class DiskFileUploadTest { + + private DiskFileUpload upload; + + @Before + public void setUp() { + upload = new DiskFileUpload(); + } + + @Test + public void testWithInvalidRequest() { + HttpServletRequest req = HttpServletRequestFactory.createInvalidHttpServletRequest(); + + try { + upload.parseRequest(req); + fail("testWithInvalidRequest: expected exception was not thrown"); + } catch (FileUploadException expected) { + // this exception is expected + } + } + + @Test + public void testWithNullContentType() { + HttpServletRequest req = HttpServletRequestFactory.createHttpServletRequestWithNullContentType(); + + try { + upload.parseRequest(req); + fail("testWithNullContentType: expected exception was not thrown"); + } catch (DiskFileUpload.InvalidContentTypeException expected) { + // this exception is expected + } catch (FileUploadException unexpected) { + fail("testWithNullContentType: unexpected exception was thrown"); + } + } + +} diff --git a/src/test/java/org/apache/commons/fileupload/FileItemHeadersTest.java b/src/test/java/org/apache/commons/fileupload/FileItemHeadersTest.java index 2042488..0b654aa 100644 --- a/src/test/java/org/apache/commons/fileupload/FileItemHeadersTest.java +++ b/src/test/java/org/apache/commons/fileupload/FileItemHeadersTest.java @@ -29,8 +29,6 @@ import org.junit.Test; /** * Unit tests {@link FileItemHeaders} and * {@link FileItemHeadersImpl}. - * - * @version $Id$ */ public class FileItemHeadersTest { diff --git a/src/test/java/org/apache/commons/fileupload/ServletFileUploadTest.java b/src/test/java/org/apache/commons/fileupload/FileUploadTest.java similarity index 78% rename from src/test/java/org/apache/commons/fileupload/ServletFileUploadTest.java rename to src/test/java/org/apache/commons/fileupload/FileUploadTest.java index 27c1ec8..3739b8d 100644 --- a/src/test/java/org/apache/commons/fileupload/ServletFileUploadTest.java +++ b/src/test/java/org/apache/commons/fileupload/FileUploadTest.java @@ -20,64 +20,52 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.List; -import java.util.Map; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.fileupload.disk.DiskFileItemFactory; -import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.fileupload.portlet.PortletFileUploadTest; +import org.apache.commons.fileupload.servlet.ServletFileUploadTest; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; /** - * Unit tests {@link org.apache.commons.fileupload.DiskFileUpload}. + * Common tests for implementations of {@link FileUpload}. This is a parameterized test. + * Tests must be valid and common to all implementations of FileUpload added as parameter + * in this class. * - * @version $Id$ + * @see ServletFileUploadTest + * @see PortletFileUploadTest + * @since 1.4 */ -@SuppressWarnings({"deprecation", "javadoc"}) // unit tests for deprecated class -public class ServletFileUploadTest extends FileUploadTestCase { - - @Test - public void testWithInvalidRequest() { - FileUploadBase fu = null; - - fu = new DiskFileUpload(); +@RunWith(Parameterized.class) +public class FileUploadTest { - HttpServletRequest req = HttpServletRequestFactory.createInvalidHttpServletRequest(); - - - try { - fu.parseRequest(req); - fail("testWithInvalidRequest: expected exception was not thrown"); - } catch (FileUploadException expected) { - // this exception is expected - } + /** + * @return {@link FileUpload} classes under test. + */ + @Parameters(name="{0}") + public static Iterable<? extends Object> data() { + return Util.fileUploadImplementations(); } - @Test - public void testWithNullContentType() { - FileUploadBase fu = new DiskFileUpload(); - - HttpServletRequest req = HttpServletRequestFactory.createHttpServletRequestWithNullContentType(); - - try { - fu.parseRequest(req); - fail("testWithNullContentType: expected exception was not thrown"); - } catch (DiskFileUpload.InvalidContentTypeException expected) { - // this exception is expected - } catch (FileUploadException unexpected) { - fail("testWithNullContentType: unexpected exception was thrown"); - } - } + /** + * Current parameterized FileUpload. + */ + @Parameter + public FileUpload upload; + + // --- Test methods common to all implementations of a FileUpload @Test public void testFileUpload() throws IOException, FileUploadException { - List<FileItem> fileItems = parseUpload("-----1234\r\n" + + List<FileItem> fileItems = Util.parseUpload(upload, + "-----1234\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" + "Content-Type: text/whatever\r\n" + "\r\n" + @@ -124,7 +112,8 @@ public class ServletFileUploadTest extends FileUploadTestCase { @Test public void testFilenameCaseSensitivity() throws IOException, FileUploadException { - List<FileItem> fileItems = parseUpload("-----1234\r\n" + + List<FileItem> fileItems = Util.parseUpload(upload, + "-----1234\r\n" + "Content-Disposition: form-data; name=\"FiLe\"; filename=\"FOO.tab\"\r\n" + "Content-Type: text/whatever\r\n" + "\r\n" + @@ -144,7 +133,8 @@ public class ServletFileUploadTest extends FileUploadTestCase { @Test public void testEmptyFile() throws UnsupportedEncodingException, FileUploadException { - List<FileItem> fileItems = parseUpload ("-----1234\r\n" + + List<FileItem> fileItems = Util.parseUpload (upload, + "-----1234\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"\"\r\n" + "\r\n" + "\r\n" + @@ -165,7 +155,8 @@ public class ServletFileUploadTest extends FileUploadTestCase { @Test public void testIE5MacBug() throws UnsupportedEncodingException, FileUploadException { - List<FileItem> fileItems = parseUpload("-----1234\r\n" + + List<FileItem> fileItems = Util.parseUpload(upload, + "-----1234\r\n" + "Content-Disposition: form-data; name=\"field1\"\r\n" + "\r\n" + "fieldValue\r\n" + @@ -234,7 +225,7 @@ public class ServletFileUploadTest extends FileUploadTestCase { "...contents of file2.gif...\r\n" + "--BbC04y--\r\n" + "--AaB03x--"; - List<FileItem> fileItems = parseUpload(request.getBytes("US-ASCII"), contentType); + List<FileItem> fileItems = Util.parseUpload(upload, request.getBytes("US-ASCII"), contentType); assertEquals(3, fileItems.size()); FileItem item0 = fileItems.get(0); assertEquals("field1", item0.getFieldName()); @@ -256,7 +247,7 @@ public class ServletFileUploadTest extends FileUploadTestCase { @Test public void testFoldedHeaders() throws IOException, FileUploadException { - List<FileItem> fileItems = parseUpload("-----1234\r\n" + + List<FileItem> fileItems = Util.parseUpload(upload, "-----1234\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" + "Content-Type: text/whatever\r\n" + "\r\n" + @@ -316,7 +307,8 @@ public class ServletFileUploadTest extends FileUploadTestCase { { "present", "Is there", "Here", "Is That" }; - List<FileItem> fileItems = parseUpload("-----1234\r\n" + + List<FileItem> fileItems = Util.parseUpload(upload, + "-----1234\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" + "Content-Type: text/whatever\r\n" + headerNames[0] + ": " + headerValues[0] + "\r\n" + @@ -357,48 +349,45 @@ public class ServletFileUploadTest extends FileUploadTestCase { } /** - * Test case for <a href="http://issues.apache.org/jira/browse/FILEUPLOAD-210"> + * Test for <a href="http://issues.apache.org/jira/browse/FILEUPLOAD-239">FILEUPLOAD-239</a> */ @Test - public void parseParameterMap() - throws Exception { - String text = "-----1234\r\n" + - "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" + - "Content-Type: text/whatever\r\n" + - "\r\n" + - "This is the content of the file\n" + - "\r\n" + - "-----1234\r\n" + - "Content-Disposition: form-data; name=\"field\"\r\n" + - "\r\n" + - "fieldValue\r\n" + - "-----1234\r\n" + - "Content-Disposition: form-data; name=\"multi\"\r\n" + - "\r\n" + - "value1\r\n" + - "-----1234\r\n" + - "Content-Disposition: form-data; name=\"multi\"\r\n" + - "\r\n" + - "value2\r\n" + - "-----1234--\r\n"; - byte[] bytes = text.getBytes("US-ASCII"); - ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); - HttpServletRequest request = new MockHttpServletRequest(bytes, CONTENT_TYPE); - - Map<String, List<FileItem>> mappedParameters = upload.parseParameterMap(request); - assertTrue(mappedParameters.containsKey("file")); - assertEquals(1, mappedParameters.get("file").size()); - - assertTrue(mappedParameters.containsKey("field")); - assertEquals(1, mappedParameters.get("field").size()); - - assertTrue(mappedParameters.containsKey("multi")); - assertEquals(2, mappedParameters.get("multi").size()); + public void testContentTypeAttachment() + throws IOException, FileUploadException { + List<FileItem> fileItems = Util.parseUpload(upload, + "-----1234\r\n" + + "content-disposition: form-data; name=\"field1\"\r\n" + + "\r\n" + + "Joe Blow\r\n" + + "-----1234\r\n" + + "content-disposition: form-data; name=\"pics\"\r\n" + + "Content-type: multipart/mixed, boundary=---9876\r\n" + + "\r\n" + + "-----9876\r\n" + + "Content-disposition: attachment; filename=\"file1.txt\"\r\n" + + "Content-Type: text/plain\r\n" + + "\r\n" + + "... contents of file1.txt ...\r\n" + + "-----9876--\r\n" + + "-----1234--\r\n"); + assertEquals(2, fileItems.size()); + + FileItem field = fileItems.get(0); + assertEquals("field1", field.getFieldName()); + assertTrue(field.isFormField()); + assertEquals("Joe Blow", field.getString()); + + FileItem file = fileItems.get(1); + assertEquals("pics", file.getFieldName()); + assertFalse(file.isFormField()); + assertEquals("... contents of file1.txt ...", file.getString()); + assertEquals("text/plain", file.getContentType()); + assertEquals("file1.txt", file.getName()); } private void assertHeaders(String[] pHeaderNames, String[] pHeaderValues, - FileItem pItem, int pIndex) { - for (int i = 0; i < pHeaderNames.length; i++) { + FileItem pItem, int pIndex) { + for (int i = 0; i < pHeaderNames.length; i++) { final String value = pItem.getHeaders().getHeader(pHeaderNames[i]); if (i == pIndex) { assertEquals(pHeaderValues[i], value); @@ -407,5 +396,4 @@ public class ServletFileUploadTest extends FileUploadTestCase { } } } - } diff --git a/src/test/java/org/apache/commons/fileupload/HttpServletRequestFactory.java b/src/test/java/org/apache/commons/fileupload/HttpServletRequestFactory.java index 0f478dd..c9833a7 100644 --- a/src/test/java/org/apache/commons/fileupload/HttpServletRequestFactory.java +++ b/src/test/java/org/apache/commons/fileupload/HttpServletRequestFactory.java @@ -18,9 +18,6 @@ package org.apache.commons.fileupload; import javax.servlet.http.HttpServletRequest; -/** - * @version $Id$ - */ final class HttpServletRequestFactory { static public HttpServletRequest createHttpServletRequestWithNullContentType() { diff --git a/src/test/java/org/apache/commons/fileupload/MockHttpServletRequest.java b/src/test/java/org/apache/commons/fileupload/MockHttpServletRequest.java index f324929..07ca064 100644 --- a/src/test/java/org/apache/commons/fileupload/MockHttpServletRequest.java +++ b/src/test/java/org/apache/commons/fileupload/MockHttpServletRequest.java @@ -32,16 +32,13 @@ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; -/** - * @version $Id$ - */ -class MockHttpServletRequest implements HttpServletRequest { +public class MockHttpServletRequest implements HttpServletRequest { private final InputStream m_requestData; private long length; - private String m_strContentType; + private final String m_strContentType; private int readLimit = -1; @@ -75,6 +72,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getAuthType() */ + @Override public String getAuthType() { return null; } @@ -82,6 +80,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getCookies() */ + @Override public Cookie[] getCookies() { return null; } @@ -89,6 +88,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getDateHeader(String) */ + @Override public long getDateHeader(String arg0) { return 0; } @@ -96,6 +96,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getHeader(String) */ + @Override public String getHeader(String headerName) { return m_headers.get(headerName); } @@ -103,6 +104,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getHeaders(String) */ + @Override public Enumeration<String> getHeaders(String arg0) { // todo - implement return null; @@ -111,6 +113,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getHeaderNames() */ + @Override public Enumeration<String> getHeaderNames() { // todo - implement return null; @@ -119,6 +122,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getIntHeader(String) */ + @Override public int getIntHeader(String arg0) { return 0; } @@ -126,6 +130,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getMethod() */ + @Override public String getMethod() { return null; } @@ -133,6 +138,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getPathInfo() */ + @Override public String getPathInfo() { return null; } @@ -140,6 +146,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getPathTranslated() */ + @Override public String getPathTranslated() { return null; } @@ -147,6 +154,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getContextPath() */ + @Override public String getContextPath() { return null; } @@ -154,6 +162,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getQueryString() */ + @Override public String getQueryString() { return null; } @@ -161,6 +170,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getRemoteUser() */ + @Override public String getRemoteUser() { return null; } @@ -168,6 +178,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#isUserInRole(String) */ + @Override public boolean isUserInRole(String arg0) { return false; } @@ -175,6 +186,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getUserPrincipal() */ + @Override public Principal getUserPrincipal() { return null; } @@ -182,6 +194,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getRequestedSessionId() */ + @Override public String getRequestedSessionId() { return null; } @@ -189,6 +202,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getRequestURI() */ + @Override public String getRequestURI() { return null; } @@ -196,6 +210,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getRequestURL() */ + @Override public StringBuffer getRequestURL() { return null; } @@ -203,6 +218,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getServletPath() */ + @Override public String getServletPath() { return null; } @@ -210,6 +226,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getSession(boolean) */ + @Override public HttpSession getSession(boolean arg0) { return null; } @@ -217,6 +234,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#getSession() */ + @Override public HttpSession getSession() { return null; } @@ -224,6 +242,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdValid() */ + @Override public boolean isRequestedSessionIdValid() { return false; } @@ -231,6 +250,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromCookie() */ + @Override public boolean isRequestedSessionIdFromCookie() { return false; } @@ -238,6 +258,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromURL() */ + @Override public boolean isRequestedSessionIdFromURL() { return false; } @@ -246,6 +267,7 @@ class MockHttpServletRequest implements HttpServletRequest { * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromUrl() * @deprecated */ + @Override @Deprecated public boolean isRequestedSessionIdFromUrl() { return false; @@ -254,6 +276,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getAttribute(String) */ + @Override public Object getAttribute(String arg0) { return null; } @@ -261,6 +284,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getAttributeNames() */ + @Override public Enumeration<String> getAttributeNames() { return null; } @@ -268,6 +292,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getCharacterEncoding() */ + @Override public String getCharacterEncoding() { return null; } @@ -275,6 +300,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#setCharacterEncoding(String) */ + @Override public void setCharacterEncoding(String arg0) throws UnsupportedEncodingException { } @@ -282,6 +308,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getContentLength() */ + @Override public int getContentLength() { int iLength = 0; @@ -306,6 +333,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getContentType() */ + @Override public String getContentType() { return m_strContentType; } @@ -313,6 +341,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getInputStream() */ + @Override public ServletInputStream getInputStream() throws IOException { ServletInputStream sis = new MyServletInputStream(m_requestData, readLimit); return sis; @@ -330,6 +359,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getParameter(String) */ + @Override public String getParameter(String arg0) { return null; } @@ -337,6 +367,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getParameterNames() */ + @Override public Enumeration<String> getParameterNames() { return null; } @@ -344,6 +375,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getParameterValues(String) */ + @Override public String[] getParameterValues(String arg0) { return null; } @@ -351,6 +383,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getParameterMap() */ + @Override public Map<String, String[]> getParameterMap() { return null; } @@ -358,6 +391,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getProtocol() */ + @Override public String getProtocol() { return null; } @@ -365,6 +399,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getScheme() */ + @Override public String getScheme() { return null; } @@ -372,6 +407,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getServerName() */ + @Override public String getServerName() { return null; } @@ -379,6 +415,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getLocalName() */ + @Override @SuppressWarnings("javadoc") // This is a Servlet 2.4 method public String getLocalName() { return null; @@ -387,6 +424,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getServerPort() */ + @Override public int getServerPort() { return 0; } @@ -394,6 +432,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getLocalPort() */ + @Override @SuppressWarnings("javadoc") // This is a Servlet 2.4 method public int getLocalPort() { return 0; @@ -402,6 +441,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getRemotePort() */ + @Override @SuppressWarnings("javadoc") // This is a Servlet 2.4 method public int getRemotePort() { return 0; @@ -410,6 +450,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getReader() */ + @Override public BufferedReader getReader() throws IOException { return null; } @@ -417,6 +458,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getRemoteAddr() */ + @Override public String getRemoteAddr() { return null; } @@ -424,6 +466,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getLocalAddr() */ + @Override @SuppressWarnings("javadoc") // This is a Servlet 2.4 method public String getLocalAddr() { return null; @@ -432,6 +475,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getRemoteHost() */ + @Override public String getRemoteHost() { return null; } @@ -439,18 +483,21 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#setAttribute(String, Object) */ + @Override public void setAttribute(String arg0, Object arg1) { } /** * @see javax.servlet.ServletRequest#removeAttribute(String) */ + @Override public void removeAttribute(String arg0) { } /** * @see javax.servlet.ServletRequest#getLocale() */ + @Override public Locale getLocale() { return null; } @@ -458,6 +505,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getLocales() */ + @Override public Enumeration<Locale> getLocales() { return null; } @@ -465,6 +513,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#isSecure() */ + @Override public boolean isSecure() { return false; } @@ -472,6 +521,7 @@ class MockHttpServletRequest implements HttpServletRequest { /** * @see javax.servlet.ServletRequest#getRequestDispatcher(String) */ + @Override public RequestDispatcher getRequestDispatcher(String arg0) { return null; } @@ -480,6 +530,7 @@ class MockHttpServletRequest implements HttpServletRequest { * @see javax.servlet.ServletRequest#getRealPath(String) * @deprecated */ + @Override @Deprecated public String getRealPath(String arg0) { return null; diff --git a/src/test/java/org/apache/commons/fileupload/MultipartStreamTest.java b/src/test/java/org/apache/commons/fileupload/MultipartStreamTest.java index af708c1..edbc370 100644 --- a/src/test/java/org/apache/commons/fileupload/MultipartStreamTest.java +++ b/src/test/java/org/apache/commons/fileupload/MultipartStreamTest.java @@ -25,8 +25,6 @@ import org.junit.Test; /** * Unit tests {@link org.apache.commons.fileupload.MultipartStream}. - * - * @version $Id$ */ public class MultipartStreamTest { @@ -48,7 +46,6 @@ public class MultipartStreamTest { assertNotNull(ms); } - @SuppressWarnings("unused") @Test(expected=IllegalArgumentException.class) public void testSmallBuffer() throws Exception { final String strData = "foobar"; diff --git a/src/test/java/org/apache/commons/fileupload/ParameterParserTest.java b/src/test/java/org/apache/commons/fileupload/ParameterParserTest.java index 4e55c77..da86ec6 100644 --- a/src/test/java/org/apache/commons/fileupload/ParameterParserTest.java +++ b/src/test/java/org/apache/commons/fileupload/ParameterParserTest.java @@ -25,8 +25,6 @@ import org.junit.Test; /** * Unit tests for {@link ParameterParser}. - * - * @version $Id$ */ public class ParameterParserTest { diff --git a/src/test/java/org/apache/commons/fileupload/ProgressListenerTest.java b/src/test/java/org/apache/commons/fileupload/ProgressListenerTest.java index 884f8f8..4b30080 100644 --- a/src/test/java/org/apache/commons/fileupload/ProgressListenerTest.java +++ b/src/test/java/org/apache/commons/fileupload/ProgressListenerTest.java @@ -28,11 +28,9 @@ import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.junit.Test; /** - * Tests the progress listener. - * - * @version $Id$ + * Tests the {@link ProgressListener}. */ -public class ProgressListenerTest extends FileUploadTestCase { +public class ProgressListenerTest { private class ProgressListenerImpl implements ProgressListener { @@ -49,6 +47,7 @@ public class ProgressListenerTest extends FileUploadTestCase { expectedItems = pItems; } + @Override public void update(long pBytesRead, long pContentLength, int pItems) { assertTrue(pBytesRead >= 0 && pBytesRead <= expectedContentLength); assertTrue(pContentLength == -1 || pContentLength == expectedContentLength); @@ -87,9 +86,9 @@ public class ProgressListenerTest extends FileUploadTestCase { baos.write("-----1234--\r\n".getBytes("US-ASCII")); byte[] contents = baos.toByteArray(); - MockHttpServletRequest request = new MockHttpServletRequest(contents, "multipart/form-data; boundary=---1234"); + MockHttpServletRequest request = new MockHttpServletRequest(contents, Constants.CONTENT_TYPE); runTest(NUM_ITEMS, contents.length, request); - request = new MockHttpServletRequest(contents, "multipart/form-data; boundary=---1234"){ + request = new MockHttpServletRequest(contents, Constants.CONTENT_TYPE){ @Override public int getContentLength() { return -1; @@ -120,6 +119,7 @@ public class ProgressListenerTest extends FileUploadTestCase { } } assertEquals(-1, istream.read()); + istream.close(); } assertTrue(!iter.hasNext()); listener.checkFinished(); diff --git a/src/test/java/org/apache/commons/fileupload/SizesTest.java b/src/test/java/org/apache/commons/fileupload/SizesTest.java index a2a6536..a0c90d2 100644 --- a/src/test/java/org/apache/commons/fileupload/SizesTest.java +++ b/src/test/java/org/apache/commons/fileupload/SizesTest.java @@ -38,10 +38,8 @@ import org.junit.Test; /** * Unit test for items with varying sizes. - * - * @version $Id$ */ -public class SizesTest extends FileUploadTestCase { +public class SizesTest { /** * Runs a test with varying file sizes. @@ -67,7 +65,8 @@ public class SizesTest extends FileUploadTestCase { } baos.write("-----1234--\r\n".getBytes("US-ASCII")); - List<FileItem> fileItems = parseUpload(baos.toByteArray()); + List<FileItem> fileItems = + Util.parseUpload(new ServletFileUpload(new DiskFileItemFactory()), baos.toByteArray()); Iterator<FileItem> fileIter = fileItems.iterator(); add = 16; num = 0; @@ -102,7 +101,8 @@ public class SizesTest extends FileUploadTestCase { ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); upload.setFileSizeMax(-1); - HttpServletRequest req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE); + HttpServletRequest req = new MockHttpServletRequest( + request.getBytes("US-ASCII"), Constants.CONTENT_TYPE); List<FileItem> fileItems = upload.parseRequest(req); assertEquals(1, fileItems.size()); FileItem item = fileItems.get(0); @@ -110,7 +110,7 @@ public class SizesTest extends FileUploadTestCase { upload = new ServletFileUpload(new DiskFileItemFactory()); upload.setFileSizeMax(40); - req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE); + req = new MockHttpServletRequest(request.getBytes("US-ASCII"), Constants.CONTENT_TYPE); fileItems = upload.parseRequest(req); assertEquals(1, fileItems.size()); item = fileItems.get(0); @@ -118,7 +118,7 @@ public class SizesTest extends FileUploadTestCase { upload = new ServletFileUpload(new DiskFileItemFactory()); upload.setFileSizeMax(30); - req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE); + req = new MockHttpServletRequest(request.getBytes("US-ASCII"), Constants.CONTENT_TYPE); try { upload.parseRequest(req); fail("Expected exception."); @@ -144,7 +144,8 @@ public class SizesTest extends FileUploadTestCase { ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); upload.setFileSizeMax(-1); - HttpServletRequest req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE); + HttpServletRequest req = new MockHttpServletRequest( + request.getBytes("US-ASCII"), Constants.CONTENT_TYPE); List<FileItem> fileItems = upload.parseRequest(req); assertEquals(1, fileItems.size()); FileItem item = fileItems.get(0); @@ -152,7 +153,7 @@ public class SizesTest extends FileUploadTestCase { upload = new ServletFileUpload(new DiskFileItemFactory()); upload.setFileSizeMax(40); - req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE); + req = new MockHttpServletRequest(request.getBytes("US-ASCII"), Constants.CONTENT_TYPE); fileItems = upload.parseRequest(req); assertEquals(1, fileItems.size()); item = fileItems.get(0); @@ -161,7 +162,7 @@ public class SizesTest extends FileUploadTestCase { // provided Content-Length is larger than the FileSizeMax -> handled by ctor upload = new ServletFileUpload(new DiskFileItemFactory()); upload.setFileSizeMax(5); - req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE); + req = new MockHttpServletRequest(request.getBytes("US-ASCII"), Constants.CONTENT_TYPE); try { upload.parseRequest(req); fail("Expected exception."); @@ -172,7 +173,7 @@ public class SizesTest extends FileUploadTestCase { // provided Content-Length is wrong, actual content is larger -> handled by LimitedInputStream upload = new ServletFileUpload(new DiskFileItemFactory()); upload.setFileSizeMax(15); - req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE); + req = new MockHttpServletRequest(request.getBytes("US-ASCII"), Constants.CONTENT_TYPE); try { upload.parseRequest(req); fail("Expected exception."); @@ -206,14 +207,14 @@ public class SizesTest extends FileUploadTestCase { upload.setFileSizeMax(-1); upload.setSizeMax(200); - MockHttpServletRequest req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE); + MockHttpServletRequest req = new MockHttpServletRequest( + request.getBytes("US-ASCII"), Constants.CONTENT_TYPE); try { upload.parseRequest(req); fail("Expected exception."); } catch (FileUploadBase.SizeLimitExceededException e) { assertEquals(200, e.getPermittedSize()); } - } @Test @@ -243,7 +244,8 @@ public class SizesTest extends FileUploadTestCase { // set the read limit to 10 to simulate a "real" stream // otherwise the buffer would be immediately filled - MockHttpServletRequest req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE); + MockHttpServletRequest req = new MockHttpServletRequest( + request.getBytes("US-ASCII"), Constants.CONTENT_TYPE); req.setContentLength(-1); req.setReadLimit(10); @@ -255,12 +257,10 @@ public class SizesTest extends FileUploadTestCase { assertEquals("file1", item.getFieldName()); assertEquals("foo1.tab", item.getName()); - try { + { InputStream stream = item.openStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); Streams.copy(stream, baos, true); - } catch (FileUploadIOException e) { - fail(e.getMessage()); } // the second item is over the size max, thus we expect an error @@ -281,7 +281,6 @@ public class SizesTest extends FileUploadTestCase { } catch (FileUploadIOException e) { // expected } - } } diff --git a/src/test/java/org/apache/commons/fileupload/StreamingTest.java b/src/test/java/org/apache/commons/fileupload/StreamingTest.java index 030c0ee..0425dc0 100644 --- a/src/test/java/org/apache/commons/fileupload/StreamingTest.java +++ b/src/test/java/org/apache/commons/fileupload/StreamingTest.java @@ -35,8 +35,6 @@ import junit.framework.TestCase; /** * Unit test for items with varying sizes. - * - * @version $Id$ */ public class StreamingTest extends TestCase { diff --git a/src/test/java/org/apache/commons/fileupload/FileUploadTestCase.java b/src/test/java/org/apache/commons/fileupload/Util.java similarity index 50% rename from src/test/java/org/apache/commons/fileupload/FileUploadTestCase.java rename to src/test/java/org/apache/commons/fileupload/Util.java index 131985b..692fb6e 100644 --- a/src/test/java/org/apache/commons/fileupload/FileUploadTestCase.java +++ b/src/test/java/org/apache/commons/fileupload/Util.java @@ -17,38 +17,46 @@ package org.apache.commons.fileupload; import java.io.UnsupportedEncodingException; +import java.util.Arrays; import java.util.List; import javax.servlet.http.HttpServletRequest; import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.portlet.PortletFileUpload; import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.fileupload.servlet.ServletRequestContext; /** - * Base class for deriving test cases. + * Test utility methods. * - * @version $Id$ + * @since 1.4 */ -public abstract class FileUploadTestCase { +public class Util { - protected static final String CONTENT_TYPE = "multipart/form-data; boundary=---1234"; - - protected List<FileItem> parseUpload(byte[] bytes) throws FileUploadException { - return parseUpload(bytes, CONTENT_TYPE); + public static List<FileItem> parseUpload(FileUpload upload, byte[] bytes) throws FileUploadException { + return parseUpload(upload, bytes, Constants.CONTENT_TYPE); } - protected List<FileItem> parseUpload(byte[] bytes, String contentType) throws FileUploadException { - ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); - HttpServletRequest request = new MockHttpServletRequest(bytes, contentType); - - List<FileItem> fileItems = upload.parseRequest(request); + public static List<FileItem> parseUpload(FileUpload upload, byte[] bytes, String contentType) throws FileUploadException { + final HttpServletRequest request = new MockHttpServletRequest(bytes, contentType); + List<FileItem> fileItems = upload.parseRequest(new ServletRequestContext(request)); return fileItems; } - protected List<FileItem> parseUpload(String content) + public static List<FileItem> parseUpload(FileUpload upload, String content) throws UnsupportedEncodingException, FileUploadException { byte[] bytes = content.getBytes("US-ASCII"); - return parseUpload(bytes, CONTENT_TYPE); + return parseUpload(upload, bytes, Constants.CONTENT_TYPE); } + /** + * Return a list of {@link FileUpload} implementations for parameterized tests. + * @return a list of {@link FileUpload} implementations + */ + public static List<FileUpload> fileUploadImplementations() { + return Arrays.asList( + new ServletFileUpload(new DiskFileItemFactory()), + new PortletFileUpload(new DiskFileItemFactory())); + } } diff --git a/src/test/java/org/apache/commons/fileupload/portlet/MockPortletActionRequest.java b/src/test/java/org/apache/commons/fileupload/portlet/MockPortletActionRequest.java new file mode 100644 index 0000000..b9a3a1b --- /dev/null +++ b/src/test/java/org/apache/commons/fileupload/portlet/MockPortletActionRequest.java @@ -0,0 +1,271 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.fileupload.portlet; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Locale; +import java.util.Map; + +import javax.portlet.ActionRequest; +import javax.portlet.PortalContext; +import javax.portlet.PortletMode; +import javax.portlet.PortletPreferences; +import javax.portlet.PortletSession; +import javax.portlet.WindowState; + +import org.apache.commons.fileupload.FileUploadBase; + +/** + * Mock class for tests. Implements an {@link ActionRequest}. + * + * @see PortletFileUploadTest + * @since 1.4 + */ +@SuppressWarnings("rawtypes") // because of the portlet ActionRequest API does not use generics +public class MockPortletActionRequest implements ActionRequest { + + private final Hashtable<String, Object> attributes = new Hashtable<String, Object>(); + + private final Map<String, String> parameters = new HashMap<String, String>(); + + private String characterEncoding; + private final int length; + private final String contentType; + private final InputStream requestData; + + public MockPortletActionRequest(final byte[] requestData, final String contentType) { + this(new ByteArrayInputStream(requestData), requestData.length, contentType); + } + + public MockPortletActionRequest(ByteArrayInputStream byteArrayInputStream, int requestLength, String contentType) { + this.requestData = byteArrayInputStream; + length = requestLength; + this.contentType = contentType; + attributes.put(FileUploadBase.CONTENT_TYPE, contentType); + } + + @Override + public Object getAttribute(String key) { + return attributes.get(key); + } + + @Override + public Enumeration getAttributeNames() { + return attributes.keys(); + } + + @Override + public String getAuthType() { + return null; + } + + @Override + public String getContextPath() { + return null; + } + + @Override + public Locale getLocale() { + return Locale.getDefault(); + } + + @Override + public Enumeration getLocales() { + return Collections.enumeration(Arrays.asList(Locale.getAvailableLocales())); + } + + @Override + public String getParameter(String key) { + return parameters.get(key); + } + + @Override + public Map getParameterMap() { + return Collections.unmodifiableMap(parameters); + } + + @Override + public Enumeration getParameterNames() { + return Collections.enumeration(parameters.keySet()); + } + + @Override + public String[] getParameterValues(String arg0) { + return null; + } + + @Override + public PortalContext getPortalContext() { + return null; + } + + @Override + public PortletMode getPortletMode() { + return null; + } + + @Override + public PortletSession getPortletSession() { + return null; + } + + @Override + public PortletSession getPortletSession(boolean arg0) { + return null; + } + + @Override + public PortletPreferences getPreferences() { + return null; + } + + @Override + public Enumeration getProperties(String arg0) { + return null; + } + + @Override + public String getProperty(String arg0) { + return null; + } + + @Override + public Enumeration getPropertyNames() { + return null; + } + + @Override + public String getRemoteUser() { + return null; + } + + @Override + public String getRequestedSessionId() { + return null; + } + + @Override + public String getResponseContentType() { + return null; + } + + @Override + public Enumeration getResponseContentTypes() { + return null; + } + + @Override + public String getScheme() { + return null; + } + + @Override + public String getServerName() { + return null; + } + + @Override + public int getServerPort() { + return 0; + } + + @Override + public Principal getUserPrincipal() { + return null; + } + + @Override + public WindowState getWindowState() { + return null; + } + + @Override + public boolean isPortletModeAllowed(PortletMode arg0) { + return false; + } + + @Override + public boolean isRequestedSessionIdValid() { + return false; + } + + @Override + public boolean isSecure() { + return false; + } + + @Override + public boolean isUserInRole(String arg0) { + return false; + } + + @Override + public boolean isWindowStateAllowed(WindowState arg0) { + return false; + } + + @Override + public void removeAttribute(String key) { + attributes.remove(key); + } + + @Override + public void setAttribute(String key, Object value) { + attributes.put(key, value); + } + + @Override + public String getCharacterEncoding() { + return characterEncoding; + } + + @Override + public int getContentLength() { + return length; + } + + @Override + public String getContentType() { + return contentType; + } + + @Override + public InputStream getPortletInputStream() throws IOException { + return requestData; + } + + @Override + public BufferedReader getReader() throws UnsupportedEncodingException, IOException { + return null; + } + + @Override + public void setCharacterEncoding(String characterEncoding) throws UnsupportedEncodingException { + this.characterEncoding = characterEncoding; + } + +} diff --git a/src/test/java/org/apache/commons/fileupload/portlet/PortletFileUploadTest.java b/src/test/java/org/apache/commons/fileupload/portlet/PortletFileUploadTest.java new file mode 100644 index 0000000..b56444f --- /dev/null +++ b/src/test/java/org/apache/commons/fileupload/portlet/PortletFileUploadTest.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.fileupload.portlet; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.Map; + +import javax.portlet.ActionRequest; + +import org.apache.commons.fileupload.Constants; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileUploadTest; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.junit.Before; +import org.junit.Test; + +/** + * Test for {@link PortletFileUpload}. + * + * @see FileUploadTest + * @since 1.4 + */ +public class PortletFileUploadTest { + + private PortletFileUpload upload; + + @Before + public void setUp() { + upload = new PortletFileUpload(new DiskFileItemFactory()); + } + + @Test + public void parseParameterMap() + throws Exception { + String text = "-----1234\r\n" + + "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" + + "Content-Type: text/whatever\r\n" + + "\r\n" + + "This is the content of the file\n" + + "\r\n" + + "-----1234\r\n" + + "Content-Disposition: form-data; name=\"field\"\r\n" + + "\r\n" + + "fieldValue\r\n" + + "-----1234\r\n" + + "Content-Disposition: form-data; name=\"multi\"\r\n" + + "\r\n" + + "value1\r\n" + + "-----1234\r\n" + + "Content-Disposition: form-data; name=\"multi\"\r\n" + + "\r\n" + + "value2\r\n" + + "-----1234--\r\n"; + byte[] bytes = text.getBytes("US-ASCII"); + ActionRequest request = new MockPortletActionRequest(bytes, Constants.CONTENT_TYPE); + + Map<String, List<FileItem>> mappedParameters = upload.parseParameterMap(request); + assertTrue(mappedParameters.containsKey("file")); + assertEquals(1, mappedParameters.get("file").size()); + + assertTrue(mappedParameters.containsKey("field")); + assertEquals(1, mappedParameters.get("field").size()); + + assertTrue(mappedParameters.containsKey("multi")); + assertEquals(2, mappedParameters.get("multi").size()); + } + +} diff --git a/src/test/java/org/apache/commons/fileupload/servlet/ServletFileUploadTest.java b/src/test/java/org/apache/commons/fileupload/servlet/ServletFileUploadTest.java new file mode 100644 index 0000000..5513ea6 --- /dev/null +++ b/src/test/java/org/apache/commons/fileupload/servlet/ServletFileUploadTest.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.fileupload.servlet; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.fileupload.Constants; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.MockHttpServletRequest; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.junit.Test; + +/** + * Test for {@link ServletFileUpload}. + * + * @see FileUploadTest + * @since 1.4 + */ +public class ServletFileUploadTest { + + /** + * Test case for <a href="http://issues.apache.org/jira/browse/FILEUPLOAD-210"> + */ + @Test + public void parseParameterMap() + throws Exception { + String text = "-----1234\r\n" + + "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" + + "Content-Type: text/whatever\r\n" + + "\r\n" + + "This is the content of the file\n" + + "\r\n" + + "-----1234\r\n" + + "Content-Disposition: form-data; name=\"field\"\r\n" + + "\r\n" + + "fieldValue\r\n" + + "-----1234\r\n" + + "Content-Disposition: form-data; name=\"multi\"\r\n" + + "\r\n" + + "value1\r\n" + + "-----1234\r\n" + + "Content-Disposition: form-data; name=\"multi\"\r\n" + + "\r\n" + + "value2\r\n" + + "-----1234--\r\n"; + byte[] bytes = text.getBytes("US-ASCII"); + HttpServletRequest request = new MockHttpServletRequest(bytes, Constants.CONTENT_TYPE); + + ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); + Map<String, List<FileItem>> mappedParameters = upload.parseParameterMap(request); + assertTrue(mappedParameters.containsKey("file")); + assertEquals(1, mappedParameters.get("file").size()); + + assertTrue(mappedParameters.containsKey("field")); + assertEquals(1, mappedParameters.get("field").size()); + + assertTrue(mappedParameters.containsKey("multi")); + assertEquals(2, mappedParameters.get("multi").size()); + } + + + @Test + public void parseImpliedUtf8() + throws Exception { + // utf8 encoded form-data without explicit content-type encoding + String text = "-----1234\r\n" + + "Content-Disposition: form-data; name=\"utf8Html\"\r\n" + + "\r\n" + + "Th�s �s the co�te�t of the f�le\n" + + "\r\n" + + "-----1234--\r\n"; + + byte[] bytes = text.getBytes("UTF-8"); + HttpServletRequest request = new MockHttpServletRequest(bytes, Constants.CONTENT_TYPE); + + DiskFileItemFactory fileItemFactory = new DiskFileItemFactory(); + fileItemFactory.setDefaultCharset("UTF-8"); + ServletFileUpload upload = new ServletFileUpload(fileItemFactory); + List<FileItem> fileItems = upload.parseRequest(request); + FileItem fileItem = fileItems.get(0); + assertTrue(fileItem.getString(), fileItem.getString().contains("co�te�t")); + } +} -- GitLab