You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by or...@apache.org on 2022/05/31 12:04:59 UTC

[camel] branch main updated: CAMEL-17949 - Infinite loop when setting retries

This is an automated email from the ASF dual-hosted git repository.

orpiske 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 5d642dc6b07 CAMEL-17949 -  Infinite loop when setting retries
5d642dc6b07 is described below

commit 5d642dc6b0749678c16b50586a1e82816554c34f
Author: Rhuan Rocha <rh...@gmail.com>
AuthorDate: Sun May 29 20:46:07 2022 -0300

    CAMEL-17949 -  Infinite loop when setting retries
    
    Signed-off-by: Rhuan Rocha <rh...@gmail.com>
---
 .../netty/http/DefaultNettyHttpBinding.java        | 16 ++++
 .../component/netty/http/NettyHttpProducer.java    | 22 +++++-
 .../netty/http/NettyHttpLoopErrorTest.java         | 87 ++++++++++++++++++++++
 3 files changed, 124 insertions(+), 1 deletion(-)

diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/DefaultNettyHttpBinding.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/DefaultNettyHttpBinding.java
index b536ed23336..f3785da9199 100644
--- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/DefaultNettyHttpBinding.java
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/DefaultNettyHttpBinding.java
@@ -285,6 +285,20 @@ public class DefaultNettyHttpBinding implements NettyHttpBinding, Cloneable {
 
     }
 
+    /**
+     * Copy camel header from exchange to headers map.
+     *
+     * @param headers  the map headers
+     * @param exchange the exchange
+     */
+    protected void copyCamelHeaders(Map<String, Object> headers, Exchange exchange) {
+        exchange.getIn().getHeaders().keySet()
+                .stream()
+                .filter(key -> key.startsWith("Camel"))
+                .forEach(key -> headers.put(key, exchange.getIn().getHeaders().get(key)));
+
+    }
+
     /**
      * Decodes the header if needed to, or returns the header value as is.
      *
@@ -356,6 +370,8 @@ public class DefaultNettyHttpBinding implements NettyHttpBinding, Cloneable {
             HttpResponse response, Map<String, Object> headers, Exchange exchange, NettyHttpConfiguration configuration) {
         LOG.trace("populateCamelHeaders: {}", response);
 
+        copyCamelHeaders(headers, exchange);
+
         headers.put(NettyHttpConstants.HTTP_RESPONSE_CODE, response.status().code());
         headers.put(Exchange.HTTP_RESPONSE_TEXT, response.status().reasonPhrase());
 
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpProducer.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpProducer.java
index e4f40352560..c96c0c73698 100644
--- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpProducer.java
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpProducer.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.netty.http;
 import java.net.URI;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 import io.netty.handler.codec.http.FullHttpResponse;
 import io.netty.handler.codec.http.HttpRequest;
@@ -169,7 +170,10 @@ public class NettyHttpProducer extends NettyProducer {
                             } else {
                                 ok = NettyHttpHelper.isStatusCodeOk(code, configuration.getOkStatusCodeRange());
                             }
-                            if (!ok && getConfiguration().isThrowExceptionOnFailure()) {
+
+                            if (ok) {
+                                removeCamelHeaders(exchange);
+                            } else if (getConfiguration().isThrowExceptionOnFailure()) {
                                 // operation failed so populate exception to throw
                                 Exception cause = NettyHttpHelper.populateNettyHttpOperationFailedException(exchange, actualUrl,
                                         response, code, getConfiguration().isTransferException());
@@ -184,4 +188,20 @@ public class NettyHttpProducer extends NettyProducer {
             }
         }
     }
+
+    /**
+     * Remove Camel headers from Out message
+     *
+     * @param exchange the exchange
+     */
+    protected void removeCamelHeaders(Exchange exchange) {
+        List<String> headersToRemove = exchange.getMessage().getHeaders().keySet()
+                .stream()
+                .filter(key -> !key.equalsIgnoreCase(Exchange.HTTP_RESPONSE_CODE)
+                        && !key.equalsIgnoreCase(Exchange.HTTP_RESPONSE_TEXT)
+                        && key.startsWith("Camel"))
+                .collect(Collectors.toList());
+
+        headersToRemove.stream().forEach(header -> exchange.getMessage().removeHeaders(header));
+    }
 }
diff --git a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpLoopErrorTest.java b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpLoopErrorTest.java
new file mode 100644
index 00000000000..fc85b2879a6
--- /dev/null
+++ b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpLoopErrorTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.netty.http;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.LoggingLevel;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.direct.DirectEndpoint;
+import org.apache.camel.http.base.HttpOperationFailedException;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class NettyHttpLoopErrorTest extends BaseNettyTest {
+
+    @EndpointInject("direct:input")
+    DirectEndpoint directEndpoint;
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+
+            @Override
+            public void configure() throws Exception {
+                onException(NettyHttpOperationFailedException.class)
+                        .maximumRedeliveries(2)
+                        .retryAttemptedLogLevel(LoggingLevel.WARN)
+                        .maximumRedeliveryDelay(1000)
+                        .handled(false);
+
+                onException(HttpOperationFailedException.class)
+                        .maximumRedeliveries(2)
+                        .retryAttemptedLogLevel(LoggingLevel.WARN)
+                        .maximumRedeliveryDelay(1000)
+                        .handled(false);
+
+                from("direct:input")
+                        .routeId("test-route")
+                        .toD("${body}");
+            }
+        };
+    }
+
+    @Test
+    void testRetryWithExchangeInOnly() {
+        boolean isException = false;
+        try {
+            template.sendBody(directEndpoint, ExchangePattern.InOnly, "netty-http:http://example.com/return_404");
+        } catch (Exception e) {
+            isException = true;
+        }
+
+        assertTrue(isException);
+
+    }
+
+    @Test
+    void testRetryWithExchangeInOut() {
+
+        boolean isException = false;
+        try {
+            template.sendBody(directEndpoint, ExchangePattern.InOut, "netty-http:http://example.com/return_404");
+        } catch (Exception e) {
+            isException = true;
+        }
+
+        assertTrue(isException);
+
+    }
+
+}