Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CAMEL-20019: add platform http vertx cookie handler #13301

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,23 @@
"properties": {
"path": { "index": 0, "kind": "path", "displayName": "Path", "group": "consumer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The path under which this endpoint serves the HTTP requests, for proxy use 'proxy'" },
"consumes": { "index": 1, "kind": "parameter", "displayName": "Consumes", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The content type this endpoint accepts as an input, such as application\/xml or application\/json. null or *\/* mean no restriction." },
"httpMethodRestrict": { "index": 2, "kind": "parameter", "displayName": "Http Method Restrict", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "A comma separated list of HTTP methods to serve, e.g. GET,POST . If no methods are specified, all methods will be served." },
"matchOnUriPrefix": { "index": 3, "kind": "parameter", "displayName": "Match On Uri Prefix", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether or not the consumer should try to find a target consumer by matching the URI prefix if no exact match is found." },
"muteException": { "index": 4, "kind": "parameter", "displayName": "Mute Exception", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "If enabled and an Exchange failed processing on the consumer side the response's body won't contain the exception's stack trace." },
"produces": { "index": 5, "kind": "parameter", "displayName": "Produces", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The content type this endpoint produces, such as application\/xml or application\/json." },
"useStreaming": { "index": 6, "kind": "parameter", "displayName": "Use Streaming", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to use streaming for large requests and responses (currently only supported by camel-platform-http-vertx)" },
"bridgeErrorHandler": { "index": 7, "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." },
"exceptionHandler": { "index": 8, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored." },
"exchangePattern": { "index": 9, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." },
"fileNameExtWhitelist": { "index": 10, "kind": "parameter", "displayName": "File Name Ext Whitelist", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "A comma or whitespace separated list of file extensions. Uploads having these extensions will be stored locally. Null value or asterisk () will allow all files." },
"headerFilterStrategy": { "index": 11, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom HeaderFilterStrategy to filter headers to and from Camel message." },
"platformHttpEngine": { "index": 12, "kind": "parameter", "displayName": "Platform Http Engine", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.platform.http.spi.PlatformHttpEngine", "deprecated": false, "autowired": false, "secret": false, "description": "An HTTP Server engine implementation to serve the requests of this endpoint." }
"cookieDomain": { "index": 2, "kind": "parameter", "displayName": "Cookie Domain", "group": "consumer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.platform.http.cookie.CookieConfiguration", "configurationField": "cookieConfiguration", "description": "Sets which server can receive cookies." },
"cookieHttpOnly": { "index": 3, "kind": "parameter", "displayName": "Cookie Http Only", "group": "consumer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.platform.http.cookie.CookieConfiguration", "configurationField": "cookieConfiguration", "description": "Sets whether to prevent client side scripts from accessing created cookies." },
"cookieMaxAge": { "index": 4, "kind": "parameter", "displayName": "Cookie Max Age", "group": "consumer", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.platform.http.cookie.CookieConfiguration", "configurationField": "cookieConfiguration", "description": "Sets the maximum cookie age in seconds." },
"cookiePath": { "index": 5, "kind": "parameter", "displayName": "Cookie Path", "group": "consumer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "\/", "configurationClass": "org.apache.camel.component.platform.http.cookie.CookieConfiguration", "configurationField": "cookieConfiguration", "description": "Sets the URL path that must exist in the requested URL in order to send the Cookie." },
"cookieSameSite": { "index": 6, "kind": "parameter", "displayName": "Cookie Same Site", "group": "consumer", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.platform.http.cookie.CookieConfiguration.CookieSameSite", "enum": [ "STRICT", "LAX", "NONE" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "Lax", "configurationClass": "org.apache.camel.component.platform.http.cookie.CookieConfiguration", "configurationField": "cookieConfiguration", "description": "Sets whether to prevent the browser from sending cookies along with cross-site requests." },
"cookieSecure": { "index": 7, "kind": "parameter", "displayName": "Cookie Secure", "group": "consumer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.platform.http.cookie.CookieConfiguration", "configurationField": "cookieConfiguration", "description": "Sets whether the cookie is only sent to the server with an encrypted request over HTTPS." },
"httpMethodRestrict": { "index": 8, "kind": "parameter", "displayName": "Http Method Restrict", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "A comma separated list of HTTP methods to serve, e.g. GET,POST . If no methods are specified, all methods will be served." },
"matchOnUriPrefix": { "index": 9, "kind": "parameter", "displayName": "Match On Uri Prefix", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether or not the consumer should try to find a target consumer by matching the URI prefix if no exact match is found." },
"muteException": { "index": 10, "kind": "parameter", "displayName": "Mute Exception", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "If enabled and an Exchange failed processing on the consumer side the response's body won't contain the exception's stack trace." },
"produces": { "index": 11, "kind": "parameter", "displayName": "Produces", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The content type this endpoint produces, such as application\/xml or application\/json." },
"useCookieHandler": { "index": 12, "kind": "parameter", "displayName": "Use Cookie Handler", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable the Cookie Handler that allows Cookie addition, expiry, and retrieval (currently only supported by camel-platform-http-vertx)" },
"useStreaming": { "index": 13, "kind": "parameter", "displayName": "Use Streaming", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to use streaming for large requests and responses (currently only supported by camel-platform-http-vertx)" },
"bridgeErrorHandler": { "index": 14, "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." },
"exceptionHandler": { "index": 15, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored." },
"exchangePattern": { "index": 16, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." },
"fileNameExtWhitelist": { "index": 17, "kind": "parameter", "displayName": "File Name Ext Whitelist", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "A comma or whitespace separated list of file extensions. Uploads having these extensions will be stored locally. Null value or asterisk () will allow all files." },
"headerFilterStrategy": { "index": 18, "kind": "parameter", "displayName": "Header Filter Strategy", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom HeaderFilterStrategy to filter headers to and from Camel message." },
"platformHttpEngine": { "index": 19, "kind": "parameter", "displayName": "Platform Http Engine", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.platform.http.spi.PlatformHttpEngine", "deprecated": false, "autowired": false, "secret": false, "description": "An HTTP Server engine implementation to serve the requests of this endpoint." }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import io.vertx.core.Handler;
import io.vertx.core.MultiMap;
import io.vertx.core.Vertx;
import io.vertx.core.http.Cookie;
import io.vertx.core.http.CookieSameSite;
import io.vertx.core.http.HttpMethod;
import io.vertx.ext.auth.User;
import io.vertx.ext.web.FileUpload;
Expand All @@ -46,6 +48,8 @@
import org.apache.camel.attachment.AttachmentMessage;
import org.apache.camel.attachment.CamelFileDataSource;
import org.apache.camel.component.platform.http.PlatformHttpEndpoint;
import org.apache.camel.component.platform.http.cookie.CookieConfiguration;
import org.apache.camel.component.platform.http.cookie.CookieHandler;
import org.apache.camel.component.platform.http.spi.Method;
import org.apache.camel.spi.HeaderFilterStrategy;
import org.apache.camel.support.DefaultConsumer;
Expand Down Expand Up @@ -75,6 +79,7 @@ public class VertxPlatformHttpConsumer extends DefaultConsumer implements Suspen
private Route route;
private VertxPlatformHttpRouter router;
private HttpRequestBodyHandler httpRequestBodyHandler;
private CookieConfiguration cookieConfiguration;

public VertxPlatformHttpConsumer(PlatformHttpEndpoint endpoint,
Processor processor,
Expand Down Expand Up @@ -103,6 +108,9 @@ protected void doInit() throws Exception {
} else {
httpRequestBodyHandler = new DefaultHttpRequestBodyHandler(router.bodyHandler());
}
if (getEndpoint().isUseCookieHandler()) {
cookieConfiguration = getEndpoint().getCookieConfiguration();
}
}

@Override
Expand Down Expand Up @@ -269,6 +277,9 @@ protected Future<Void> processHttpRequest(Exchange exchange, RoutingContext ctx)
if (user != null) {
in.setHeader(VertxPlatformHttpConstants.AUTHENTICATED_USER, user);
}
if (getEndpoint().isUseCookieHandler()) {
exchange.setProperty(Exchange.COOKIE_HANDLER, new VertxCookieHandler(ctx));
}

return populateCamelMessage(ctx, exchange, in);
}
Expand Down Expand Up @@ -335,4 +346,49 @@ protected void populateAttachments(List<FileUpload> uploads, Message message) {
}
}
}

class VertxCookieHandler implements CookieHandler {

private RoutingContext routingContext;

VertxCookieHandler(RoutingContext routingContext) {
this.routingContext = routingContext;
}

@Override
public void addCookie(String name, String value) {
Cookie cookie = Cookie.cookie(name, value)
.setPath(cookieConfiguration.getCookiePath())
.setDomain(cookieConfiguration.getCookieDomain())
.setSecure(cookieConfiguration.isCookieSecure())
.setHttpOnly(cookieConfiguration.isCookieHttpOnly())
.setSameSite(getSameSite(cookieConfiguration.getCookieSameSite()));
if (cookieConfiguration.getCookieMaxAge() != null) {
cookie.setMaxAge(cookieConfiguration.getCookieMaxAge());
}
routingContext.response().addCookie(cookie);
}

private CookieSameSite getSameSite(CookieConfiguration.CookieSameSite sameSite) {
for (CookieSameSite css : CookieSameSite.values()) {
// 'Strict', 'Lax', or 'None'
if (css.toString().equals(sameSite.getValue())) {
return css;
}
}
return null;
}

@Override
public String removeCookie(String name) {
Cookie cookie = routingContext.response().removeCookie(name);
return cookie == null ? null : cookie.getValue();
}

@Override
public String getCookieValue(String name) {
Cookie cookie = routingContext.request().getCookie(name);
return cookie == null ? null : cookie.getValue();
}
}
}