Skip to content

Commit

Permalink
CAMEL-21300: camel-platform-http - Consumer should have option to con…
Browse files Browse the repository at this point in the history
…trol if writing response failing should cause Exchange to fail
  • Loading branch information
davsclaus committed Oct 2, 2024
1 parent 285ce2c commit 8a04e3e
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,19 @@
"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." },
"returnHttpRequestHeaders": { "index": 12, "kind": "parameter", "displayName": "Return Http Request Headers", "group": "consumer", "label": "advanced,consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to include HTTP request headers (Accept, User-Agent, etc.) into HTTP response produced by this endpoint." },
"useCookieHandler": { "index": 13, "kind": "parameter", "displayName": "Use Cookie Handler", "group": "consumer", "label": "advanced,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": 14, "kind": "parameter", "displayName": "Use Streaming", "group": "consumer", "label": "advanced,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": 15, "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": 16, "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": 17, "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": 18, "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": 19, "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": 20, "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." }
"handleWriteResponseError": { "index": 8, "kind": "parameter", "displayName": "Handle Write Response Error", "group": "consumer", "label": "advanced,consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "When Camel is complete processing the message, and the HTTP server is writing response. This option controls whether Camel should catch any failure during writing response and store this on the Exchange, which allows onCompletion\/UnitOfWork to regard the Exchange as failed and have access to the caused exception from the HTTP server." },
"httpMethodRestrict": { "index": 9, "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": 10, "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": 11, "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": 12, "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." },
"returnHttpRequestHeaders": { "index": 13, "kind": "parameter", "displayName": "Return Http Request Headers", "group": "consumer", "label": "advanced,consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to include HTTP request headers (Accept, User-Agent, etc.) into HTTP response produced by this endpoint." },
"useCookieHandler": { "index": 14, "kind": "parameter", "displayName": "Use Cookie Handler", "group": "consumer", "label": "advanced,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": 15, "kind": "parameter", "displayName": "Use Streaming", "group": "consumer", "label": "advanced,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": 16, "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": 17, "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": 18, "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": 19, "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": 20, "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": 21, "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 @@ -76,6 +76,7 @@ public class VertxPlatformHttpConsumer extends DefaultConsumer
private final List<Handler<RoutingContext>> handlers;
private final String fileNameExtWhitelist;
private final boolean muteExceptions;
private final boolean handleWriteResponseError;
private Set<Method> methods;
private String path;
private Route route;
Expand All @@ -92,6 +93,7 @@ public VertxPlatformHttpConsumer(PlatformHttpEndpoint endpoint,
this.fileNameExtWhitelist
= endpoint.getFileNameExtWhitelist() == null ? null : endpoint.getFileNameExtWhitelist().toLowerCase(Locale.US);
this.muteExceptions = endpoint.isMuteException();
this.handleWriteResponseError = endpoint.isHandleWriteResponseError();
}

@Override
Expand Down Expand Up @@ -238,6 +240,13 @@ private void handleFailure(Exchange exchange, RoutingContext ctx, Throwable fail
"Failed handling platform-http endpoint " + getEndpoint().getPath(),
failure);
ctx.fail(failure);
if (handleWriteResponseError && failure != null) {
Exception existing = exchange.getException();
if (existing != null) {
failure.addSuppressed(existing);
}
exchange.setException(failure);
}
handleExchangeComplete(exchange);
}

Expand Down Expand Up @@ -351,7 +360,7 @@ protected void populateAttachments(List<FileUpload> uploads, Message message) {

class VertxCookieHandler implements CookieHandler {

private RoutingContext routingContext;
private final RoutingContext routingContext;

VertxCookieHandler(RoutingContext routingContext) {
this.routingContext = routingContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj
case "exchangePattern": target.setExchangePattern(property(camelContext, org.apache.camel.ExchangePattern.class, value)); return true;
case "filenameextwhitelist":
case "fileNameExtWhitelist": target.setFileNameExtWhitelist(property(camelContext, java.lang.String.class, value)); return true;
case "handlewriteresponseerror":
case "handleWriteResponseError": target.setHandleWriteResponseError(property(camelContext, boolean.class, value)); return true;
case "headerfilterstrategy":
case "headerFilterStrategy": target.setHeaderFilterStrategy(property(camelContext, org.apache.camel.spi.HeaderFilterStrategy.class, value)); return true;
case "httpmethodrestrict":
Expand Down Expand Up @@ -89,6 +91,8 @@ public Class<?> getOptionType(String name, boolean ignoreCase) {
case "exchangePattern": return org.apache.camel.ExchangePattern.class;
case "filenameextwhitelist":
case "fileNameExtWhitelist": return java.lang.String.class;
case "handlewriteresponseerror":
case "handleWriteResponseError": return boolean.class;
case "headerfilterstrategy":
case "headerFilterStrategy": return org.apache.camel.spi.HeaderFilterStrategy.class;
case "httpmethodrestrict":
Expand Down Expand Up @@ -135,6 +139,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
case "exchangePattern": return target.getExchangePattern();
case "filenameextwhitelist":
case "fileNameExtWhitelist": return target.getFileNameExtWhitelist();
case "handlewriteresponseerror":
case "handleWriteResponseError": return target.isHandleWriteResponseError();
case "headerfilterstrategy":
case "headerFilterStrategy": return target.getHeaderFilterStrategy();
case "httpmethodrestrict":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class PlatformHttpEndpointUriFactory extends org.apache.camel.support.com
private static final Set<String> SECRET_PROPERTY_NAMES;
private static final Set<String> MULTI_VALUE_PREFIXES;
static {
Set<String> props = new HashSet<>(21);
Set<String> props = new HashSet<>(22);
props.add("bridgeErrorHandler");
props.add("consumes");
props.add("cookieDomain");
Expand All @@ -35,6 +35,7 @@ public class PlatformHttpEndpointUriFactory extends org.apache.camel.support.com
props.add("exceptionHandler");
props.add("exchangePattern");
props.add("fileNameExtWhitelist");
props.add("handleWriteResponseError");
props.add("headerFilterStrategy");
props.add("httpMethodRestrict");
props.add("matchOnUriPrefix");
Expand Down
Loading

0 comments on commit 8a04e3e

Please sign in to comment.