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 123eab092e8 CAMEL-18093 - Add option to turn on follow redirects
123eab092e8 is described below

commit 123eab092e87d09edb259afb9d519b1accf527e1
Author: Rhuan Rocha <[email protected]>
AuthorDate: Sun Jul 3 23:21:50 2022 -0300

    CAMEL-18093 - Add option to turn on follow redirects
    
    Signed-off-by: Rhuan Rocha <[email protected]>
---
 .../component/http/HttpComponentConfigurer.java    |  6 +++
 .../component/http/HttpEndpointConfigurer.java     |  6 +++
 .../component/http/HttpEndpointUriFactory.java     |  3 +-
 .../org/apache/camel/component/http/http.json      |  2 +
 .../org/apache/camel/component/http/https.json     |  2 +
 .../apache/camel/component/http/HttpComponent.java | 18 +++++++
 .../apache/camel/component/http/HttpEndpoint.java  | 22 ++++++++
 .../component/http/CamelComponentVerifierTest.java | 15 ++++++
 .../camel/component/http/HttpRedirectTest.java     | 61 +++++++++++++++++++++-
 9 files changed, 132 insertions(+), 3 deletions(-)

diff --git 
a/components/camel-http/src/generated/java/org/apache/camel/component/http/HttpComponentConfigurer.java
 
b/components/camel-http/src/generated/java/org/apache/camel/component/http/HttpComponentConfigurer.java
index ec5c758517b..57df16e623f 100644
--- 
a/components/camel-http/src/generated/java/org/apache/camel/component/http/HttpComponentConfigurer.java
+++ 
b/components/camel-http/src/generated/java/org/apache/camel/component/http/HttpComponentConfigurer.java
@@ -51,6 +51,8 @@ public class HttpComponentConfigurer extends 
PropertyConfigurerSupport implement
         case "copyHeaders": target.setCopyHeaders(property(camelContext, 
boolean.class, value)); return true;
         case "defaultuseragentdisabled":
         case "defaultUserAgentDisabled": 
target.setDefaultUserAgentDisabled(property(camelContext, boolean.class, 
value)); return true;
+        case "followredirects":
+        case "followRedirects": 
target.setFollowRedirects(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 "httpbinding":
@@ -132,6 +134,8 @@ public class HttpComponentConfigurer extends 
PropertyConfigurerSupport implement
         case "copyHeaders": return boolean.class;
         case "defaultuseragentdisabled":
         case "defaultUserAgentDisabled": return boolean.class;
+        case "followredirects":
+        case "followRedirects": return boolean.class;
         case "headerfilterstrategy":
         case "headerFilterStrategy": return 
org.apache.camel.spi.HeaderFilterStrategy.class;
         case "httpbinding":
@@ -214,6 +218,8 @@ public class HttpComponentConfigurer extends 
PropertyConfigurerSupport implement
         case "copyHeaders": return target.isCopyHeaders();
         case "defaultuseragentdisabled":
         case "defaultUserAgentDisabled": return 
target.isDefaultUserAgentDisabled();
+        case "followredirects":
+        case "followRedirects": return target.isFollowRedirects();
         case "headerfilterstrategy":
         case "headerFilterStrategy": return target.getHeaderFilterStrategy();
         case "httpbinding":
diff --git 
a/components/camel-http/src/generated/java/org/apache/camel/component/http/HttpEndpointConfigurer.java
 
b/components/camel-http/src/generated/java/org/apache/camel/component/http/HttpEndpointConfigurer.java
index c3dbf8bcda3..9c41e61ab7d 100644
--- 
a/components/camel-http/src/generated/java/org/apache/camel/component/http/HttpEndpointConfigurer.java
+++ 
b/components/camel-http/src/generated/java/org/apache/camel/component/http/HttpEndpointConfigurer.java
@@ -59,6 +59,8 @@ public class HttpEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "deleteWithBody": target.setDeleteWithBody(property(camelContext, 
boolean.class, value)); return true;
         case "disablestreamcache":
         case "disableStreamCache": 
target.setDisableStreamCache(property(camelContext, boolean.class, value)); 
return true;
+        case "followredirects":
+        case "followRedirects": 
target.setFollowRedirects(property(camelContext, boolean.class, value)); return 
true;
         case "getwithbody":
         case "getWithBody": target.setGetWithBody(property(camelContext, 
boolean.class, value)); return true;
         case "headerfilterstrategy":
@@ -162,6 +164,8 @@ public class HttpEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "deleteWithBody": return boolean.class;
         case "disablestreamcache":
         case "disableStreamCache": return boolean.class;
+        case "followredirects":
+        case "followRedirects": return boolean.class;
         case "getwithbody":
         case "getWithBody": return boolean.class;
         case "headerfilterstrategy":
@@ -266,6 +270,8 @@ public class HttpEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "deleteWithBody": return target.isDeleteWithBody();
         case "disablestreamcache":
         case "disableStreamCache": return target.isDisableStreamCache();
+        case "followredirects":
+        case "followRedirects": return target.isFollowRedirects();
         case "getwithbody":
         case "getWithBody": return target.isGetWithBody();
         case "headerfilterstrategy":
diff --git 
a/components/camel-http/src/generated/java/org/apache/camel/component/http/HttpEndpointUriFactory.java
 
b/components/camel-http/src/generated/java/org/apache/camel/component/http/HttpEndpointUriFactory.java
index ae78420b746..7e91843ef16 100644
--- 
a/components/camel-http/src/generated/java/org/apache/camel/component/http/HttpEndpointUriFactory.java
+++ 
b/components/camel-http/src/generated/java/org/apache/camel/component/http/HttpEndpointUriFactory.java
@@ -22,7 +22,7 @@ public class HttpEndpointUriFactory extends 
org.apache.camel.support.component.E
     private static final Set<String> SECRET_PROPERTY_NAMES;
     private static final Set<String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(49);
+        Set<String> props = new HashSet<>(50);
         props.add("authDomain");
         props.add("authHost");
         props.add("authMethod");
@@ -42,6 +42,7 @@ public class HttpEndpointUriFactory extends 
org.apache.camel.support.component.E
         props.add("customHostHeader");
         props.add("deleteWithBody");
         props.add("disableStreamCache");
+        props.add("followRedirects");
         props.add("getWithBody");
         props.add("headerFilterStrategy");
         props.add("httpClient");
diff --git 
a/components/camel-http/src/generated/resources/org/apache/camel/component/http/http.json
 
b/components/camel-http/src/generated/resources/org/apache/camel/component/http/http.json
index 81065750f6d..9692cd7891f 100644
--- 
a/components/camel-http/src/generated/resources/org/apache/camel/component/http/http.json
+++ 
b/components/camel-http/src/generated/resources/org/apache/camel/component/http/http.json
@@ -29,6 +29,7 @@
     "copyHeaders": { "kind": "property", "displayName": "Copy Headers", 
"group": "producer", "label": "producer", "required": false, "type": "boolean", 
"javaType": "boolean", "deprecated": false, "autowired": false, "secret": 
false, "defaultValue": true, "description": "If this option is true then IN 
exchange headers will be copied to OUT exchange headers according to copy 
strategy. Setting this to false, allows to only include the headers from the 
HTTP response (not propagating IN heade [...]
     "lazyStartProducer": { "kind": "property", "displayName": "Lazy Start 
Producer", "group": "producer", "label": "producer", "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 producer 
may otherwise fail during star [...]
     "responsePayloadStreamingThreshold": { "kind": "property", "displayName": 
"Response Payload Streaming Threshold", "group": "producer", "label": 
"producer", "required": false, "type": "integer", "javaType": "int", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 8192, 
"description": "This threshold in bytes controls whether the response payload 
should be stored in memory as a byte array or be streaming based. Set this to 
-1 to always use streaming mode." },
+    "followRedirects": { "kind": "property", "displayName": "Follow 
Redirects", "group": "producer (advanced)", "label": "producer,advanced", 
"required": false, "type": "boolean", "javaType": "boolean", "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": false, 
"description": "Whether to the HTTP request should follow redirects. By default 
the HTTP request does not follow redirects" },
     "skipRequestHeaders": { "kind": "property", "displayName": "Skip Request 
Headers", "group": "producer (advanced)", "label": "producer,advanced", 
"required": false, "type": "boolean", "javaType": "boolean", "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": false, 
"description": "Whether to skip mapping all the Camel headers as HTTP request 
headers. If there are no data from Camel headers needed to be included in the 
HTTP request then this can avoid parsing over [...]
     "skipResponseHeaders": { "kind": "property", "displayName": "Skip Response 
Headers", "group": "producer (advanced)", "label": "producer,advanced", 
"required": false, "type": "boolean", "javaType": "boolean", "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": false, 
"description": "Whether to skip mapping all the HTTP response headers to Camel 
headers. If there are no data needed from HTTP headers then this can avoid 
parsing overhead with many object allocations [...]
     "allowJavaSerializedObject": { "kind": "property", "displayName": "Allow 
Java Serialized Object", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether to allow java serialization when a request uses 
context-type=application\/x-java-serialized-object. This is by default turned 
off. If you enable this then be aware that Java will des [...]
@@ -95,6 +96,7 @@
     "cookieHandler": { "kind": "parameter", "displayName": "Cookie Handler", 
"group": "producer (advanced)", "label": "producer,advanced", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.http.base.cookie.CookieHandler", "deprecated": false, 
"autowired": false, "secret": false, "description": "Configure a cookie handler 
to maintain a HTTP session" },
     "cookieStore": { "kind": "parameter", "displayName": "Cookie Store", 
"group": "producer (advanced)", "label": "producer,advanced", "required": 
false, "type": "object", "javaType": "org.apache.http.client.CookieStore", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
use a custom CookieStore. By default the BasicCookieStore is used which is an 
in-memory only cookie store. Notice if bridgeEndpoint=true then the cookie 
store is forced to be a noop cookie stor [...]
     "deleteWithBody": { "kind": "parameter", "displayName": "Delete With 
Body", "group": "producer (advanced)", "label": "producer,advanced", 
"required": false, "type": "boolean", "javaType": "boolean", "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": false, 
"description": "Whether the HTTP DELETE should include the message body or not. 
By default HTTP DELETE do not include any HTTP body. However in some rare cases 
users may need to be able to include the message [...]
+    "followRedirects": { "kind": "parameter", "displayName": "Follow 
Redirects", "group": "producer (advanced)", "label": "producer,advanced", 
"required": false, "type": "boolean", "javaType": "boolean", "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": false, 
"description": "Whether to the HTTP request should follow redirects. By default 
the HTTP request does not follow redirects" },
     "getWithBody": { "kind": "parameter", "displayName": "Get With Body", 
"group": "producer (advanced)", "label": "producer,advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether the HTTP GET should include the message body or not. By default HTTP 
GET do not include any HTTP body. However in some rare cases users may need to 
be able to include the message body." },
     "lazyStartProducer": { "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 producer may other [...]
     "okStatusCodeRange": { "kind": "parameter", "displayName": "Ok Status Code 
Range", "group": "producer (advanced)", "label": "producer,advanced", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 
"200-299", "description": "The status codes which are considered a success 
response. The values are inclusive. Multiple ranges can be defined, separated 
by comma, e.g. 200-204,209,301-304. Each range  [...]
diff --git 
a/components/camel-http/src/generated/resources/org/apache/camel/component/http/https.json
 
b/components/camel-http/src/generated/resources/org/apache/camel/component/http/https.json
index 7183e25b1cc..2a3e0c63cec 100644
--- 
a/components/camel-http/src/generated/resources/org/apache/camel/component/http/https.json
+++ 
b/components/camel-http/src/generated/resources/org/apache/camel/component/http/https.json
@@ -29,6 +29,7 @@
     "copyHeaders": { "kind": "property", "displayName": "Copy Headers", 
"group": "producer", "label": "producer", "required": false, "type": "boolean", 
"javaType": "boolean", "deprecated": false, "autowired": false, "secret": 
false, "defaultValue": true, "description": "If this option is true then IN 
exchange headers will be copied to OUT exchange headers according to copy 
strategy. Setting this to false, allows to only include the headers from the 
HTTP response (not propagating IN heade [...]
     "lazyStartProducer": { "kind": "property", "displayName": "Lazy Start 
Producer", "group": "producer", "label": "producer", "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 producer 
may otherwise fail during star [...]
     "responsePayloadStreamingThreshold": { "kind": "property", "displayName": 
"Response Payload Streaming Threshold", "group": "producer", "label": 
"producer", "required": false, "type": "integer", "javaType": "int", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 8192, 
"description": "This threshold in bytes controls whether the response payload 
should be stored in memory as a byte array or be streaming based. Set this to 
-1 to always use streaming mode." },
+    "followRedirects": { "kind": "property", "displayName": "Follow 
Redirects", "group": "producer (advanced)", "label": "producer,advanced", 
"required": false, "type": "boolean", "javaType": "boolean", "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": false, 
"description": "Whether to the HTTP request should follow redirects. By default 
the HTTP request does not follow redirects" },
     "skipRequestHeaders": { "kind": "property", "displayName": "Skip Request 
Headers", "group": "producer (advanced)", "label": "producer,advanced", 
"required": false, "type": "boolean", "javaType": "boolean", "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": false, 
"description": "Whether to skip mapping all the Camel headers as HTTP request 
headers. If there are no data from Camel headers needed to be included in the 
HTTP request then this can avoid parsing over [...]
     "skipResponseHeaders": { "kind": "property", "displayName": "Skip Response 
Headers", "group": "producer (advanced)", "label": "producer,advanced", 
"required": false, "type": "boolean", "javaType": "boolean", "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": false, 
"description": "Whether to skip mapping all the HTTP response headers to Camel 
headers. If there are no data needed from HTTP headers then this can avoid 
parsing overhead with many object allocations [...]
     "allowJavaSerializedObject": { "kind": "property", "displayName": "Allow 
Java Serialized Object", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether to allow java serialization when a request uses 
context-type=application\/x-java-serialized-object. This is by default turned 
off. If you enable this then be aware that Java will des [...]
@@ -95,6 +96,7 @@
     "cookieHandler": { "kind": "parameter", "displayName": "Cookie Handler", 
"group": "producer (advanced)", "label": "producer,advanced", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.http.base.cookie.CookieHandler", "deprecated": false, 
"autowired": false, "secret": false, "description": "Configure a cookie handler 
to maintain a HTTP session" },
     "cookieStore": { "kind": "parameter", "displayName": "Cookie Store", 
"group": "producer (advanced)", "label": "producer,advanced", "required": 
false, "type": "object", "javaType": "org.apache.http.client.CookieStore", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
use a custom CookieStore. By default the BasicCookieStore is used which is an 
in-memory only cookie store. Notice if bridgeEndpoint=true then the cookie 
store is forced to be a noop cookie stor [...]
     "deleteWithBody": { "kind": "parameter", "displayName": "Delete With 
Body", "group": "producer (advanced)", "label": "producer,advanced", 
"required": false, "type": "boolean", "javaType": "boolean", "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": false, 
"description": "Whether the HTTP DELETE should include the message body or not. 
By default HTTP DELETE do not include any HTTP body. However in some rare cases 
users may need to be able to include the message [...]
+    "followRedirects": { "kind": "parameter", "displayName": "Follow 
Redirects", "group": "producer (advanced)", "label": "producer,advanced", 
"required": false, "type": "boolean", "javaType": "boolean", "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": false, 
"description": "Whether to the HTTP request should follow redirects. By default 
the HTTP request does not follow redirects" },
     "getWithBody": { "kind": "parameter", "displayName": "Get With Body", 
"group": "producer (advanced)", "label": "producer,advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether the HTTP GET should include the message body or not. By default HTTP 
GET do not include any HTTP body. However in some rare cases users may need to 
be able to include the message body." },
     "lazyStartProducer": { "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 producer may other [...]
     "okStatusCodeRange": { "kind": "parameter", "displayName": "Ok Status Code 
Range", "group": "producer (advanced)", "label": "producer,advanced", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 
"200-299", "description": "The status codes which are considered a success 
response. The values are inclusive. Multiple ranges can be defined, separated 
by comma, e.g. 200-204,209,301-304. Each range  [...]
diff --git 
a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpComponent.java
 
b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpComponent.java
index 54ecf90eed3..94153901e37 100644
--- 
a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpComponent.java
+++ 
b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpComponent.java
@@ -65,6 +65,7 @@ import 
org.apache.http.conn.socket.PlainConnectionSocketFactory;
 import org.apache.http.conn.ssl.DefaultHostnameVerifier;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.LaxRedirectStrategy;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.ssl.SSLContexts;
@@ -183,6 +184,12 @@ public class HttpComponent extends HttpCommonComponent 
implements RestProducerFa
                             + " If there are no data needed from HTTP headers 
then this can avoid parsing overhead"
                             + " with many object allocations for the JVM 
garbage collector.")
     protected boolean skipResponseHeaders;
+
+    @Metadata(label = "producer,advanced", defaultValue = "false",
+              description = "Whether to the HTTP request should follow 
redirects."
+                            + " By default the HTTP request does not follow 
redirects ")
+    protected boolean followRedirects;
+
     @UriParam(label = "producer,advanced", description = "To set a custom HTTP 
User-Agent request header")
     protected String userAgent;
 
@@ -477,6 +484,9 @@ public class HttpComponent extends HttpCommonComponent 
implements RestProducerFa
         if (defaultUserAgentDisabled) {
             clientBuilder.disableDefaultUserAgent();
         }
+        if (followRedirects) {
+            clientBuilder.setRedirectStrategy(new LaxRedirectStrategy());
+        }
 
         return clientBuilder;
     }
@@ -916,6 +926,14 @@ public class HttpComponent extends HttpCommonComponent 
implements RestProducerFa
         this.skipResponseHeaders = skipResponseHeaders;
     }
 
+    public boolean isFollowRedirects() {
+        return followRedirects;
+    }
+
+    public void setFollowRedirects(boolean followRedirects) {
+        this.followRedirects = followRedirects;
+    }
+
     public String getUserAgent() {
         return userAgent;
     }
diff --git 
a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpEndpoint.java
 
b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpEndpoint.java
index fe297eae29f..b69cb6987f0 100644
--- 
a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpEndpoint.java
+++ 
b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpEndpoint.java
@@ -47,6 +47,7 @@ import org.apache.http.conn.HttpClientConnectionManager;
 import org.apache.http.conn.ssl.DefaultHostnameVerifier;
 import org.apache.http.impl.client.BasicCookieStore;
 import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.LaxRedirectStrategy;
 import org.apache.http.pool.ConnPoolControl;
 import org.apache.http.pool.PoolStats;
 import org.apache.http.protocol.HttpContext;
@@ -144,6 +145,12 @@ public class HttpEndpoint extends HttpCommonEndpoint {
                             + " If there are no data from Camel headers needed 
to be included in the HTTP request then this can avoid"
                             + " parsing overhead with many object allocations 
for the JVM garbage collector.")
     private boolean skipRequestHeaders;
+
+    @UriParam(label = "producer,advanced", defaultValue = "false",
+              description = "Whether to the HTTP request should follow 
redirects."
+                            + " By default the HTTP request does not follow 
redirects ")
+    private boolean followRedirects;
+
     @UriParam(label = "producer,advanced",
               description = "Whether to skip mapping all the HTTP response 
headers to Camel headers."
                             + " If there are no data needed from HTTP headers 
then this can avoid parsing overhead"
@@ -267,6 +274,10 @@ public class HttpEndpoint extends HttpCommonEndpoint {
             clientBuilder.setDefaultCookieStore(new NoopCookieStore());
         }
 
+        if (isFollowRedirects()) {
+            clientBuilder.setRedirectStrategy(new LaxRedirectStrategy());
+        }
+
         LOG.debug("Setup the HttpClientBuilder {}", clientBuilder);
         return clientBuilder.build();
     }
@@ -565,6 +576,17 @@ public class HttpEndpoint extends HttpCommonEndpoint {
         this.skipRequestHeaders = skipRequestHeaders;
     }
 
+    public boolean isFollowRedirects() {
+        return followRedirects;
+    }
+
+    /**
+     * Whether to the HTTP request should follow redirects. By default the 
HTTP request does not follow redirects
+     */
+    public void setFollowRedirects(boolean followRedirects) {
+        this.followRedirects = followRedirects;
+    }
+
     public boolean isSkipResponseHeaders() {
         return skipResponseHeaders;
     }
diff --git 
a/components/camel-http/src/test/java/org/apache/camel/component/http/CamelComponentVerifierTest.java
 
b/components/camel-http/src/test/java/org/apache/camel/component/http/CamelComponentVerifierTest.java
index 0fd68a442a6..aedb39ea67e 100644
--- 
a/components/camel-http/src/test/java/org/apache/camel/component/http/CamelComponentVerifierTest.java
+++ 
b/components/camel-http/src/test/java/org/apache/camel/component/http/CamelComponentVerifierTest.java
@@ -233,4 +233,19 @@ public class CamelComponentVerifierTest extends 
BaseHttpTest {
                 
error.getDetails().get(ComponentVerifierExtension.VerificationError.HttpAttribute.HTTP_REDIRECT));
         assertTrue(error.getParameterKeys().contains("httpUri"));
     }
+
+    @Test
+    public void testConnectivityWithFollowRedirectEnabled() throws Exception {
+        Map<String, Object> parameters = new HashMap<>();
+        parameters.put("httpUri", getLocalServerUri("/redirect"));
+        parameters.put("httpMethod", "POST");
+        parameters.put("followRedirects", "true");
+
+        ComponentVerifierExtension.Result result = 
verifier.verify(ComponentVerifierExtension.Scope.CONNECTIVITY, parameters);
+
+        assertEquals(ComponentVerifierExtension.Result.Status.OK, 
result.getStatus());
+        assertEquals(0, result.getErrors().size());
+
+    }
+
 }
diff --git 
a/components/camel-http/src/test/java/org/apache/camel/component/http/HttpRedirectTest.java
 
b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpRedirectTest.java
index 71e5ab4080b..23b70729d88 100644
--- 
a/components/camel-http/src/test/java/org/apache/camel/component/http/HttpRedirectTest.java
+++ 
b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpRedirectTest.java
@@ -34,8 +34,8 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import static org.apache.camel.component.http.HttpMethods.GET;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.apache.camel.component.http.HttpMethods.POST;
+import static org.junit.jupiter.api.Assertions.*;
 
 /**
  *
@@ -51,6 +51,8 @@ public class HttpRedirectTest extends BaseHttpTest {
                 
.setConnectionReuseStrategy(getConnectionReuseStrategy()).setResponseFactory(getHttpResponseFactory())
                 
.setExpectationVerifier(getHttpExpectationVerifier()).setSslContext(getSSLContext())
                 .registerHandler("/someplaceelse", new 
BasicValidationHandler(GET.name(), null, null, "Bye World"))
+                .registerHandler("/redirectplace", new 
BasicValidationHandler(POST.name(), null, null, ""))
+                .registerHandler("/testPost", new RedirectPostHandler(308))
                 .registerHandler("/test", new 
RedirectHandler(HttpStatus.SC_MOVED_PERMANENTLY)).create();
         localServer.start();
 
@@ -102,6 +104,44 @@ public class HttpRedirectTest extends BaseHttpTest {
         assertEquals("Bye World", out.getMessage().getBody(String.class));
     }
 
+    @Test
+    public void httpHandleFollowRedirect() throws Exception {
+
+        String uri = "http://"; + localServer.getInetAddress().getHostName() + 
":" + localServer.getLocalPort()
+                     + 
"/testPost?httpClient.socketTimeout=60000&httpClient.connectTimeout=60000"
+                     + 
"&httpClient.staleConnectionCheckEnabled=false&followRedirects=true&httpMethod=POST";
+        Exchange out = template.request(uri, exchange -> {
+            // no data
+        });
+
+        assertNotNull(out);
+        assertEquals(HttpStatus.SC_OK, 
out.getMessage().getHeader(Exchange.HTTP_RESPONSE_CODE));
+        assertEquals("OK", 
out.getMessage().getHeader(Exchange.HTTP_RESPONSE_TEXT));
+        assertEquals("", out.getMessage().getBody(String.class));
+    }
+
+    @Test
+    public void httpHandleFollowRedirectWithComponent() throws Exception {
+
+        HttpComponent component = context.getComponent("http", 
HttpComponent.class);
+        component.setFollowRedirects(true);
+        component.setConnectionTimeToLive(1000L);
+        String uri = "http://"; + localServer.getInetAddress().getHostName() + 
":" + localServer.getLocalPort()
+                     + 
"/testPost?httpClient.socketTimeout=60000&httpClient.connectTimeout=60000"
+                     + 
"&httpClient.staleConnectionCheckEnabled=false&httpMethod=POST";
+        HttpEndpoint httpEndpoint = (HttpEndpoint) 
component.createEndpoint(uri);
+
+        Exchange out = template.request(httpEndpoint, exchange -> {
+            // no data
+        });
+
+        assertNotNull(out);
+        assertEquals(HttpStatus.SC_OK, 
out.getMessage().getHeader(Exchange.HTTP_RESPONSE_CODE));
+        assertEquals("OK", 
out.getMessage().getHeader(Exchange.HTTP_RESPONSE_TEXT));
+        assertEquals("", out.getMessage().getBody(String.class));
+
+    }
+
     private final class RedirectHandler implements HttpRequestHandler {
 
         private final int code;
@@ -119,4 +159,21 @@ public class HttpRedirectTest extends BaseHttpTest {
         }
     }
 
+    private final class RedirectPostHandler implements HttpRequestHandler {
+
+        private final int code;
+
+        private RedirectPostHandler(int code) {
+            this.code = code;
+        }
+
+        @Override
+        public void handle(HttpRequest httpRequest, HttpResponse httpResponse, 
HttpContext httpContext)
+                throws HttpException, IOException {
+            httpResponse.setHeader("location", "http://"; + 
localServer.getInetAddress().getHostName() + ":"
+                                               + localServer.getLocalPort() + 
"/redirectplace");
+            httpResponse.setStatusCode(code);
+        }
+    }
+
 }

Reply via email to