Snap for 8730993 from 81b4443c6d7b888458ceaa306bdb68e807d71c81 to mainline-tzdata3-release

Change-Id: Ied6c349f48e854678dc8c340e463b750f8e8b960
diff --git a/fileupload/.gitignore b/fileupload/.gitignore
new file mode 100644
index 0000000..868a6b2
--- /dev/null
+++ b/fileupload/.gitignore
@@ -0,0 +1,2 @@
+/.settings/
+/LICENSE.txt
diff --git a/fileupload/README b/fileupload/README
deleted file mode 100644
index 4c70d72..0000000
--- a/fileupload/README
+++ /dev/null
@@ -1 +0,0 @@
-nanohttpd/fileupload is removed due to CVE-2016-1000031
\ No newline at end of file
diff --git a/fileupload/pom.xml b/fileupload/pom.xml
new file mode 100644
index 0000000..a90469a
--- /dev/null
+++ b/fileupload/pom.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<parent>
+		<artifactId>nanohttpd-project</artifactId>
+		<groupId>org.nanohttpd</groupId>
+		<version>2.2.0</version>
+	</parent>
+	<modelVersion>4.0.0</modelVersion>
+	<artifactId>nanohttpd-apache-fileupload</artifactId>
+	<name>NanoHttpd-apache file upload integration</name>
+	<description>nanohttpd-apache-fileupload integrates the apache file upload framework into nanohttpd</description>
+	<dependencies>
+		<dependency>
+			<groupId>org.nanohttpd</groupId>
+			<artifactId>nanohttpd</artifactId>
+			<version>2.2.0</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>commons-fileupload</groupId>
+			<artifactId>commons-fileupload</artifactId>
+			<version>1.3.1</version>
+		</dependency>
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>servlet-api</artifactId>
+			<version>2.5</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpclient</artifactId>
+			<version>4.4.1</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpmime</artifactId>
+			<version>4.4.1</version>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+	<properties>
+		<minimal.coverage>0.99</minimal.coverage>
+	</properties>
+</project>
\ No newline at end of file
diff --git a/fileupload/src/main/java/fi/iki/elonen/NanoFileUpload.java b/fileupload/src/main/java/fi/iki/elonen/NanoFileUpload.java
new file mode 100644
index 0000000..ec02d4a
--- /dev/null
+++ b/fileupload/src/main/java/fi/iki/elonen/NanoFileUpload.java
@@ -0,0 +1,118 @@
+package fi.iki.elonen;
+
+/*
+ * #%L
+ * apache-fileupload-integration
+ * %%
+ * Copyright (C) 2012 - 2015 nanohttpd
+ * %%
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the nanohttpd nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+
+import static fi.iki.elonen.NanoHTTPD.Method.POST;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.FileItemFactory;
+import org.apache.commons.fileupload.FileItemIterator;
+import org.apache.commons.fileupload.FileUpload;
+import org.apache.commons.fileupload.FileUploadBase;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.commons.fileupload.UploadContext;
+
+/**
+ * @author victor & ritchieGitHub
+ */
+public class NanoFileUpload extends FileUpload {
+
+    public static class NanoHttpdContext implements UploadContext {
+
+        private NanoHTTPD.IHTTPSession session;
+
+        public NanoHttpdContext(NanoHTTPD.IHTTPSession session) {
+            this.session = session;
+        }
+
+        @Override
+        public long contentLength() {
+            long size;
+            try {
+                String cl1 = session.getHeaders().get("content-length");
+                size = Long.parseLong(cl1);
+            } catch (NumberFormatException var4) {
+                size = -1L;
+            }
+
+            return size;
+        }
+
+        @Override
+        public String getCharacterEncoding() {
+            return "UTF-8";
+        }
+
+        @Override
+        public String getContentType() {
+            return this.session.getHeaders().get("content-type");
+        }
+
+        @Override
+        public int getContentLength() {
+            return (int) contentLength();
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            return session.getInputStream();
+        }
+    }
+
+    public static final boolean isMultipartContent(NanoHTTPD.IHTTPSession session) {
+        return session.getMethod() == POST && FileUploadBase.isMultipartContent(new NanoHttpdContext(session));
+    }
+
+    public NanoFileUpload(FileItemFactory fileItemFactory) {
+        super(fileItemFactory);
+    }
+
+    public List<FileItem> parseRequest(NanoHTTPD.IHTTPSession session) throws FileUploadException {
+        return this.parseRequest(new NanoHttpdContext(session));
+    }
+
+    public Map<String, List<FileItem>> parseParameterMap(NanoHTTPD.IHTTPSession session) throws FileUploadException {
+        return this.parseParameterMap(new NanoHttpdContext(session));
+    }
+
+    public FileItemIterator getItemIterator(NanoHTTPD.IHTTPSession session) throws FileUploadException, IOException {
+        return super.getItemIterator(new NanoHttpdContext(session));
+    }
+
+}
diff --git a/fileupload/src/test/java/fi/iki/elonen/TestNanoFileUpLoad.java b/fileupload/src/test/java/fi/iki/elonen/TestNanoFileUpLoad.java
new file mode 100644
index 0000000..ac18e3a
--- /dev/null
+++ b/fileupload/src/test/java/fi/iki/elonen/TestNanoFileUpLoad.java
@@ -0,0 +1,246 @@
+package fi.iki.elonen;
+
+/*
+ * #%L
+ * NanoHttpd-apache file upload integration
+ * %%
+ * Copyright (C) 2012 - 2015 nanohttpd
+ * %%
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the nanohttpd nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.FileItemIterator;
+import org.apache.commons.fileupload.FileItemStream;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.apache.commons.fileupload.util.Streams;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpTrace;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.mime.HttpMultipartMode;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
+import org.apache.http.entity.mime.content.FileBody;
+import org.apache.http.entity.mime.content.StringBody;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.internal.runners.statements.Fail;
+
+import fi.iki.elonen.NanoHTTPD.Response.Status;
+
+/**
+ * very strange but if the file upload is the first request the test fails.
+ * 
+ * @author ritchieGitHub
+ */
+@FixMethodOrder
+public class TestNanoFileUpLoad {
+
+    protected TestServer testServer;
+
+    public static class TestServer extends NanoHTTPD {
+
+        public Response response = newFixedLengthResponse("");
+
+        public String uri;
+
+        public Method method;
+
+        public Map<String, String> header;
+
+        public Map<String, String> parms;
+
+        public Map<String, List<FileItem>> files;
+
+        public Map<String, List<String>> decodedParamters;
+
+        public Map<String, List<String>> decodedParamtersFromParameter;
+
+        public String queryParameterString;
+
+        public TestServer() {
+            super(8192);
+            uploader = new NanoFileUpload(new DiskFileItemFactory());
+        }
+
+        public HTTPSession createSession(TempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream) {
+            return new HTTPSession(tempFileManager, inputStream, outputStream);
+        }
+
+        public HTTPSession createSession(TempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream, InetAddress inetAddress) {
+            return new HTTPSession(tempFileManager, inputStream, outputStream, inetAddress);
+        }
+
+        NanoFileUpload uploader;
+
+        @Override
+        public Response serve(IHTTPSession session) {
+
+            this.uri = session.getUri();
+            this.method = session.getMethod();
+            this.header = session.getHeaders();
+            this.parms = session.getParms();
+            if (NanoFileUpload.isMultipartContent(session)) {
+                try {
+                    if ("/uploadFile1".equals(this.uri)) {
+                        session.getHeaders().put("content-length", "AA");
+                        files = uploader.parseParameterMap(session);
+                    }
+                    if ("/uploadFile2".equals(this.uri)) {
+                        files = new HashMap<String, List<FileItem>>();
+                        List<FileItem> parseRequest = uploader.parseRequest(session);
+                        files.put(parseRequest.get(0).getFieldName(), parseRequest);
+                    }
+                    if ("/uploadFile3".equals(this.uri)) {
+                        files = new HashMap<String, List<FileItem>>();
+                        FileItemIterator iter = uploader.getItemIterator(session);
+                        while (iter.hasNext()) {
+                            FileItemStream item = iter.next();
+                            final String fileName = item.getName();
+                            FileItem fileItem = uploader.getFileItemFactory().createItem(item.getFieldName(), item.getContentType(), item.isFormField(), fileName);
+                            files.put(fileItem.getFieldName(), Arrays.asList(new FileItem[]{
+                                fileItem
+                            }));
+                            try {
+                                Streams.copy(item.openStream(), fileItem.getOutputStream(), true);
+                            } catch (Exception e) {
+                            }
+                            fileItem.setHeaders(item.getHeaders());
+                        }
+                    }
+                } catch (Exception e) {
+                    this.response.setStatus(Status.INTERNAL_ERROR);
+                    e.printStackTrace();
+                }
+            }
+            this.queryParameterString = session.getQueryParameterString();
+            this.decodedParamtersFromParameter = decodeParameters(this.queryParameterString);
+            this.decodedParamters = decodeParameters(session.getQueryParameterString());
+            return this.response;
+        }
+
+    }
+
+    @Test
+    public void testNormalRequest() throws Exception {
+        CloseableHttpClient httpclient = HttpClients.createDefault();
+        HttpTrace httphead = new HttpTrace("http://localhost:8192/index.html");
+        CloseableHttpResponse response = httpclient.execute(httphead);
+        Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+        response.close();
+    }
+
+    @Test
+    public void testPostWithMultipartFormUpload1() throws Exception {
+        CloseableHttpClient httpclient = HttpClients.createDefault();
+        String textFileName = "src/test/java/fi/iki/elonen/TestNanoFileUpLoad.java";
+        HttpPost post = new HttpPost("http://localhost:8192/uploadFile1");
+
+        executeUpload(httpclient, textFileName, post);
+        FileItem file = this.testServer.files.get("upfile").get(0);
+        Assert.assertEquals(file.getSize(), new File(textFileName).length());
+    }
+
+    @Test
+    public void testPostWithMultipartFormUpload2() throws Exception {
+        CloseableHttpClient httpclient = HttpClients.createDefault();
+        String textFileName = "src/test/java/fi/iki/elonen/TestNanoFileUpLoad.java";
+        HttpPost post = new HttpPost("http://localhost:8192/uploadFile2");
+
+        executeUpload(httpclient, textFileName, post);
+        FileItem file = this.testServer.files.get("upfile").get(0);
+        Assert.assertEquals(file.getSize(), new File(textFileName).length());
+    }
+
+    @Test
+    public void testPostWithMultipartFormUpload3() throws Exception {
+        CloseableHttpClient httpclient = HttpClients.createDefault();
+        String textFileName = "src/test/java/fi/iki/elonen/TestNanoFileUpLoad.java";
+        HttpPost post = new HttpPost("http://localhost:8192/uploadFile3");
+
+        executeUpload(httpclient, textFileName, post);
+        FileItem file = this.testServer.files.get("upfile").get(0);
+        Assert.assertEquals(file.getSize(), new File(textFileName).length());
+    }
+
+    private void executeUpload(CloseableHttpClient httpclient, String textFileName, HttpPost post) throws IOException, ClientProtocolException {
+        FileBody fileBody = new FileBody(new File(textFileName), ContentType.DEFAULT_BINARY);
+        StringBody stringBody1 = new StringBody("Message 1", ContentType.MULTIPART_FORM_DATA);
+
+        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+        builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
+        builder.addPart("upfile", fileBody);
+        builder.addPart("text1", stringBody1);
+        HttpEntity entity = builder.build();
+        //
+        post.setEntity(entity);
+        HttpResponse response = httpclient.execute(post);
+        Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+    }
+
+    @Before
+    public void setUp() throws IOException {
+        this.testServer = new TestServer();
+        this.testServer.start();
+        try {
+            long start = System.currentTimeMillis();
+            Thread.sleep(100L);
+            while (!this.testServer.wasStarted()) {
+                Thread.sleep(100L);
+                if (System.currentTimeMillis() - start > 2000) {
+                    Assert.fail("could not start server");
+                }
+            }
+        } catch (InterruptedException e) {
+        }
+    }
+
+    @After
+    public void tearDown() {
+        this.testServer.stop();
+    }
+
+}