1package fi.iki.elonen;
2
3/*
4 * #%L
5 * NanoHttpd-apache file upload integration
6 * %%
7 * Copyright (C) 2012 - 2015 nanohttpd
8 * %%
9 * Redistribution and use in source and binary forms, with or without modification,
10 * are permitted provided that the following conditions are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright notice, this
13 *    list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 *    this list of conditions and the following disclaimer in the documentation
17 *    and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the nanohttpd nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software without
21 *    specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
32 * OF THE POSSIBILITY OF SUCH DAMAGE.
33 * #L%
34 */
35
36import java.io.File;
37import java.io.IOException;
38import java.io.InputStream;
39import java.io.OutputStream;
40import java.net.InetAddress;
41import java.util.Arrays;
42import java.util.HashMap;
43import java.util.List;
44import java.util.Map;
45
46import org.apache.commons.fileupload.FileItem;
47import org.apache.commons.fileupload.FileItemIterator;
48import org.apache.commons.fileupload.FileItemStream;
49import org.apache.commons.fileupload.FileUploadException;
50import org.apache.commons.fileupload.disk.DiskFileItemFactory;
51import org.apache.commons.fileupload.util.Streams;
52import org.apache.http.HttpEntity;
53import org.apache.http.HttpResponse;
54import org.apache.http.client.ClientProtocolException;
55import org.apache.http.client.methods.CloseableHttpResponse;
56import org.apache.http.client.methods.HttpPost;
57import org.apache.http.client.methods.HttpTrace;
58import org.apache.http.entity.ContentType;
59import org.apache.http.entity.mime.HttpMultipartMode;
60import org.apache.http.entity.mime.MultipartEntityBuilder;
61import org.apache.http.entity.mime.content.FileBody;
62import org.apache.http.entity.mime.content.StringBody;
63import org.apache.http.impl.client.CloseableHttpClient;
64import org.apache.http.impl.client.HttpClients;
65import org.junit.After;
66import org.junit.Assert;
67import org.junit.Before;
68import org.junit.FixMethodOrder;
69import org.junit.Test;
70import org.junit.internal.runners.statements.Fail;
71
72import fi.iki.elonen.NanoHTTPD.Response.Status;
73
74/**
75 * very strange but if the file upload is the first request the test fails.
76 *
77 * @author ritchieGitHub
78 */
79@FixMethodOrder
80public class TestNanoFileUpLoad {
81
82    protected TestServer testServer;
83
84    public static class TestServer extends NanoHTTPD {
85
86        public Response response = newFixedLengthResponse("");
87
88        public String uri;
89
90        public Method method;
91
92        public Map<String, String> header;
93
94        public Map<String, String> parms;
95
96        public Map<String, List<FileItem>> files;
97
98        public Map<String, List<String>> decodedParamters;
99
100        public Map<String, List<String>> decodedParamtersFromParameter;
101
102        public String queryParameterString;
103
104        public TestServer() {
105            super(8192);
106            uploader = new NanoFileUpload(new DiskFileItemFactory());
107        }
108
109        public HTTPSession createSession(TempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream) {
110            return new HTTPSession(tempFileManager, inputStream, outputStream);
111        }
112
113        public HTTPSession createSession(TempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream, InetAddress inetAddress) {
114            return new HTTPSession(tempFileManager, inputStream, outputStream, inetAddress);
115        }
116
117        NanoFileUpload uploader;
118
119        @Override
120        public Response serve(IHTTPSession session) {
121
122            this.uri = session.getUri();
123            this.method = session.getMethod();
124            this.header = session.getHeaders();
125            this.parms = session.getParms();
126            if (NanoFileUpload.isMultipartContent(session)) {
127                try {
128                    if ("/uploadFile1".equals(this.uri)) {
129                        session.getHeaders().put("content-length", "AA");
130                        files = uploader.parseParameterMap(session);
131                    }
132                    if ("/uploadFile2".equals(this.uri)) {
133                        files = new HashMap<String, List<FileItem>>();
134                        List<FileItem> parseRequest = uploader.parseRequest(session);
135                        files.put(parseRequest.get(0).getFieldName(), parseRequest);
136                    }
137                    if ("/uploadFile3".equals(this.uri)) {
138                        files = new HashMap<String, List<FileItem>>();
139                        FileItemIterator iter = uploader.getItemIterator(session);
140                        while (iter.hasNext()) {
141                            FileItemStream item = iter.next();
142                            final String fileName = item.getName();
143                            FileItem fileItem = uploader.getFileItemFactory().createItem(item.getFieldName(), item.getContentType(), item.isFormField(), fileName);
144                            files.put(fileItem.getFieldName(), Arrays.asList(new FileItem[]{
145                                fileItem
146                            }));
147                            try {
148                                Streams.copy(item.openStream(), fileItem.getOutputStream(), true);
149                            } catch (Exception e) {
150                            }
151                            fileItem.setHeaders(item.getHeaders());
152                        }
153                    }
154                } catch (Exception e) {
155                    this.response.setStatus(Status.INTERNAL_ERROR);
156                    e.printStackTrace();
157                }
158            }
159            this.queryParameterString = session.getQueryParameterString();
160            this.decodedParamtersFromParameter = decodeParameters(this.queryParameterString);
161            this.decodedParamters = decodeParameters(session.getQueryParameterString());
162            return this.response;
163        }
164
165    }
166
167    @Test
168    public void testNormalRequest() throws Exception {
169        CloseableHttpClient httpclient = HttpClients.createDefault();
170        HttpTrace httphead = new HttpTrace("http://localhost:8192/index.html");
171        CloseableHttpResponse response = httpclient.execute(httphead);
172        Assert.assertEquals(200, response.getStatusLine().getStatusCode());
173        response.close();
174    }
175
176    @Test
177    public void testPostWithMultipartFormUpload1() throws Exception {
178        CloseableHttpClient httpclient = HttpClients.createDefault();
179        String textFileName = "src/test/java/fi/iki/elonen/TestNanoFileUpLoad.java";
180        HttpPost post = new HttpPost("http://localhost:8192/uploadFile1");
181
182        executeUpload(httpclient, textFileName, post);
183        FileItem file = this.testServer.files.get("upfile").get(0);
184        Assert.assertEquals(file.getSize(), new File(textFileName).length());
185    }
186
187    @Test
188    public void testPostWithMultipartFormUpload2() throws Exception {
189        CloseableHttpClient httpclient = HttpClients.createDefault();
190        String textFileName = "src/test/java/fi/iki/elonen/TestNanoFileUpLoad.java";
191        HttpPost post = new HttpPost("http://localhost:8192/uploadFile2");
192
193        executeUpload(httpclient, textFileName, post);
194        FileItem file = this.testServer.files.get("upfile").get(0);
195        Assert.assertEquals(file.getSize(), new File(textFileName).length());
196    }
197
198    @Test
199    public void testPostWithMultipartFormUpload3() throws Exception {
200        CloseableHttpClient httpclient = HttpClients.createDefault();
201        String textFileName = "src/test/java/fi/iki/elonen/TestNanoFileUpLoad.java";
202        HttpPost post = new HttpPost("http://localhost:8192/uploadFile3");
203
204        executeUpload(httpclient, textFileName, post);
205        FileItem file = this.testServer.files.get("upfile").get(0);
206        Assert.assertEquals(file.getSize(), new File(textFileName).length());
207    }
208
209    private void executeUpload(CloseableHttpClient httpclient, String textFileName, HttpPost post) throws IOException, ClientProtocolException {
210        FileBody fileBody = new FileBody(new File(textFileName), ContentType.DEFAULT_BINARY);
211        StringBody stringBody1 = new StringBody("Message 1", ContentType.MULTIPART_FORM_DATA);
212
213        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
214        builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
215        builder.addPart("upfile", fileBody);
216        builder.addPart("text1", stringBody1);
217        HttpEntity entity = builder.build();
218        //
219        post.setEntity(entity);
220        HttpResponse response = httpclient.execute(post);
221        Assert.assertEquals(200, response.getStatusLine().getStatusCode());
222    }
223
224    @Before
225    public void setUp() throws IOException {
226        this.testServer = new TestServer();
227        this.testServer.start();
228        try {
229            long start = System.currentTimeMillis();
230            Thread.sleep(100L);
231            while (!this.testServer.wasStarted()) {
232                Thread.sleep(100L);
233                if (System.currentTimeMillis() - start > 2000) {
234                    Assert.fail("could not start server");
235                }
236            }
237        } catch (InterruptedException e) {
238        }
239    }
240
241    @After
242    public void tearDown() {
243        this.testServer.stop();
244    }
245
246}
247