This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push: new d51f284eb75 CAMEL-22044: camel-vertx-http - Make it easier to do file upload as MultiPart-Form d51f284eb75 is described below commit d51f284eb753b76b37070f59fdf2fb3947b2bb58 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Sat May 3 17:42:25 2025 +0200 CAMEL-22044: camel-vertx-http - Make it easier to do file upload as MultiPart-Form --- .../camel/catalog/components/vertx-http.json | 40 ++++++------ .../apache/camel/component/http/HttpProducer.java | 4 +- .../vertx/http/VertxHttpEndpointConfigurer.java | 12 ++++ .../vertx/http/VertxHttpEndpointUriFactory.java | 4 +- .../camel/component/vertx/http/vertx-http.json | 40 ++++++------ .../vertx/http/VertxHttpConfiguration.java | 22 +++++++ .../component/vertx/http/VertxHttpProducer.java | 57 +++++++++++++---- .../http/VertxHttpFileUploadMultipartEasyTest.java | 68 ++++++++++++++++++++ .../http/VertxHttpFileUploadMultipartTest.java | 72 ++++++++++++++++++++++ .../dsl/VertxHttpEndpointBuilderFactory.java | 51 +++++++++++++++ 10 files changed, 316 insertions(+), 54 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx-http.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx-http.json index af190291b2c..9c4ac033ff6 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx-http.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx-http.json @@ -60,24 +60,26 @@ "cookieStore": { "index": 2, "kind": "parameter", "displayName": "Cookie Store", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "io.vertx.ext.web.client.spi.CookieStore", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "InMemoryCookieStore", "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "A custom CookieStore to use when se [...] "headerFilterStrategy": { "index": 3, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "VertxHttpHeaderFilterStrategy", "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "A cu [...] "httpMethod": { "index": 4, "kind": "parameter", "displayName": "Http Method", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "io.vertx.core.http.HttpMethod", "enum": [ "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", "PATCH", "PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK", "MKCALENDAR", "VERSION_CONTROL", "REPORT", "CHECKIN", "CHECKOUT", "UNCHECKOUT", "MKWORKSPACE", "UPDATE", "LABEL", "MERGE", "BAS [...] - "okStatusCodeRange": { "index": 5, "kind": "parameter", "displayName": "Ok Status Code Range", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "200-299", "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The status codes which are considered a success response [...] - "responsePayloadAsByteArray": { "index": 6, "kind": "parameter", "displayName": "Response Payload As Byte Array", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Whether the response body should be byte or as io. [...] - "sessionManagement": { "index": 7, "kind": "parameter", "displayName": "Session Management", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Enables session management via WebClientSession. By default the client [...] - "throwExceptionOnFailure": { "index": 8, "kind": "parameter", "displayName": "Throw Exception On Failure", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Disable throwing HttpOperationFailedException in case of [...] - "timeout": { "index": 9, "kind": "parameter", "displayName": "Timeout", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": -1, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The amount of time in milliseconds after which if the request does not return any data within the [...] - "transferException": { "index": 10, "kind": "parameter", "displayName": "Transfer Exception", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "If enabled and an Exchange failed processing on the consumer side, an [...] - "useCompression": { "index": 11, "kind": "parameter", "displayName": "Use Compression", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Set whether compression is enabled to handled compressed (E.g gzipped) resp [...] - "vertxHttpBinding": { "index": 12, "kind": "parameter", "displayName": "Vertx Http Binding", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.vertx.http.VertxHttpBinding", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "A custom VertxHttpBinding which can control how [...] - "webClientOptions": { "index": 13, "kind": "parameter", "displayName": "Web Client Options", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "io.vertx.ext.web.client.WebClientOptions", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Sets customized options for configuring the Vert.x WebClient" }, - "lazyStartProducer": { "index": 14, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...] - "proxyHost": { "index": 15, "kind": "parameter", "displayName": "Proxy Host", "group": "proxy", "label": "proxy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server host address" }, - "proxyPassword": { "index": 16, "kind": "parameter", "displayName": "Proxy Password", "group": "proxy", "label": "proxy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server password if authentication is required" }, - "proxyPort": { "index": 17, "kind": "parameter", "displayName": "Proxy Port", "group": "proxy", "label": "proxy", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server port" }, - "proxyType": { "index": 18, "kind": "parameter", "displayName": "Proxy Type", "group": "proxy", "label": "proxy", "required": false, "type": "object", "javaType": "io.vertx.core.net.ProxyType", "enum": [ "HTTP", "SOCKS4", "SOCKS5" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server type" }, - "proxyUsername": { "index": 19, "kind": "parameter", "displayName": "Proxy Username", "group": "proxy", "label": "proxy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server username if authentication is required" }, - "basicAuthPassword": { "index": 20, "kind": "parameter", "displayName": "Basic Auth Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The password to use for basic authentication" }, - "basicAuthUsername": { "index": 21, "kind": "parameter", "displayName": "Basic Auth Username", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The user name to use for basic authentication" }, - "bearerToken": { "index": 22, "kind": "parameter", "displayName": "Bearer Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The bearer token to use for bearer token authentication" }, - "sslContextParameters": { "index": 23, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParam [...] + "multipartUpload": { "index": 5, "kind": "parameter", "displayName": "Multipart Upload", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Whether to force using multipart\/form-data for easy file uploads. This is [...] + "multipartUploadName": { "index": 6, "kind": "parameter", "displayName": "Multipart Upload Name", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "data", "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The name of the multipart\/form-data when multipartUploa [...] + "okStatusCodeRange": { "index": 7, "kind": "parameter", "displayName": "Ok Status Code Range", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "200-299", "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The status codes which are considered a success response [...] + "responsePayloadAsByteArray": { "index": 8, "kind": "parameter", "displayName": "Response Payload As Byte Array", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Whether the response body should be byte or as io. [...] + "sessionManagement": { "index": 9, "kind": "parameter", "displayName": "Session Management", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Enables session management via WebClientSession. By default the client [...] + "throwExceptionOnFailure": { "index": 10, "kind": "parameter", "displayName": "Throw Exception On Failure", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Disable throwing HttpOperationFailedException in case of [...] + "timeout": { "index": 11, "kind": "parameter", "displayName": "Timeout", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": -1, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The amount of time in milliseconds after which if the request does not return any data within th [...] + "transferException": { "index": 12, "kind": "parameter", "displayName": "Transfer Exception", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "If enabled and an Exchange failed processing on the consumer side, an [...] + "useCompression": { "index": 13, "kind": "parameter", "displayName": "Use Compression", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Set whether compression is enabled to handled compressed (E.g gzipped) resp [...] + "vertxHttpBinding": { "index": 14, "kind": "parameter", "displayName": "Vertx Http Binding", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.vertx.http.VertxHttpBinding", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "A custom VertxHttpBinding which can control how [...] + "webClientOptions": { "index": 15, "kind": "parameter", "displayName": "Web Client Options", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "io.vertx.ext.web.client.WebClientOptions", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Sets customized options for configuring the Vert.x WebClient" }, + "lazyStartProducer": { "index": 16, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...] + "proxyHost": { "index": 17, "kind": "parameter", "displayName": "Proxy Host", "group": "proxy", "label": "proxy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server host address" }, + "proxyPassword": { "index": 18, "kind": "parameter", "displayName": "Proxy Password", "group": "proxy", "label": "proxy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server password if authentication is required" }, + "proxyPort": { "index": 19, "kind": "parameter", "displayName": "Proxy Port", "group": "proxy", "label": "proxy", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server port" }, + "proxyType": { "index": 20, "kind": "parameter", "displayName": "Proxy Type", "group": "proxy", "label": "proxy", "required": false, "type": "object", "javaType": "io.vertx.core.net.ProxyType", "enum": [ "HTTP", "SOCKS4", "SOCKS5" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server type" }, + "proxyUsername": { "index": 21, "kind": "parameter", "displayName": "Proxy Username", "group": "proxy", "label": "proxy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server username if authentication is required" }, + "basicAuthPassword": { "index": 22, "kind": "parameter", "displayName": "Basic Auth Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The password to use for basic authentication" }, + "basicAuthUsername": { "index": 23, "kind": "parameter", "displayName": "Basic Auth Username", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The user name to use for basic authentication" }, + "bearerToken": { "index": 24, "kind": "parameter", "displayName": "Bearer Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The bearer token to use for bearer token authentication" }, + "sslContextParameters": { "index": 25, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParam [...] } } diff --git a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java index 569f9981eb1..60141d0f8e3 100644 --- a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java +++ b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java @@ -41,7 +41,7 @@ import org.apache.camel.LineNumberAware; import org.apache.camel.Message; import org.apache.camel.RuntimeCamelException; import org.apache.camel.TypeConverter; -import org.apache.camel.component.file.GenericFile; +import org.apache.camel.WrappedFile; import org.apache.camel.component.http.helper.HttpMethodHelper; import org.apache.camel.http.base.HttpOperationFailedException; import org.apache.camel.http.base.cookie.CookieHandler; @@ -760,7 +760,7 @@ public class HttpProducer extends DefaultProducer implements LineNumberAware { HttpHelper.writeObjectToStream(bos, obj); answer = new ByteArrayEntity(bos.toByteArray(), HttpConstants.JAVA_SERIALIZED_OBJECT); } - } else if (data instanceof File || data instanceof GenericFile) { + } else if (data instanceof File || data instanceof WrappedFile<?>) { // file based (could potentially also be a FTP file etc) File file = in.getBody(File.class); if (file != null) { diff --git a/components/camel-vertx/camel-vertx-http/src/generated/java/org/apache/camel/component/vertx/http/VertxHttpEndpointConfigurer.java b/components/camel-vertx/camel-vertx-http/src/generated/java/org/apache/camel/component/vertx/http/VertxHttpEndpointConfigurer.java index 0697db45acc..10fff470550 100644 --- a/components/camel-vertx/camel-vertx-http/src/generated/java/org/apache/camel/component/vertx/http/VertxHttpEndpointConfigurer.java +++ b/components/camel-vertx/camel-vertx-http/src/generated/java/org/apache/camel/component/vertx/http/VertxHttpEndpointConfigurer.java @@ -39,6 +39,10 @@ public class VertxHttpEndpointConfigurer extends PropertyConfigurerSupport imple case "httpMethod": target.getConfiguration().setHttpMethod(property(camelContext, io.vertx.core.http.HttpMethod.class, value)); return true; case "lazystartproducer": case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; + case "multipartupload": + case "multipartUpload": target.getConfiguration().setMultipartUpload(property(camelContext, boolean.class, value)); return true; + case "multipartuploadname": + case "multipartUploadName": target.getConfiguration().setMultipartUploadName(property(camelContext, java.lang.String.class, value)); return true; case "okstatuscoderange": case "okStatusCodeRange": target.getConfiguration().setOkStatusCodeRange(property(camelContext, java.lang.String.class, value)); return true; case "proxyhost": @@ -91,6 +95,10 @@ public class VertxHttpEndpointConfigurer extends PropertyConfigurerSupport imple case "httpMethod": return io.vertx.core.http.HttpMethod.class; case "lazystartproducer": case "lazyStartProducer": return boolean.class; + case "multipartupload": + case "multipartUpload": return boolean.class; + case "multipartuploadname": + case "multipartUploadName": return java.lang.String.class; case "okstatuscoderange": case "okStatusCodeRange": return java.lang.String.class; case "proxyhost": @@ -144,6 +152,10 @@ public class VertxHttpEndpointConfigurer extends PropertyConfigurerSupport imple case "httpMethod": return target.getConfiguration().getHttpMethod(); case "lazystartproducer": case "lazyStartProducer": return target.isLazyStartProducer(); + case "multipartupload": + case "multipartUpload": return target.getConfiguration().isMultipartUpload(); + case "multipartuploadname": + case "multipartUploadName": return target.getConfiguration().getMultipartUploadName(); case "okstatuscoderange": case "okStatusCodeRange": return target.getConfiguration().getOkStatusCodeRange(); case "proxyhost": diff --git a/components/camel-vertx/camel-vertx-http/src/generated/java/org/apache/camel/component/vertx/http/VertxHttpEndpointUriFactory.java b/components/camel-vertx/camel-vertx-http/src/generated/java/org/apache/camel/component/vertx/http/VertxHttpEndpointUriFactory.java index 56bb531258c..6c1044be58f 100644 --- a/components/camel-vertx/camel-vertx-http/src/generated/java/org/apache/camel/component/vertx/http/VertxHttpEndpointUriFactory.java +++ b/components/camel-vertx/camel-vertx-http/src/generated/java/org/apache/camel/component/vertx/http/VertxHttpEndpointUriFactory.java @@ -23,7 +23,7 @@ public class VertxHttpEndpointUriFactory extends org.apache.camel.support.compon private static final Set<String> SECRET_PROPERTY_NAMES; private static final Set<String> MULTI_VALUE_PREFIXES; static { - Set<String> props = new HashSet<>(24); + Set<String> props = new HashSet<>(26); props.add("basicAuthPassword"); props.add("basicAuthUsername"); props.add("bearerToken"); @@ -33,6 +33,8 @@ public class VertxHttpEndpointUriFactory extends org.apache.camel.support.compon props.add("httpMethod"); props.add("httpUri"); props.add("lazyStartProducer"); + props.add("multipartUpload"); + props.add("multipartUploadName"); props.add("okStatusCodeRange"); props.add("proxyHost"); props.add("proxyPassword"); diff --git a/components/camel-vertx/camel-vertx-http/src/generated/resources/META-INF/org/apache/camel/component/vertx/http/vertx-http.json b/components/camel-vertx/camel-vertx-http/src/generated/resources/META-INF/org/apache/camel/component/vertx/http/vertx-http.json index af190291b2c..9c4ac033ff6 100644 --- a/components/camel-vertx/camel-vertx-http/src/generated/resources/META-INF/org/apache/camel/component/vertx/http/vertx-http.json +++ b/components/camel-vertx/camel-vertx-http/src/generated/resources/META-INF/org/apache/camel/component/vertx/http/vertx-http.json @@ -60,24 +60,26 @@ "cookieStore": { "index": 2, "kind": "parameter", "displayName": "Cookie Store", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "io.vertx.ext.web.client.spi.CookieStore", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "InMemoryCookieStore", "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "A custom CookieStore to use when se [...] "headerFilterStrategy": { "index": 3, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "VertxHttpHeaderFilterStrategy", "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "A cu [...] "httpMethod": { "index": 4, "kind": "parameter", "displayName": "Http Method", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "io.vertx.core.http.HttpMethod", "enum": [ "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", "PATCH", "PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK", "MKCALENDAR", "VERSION_CONTROL", "REPORT", "CHECKIN", "CHECKOUT", "UNCHECKOUT", "MKWORKSPACE", "UPDATE", "LABEL", "MERGE", "BAS [...] - "okStatusCodeRange": { "index": 5, "kind": "parameter", "displayName": "Ok Status Code Range", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "200-299", "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The status codes which are considered a success response [...] - "responsePayloadAsByteArray": { "index": 6, "kind": "parameter", "displayName": "Response Payload As Byte Array", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Whether the response body should be byte or as io. [...] - "sessionManagement": { "index": 7, "kind": "parameter", "displayName": "Session Management", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Enables session management via WebClientSession. By default the client [...] - "throwExceptionOnFailure": { "index": 8, "kind": "parameter", "displayName": "Throw Exception On Failure", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Disable throwing HttpOperationFailedException in case of [...] - "timeout": { "index": 9, "kind": "parameter", "displayName": "Timeout", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": -1, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The amount of time in milliseconds after which if the request does not return any data within the [...] - "transferException": { "index": 10, "kind": "parameter", "displayName": "Transfer Exception", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "If enabled and an Exchange failed processing on the consumer side, an [...] - "useCompression": { "index": 11, "kind": "parameter", "displayName": "Use Compression", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Set whether compression is enabled to handled compressed (E.g gzipped) resp [...] - "vertxHttpBinding": { "index": 12, "kind": "parameter", "displayName": "Vertx Http Binding", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.vertx.http.VertxHttpBinding", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "A custom VertxHttpBinding which can control how [...] - "webClientOptions": { "index": 13, "kind": "parameter", "displayName": "Web Client Options", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "io.vertx.ext.web.client.WebClientOptions", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Sets customized options for configuring the Vert.x WebClient" }, - "lazyStartProducer": { "index": 14, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...] - "proxyHost": { "index": 15, "kind": "parameter", "displayName": "Proxy Host", "group": "proxy", "label": "proxy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server host address" }, - "proxyPassword": { "index": 16, "kind": "parameter", "displayName": "Proxy Password", "group": "proxy", "label": "proxy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server password if authentication is required" }, - "proxyPort": { "index": 17, "kind": "parameter", "displayName": "Proxy Port", "group": "proxy", "label": "proxy", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server port" }, - "proxyType": { "index": 18, "kind": "parameter", "displayName": "Proxy Type", "group": "proxy", "label": "proxy", "required": false, "type": "object", "javaType": "io.vertx.core.net.ProxyType", "enum": [ "HTTP", "SOCKS4", "SOCKS5" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server type" }, - "proxyUsername": { "index": 19, "kind": "parameter", "displayName": "Proxy Username", "group": "proxy", "label": "proxy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server username if authentication is required" }, - "basicAuthPassword": { "index": 20, "kind": "parameter", "displayName": "Basic Auth Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The password to use for basic authentication" }, - "basicAuthUsername": { "index": 21, "kind": "parameter", "displayName": "Basic Auth Username", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The user name to use for basic authentication" }, - "bearerToken": { "index": 22, "kind": "parameter", "displayName": "Bearer Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The bearer token to use for bearer token authentication" }, - "sslContextParameters": { "index": 23, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParam [...] + "multipartUpload": { "index": 5, "kind": "parameter", "displayName": "Multipart Upload", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Whether to force using multipart\/form-data for easy file uploads. This is [...] + "multipartUploadName": { "index": 6, "kind": "parameter", "displayName": "Multipart Upload Name", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "data", "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The name of the multipart\/form-data when multipartUploa [...] + "okStatusCodeRange": { "index": 7, "kind": "parameter", "displayName": "Ok Status Code Range", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "200-299", "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The status codes which are considered a success response [...] + "responsePayloadAsByteArray": { "index": 8, "kind": "parameter", "displayName": "Response Payload As Byte Array", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Whether the response body should be byte or as io. [...] + "sessionManagement": { "index": 9, "kind": "parameter", "displayName": "Session Management", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Enables session management via WebClientSession. By default the client [...] + "throwExceptionOnFailure": { "index": 10, "kind": "parameter", "displayName": "Throw Exception On Failure", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Disable throwing HttpOperationFailedException in case of [...] + "timeout": { "index": 11, "kind": "parameter", "displayName": "Timeout", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": -1, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The amount of time in milliseconds after which if the request does not return any data within th [...] + "transferException": { "index": 12, "kind": "parameter", "displayName": "Transfer Exception", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "If enabled and an Exchange failed processing on the consumer side, an [...] + "useCompression": { "index": 13, "kind": "parameter", "displayName": "Use Compression", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Set whether compression is enabled to handled compressed (E.g gzipped) resp [...] + "vertxHttpBinding": { "index": 14, "kind": "parameter", "displayName": "Vertx Http Binding", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.vertx.http.VertxHttpBinding", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "A custom VertxHttpBinding which can control how [...] + "webClientOptions": { "index": 15, "kind": "parameter", "displayName": "Web Client Options", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "io.vertx.ext.web.client.WebClientOptions", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "Sets customized options for configuring the Vert.x WebClient" }, + "lazyStartProducer": { "index": 16, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...] + "proxyHost": { "index": 17, "kind": "parameter", "displayName": "Proxy Host", "group": "proxy", "label": "proxy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server host address" }, + "proxyPassword": { "index": 18, "kind": "parameter", "displayName": "Proxy Password", "group": "proxy", "label": "proxy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server password if authentication is required" }, + "proxyPort": { "index": 19, "kind": "parameter", "displayName": "Proxy Port", "group": "proxy", "label": "proxy", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server port" }, + "proxyType": { "index": 20, "kind": "parameter", "displayName": "Proxy Type", "group": "proxy", "label": "proxy", "required": false, "type": "object", "javaType": "io.vertx.core.net.ProxyType", "enum": [ "HTTP", "SOCKS4", "SOCKS5" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server type" }, + "proxyUsername": { "index": 21, "kind": "parameter", "displayName": "Proxy Username", "group": "proxy", "label": "proxy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The proxy server username if authentication is required" }, + "basicAuthPassword": { "index": 22, "kind": "parameter", "displayName": "Basic Auth Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The password to use for basic authentication" }, + "basicAuthUsername": { "index": 23, "kind": "parameter", "displayName": "Basic Auth Username", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The user name to use for basic authentication" }, + "bearerToken": { "index": 24, "kind": "parameter", "displayName": "Bearer Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "The bearer token to use for bearer token authentication" }, + "sslContextParameters": { "index": 25, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.http.VertxHttpConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParam [...] } } diff --git a/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpConfiguration.java b/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpConfiguration.java index 7046640005c..08d8f93ce3c 100644 --- a/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpConfiguration.java +++ b/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpConfiguration.java @@ -81,6 +81,12 @@ public class VertxHttpConfiguration { private String proxyPassword; @UriParam(label = "producer") private WebClientOptions webClientOptions; + @UriParam(label = "producer", + description = "Whether to force using multipart/form-data for easy file uploads. This is only to be used for uploading the message body as a single entity form-data. For uploading multiple entries then use io.vertx.ext.web.multipart.MultipartForm to build the form.") + private boolean multipartUpload; + @UriParam(label = "producer", defaultValue = "data", + description = "The name of the multipart/form-data when multipartUpload is enabled.") + private String multipartUploadName = "data"; /** * The HTTP URI to connect to @@ -355,4 +361,20 @@ public class VertxHttpConfiguration { public void setSslContextParameters(SSLContextParameters sslContextParameters) { this.sslContextParameters = sslContextParameters; } + + public boolean isMultipartUpload() { + return multipartUpload; + } + + public void setMultipartUpload(boolean multipartUpload) { + this.multipartUpload = multipartUpload; + } + + public String getMultipartUploadName() { + return multipartUploadName; + } + + public void setMultipartUploadName(String multipartUploadName) { + this.multipartUploadName = multipartUploadName; + } } diff --git a/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpProducer.java b/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpProducer.java index 8330ad6c048..6f6bae571f1 100644 --- a/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpProducer.java +++ b/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpProducer.java @@ -17,6 +17,9 @@ package org.apache.camel.component.vertx.http; import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; import java.io.Serializable; import java.util.Map; import java.util.concurrent.Callable; @@ -33,9 +36,11 @@ import org.apache.camel.AsyncCallback; import org.apache.camel.CamelExchangeException; import org.apache.camel.Exchange; import org.apache.camel.Message; +import org.apache.camel.WrappedFile; import org.apache.camel.component.vertx.common.VertxBufferConverter; import org.apache.camel.support.DefaultAsyncProducer; import org.apache.camel.support.MessageHelper; +import org.apache.camel.util.MimeTypeHelper; import org.apache.camel.util.URISupport; import static org.apache.camel.component.vertx.http.VertxHttpConstants.CONTENT_TYPE_FORM_URLENCODED; @@ -72,28 +77,55 @@ public class VertxHttpProducer extends DefaultAsyncProducer { request.send(resultHandler); } else { String contentType = MessageHelper.getContentType(message); + boolean multipart = getEndpoint().getConfiguration().isMultipartUpload(); + String multipartName = getEndpoint().getConfiguration().getMultipartUploadName(); - // Handle the request body payload - if (body instanceof MultiMap) { - request.sendForm((MultiMap) body, resultHandler); - } else if (body instanceof MultipartForm) { - request.sendMultipartForm((MultipartForm) body, resultHandler); - } else if (body instanceof ReadStream) { - request.sendStream((ReadStream<Buffer>) body, resultHandler); - } else if (body instanceof String) { + // Handle vertx specific body first + if (body instanceof MultiMap mm) { + request.sendForm(mm, resultHandler); + return false; + } else if (body instanceof MultipartForm mf) { + request.sendMultipartForm(mf, resultHandler); + return false; + } else if (body instanceof ReadStream rs) { + request.sendStream(rs, resultHandler); + return false; + } else if (body instanceof Buffer buf) { + request.sendBuffer(buf, resultHandler); + return false; + } + + if (body instanceof File || body instanceof WrappedFile<?>) { + // file based (could potentially also be a FTP file etc) + File file = message.getBody(File.class); + if (file != null) { + try (InputStream is = new FileInputStream(file)) { + Buffer buf = VertxBufferConverter.toBuffer(is); + if (multipart) { + String type = MimeTypeHelper.probeMimeType(file.getName()); + if (type == null) { + type = "application/octet-stream"; // default binary + } + MultipartForm form + = MultipartForm.create().binaryFileUpload(multipartName, file.getName(), buf, type); + request.sendMultipartForm(form, resultHandler); + } else { + request.sendBuffer(buf, resultHandler); + } + } + } + } else if (body instanceof String str) { // Try to extract URL encoded form data from the message body if (CONTENT_TYPE_FORM_URLENCODED.equals(contentType)) { MultiMap map = MultiMap.caseInsensitiveMultiMap(); - Map<String, Object> formParams = URISupport.parseQuery((String) body); + Map<String, Object> formParams = URISupport.parseQuery(str); formParams.forEach((key, o) -> map.add(key, String.valueOf(o))); request.sendForm(map, resultHandler); } else { // Fallback to send as Buffer - Buffer buffer = VertxBufferConverter.toBuffer((String) body, exchange); + Buffer buffer = VertxBufferConverter.toBuffer(str, exchange); request.sendBuffer(buffer, resultHandler); } - } else if (body instanceof Buffer) { - request.sendBuffer((Buffer) body, resultHandler); } else { // Handle x-java-serialized-object Content-Type if (CONTENT_TYPE_JAVA_SERIALIZED_OBJECT.equals(contentType)) { @@ -101,7 +133,6 @@ public class VertxHttpProducer extends DefaultAsyncProducer { throw new CamelExchangeException( "Content-type " + CONTENT_TYPE_JAVA_SERIALIZED_OBJECT + " is not allowed", exchange); } - // Send a serialized Java object message body try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { Serializable serializable = message.getMandatoryBody(Serializable.class); diff --git a/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpFileUploadMultipartEasyTest.java b/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpFileUploadMultipartEasyTest.java new file mode 100644 index 00000000000..c61563510e0 --- /dev/null +++ b/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpFileUploadMultipartEasyTest.java @@ -0,0 +1,68 @@ +/* + * 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.vertx.http; + +import java.io.File; +import java.util.Map; + +import jakarta.activation.DataHandler; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class VertxHttpFileUploadMultipartEasyTest extends VertxHttpTestSupport { + + @Test + public void testVertxFileUpload() { + File f = new File("src/test/resources/log4j2.properties"); + + Exchange out + = template.request(getProducerUri() + "/upload2?multipartUpload=true&multipartUploadName=cheese", exchange -> { + exchange.getMessage().setBody(f); + }); + + assertNotNull(out); + assertFalse(out.isFailed(), "Should not fail"); + assertEquals("log4j2.properties", out.getMessage().getBody(String.class)); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from(getTestServerUri() + "/upload2") + .process(new Processor() { + @Override + public void process(Exchange exchange) { + // undertow store the multipart-form as map in the camel message + DataHandler dh = (DataHandler) exchange.getMessage().getBody(Map.class).get("cheese"); + String out = dh.getDataSource().getName(); + exchange.getMessage().setBody(out); + } + }); + } + }; + } +} diff --git a/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpFileUploadMultipartTest.java b/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpFileUploadMultipartTest.java new file mode 100644 index 00000000000..c32e9dc59cf --- /dev/null +++ b/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpFileUploadMultipartTest.java @@ -0,0 +1,72 @@ +/* + * 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.vertx.http; + +import java.io.File; +import java.nio.file.Files; +import java.util.Map; + +import jakarta.activation.DataHandler; + +import io.vertx.core.buffer.Buffer; +import io.vertx.ext.web.multipart.MultipartForm; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class VertxHttpFileUploadMultipartTest extends VertxHttpTestSupport { + + @Test + public void testVertxFileUpload() { + File f = new File("src/test/resources/log4j2.properties"); + + Exchange out = template.request(getProducerUri() + "/upload", exchange -> { + Buffer buf = Buffer.buffer(Files.readAllBytes(f.toPath())); + var b = MultipartForm.create().textFileUpload("mydata", "log4j2.properties", buf, "text/plain"); + exchange.getMessage().setBody(b); + }); + + assertNotNull(out); + assertFalse(out.isFailed(), "Should not fail"); + assertEquals("log4j2.properties", out.getMessage().getBody(String.class)); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from(getTestServerUri() + "/upload") + .process(new Processor() { + @Override + public void process(Exchange exchange) { + // undertow store the multipart-form as map in the camel message + DataHandler dh = (DataHandler) exchange.getMessage().getBody(Map.class).get("mydata"); + String out = dh.getDataSource().getName(); + exchange.getMessage().setBody(out); + } + }); + } + }; + } +} diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/VertxHttpEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/VertxHttpEndpointBuilderFactory.java index 6d18ddc29d9..4e7c1eff20c 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/VertxHttpEndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/VertxHttpEndpointBuilderFactory.java @@ -175,6 +175,57 @@ public interface VertxHttpEndpointBuilderFactory { doSetProperty("httpMethod", httpMethod); return this; } + /** + * Whether to force using multipart/form-data for easy file uploads. + * This is only to be used for uploading the message body as a single + * entity form-data. For uploading multiple entries then use + * io.vertx.ext.web.multipart.MultipartForm to build the form. + * + * The option is a: <code>boolean</code> type. + * + * Default: false + * Group: producer + * + * @param multipartUpload the value to set + * @return the dsl builder + */ + default VertxHttpEndpointBuilder multipartUpload(boolean multipartUpload) { + doSetProperty("multipartUpload", multipartUpload); + return this; + } + /** + * Whether to force using multipart/form-data for easy file uploads. + * This is only to be used for uploading the message body as a single + * entity form-data. For uploading multiple entries then use + * io.vertx.ext.web.multipart.MultipartForm to build the form. + * + * The option will be converted to a <code>boolean</code> type. + * + * Default: false + * Group: producer + * + * @param multipartUpload the value to set + * @return the dsl builder + */ + default VertxHttpEndpointBuilder multipartUpload(String multipartUpload) { + doSetProperty("multipartUpload", multipartUpload); + return this; + } + /** + * The name of the multipart/form-data when multipartUpload is enabled. + * + * The option is a: <code>java.lang.String</code> type. + * + * Default: data + * Group: producer + * + * @param multipartUploadName the value to set + * @return the dsl builder + */ + default VertxHttpEndpointBuilder multipartUploadName(String multipartUploadName) { + doSetProperty("multipartUploadName", multipartUploadName); + return this; + } /** * The status codes which are considered a success response. The values * are inclusive. Multiple ranges can be defined, separated by comma,