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);
}
}
}