This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch camel-3.20.x in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-3.20.x by this push: new 6f8393d9b68 CAMEL-19719: camel-vertx-http - Infinite loop when maximumRedeliveries > 0 6f8393d9b68 is described below commit 6f8393d9b6828ae1ddbe57e1bf4b6949534c6c8c Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Tue Aug 8 14:11:39 2023 +0200 CAMEL-19719: camel-vertx-http - Infinite loop when maximumRedeliveries > 0 --- .../vertx/http/DefaultVertxHttpBinding.java | 49 ++++++++++-------- .../http/VertxHttpMaximumRedeliveriesTest.java | 60 ++++++++++++++++++++++ .../http/VertxHttpThrowExceptionOnFailureTest.java | 2 +- 3 files changed, 90 insertions(+), 21 deletions(-) diff --git a/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/DefaultVertxHttpBinding.java b/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/DefaultVertxHttpBinding.java index 8a8bb1ffc06..fba375ee805 100644 --- a/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/DefaultVertxHttpBinding.java +++ b/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/DefaultVertxHttpBinding.java @@ -37,7 +37,6 @@ import org.apache.camel.TypeConverter; import org.apache.camel.http.base.HttpHelper; import org.apache.camel.http.base.HttpOperationFailedException; import org.apache.camel.spi.HeaderFilterStrategy; -import org.apache.camel.support.DefaultMessage; import org.apache.camel.support.ExchangeHelper; import org.apache.camel.util.IOHelper; import org.apache.camel.util.ObjectHelper; @@ -147,8 +146,8 @@ public class DefaultVertxHttpBinding implements VertxHttpBinding { @Override public void handleResponse(VertxHttpEndpoint endpoint, Exchange exchange, AsyncResult<HttpResponse<Buffer>> response) throws Exception { - Message message = new DefaultMessage(exchange); - exchange.setMessage(message); + + Message message = exchange.getMessage(); HttpResponse<Buffer> result = response.result(); if (response.succeeded()) { @@ -172,24 +171,34 @@ public class DefaultVertxHttpBinding implements VertxHttpBinding { message.setHeader(VertxHttpConstants.HTTP_RESPONSE_TEXT, response.statusMessage()); MultiMap headers = response.headers(); - headers.forEach(new Consumer<Map.Entry<String, String>>() { - boolean found; - - @Override - public void accept(Map.Entry<String, String> entry) { - String name = entry.getKey(); - String value = entry.getValue(); - if (!found && name.equalsIgnoreCase("content-type")) { - found = true; - name = VertxHttpConstants.CONTENT_TYPE; - exchange.setProperty(ExchangePropertyKey.CHARSET_NAME, IOHelper.getCharsetNameFromContentType(value)); - } - Object extracted = HttpHelper.extractHttpParameterValue(value); - if (strategy != null && !strategy.applyFilterToExternalHeaders(name, extracted, exchange)) { - HttpHelper.appendHeader(message.getHeaders(), name, extracted); + if (headers != null && !headers.isEmpty()) { + + // avoid duplicate headers by keeping copy of old headers + Map<String, Object> copy = new HashMap<>(exchange.getMessage().getHeaders()); + exchange.getMessage().getHeaders().clear(); + + headers.forEach(new Consumer<Map.Entry<String, String>>() { + boolean found; + + @Override + public void accept(Map.Entry<String, String> entry) { + String name = entry.getKey(); + String value = entry.getValue(); + if (!found && name.equalsIgnoreCase("content-type")) { + found = true; + name = VertxHttpConstants.CONTENT_TYPE; + exchange.setProperty(ExchangePropertyKey.CHARSET_NAME, IOHelper.getCharsetNameFromContentType(value)); + } + Object extracted = HttpHelper.extractHttpParameterValue(value); + if (strategy != null && !strategy.applyFilterToExternalHeaders(name, extracted, exchange)) { + HttpHelper.appendHeader(message.getHeaders(), name, extracted); + } } - } - }); + }); + + // and only add back old headers if they are not in the HTTP response + copy.forEach((k, v) -> exchange.getMessage().getHeaders().putIfAbsent(k, v)); + } } @Override diff --git a/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpMaximumRedeliveriesTest.java b/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpMaximumRedeliveriesTest.java new file mode 100644 index 00000000000..8b3ab06dc4d --- /dev/null +++ b/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpMaximumRedeliveriesTest.java @@ -0,0 +1,60 @@ +/* + * 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 org.apache.camel.Exchange; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.http.base.HttpOperationFailedException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class VertxHttpMaximumRedeliveriesTest extends VertxHttpTestSupport { + + @Test + public void testMaximumRedeliveries() throws Exception { + getMockEndpoint("mock:input").expectedMessageCount(1 + 3); // 1 original and 3 redelivery + + Exchange exchange = template.request("direct:start", null); + + Assertions.assertTrue(exchange.isFailed()); + HttpOperationFailedException e = exchange.getException(HttpOperationFailedException.class); + Assertions.assertNotNull(e); + Assertions.assertEquals(500, e.getStatusCode()); + + MockEndpoint.assertIsSatisfied(context); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + errorHandler(defaultErrorHandler().maximumRedeliveries(3).redeliveryDelay(0) + .retryAttemptedLogLevel(org.apache.camel.LoggingLevel.WARN)); + + from("direct:start") + .to(getTestServerUri()); + + from(getTestServerUri()) + .to("mock:input") + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(500)); + } + }; + } +} diff --git a/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpThrowExceptionOnFailureTest.java b/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpThrowExceptionOnFailureTest.java index 75e501b01fb..6851c33d0a9 100644 --- a/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpThrowExceptionOnFailureTest.java +++ b/components/camel-vertx/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpThrowExceptionOnFailureTest.java @@ -101,7 +101,7 @@ public class VertxHttpThrowExceptionOnFailureTest extends VertxHttpTestSupport { HttpOperationFailedException exception = exchange.getException(HttpOperationFailedException.class); assertEquals(500, exception.getStatusCode()); assertEquals("Internal Server Error", exception.getStatusText()); - assertEquals(getTestServerUrl(), exception.getUri()); + assertEquals(getTestServerUrl() + "/redirect", exception.getUri()); } @Test