You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2016/11/09 08:49:28 UTC
[2/2] camel git commit: CAMEL-10451 camel-undertow - Add multipart
request support
CAMEL-10451 camel-undertow - Add multipart request support
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/015f8128
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/015f8128
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/015f8128
Branch: refs/heads/master
Commit: 015f8128df5a50dba32661c6351b6e1839df0d59
Parents: cf83fca
Author: Tomohisa Igarashi <tm...@gmail.com>
Authored: Wed Nov 9 01:29:53 2016 +0900
Committer: Claus Ibsen <da...@apache.org>
Committed: Wed Nov 9 09:47:54 2016 +0100
----------------------------------------------------------------------
.../undertow/DefaultUndertowHttpBinding.java | 62 +++++++++--
.../component/undertow/UndertowComponent.java | 2 +-
.../component/undertow/UndertowConsumer.java | 6 ++
.../component/undertow/MultiPartFormTest.java | 102 +++++++++++++++++++
.../PreservePostFormUrlEncodedBodyTest.java | 71 +++++++++++++
5 files changed, 236 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/015f8128/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHttpBinding.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHttpBinding.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHttpBinding.java
index a0bd90b..3c231fd 100644
--- a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHttpBinding.java
+++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHttpBinding.java
@@ -17,21 +17,30 @@
package org.apache.camel.component.undertow;
import java.io.ByteArrayOutputStream;
+import java.io.File;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.ByteBuffer;
+import java.nio.file.Path;
import java.util.Deque;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
+import javax.activation.DataHandler;
+import javax.activation.FileDataSource;
+
import io.undertow.client.ClientExchange;
import io.undertow.client.ClientRequest;
import io.undertow.client.ClientResponse;
import io.undertow.predicate.Predicate;
import io.undertow.server.HttpServerExchange;
+import io.undertow.server.handlers.form.FormData;
+import io.undertow.server.handlers.form.FormData.FormValue;
+import io.undertow.server.handlers.form.FormDataParser;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
import io.undertow.util.Methods;
@@ -39,6 +48,7 @@ import io.undertow.util.Methods;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.TypeConverter;
+import org.apache.camel.impl.DefaultAttachment;
import org.apache.camel.impl.DefaultMessage;
import org.apache.camel.spi.HeaderFilterStrategy;
import org.apache.camel.util.ExchangeHelper;
@@ -94,14 +104,33 @@ public class DefaultUndertowHttpBinding implements UndertowHttpBinding {
populateCamelHeaders(httpExchange, result.getHeaders(), exchange);
- //extract body if the method is allowed to have one
- //body is extracted as byte[] then auto TypeConverter kicks in
- if (Methods.POST.equals(httpExchange.getRequestMethod()) || Methods.PUT.equals(httpExchange.getRequestMethod())) {
- result.setBody(readFromChannel(httpExchange.getRequestChannel()));
+ // Map form data which is parsed by undertow form parsers
+ FormData formData = httpExchange.getAttachment(FormDataParser.FORM_DATA);
+ if (formData != null) {
+ Map<String, Object> body = new HashMap<>();
+ formData.forEach(key -> {
+ formData.get(key).forEach(value -> {
+ if (value.isFile()) {
+ DefaultAttachment attachment = new DefaultAttachment(new FilePartDataSource(value));
+ result.addAttachmentObject(key, attachment);
+ body.put(key, attachment.getDataHandler());
+ } else if (headerFilterStrategy != null
+ && !headerFilterStrategy.applyFilterToExternalHeaders(key, value.getValue(), exchange)) {
+ UndertowHelper.appendHeader(result.getHeaders(), key, value.getValue());
+ UndertowHelper.appendHeader(body, key, value.getValue());
+ }
+ });
+ });
+ result.setBody(body);
} else {
- result.setBody(null);
+ //extract body by myself if undertow parser didn't handle and the method is allowed to have one
+ //body is extracted as byte[] then auto TypeConverter kicks in
+ if (Methods.POST.equals(httpExchange.getRequestMethod()) || Methods.PUT.equals(httpExchange.getRequestMethod())) {
+ result.setBody(readFromChannel(httpExchange.getRequestChannel()));
+ } else {
+ result.setBody(null);
+ }
}
-
return result;
}
@@ -390,4 +419,25 @@ public class DefaultUndertowHttpBinding implements UndertowHttpBinding {
}
}
}
+
+ class FilePartDataSource extends FileDataSource {
+ private String name;
+ private String contentType;
+
+ FilePartDataSource(FormValue value) {
+ super(value.getPath().toFile());
+ this.name = value.getFileName();
+ this.contentType = value.getHeaders().getFirst(Headers.CONTENT_TYPE);
+ }
+
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ @Override
+ public String getContentType() {
+ return this.contentType;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/015f8128/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowComponent.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowComponent.java
index d757070..37891f4 100644
--- a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowComponent.java
+++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowComponent.java
@@ -287,7 +287,7 @@ public class UndertowComponent extends UriEndpointComponent implements RestConsu
undertowRegistry.put(key, host);
}
host.validateEndpointURI(uri);
- host.registerHandler(consumer.getHttpHandlerRegistrationInfo(), consumer);
+ host.registerHandler(consumer.getHttpHandlerRegistrationInfo(), consumer.getHttpHandler());
}
public void unregisterConsumer(UndertowConsumer consumer) {
http://git-wip-us.apache.org/repos/asf/camel/blob/015f8128/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java
index 6a80892..846fe63 100644
--- a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java
+++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java
@@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
+import io.undertow.server.handlers.form.EagerFormParsingHandler;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
import io.undertow.util.Methods;
@@ -75,6 +76,11 @@ public class UndertowConsumer extends DefaultConsumer implements HttpHandler {
return registrationInfo;
}
+ public HttpHandler getHttpHandler() {
+ // wrap with EagerFormParsingHandler to enable undertow form parsers
+ return new EagerFormParsingHandler().setNext(this);
+ }
+
@Override
public void handleRequest(HttpServerExchange httpExchange) throws Exception {
HttpString requestMethod = httpExchange.getRequestMethod();
http://git-wip-us.apache.org/repos/asf/camel/blob/015f8128/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/MultiPartFormTest.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/MultiPartFormTest.java b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/MultiPartFormTest.java
new file mode 100644
index 0000000..d8a1512
--- /dev/null
+++ b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/MultiPartFormTest.java
@@ -0,0 +1,102 @@
+/**
+ * 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.camel.component.undertow;
+
+import java.io.File;
+import java.util.Map;
+
+import javax.activation.DataHandler;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.RequestEntity;
+import org.apache.commons.httpclient.methods.multipart.FilePart;
+import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
+import org.apache.commons.httpclient.methods.multipart.Part;
+import org.apache.commons.httpclient.methods.multipart.StringPart;
+import org.apache.commons.httpclient.params.HttpMethodParams;
+import org.junit.Test;
+
+public class MultiPartFormTest extends BaseUndertowTest {
+ private RequestEntity createMultipartRequestEntity() throws Exception {
+ File file = new File("src/main/resources/META-INF/NOTICE.txt");
+
+ Part[] parts = {new StringPart("comment", "A binary file of some kind"),
+ new FilePart(file.getName(), file)};
+
+ return new MultipartRequestEntity(parts, new HttpMethodParams());
+
+ }
+
+ @Test
+ public void testSendMultiPartForm() throws Exception {
+ HttpClient httpclient = new HttpClient();
+
+ PostMethod httppost = new PostMethod("http://localhost:" + getPort() + "/test");
+
+ httppost.setRequestEntity(createMultipartRequestEntity());
+
+ int status = httpclient.executeMethod(httppost);
+
+ assertEquals("Get a wrong response status", 200, status);
+ String result = httppost.getResponseBodyAsString();
+
+ assertEquals("Get a wrong result", "A binary file of some kind", result);
+
+ }
+
+ @Test
+ public void testSendMultiPartFormFromCamelHttpComponnent() throws Exception {
+ String result = template.requestBody("http://localhost:" + getPort() + "/test", createMultipartRequestEntity(), String.class);
+ assertEquals("Get a wrong result", "A binary file of some kind", result);
+ }
+
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ public void configure() throws Exception {
+ from("undertow://http://localhost:{{port}}/test").process(new Processor() {
+
+ public void process(Exchange exchange) throws Exception {
+ Message in = exchange.getIn();
+ assertEquals("Get a wrong attachement size", 1, in.getAttachments().size());
+ // The file name is attachment id
+ DataHandler data = in.getAttachment("NOTICE.txt");
+
+ assertNotNull("Should get the DataHandler NOTICE.txt", data);
+ assertEquals("Got the wrong name", "NOTICE.txt", data.getName());
+
+ assertTrue("We should get the data from the DataHandler", data.getDataSource()
+ .getInputStream().available() > 0);
+
+ // form data should also be available as a body
+ Map body = in.getBody(Map.class);
+ assertEquals("A binary file of some kind", body.get("comment"));
+ assertEquals(data, body.get("NOTICE.txt"));
+ exchange.getOut().setBody(in.getHeader("comment"));
+ }
+
+ });
+ // END SNIPPET: e1
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/015f8128/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/PreservePostFormUrlEncodedBodyTest.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/PreservePostFormUrlEncodedBodyTest.java b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/PreservePostFormUrlEncodedBodyTest.java
new file mode 100644
index 0000000..9cd52e8
--- /dev/null
+++ b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/PreservePostFormUrlEncodedBodyTest.java
@@ -0,0 +1,71 @@
+/**
+ * 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.camel.component.undertow;
+
+import java.util.Map;
+
+import io.undertow.server.handlers.form.FormData;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.http.HttpMethods;
+import org.junit.Test;
+
+public class PreservePostFormUrlEncodedBodyTest extends BaseUndertowTest {
+
+ @Test
+ public void testSendToUndertow() throws Exception {
+ Exchange exchange = template.request("http://localhost:{{port}}/myapp/myservice?query1=a&query2=b", new Processor() {
+
+ public void process(Exchange exchange) throws Exception {
+ exchange.getIn().setBody("b1=x&b2=y");
+ exchange.getIn().setHeader("content-type", "application/x-www-form-urlencoded");
+ exchange.getIn().setHeader(Exchange.HTTP_METHOD, HttpMethods.POST);
+ }
+
+ });
+ // convert the response to a String
+ String body = exchange.getOut().getBody(String.class);
+ assertEquals("Request message is OK", body);
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ public void configure() throws Exception {
+ from("undertow:http://localhost:{{port}}/myapp/myservice?map").process(new Processor() {
+ public void process(Exchange exchange) throws Exception {
+ Map body = exchange.getIn().getBody(Map.class);
+
+ // for unit testing make sure we got right message
+ assertNotNull(body);
+ assertEquals("x", body.get("b1"));
+ assertEquals("y", body.get("b2"));
+ assertEquals("a", exchange.getIn().getHeader("query1"));
+ assertEquals("b", exchange.getIn().getHeader("query2"));
+ assertEquals("x", exchange.getIn().getHeader("b1"));
+ assertEquals("y", exchange.getIn().getHeader("b2"));
+
+ // send a response
+ exchange.getOut().setBody("Request message is OK");
+ }
+ });
+ }
+ };
+ }
+
+}