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

davsclaus 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 b1f6cd0ecdb CAMEL-21468: camel-http - Allow to log request/repsonse 
HTTP raw data to see what is sent over the wire.
b1f6cd0ecdb is described below

commit b1f6cd0ecdb9d146d923cde8018f84c44a499a86
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Dec 11 16:54:51 2024 +0100

    CAMEL-21468: camel-http - Allow to log request/repsonse HTTP raw data to 
see what is sent over the wire.
---
 .../camel/component/http/HttpActivityListener.java | 16 +++++---
 .../apache/camel/component/http/HttpEndpoint.java  | 37 +++++++++++++++++
 .../apache/camel/component/http/HttpProducer.java  | 14 ++-----
 .../http/LoggingHttpActivityListener.java          | 47 +++++++++++++++-------
 4 files changed, 83 insertions(+), 31 deletions(-)

diff --git 
a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpActivityListener.java
 
b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpActivityListener.java
index 0ceb5ae595c..a0828764438 100644
--- 
a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpActivityListener.java
+++ 
b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpActivityListener.java
@@ -17,9 +17,10 @@
 package org.apache.camel.component.http;
 
 import org.apache.camel.Exchange;
-import org.apache.hc.core5.http.ClassicHttpRequest;
-import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.HttpEntity;
 import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpResponse;
 
 /**
  * Listener when HTTP requests and responses are sent and received.
@@ -31,20 +32,23 @@ public interface HttpActivityListener {
      *
      * @param source   the http producer that are used
      * @param exchange the current exchange
-     * @param httpHost the host the request is sent to
+     * @param host     the host where the request is sent to
      * @param request  the http request
+     * @param entity   the http data
      */
-    void onRequestSubmitted(Object source, Exchange exchange, HttpHost 
httpHost, ClassicHttpRequest request);
+    void onRequestSubmitted(Object source, Exchange exchange, HttpHost host, 
HttpRequest request, HttpEntity entity);
 
     /**
      * HTTP response received
      *
      * @param source   the http producer that are used
      * @param exchange the current exchange
-     * @param httpHost the host the request is received from
+     * @param host     the host where the response was received from
      * @param response the http response
+     * @param entity   the http data
      * @param elapsed  time in millis before the response was received after 
sending
      */
-    void onResponseReceived(Object source, Exchange exchange, HttpHost 
httpHost, ClassicHttpResponse response, long elapsed);
+    void onResponseReceived(
+            Object source, Exchange exchange, HttpHost host, HttpResponse 
response, HttpEntity entity, long elapsed);
 
 }
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 3ca8bf6eef8..2df8b4ebd3f 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
@@ -17,6 +17,7 @@
 package org.apache.camel.component.http;
 
 import java.io.Closeable;
+import java.io.IOException;
 import java.net.URI;
 import java.util.Map;
 
@@ -25,6 +26,7 @@ import javax.net.ssl.HostnameVerifier;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
+import org.apache.camel.Exchange;
 import org.apache.camel.LineNumberAware;
 import org.apache.camel.PollingConsumer;
 import org.apache.camel.Processor;
@@ -41,6 +43,7 @@ import org.apache.camel.support.jsse.SSLContextParameters;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StopWatch;
 import org.apache.hc.client5.http.classic.HttpClient;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.cookie.BasicCookieStore;
@@ -48,7 +51,14 @@ import org.apache.hc.client5.http.cookie.CookieStore;
 import org.apache.hc.client5.http.impl.DefaultRedirectStrategy;
 import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
 import org.apache.hc.client5.http.io.HttpClientConnectionManager;
+import org.apache.hc.core5.http.EntityDetails;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpRequestInterceptor;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.HttpResponseInterceptor;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.pool.ConnPoolControl;
 import org.apache.hc.core5.pool.PoolStats;
@@ -303,6 +313,33 @@ public class HttpEndpoint extends HttpCommonEndpoint 
implements LineNumberAware
             configurer.configureHttpClient(clientBuilder);
         }
 
+        if (httpActivityListener != null) {
+            clientBuilder.addRequestInterceptorLast(new 
HttpRequestInterceptor() {
+                @Override
+                public void process(HttpRequest request, EntityDetails entity, 
HttpContext context)
+                        throws HttpException, IOException {
+                    Exchange exchange = (Exchange) 
context.getAttribute("org.apache.camel.Exchange");
+                    HttpHost host = (HttpHost) 
context.getAttribute("org.apache.hc.core5.http.HttpHost");
+                    context.setAttribute("org.apache.camel.util.StopWatch", 
new StopWatch());
+                    httpActivityListener.onRequestSubmitted(this, exchange, 
host, request, (HttpEntity) entity);
+                }
+            });
+            clientBuilder.addResponseInterceptorFirst(new 
HttpResponseInterceptor() {
+                @Override
+                public void process(HttpResponse response, EntityDetails 
entity, HttpContext context)
+                        throws HttpException, IOException {
+                    long elapsed = -1;
+                    StopWatch watch = (StopWatch) 
context.removeAttribute("org.apache.camel.util.StopWatch");
+                    if (watch != null) {
+                        elapsed = watch.taken();
+                    }
+                    Exchange exchange = (Exchange) 
context.removeAttribute("org.apache.camel.Exchange");
+                    HttpHost host = (HttpHost) 
context.removeAttribute("org.apache.hc.core5.http.HttpHost");
+                    httpActivityListener.onResponseReceived(this, exchange, 
host, response, (HttpEntity) entity, elapsed);
+                }
+            });
+        }
+
         LOG.debug("Setup the HttpClientBuilder {}", clientBuilder);
 
         return clientBuilder.build();
diff --git 
a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java
 
b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java
index 211c61ad244..32fe2d15727 100644
--- 
a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java
+++ 
b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java
@@ -57,7 +57,6 @@ import org.apache.camel.support.SynchronizationAdapter;
 import org.apache.camel.support.builder.OutputStreamBuilder;
 import org.apache.camel.support.http.HttpUtil;
 import org.apache.camel.util.IOHelper;
-import org.apache.camel.util.StopWatch;
 import org.apache.camel.util.URISupport;
 import org.apache.camel.util.UnsafeUriCharactersEncoder;
 import org.apache.hc.client5.http.classic.HttpClient;
@@ -95,7 +94,6 @@ public class HttpProducer extends DefaultProducer implements 
LineNumberAware {
     private final boolean throwException;
     private final boolean transferException;
     private final HeaderFilterStrategy httpProtocolHeaderFilterStrategy = new 
HttpProtocolHeaderFilterStrategy();
-    private final HttpActivityListener httpActivityListener;
     private int minOkRange;
     private int maxOkRange;
     private String defaultUrl;
@@ -108,7 +106,6 @@ public class HttpProducer extends DefaultProducer 
implements LineNumberAware {
         this.httpContext = endpoint.getHttpContext();
         this.throwException = endpoint.isThrowExceptionOnFailure();
         this.transferException = endpoint.isTransferException();
-        this.httpActivityListener = endpoint.getHttpActivityListener();
     }
 
     @Override
@@ -479,22 +476,19 @@ public class HttpProducer extends DefaultProducer 
implements LineNumberAware {
     protected <T> T executeMethod(
             Exchange exchange, HttpHost httpHost, HttpUriRequest httpRequest, 
HttpClientResponseHandler<T> handler)
             throws IOException, HttpException {
+        // use a local context per execution
         HttpContext localContext;
         if (httpContext != null) {
             localContext = new BasicHttpContext(httpContext);
         } else {
             localContext = HttpClientContext.create();
         }
-        StopWatch watch = null;
-        if (httpActivityListener != null) {
-            watch = new StopWatch();
-            httpActivityListener.onRequestSubmitted(this, exchange, httpHost, 
httpRequest);
+        if (getEndpoint().getHttpActivityListener() != null) {
+            localContext.setAttribute("org.apache.camel.Exchange", exchange);
+            localContext.setAttribute("org.apache.hc.core5.http.HttpHost", 
httpHost);
         }
         // execute open that does not automatic close response input-stream 
(this is done in exchange on-completion by Camel)
         ClassicHttpResponse res = httpClient.executeOpen(httpHost, 
httpRequest, localContext);
-        if (httpActivityListener != null) {
-            httpActivityListener.onResponseReceived(this, exchange, httpHost, 
res, watch.taken());
-        }
         return handler.handleResponse(res);
     }
 
diff --git 
a/components/camel-http/src/main/java/org/apache/camel/component/http/LoggingHttpActivityListener.java
 
b/components/camel-http/src/main/java/org/apache/camel/component/http/LoggingHttpActivityListener.java
index 185311473e5..29184af7cc2 100644
--- 
a/components/camel-http/src/main/java/org/apache/camel/component/http/LoggingHttpActivityListener.java
+++ 
b/components/camel-http/src/main/java/org/apache/camel/component/http/LoggingHttpActivityListener.java
@@ -16,7 +16,9 @@
  */
 package org.apache.camel.component.http;
 
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.StringJoiner;
@@ -30,13 +32,18 @@ import org.apache.camel.spi.Configurer;
 import org.apache.camel.spi.MaskingFormatter;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.support.ExchangeHelper;
+import org.apache.camel.support.GZIPHelper;
 import org.apache.camel.support.processor.DefaultMaskingFormatter;
 import org.apache.camel.support.service.ServiceSupport;
-import org.apache.hc.core5.http.ClassicHttpRequest;
-import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.camel.util.IOHelper;
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpEntityContainer;
+import org.apache.hc.core5.http.HttpHeaders;
 import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
 
 import static org.apache.camel.support.LoggerHelper.getLineNumberLoggerName;
@@ -86,24 +93,24 @@ public class LoggingHttpActivityListener extends 
ServiceSupport implements Camel
     }
 
     @Override
-    public void onRequestSubmitted(Object source, Exchange exchange, HttpHost 
httpHost, ClassicHttpRequest request) {
+    public void onRequestSubmitted(Object source, Exchange exchange, HttpHost 
host, HttpRequest request, HttpEntity entity) {
         CamelLogger logger = getLogger(source, exchange);
         if (logger.shouldLog()) {
-            onActivity(logger, exchange, httpHost, request, null, -1);
+            onActivity(logger, exchange, host, request, null, entity, -1);
         }
     }
 
     @Override
     public void onResponseReceived(
-            Object source, Exchange exchange, HttpHost httpHost, 
ClassicHttpResponse response, long elapsed) {
+            Object source, Exchange exchange, HttpHost host, HttpResponse 
response, HttpEntity entity, long elapsed) {
         CamelLogger logger = getLogger(source, exchange);
         if (logger.shouldLog()) {
-            onActivity(logger, exchange, httpHost, null, response, elapsed);
+            onActivity(logger, exchange, host, null, response, entity, 
elapsed);
         }
     }
 
     protected void onActivity(
-            CamelLogger logger, Exchange exchange, HttpHost httpHost, 
ClassicHttpRequest request, ClassicHttpResponse response,
+            CamelLogger logger, Exchange exchange, HttpHost host, HttpRequest 
request, HttpResponse response, HttpEntity entity,
             long elapsed) {
         final StringJoiner top = new StringJoiner("");
         final List<String> lines = new ArrayList<>();
@@ -111,7 +118,6 @@ public class LoggingHttpActivityListener extends 
ServiceSupport implements Camel
         String routeId = ExchangeHelper.getRouteId(exchange);
         String routeGroup = ExchangeHelper.getRouteGroup(exchange);
         String exchangeId = exchange.getExchangeId();
-        String host = httpHost.toHostString();
         String protocol = null;
         if (request != null) {
             protocol = request.getVersion() != null ? 
request.getVersion().toString() : "HTTP/1.1";
@@ -122,7 +128,7 @@ public class LoggingHttpActivityListener extends 
ServiceSupport implements Camel
         } else {
             top.add("Received HTTP Response (");
         }
-        top.add(String.format("host: %s", host));
+        top.add(String.format("host: %s", host.toHostString()));
         if (showRouteGroup && showRouteId) {
             if (routeGroup != null && routeId != null) {
                 top.add(String.format(" route: %s/%s", routeGroup, routeId));
@@ -152,14 +158,25 @@ public class LoggingHttpActivityListener extends 
ServiceSupport implements Camel
         if (showBody) {
             lines.add(""); // empty line before body
             try {
-                var e = request != null ? request.getEntity() : 
response.getEntity();
+                var e = entity;
                 if (e != null) {
                     if (e.isStreaming() && !showStreams) {
                         lines.add("WARN: Cannot log HTTP body because the body 
is streaming");
                     } else {
+                        Header ce = request != null
+                                ? 
request.getHeader(HttpHeaders.CONTENT_ENCODING)
+                                : 
response.getHeader(HttpHeaders.CONTENT_ENCODING);
                         ByteArrayOutputStream bos = new 
ByteArrayOutputStream();
                         e.writeTo(bos);
-                        String data = bos.toString();
+                        String data;
+                        if (ce != null && GZIPHelper.isGzip(ce.getValue())) {
+                            ByteArrayInputStream bis = new 
ByteArrayInputStream(bos.toByteArray());
+                            InputStream is = 
GZIPHelper.uncompressGzip(ce.getValue(), bis);
+                            data = new String(is.readAllBytes());
+                            IOHelper.close(is);
+                        } else {
+                            data = bos.toString();
+                        }
                         if (data.length() > maxChars) {
                             data = data.substring(0, maxChars) + " ... [Body 
clipped after " + maxChars
                                    + " chars, total length is " + 
data.length() + "]";
@@ -173,10 +190,10 @@ public class LoggingHttpActivityListener extends 
ServiceSupport implements Camel
                                 ct = ContentType.parse(e.getContentType());
                             }
                             e = new ByteArrayEntity(arr, ct);
-                            if (request != null) {
-                                request.setEntity(e);
-                            } else {
-                                response.setEntity(e);
+                            if (request instanceof HttpEntityContainer ec) {
+                                ec.setEntity(e);
+                            } else if (response instanceof HttpEntityContainer 
ec) {
+                                ec.setEntity(e);
                             }
                         }
                     }

Reply via email to