aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-06-15 21:41:41 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-06-15 21:41:41 +0000
commit138ef139f83b6a2840d4253bc17ee119338bf3cf (patch)
treeb8f8f988ccda09f844ee3f15de0c535f23c81930
parentbd4c313a7fab34900b1649579d6c22179e5ecdd3 (diff)
parent81b4443c6d7b888458ceaa306bdb68e807d71c81 (diff)
downloadnanohttpd-aml_tz3_313110000.tar.gz
Change-Id: Ied6c349f48e854678dc8c340e463b750f8e8b960
-rw-r--r--fileupload/.gitignore2
-rw-r--r--fileupload/README1
-rw-r--r--fileupload/pom.xml46
-rw-r--r--fileupload/src/main/java/fi/iki/elonen/NanoFileUpload.java118
-rw-r--r--fileupload/src/test/java/fi/iki/elonen/TestNanoFileUpLoad.java246
5 files changed, 412 insertions, 1 deletions
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();
+ }
+
+}