From eb3a88bf0204f3c5aa5dfbc7c7f7a900e7196ebf Mon Sep 17 00:00:00 2001 From: Matthias Kiefer Date: Wed, 3 Jan 2024 17:26:13 +0100 Subject: [PATCH] Make logback access logging work with Jetty 12 --- .../jetty/JettyModernServerAdapter.java | 67 ---- .../jetty/JettyNoServletApiServerAdapter.java | 186 ++++++++++ .../access/jetty/JettyServerAdapter.java | 70 ---- .../jetty/JettyServletApiServerAdapter.java | 115 +++++++ .../logback/access/jetty/RequestLogImpl.java | 15 +- .../access/servlet/TeeHttpServletRequest.java | 2 +- .../ch/qos/logback/access/servlet/Util.java | 27 +- .../access/sift/AccessEventDiscriminator.java | 23 +- .../qos/logback/access/spi/AccessEvent.java | 319 +++++++----------- .../qos/logback/access/spi/IAccessEvent.java | 11 + .../qos/logback/access/spi/ServerAdapter.java | 58 +++- .../access/spi/ServletApiServerAdapter.java | 181 ++++++++++ .../logback/access/tomcat/LogbackValve.java | 2 +- .../access/tomcat/TomcatServerAdapter.java | 24 +- .../boolex/JaninoEventEvaluatorTest.java | 6 +- .../access/dummy/DummyAccessEventBuilder.java | 2 +- .../access/dummy/DummyServerAdapter.java | 16 +- .../access/jetty/JettyFixtureBase.java | 26 +- .../logback/access/net/URLEvaluatorTest.java | 6 +- .../logback/access/pattern/ConverterTest.java | 6 +- .../spi/AccessEventSerializationTest.java | 2 +- pom.xml | 2 +- 22 files changed, 731 insertions(+), 435 deletions(-) delete mode 100644 logback-access/src/main/java/ch/qos/logback/access/jetty/JettyModernServerAdapter.java create mode 100644 logback-access/src/main/java/ch/qos/logback/access/jetty/JettyNoServletApiServerAdapter.java delete mode 100644 logback-access/src/main/java/ch/qos/logback/access/jetty/JettyServerAdapter.java create mode 100644 logback-access/src/main/java/ch/qos/logback/access/jetty/JettyServletApiServerAdapter.java create mode 100644 logback-access/src/main/java/ch/qos/logback/access/spi/ServletApiServerAdapter.java diff --git a/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyModernServerAdapter.java b/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyModernServerAdapter.java deleted file mode 100644 index 58971ee565..0000000000 --- a/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyModernServerAdapter.java +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Logback: the reliable, generic, fast and flexible logging framework. - * Copyright (C) 1999-2015, QOS.ch. All rights reserved. - *

- * This program and the accompanying materials are dual-licensed under - * either the terms of the Eclipse Public License v1.0 as published by - * the Eclipse Foundation - *

- * or (per the licensee's choosing) - *

- * under the terms of the GNU Lesser General Public License version 2.1 - * as published by the Free Software Foundation. - */ -package ch.qos.logback.access.jetty; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import ch.qos.logback.access.spi.ServerAdapter; -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Response; - -/** - * A Jetty 9.4.x and 10.0.x specific implementation of the {@link ServerAdapter} interface. - * - * @author Sébastien Pennec - * @author Ceki Gulcu - * @author Joakim Erdfelt - */ -public class JettyModernServerAdapter extends JettyServerAdapter { - - - public JettyModernServerAdapter(Request jettyRequest, Response jettyResponse) { - super(jettyRequest, jettyResponse); - } - - @Override - public long getContentLength() { - return response.getHttpChannel().getBytesWritten(); - } - - @Override - public int getStatusCode() { - return response.getCommittedMetaData().getStatus(); - } - - @Override - public long getRequestTimestamp() { - return request.getTimeStamp(); - } - - @Override - public Map buildResponseHeaderMap() { - Map responseHeaderMap = new HashMap(); - Iterator httpFieldIter = response.getHttpFields().iterator(); - while (httpFieldIter.hasNext()) { - HttpField httpField = httpFieldIter.next(); - String key = httpField.getName(); - String value = httpField.getValue(); - responseHeaderMap.put(key, value); - } - return responseHeaderMap; - } - -} diff --git a/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyNoServletApiServerAdapter.java b/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyNoServletApiServerAdapter.java new file mode 100644 index 0000000000..df987eeb58 --- /dev/null +++ b/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyNoServletApiServerAdapter.java @@ -0,0 +1,186 @@ +/** + * Logback: the reliable, generic, fast and flexible logging framework. + * Copyright (C) 1999-2024, QOS.ch. All rights reserved. + *

+ * This program and the accompanying materials are dual-licensed under + * either the terms of the Eclipse Public License v1.0 as published by + * the Eclipse Foundation + *

+ * or (per the licensee's choosing) + *

+ * under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation. + */ +package ch.qos.logback.access.jetty; + +import ch.qos.logback.access.spi.ServerAdapter; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.server.Session; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.stream.Collectors; + +public class JettyNoServletApiServerAdapter implements ServerAdapter { + + private final Request request; + private final Response response; + + public JettyNoServletApiServerAdapter(Request jettyRequest, Response jettyResponse) { + this.request = jettyRequest; + this.response = jettyResponse; + } + + @Override + public long getResponseContentLength() { + return Response.getContentBytesWritten(response); + } + + @Override + public int getStatusCode() { + return Response.getOriginalResponse(response).getStatus(); + } + + @Override + public String getContentType() { + return request.getHeaders().get(HttpHeader.CONTENT_TYPE); + } + + @Override + public String getRequestURI() { + return request.getHttpURI().getCanonicalPath(); + } + + @Override + public String getQueryString() { + return request.getHttpURI().getQuery(); + } + + @Override + public String getMethod() { + return request.getMethod(); + } + + @Override + public String getProtocol() { + return request.getConnectionMetaData().getProtocol(); + } + + @Override + public String getRemoteHost() { + return Request.getRemoteAddr(request); + } + + @Override + public String getRemoteUser() { + return request.getHttpURI().getUser(); + } + + @Override + public String getSessionId() { + Session session = request.getSession(false); + if (session != null) { + return session.getId(); + } + return null; + } + + @Override + public Object getSessionAttribute(String key) { + Session session = request.getSession(false); + if (session != null) { + return session.getAttribute(key); + } + return null; + } + + @Override + public int getLocalPort() { + return Request.getLocalPort(request); + } + + @Override + public String getServerName() { + return Request.getServerName(request); + } + + @Override + public String getRemoteAddr() { + return Request.getRemoteAddr(request); + } + + @Override + public Enumeration getHeaderNames() { + return Collections.enumeration(request.getHeaders().stream().map(HttpField::getName).collect(Collectors.toList())); + } + + @Override + public String getHeader(String key) { + return request.getHeaders().get(key); + } + + @Override + public Enumeration getParameterNames() { + try { + return Collections.enumeration(Request.getParameters(request).getNames()); + } catch (Exception e) { + // We don't want to fail the logging due to exceptions on getting the parameters + e.printStackTrace(); + return Collections.emptyEnumeration(); + } + } + + @Override + public String[] getParameterValues(String key) { + try { + return Request.getParameters(request).get(key).getValues().toArray(new String[0]); + } catch (Exception e) { + // We don't want to fail the logging due to exceptions on getting the parameters + e.printStackTrace(); + return new String[0]; + } + } + + @Override + public Enumeration getAttributeNames() { + return Collections.enumeration(request.getConnectionMetaData().getAttributeNameSet()); + } + + @Override + public Object getAttribute(String key) { + return request.getConnectionMetaData().getAttribute(key); + } + + @Override + public Cookie[] getCookies() { + return Request.getCookies(request).stream().map(cookie -> new Cookie(cookie.getName(), cookie.getValue())).toArray(Cookie[]::new); + } + + @Override + public String getResponseType() { + return response.getHeaders().get(HttpHeader.CONTENT_TYPE); + } + + @Override + public long getRequestTimestamp() { + return Request.getTimeStamp(request); + } + + @Override + public HttpServletRequest getRequest() { + // not available for recent jetty versions + return null; + } + + @Override + public HttpServletResponse getResponse() { + // not available for recent jetty versions + return null; + } +} diff --git a/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyServerAdapter.java b/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyServerAdapter.java deleted file mode 100644 index bff6da05b2..0000000000 --- a/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyServerAdapter.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Logback: the reliable, generic, fast and flexible logging framework. - * Copyright (C) 1999-2015, QOS.ch. All rights reserved. - * - * This program and the accompanying materials are dual-licensed under - * either the terms of the Eclipse Public License v1.0 as published by - * the Eclipse Foundation - * - * or (per the licensee's choosing) - * - * under the terms of the GNU Lesser General Public License version 2.1 - * as published by the Free Software Foundation. - */ -package ch.qos.logback.access.jetty; - -import ch.qos.logback.access.spi.ServerAdapter; - -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Response; - -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; - -/** - * A jetty specific implementation of the {@link ServerAdapter} interface. - * - * @author Sébastien Pennec - * @author Ceki Gulcu - */ -public class JettyServerAdapter implements ServerAdapter { - - Request request; - Response response; - - public JettyServerAdapter(Request jettyRequest, Response jettyResponse) { - this.request = jettyRequest; - this.response = jettyResponse; - } - - @Override - public long getContentLength() { - return response.getContentCount(); - } - - @Override - public int getStatusCode() { - return response.getStatus(); - } - - @Override - public long getRequestTimestamp() { - return request.getTimeStamp(); - } - - @Override - public Map buildResponseHeaderMap() { - Map responseHeaderMap = new HashMap(); - HttpFields httpFields = response.getHttpFields(); - Enumeration e = httpFields.getFieldNames(); - while (e.hasMoreElements()) { - String key = (String) e.nextElement(); - String value = response.getHeader(key); - responseHeaderMap.put(key, value); - } - return responseHeaderMap; - } - -} diff --git a/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyServletApiServerAdapter.java b/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyServletApiServerAdapter.java new file mode 100644 index 0000000000..5ce1106958 --- /dev/null +++ b/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyServletApiServerAdapter.java @@ -0,0 +1,115 @@ +/** + * Logback: the reliable, generic, fast and flexible logging framework. + * Copyright (C) 1999-2024, QOS.ch. All rights reserved. + *

+ * This program and the accompanying materials are dual-licensed under + * either the terms of the Eclipse Public License v1.0 as published by + * the Eclipse Foundation + *

+ * or (per the licensee's choosing) + *

+ * under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation. + */ +package ch.qos.logback.access.jetty; + +import ch.qos.logback.access.spi.IAccessEvent; +import ch.qos.logback.access.spi.ServerAdapter; +import ch.qos.logback.access.spi.ServletApiServerAdapter; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.server.HttpChannel; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * A Jetty pre 12 specific implementation of the {@link ServerAdapter} interface. + * + * @author Sébastien Pennec + * @author Ceki Gulcu + * @author Joakim Erdfelt + */ +public class JettyServletApiServerAdapter extends ServletApiServerAdapter { + + private final Response response; + private final Request request; + private static final Method responseGetHttpChannel; + private static final Method httpChannelGetBytesWritten; + private static final Method responseGetCommittedMetaData; + private static final Method committedMetadataGetStatus; + private static final Method requestGetTimeStamp; + + static { + // Since we can only have one version of jetty as dependency on compile time we need to + // access methods that are no longer available up from jetty 12 via injection here. + responseGetHttpChannel = getMethod(Response.class, "getHttpChannel"); + httpChannelGetBytesWritten = getMethod(HttpChannel.class, "getBytesWritten"); + responseGetCommittedMetaData = getMethod(Response.class, "getCommittedMetaData"); + committedMetadataGetStatus = getMethod(MetaData.Response.class, "getStatus"); + requestGetTimeStamp = getMethod(Request.class, "getTimeStamp"); + } + + private static Method getMethod(Class sourceClass, String methodName) { + try { + return sourceClass.getDeclaredMethod(methodName); + } catch (NoSuchMethodException e) { + // should not happen, but we don't want to fail the logging due to an error here + e.printStackTrace(); + return null; + } + } + + public JettyServletApiServerAdapter(Request jettyRequest, Response jettyResponse) { + super((HttpServletRequest) jettyRequest, (HttpServletResponse) jettyResponse); + this.request = jettyRequest; + this.response = jettyResponse; + } + + @Override + public long getResponseContentLength() { + // response.getHttpChannel().getBytesWritten() + if (responseGetHttpChannel != null && httpChannelGetBytesWritten != null) { + try { + Object httpChannel = responseGetHttpChannel.invoke(response); + return (long) httpChannelGetBytesWritten.invoke(httpChannel); + } catch (InvocationTargetException | IllegalAccessException e) { + // should not happen, but we don't want to fail the logging due to an error here + e.printStackTrace(); + } + } + return IAccessEvent.SENTINEL; + } + + @Override + public int getStatusCode() { + // response.getCommittedMetaData().getStatus() + if (responseGetCommittedMetaData != null && committedMetadataGetStatus != null) { + try { + Object committedMetaData = responseGetCommittedMetaData.invoke(response); + return (int) committedMetadataGetStatus.invoke(committedMetaData); + } catch (InvocationTargetException | IllegalAccessException e) { + // should not happen, but we don't want to fail the logging due to an error here + e.printStackTrace(); + } + } + return IAccessEvent.SENTINEL; + } + + @Override + public long getRequestTimestamp() { + // request.getTimeStamp() + if (requestGetTimeStamp != null) { + try { + return (long) requestGetTimeStamp.invoke(request); + } catch (InvocationTargetException | IllegalAccessException e) { + // should not happen, but we don't want to fail the logging due to an error here + e.printStackTrace(); + } + } + return IAccessEvent.SENTINEL; + } +} diff --git a/logback-access/src/main/java/ch/qos/logback/access/jetty/RequestLogImpl.java b/logback-access/src/main/java/ch/qos/logback/access/jetty/RequestLogImpl.java index 0c36aa9e61..bb34afb560 100644 --- a/logback-access/src/main/java/ch/qos/logback/access/jetty/RequestLogImpl.java +++ b/logback-access/src/main/java/ch/qos/logback/access/jetty/RequestLogImpl.java @@ -23,6 +23,7 @@ import ch.qos.logback.access.joran.JoranConfigurator; import ch.qos.logback.access.spi.AccessEvent; import ch.qos.logback.access.spi.IAccessEvent; +import ch.qos.logback.access.spi.ServerAdapter; import ch.qos.logback.core.Appender; import ch.qos.logback.core.ContextBase; import ch.qos.logback.core.CoreConstants; @@ -36,10 +37,10 @@ import ch.qos.logback.core.spi.FilterReply; import ch.qos.logback.core.status.ErrorStatus; import ch.qos.logback.core.status.InfoStatus; -import ch.qos.logback.core.util.EnvUtil; import ch.qos.logback.core.util.FileUtil; import ch.qos.logback.core.util.OptionHelper; import ch.qos.logback.core.util.StatusPrinter; +import jakarta.servlet.http.HttpServletRequest; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.RequestLog; import org.eclipse.jetty.server.Response; @@ -252,16 +253,20 @@ public RequestLogImpl() { @Override public void log(Request jettyRequest, Response jettyResponse) { - JettyServerAdapter adapter = makeJettyServerAdapter(jettyRequest, jettyResponse); - IAccessEvent accessEvent = new AccessEvent(this, jettyRequest, jettyResponse, adapter); + ServerAdapter adapter = makeJettyServerAdapter(jettyRequest, jettyResponse); + IAccessEvent accessEvent = new AccessEvent(this, adapter); if (getFilterChainDecision(accessEvent) == FilterReply.DENY) { return; } aai.appendLoopOnAppenders(accessEvent); } - private JettyServerAdapter makeJettyServerAdapter(Request jettyRequest, Response jettyResponse) { - return new JettyModernServerAdapter(jettyRequest, jettyResponse); + private ServerAdapter makeJettyServerAdapter(Request jettyRequest, Response jettyResponse) { + if (jettyRequest instanceof HttpServletRequest) { + return new JettyServletApiServerAdapter(jettyRequest, jettyResponse); + } else { + return new JettyNoServletApiServerAdapter(jettyRequest, jettyResponse); + } } protected void addInfo(String msg) { diff --git a/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeHttpServletRequest.java b/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeHttpServletRequest.java index 0abb0059f8..60f1fdff2e 100644 --- a/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeHttpServletRequest.java +++ b/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeHttpServletRequest.java @@ -38,7 +38,7 @@ class TeeHttpServletRequest extends HttpServletRequestWrapper { super(request); // we can't access the input stream and access the request parameters // at the same time - if (Util.isFormUrlEncoded(request)) { + if (Util.isFormUrlEncoded(request.getContentType(), request.getMethod())) { postedParametersMode = true; } else { inStream = new TeeServletInputStream(request); diff --git a/logback-access/src/main/java/ch/qos/logback/access/servlet/Util.java b/logback-access/src/main/java/ch/qos/logback/access/servlet/Util.java index 0d033a98a6..52ae474e3a 100755 --- a/logback-access/src/main/java/ch/qos/logback/access/servlet/Util.java +++ b/logback-access/src/main/java/ch/qos/logback/access/servlet/Util.java @@ -15,30 +15,15 @@ import ch.qos.logback.access.AccessConstants; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - public class Util { - - public static boolean isFormUrlEncoded(HttpServletRequest request) { - - String contentTypeStr = request.getContentType(); - if ("POST".equalsIgnoreCase(request.getMethod()) && contentTypeStr != null - && contentTypeStr.startsWith(AccessConstants.X_WWW_FORM_URLECODED)) { - return true; - } else { - return false; - } + private Util() { } - public static boolean isImageResponse(HttpServletResponse response) { - - String responseType = response.getContentType(); + public static boolean isFormUrlEncoded(String contentType, String method) { + return "POST".equalsIgnoreCase(method) && contentType != null && contentType.startsWith(AccessConstants.X_WWW_FORM_URLECODED); + } - if (responseType != null && responseType.startsWith(AccessConstants.IMAGE_CONTENT_TYPE)) { - return true; - } else { - return false; - } + public static boolean isImageResponse(String contentType) { + return contentType != null && contentType.startsWith(AccessConstants.IMAGE_CONTENT_TYPE); } } diff --git a/logback-access/src/main/java/ch/qos/logback/access/sift/AccessEventDiscriminator.java b/logback-access/src/main/java/ch/qos/logback/access/sift/AccessEventDiscriminator.java index 21ebd9603e..a0c431d245 100644 --- a/logback-access/src/main/java/ch/qos/logback/access/sift/AccessEventDiscriminator.java +++ b/logback-access/src/main/java/ch/qos/logback/access/sift/AccessEventDiscriminator.java @@ -13,9 +13,6 @@ */ package ch.qos.logback.access.sift; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpSession; - import ch.qos.logback.access.spi.IAccessEvent; import ch.qos.logback.core.sift.AbstractDiscriminator; @@ -100,18 +97,12 @@ private String getRequestURI(IAccessEvent acccessEvent) { } private String getSessionAttribute(IAccessEvent acccessEvent) { - HttpServletRequest req = acccessEvent.getRequest(); - if (req != null) { - HttpSession session = req.getSession(false); - if (session != null) { - if ("id".equalsIgnoreCase(additionalKey)) { - return session.getId(); - } else { - Object v = session.getAttribute(additionalKey); - if (v != null) { - return v.toString(); - } - } + if ("id".equalsIgnoreCase(additionalKey)) { + return acccessEvent.getSessionID(); + } else { + Object v = acccessEvent.getSessionAttribute(additionalKey); + if (v != null) { + return v.toString(); } } return null; @@ -135,7 +126,7 @@ public void start() { case REQUEST_ATTRIBUTE: case COOKIE: if (additionalKey == null) { - addError("\"OptionalKey\" property is mandatory for field name " + fieldName.toString()); + addError("\"OptionalKey\" property is mandatory for field name " + fieldName); errorCount++; } } diff --git a/logback-access/src/main/java/ch/qos/logback/access/spi/AccessEvent.java b/logback-access/src/main/java/ch/qos/logback/access/spi/AccessEvent.java index fe32b68460..285cca2f9d 100755 --- a/logback-access/src/main/java/ch/qos/logback/access/spi/AccessEvent.java +++ b/logback-access/src/main/java/ch/qos/logback/access/spi/AccessEvent.java @@ -22,16 +22,15 @@ import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import jakarta.servlet.http.HttpSession; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; -import java.util.Vector; // Contributors: Joern Huxhorn (see also bug #110) @@ -52,9 +51,6 @@ public class AccessEvent implements Serializable, IAccessEvent { private static final String EMPTY = ""; - private transient final HttpServletRequest httpRequest; - private transient final HttpServletResponse httpResponse; - String queryString; String requestURI; String requestURL; @@ -89,10 +85,7 @@ public class AccessEvent implements Serializable, IAccessEvent { private long sequenceNumber = 0; - public AccessEvent(Context context, HttpServletRequest httpRequest, HttpServletResponse httpResponse, - ServerAdapter adapter) { - this.httpRequest = httpRequest; - this.httpResponse = httpResponse; + public AccessEvent(Context context, ServerAdapter adapter) { this.timeStamp = System.currentTimeMillis(); SequenceNumberGenerator sng = context.getSequenceNumberGenerator(); @@ -103,26 +96,20 @@ public AccessEvent(Context context, HttpServletRequest httpRequest, HttpServletR this.elapsedTime = calculateElapsedTime(); } - /** - * Returns the underlying HttpServletRequest. After serialization the returned - * value will be null. - * - * @return - */ @Override public HttpServletRequest getRequest() { - return httpRequest; + if (serverAdapter != null) { + return serverAdapter.getRequest(); + } + return null; } - /** - * Returns the underlying HttpServletResponse. After serialization the returned - * value will be null. - * - * @return - */ @Override public HttpServletResponse getResponse() { - return httpResponse; + if (serverAdapter != null) { + return serverAdapter.getResponse(); + } + return null; } @Override @@ -157,8 +144,8 @@ public String getThreadName() { @Override public String getRequestURI() { if (requestURI == null) { - if (httpRequest != null) { - requestURI = httpRequest.getRequestURI(); + if (serverAdapter != null) { + requestURI = serverAdapter.getRequestURI(); } else { requestURI = NA; } @@ -169,9 +156,9 @@ public String getRequestURI() { @Override public String getQueryString() { if (queryString == null) { - if (httpRequest != null) { + if (serverAdapter != null) { StringBuilder buf = new StringBuilder(); - final String qStr = httpRequest.getQueryString(); + final String qStr = serverAdapter.getQueryString(); if (qStr != null) { buf.append(AccessConverter.QUESTION_CHAR); buf.append(qStr); @@ -190,14 +177,14 @@ public String getQueryString() { @Override public String getRequestURL() { if (requestURL == null) { - if (httpRequest != null) { + if (serverAdapter != null) { StringBuilder buf = new StringBuilder(); - buf.append(httpRequest.getMethod()); + buf.append(serverAdapter.getMethod()); buf.append(AccessConverter.SPACE_CHAR); - buf.append(httpRequest.getRequestURI()); + buf.append(serverAdapter.getRequestURI()); buf.append(getQueryString()); buf.append(AccessConverter.SPACE_CHAR); - buf.append(httpRequest.getProtocol()); + buf.append(serverAdapter.getProtocol()); requestURL = buf.toString(); } else { requestURL = NA; @@ -209,11 +196,12 @@ public String getRequestURL() { @Override public String getRemoteHost() { if (remoteHost == null) { - if (httpRequest != null) { + if (serverAdapter != null) { // the underlying implementation of HttpServletRequest will // determine if remote lookup will be performed - remoteHost = httpRequest.getRemoteHost(); - } else { + remoteHost = serverAdapter.getRemoteHost(); + } + if (remoteHost == null) { remoteHost = NA; } } @@ -223,9 +211,10 @@ public String getRemoteHost() { @Override public String getRemoteUser() { if (remoteUser == null) { - if (httpRequest != null) { - remoteUser = httpRequest.getRemoteUser(); - } else { + if (serverAdapter != null) { + remoteUser = serverAdapter.getRemoteUser(); + } + if (remoteUser == null) { remoteUser = NA; } } @@ -235,9 +224,10 @@ public String getRemoteUser() { @Override public String getProtocol() { if (protocol == null) { - if (httpRequest != null) { - protocol = httpRequest.getProtocol(); - } else { + if (serverAdapter != null) { + protocol = serverAdapter.getProtocol(); + } + if (protocol == null) { protocol = NA; } } @@ -247,9 +237,10 @@ public String getProtocol() { @Override public String getMethod() { if (method == null) { - if (httpRequest != null) { - method = httpRequest.getMethod(); - } else { + if (serverAdapter != null) { + method = serverAdapter.getMethod(); + } + if (method == null) { method = NA; } } @@ -259,12 +250,10 @@ public String getMethod() { @Override public String getSessionID() { if (sessionID == null) { - if (httpRequest != null) { - final HttpSession session = httpRequest.getSession(false); - if (session != null) { - sessionID = session.getId(); - } - } else { + if (serverAdapter != null) { + sessionID = serverAdapter.getSessionId(); + } + if (sessionID == null) { sessionID = NA; } } @@ -274,9 +263,10 @@ public String getSessionID() { @Override public String getServerName() { if (serverName == null) { - if (httpRequest != null) { - serverName = httpRequest.getServerName(); - } else { + if (serverAdapter != null) { + serverName = serverAdapter.getServerName(); + } + if (serverName == null) { serverName = NA; } } @@ -286,8 +276,8 @@ public String getServerName() { @Override public String getRemoteAddr() { if (remoteAddr == null) { - if (httpRequest != null) { - remoteAddr = httpRequest.getRemoteAddr(); + if (serverAdapter != null) { + remoteAddr = serverAdapter.getRemoteAddr(); } else { remoteAddr = NA; } @@ -297,81 +287,46 @@ public String getRemoteAddr() { @Override public String getRequestHeader(String key) { - String result = null; key = key.toLowerCase(); - if (requestHeaderMap == null) { - if (httpRequest != null) { - buildRequestHeaderMap(); - result = requestHeaderMap.get(key); - } - } else { - result = requestHeaderMap.get(key); - } - - if (result != null) { - return result; - } else { - return NA; + Map headerMap = getRequestHeaderMap(); + String result = headerMap.get(key); + if (result == null) { + result = NA; } + return result; } @Override public Enumeration getRequestHeaderNames() { - // post-serialization - if (httpRequest == null) { - Vector list = new Vector(getRequestHeaderMap().keySet()); - return list.elements(); - } - return httpRequest.getHeaderNames(); + return Collections.enumeration(getRequestHeaderMap().keySet()); } @Override public Map getRequestHeaderMap() { if (requestHeaderMap == null) { - buildRequestHeaderMap(); - } - return requestHeaderMap; - } - - public void buildRequestHeaderMap() { - // according to RFC 2616 header names are case-insensitive - // latest versions of Tomcat return header names in lower-case - requestHeaderMap = new TreeMap(String.CASE_INSENSITIVE_ORDER); - Enumeration e = httpRequest.getHeaderNames(); - if (e == null) { - return; - } - while (e.hasMoreElements()) { - String key = e.nextElement(); - requestHeaderMap.put(key, httpRequest.getHeader(key)); - } - } - - public void buildRequestParameterMap() { - requestParameterMap = new HashMap(); - try { - Enumeration e = httpRequest.getParameterNames(); - if (e == null) { - return; - } - while (e.hasMoreElements()) { - String key = e.nextElement(); - requestParameterMap.put(key, httpRequest.getParameterValues(key)); + // according to RFC 2616 header names are case-insensitive + // latest versions of Tomcat return header names in lower-case + requestHeaderMap = new TreeMap(String.CASE_INSENSITIVE_ORDER); + Enumeration e = serverAdapter.getHeaderNames(); + if (e != null) { + while (e.hasMoreElements()) { + String key = e.nextElement(); + requestHeaderMap.put(key, serverAdapter.getHeader(key)); + } } - } catch(Throwable t) { - // The use of HttpServletRequest.getParameterNames() can cause - // a READ of the Request body content. This can fail with various - // Throwable failures depending on the state of the Request - // at the time this method is called. - // We don't want to fail the logging due to these types of requests - t.printStackTrace(); } + return requestHeaderMap; } @Override public Map getRequestParameterMap() { if (requestParameterMap == null) { - buildRequestParameterMap(); + requestParameterMap = new HashMap(); + Enumeration e = serverAdapter.getParameterNames(); + while (e.hasMoreElements()) { + String key = e.nextElement(); + requestParameterMap.put(key, serverAdapter.getParameterValues(key)); + } } return requestParameterMap; } @@ -383,9 +338,9 @@ public String getAttribute(String key) { // Event was prepared for deferred processing so we have a copy of attribute map // and must use that copy value = attributeMap.get(key); - } else if (httpRequest != null) { + } else if (serverAdapter != null) { // We have original request so take attribute from it - value = httpRequest.getAttribute(key); + value = serverAdapter.getAttribute(key); } return value != null ? value.toString() : NA; @@ -393,7 +348,7 @@ public String getAttribute(String key) { private void copyAttributeMap() { - if (httpRequest == null) { + if (serverAdapter == null) { return; } @@ -404,11 +359,11 @@ private void copyAttributeMap() { attributeMap = new HashMap(); - Enumeration names = httpRequest.getAttributeNames(); + Enumeration names = serverAdapter.getAttributeNames(); while (names.hasMoreElements()) { String name = names.nextElement(); - Object value = httpRequest.getAttribute(name); + Object value = serverAdapter.getAttribute(name); if (shouldCopyAttribute(name, value)) { attributeMap.put(name, value); } @@ -433,22 +388,15 @@ private boolean shouldCopyAttribute(String name, Object value) { @Override public String[] getRequestParameter(String key) { - String[] value = null; - - if (requestParameterMap != null) { - value = requestParameterMap.get(key); - } else if (httpRequest != null) { - value = httpRequest.getParameterValues(key); - } - + Map parameterMap = getRequestParameterMap(); + String[] value = parameterMap.get(key); return (value != null) ? value : NA_STRING_ARRAY; } @Override public String getCookie(String key) { - - if (httpRequest != null) { - Cookie[] cookieArray = httpRequest.getCookies(); + if (serverAdapter != null) { + Cookie[] cookieArray = serverAdapter.getCookies(); if (cookieArray == null) { return NA; } @@ -464,20 +412,15 @@ public String getCookie(String key) { @Override public long getContentLength() { - if (contentLength == SENTINEL) { - if (httpResponse != null) { - contentLength = serverAdapter.getContentLength(); - return contentLength; - } + if (contentLength == SENTINEL && serverAdapter != null) { + contentLength = serverAdapter.getResponseContentLength(); } return contentLength; } public int getStatusCode() { - if (statusCode == SENTINEL) { - if (httpResponse != null) { - statusCode = serverAdapter.getStatusCode(); - } + if (statusCode == SENTINEL && serverAdapter != null) { + statusCode = serverAdapter.getStatusCode(); } return statusCode; } @@ -491,7 +434,7 @@ public long getElapsedTime() { } private long calculateElapsedTime() { - if (serverAdapter.getRequestTimestamp() < 0) { + if (serverAdapter == null || serverAdapter.getRequestTimestamp() < 0) { return -1; } return getTimeStamp() - serverAdapter.getRequestTimestamp(); @@ -502,51 +445,40 @@ public String getRequestContent() { return requestContent; } - if (Util.isFormUrlEncoded(httpRequest)) { - StringBuilder buf = new StringBuilder(); - - try { - Enumeration pramEnumeration = httpRequest.getParameterNames(); + if (serverAdapter != null) { + if (Util.isFormUrlEncoded(serverAdapter.getContentType(), serverAdapter.getMethod())) { + StringBuilder buf = new StringBuilder(); + Enumeration paramEnumeration = serverAdapter.getParameterNames(); // example: id=1234&user=cgu // number=1233&x=1 int count = 0; - while (pramEnumeration.hasMoreElements()) { - - String key = pramEnumeration.nextElement(); + while (paramEnumeration.hasMoreElements()) { + String key = paramEnumeration.nextElement(); if (count++ != 0) { buf.append("&"); } buf.append(key); buf.append("="); - String val = httpRequest.getParameter(key); + String val = serverAdapter.getParameterValues(key)[0]; if (val != null) { buf.append(val); } else { buf.append(""); } } - } catch (Throwable t) { - // The use of HttpServletRequest.getParameterNames() and - // HttpServletRequest.getParameter(String) can cause - // a READ of the Request body content. This can fail with various - // Throwable failures depending on the state of the Request - // at the time this method is called. - // We don't want to fail the logging due to these types of requests - t.printStackTrace(); - } - requestContent = buf.toString(); - } else { - // retrieve the byte array placed by TeeFilter - byte[] inputBuffer = (byte[]) httpRequest.getAttribute(AccessConstants.LB_INPUT_BUFFER); - - if (inputBuffer != null) { - requestContent = new String(inputBuffer); + requestContent = buf.toString(); + } else { + // retrieve the byte array placed by TeeFilter + byte[] inputBuffer = (byte[]) serverAdapter.getAttribute(AccessConstants.LB_INPUT_BUFFER); + if (inputBuffer != null) { + requestContent = new String(inputBuffer); + } } + } - if (requestContent == null || requestContent.length() == 0) { - requestContent = EMPTY; - } + if (requestContent == null || requestContent.isEmpty()) { + requestContent = EMPTY; } return requestContent; @@ -557,57 +489,62 @@ public String getResponseContent() { return responseContent; } - if (Util.isImageResponse(httpResponse)) { - responseContent = "[IMAGE CONTENTS SUPPRESSED]"; - } else { - - // retrieve the byte array previously placed by TeeFilter - byte[] outputBuffer = (byte[]) httpRequest.getAttribute(AccessConstants.LB_OUTPUT_BUFFER); + if (serverAdapter != null) { + if (Util.isImageResponse(serverAdapter.getResponseType())) { + responseContent = "[IMAGE CONTENTS SUPPRESSED]"; + } else { + // retrieve the byte array previously placed by TeeFilter + byte[] outputBuffer = (byte[]) serverAdapter.getAttribute(AccessConstants.LB_OUTPUT_BUFFER); - if (outputBuffer != null) { - responseContent = new String(outputBuffer); - } - if (responseContent == null || responseContent.length() == 0) { - responseContent = EMPTY; + if (outputBuffer != null) { + responseContent = new String(outputBuffer); + } } } + if (responseContent == null || responseContent.isEmpty()) { + responseContent = EMPTY; + } + return responseContent; } public int getLocalPort() { - if (localPort == SENTINEL) { - if (httpRequest != null) { - localPort = httpRequest.getLocalPort(); - } - + if (localPort == SENTINEL && serverAdapter != null) { + localPort = serverAdapter.getLocalPort(); } return localPort; } + @Override public ServerAdapter getServerAdapter() { return serverAdapter; } public String getResponseHeader(String key) { - buildResponseHeaderMap(); - return responseHeaderMap.get(key); + return getResponseHeaderMap().get(key); } - void buildResponseHeaderMap() { + public Map getResponseHeaderMap() { if (responseHeaderMap == null) { - responseHeaderMap = serverAdapter.buildResponseHeaderMap(); + responseHeaderMap = new HashMap(); + Enumeration headerNames = serverAdapter.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String key = headerNames.nextElement(); + String value = serverAdapter.getHeader(key); + responseHeaderMap.put(key, value); + } } - } - - public Map getResponseHeaderMap() { - buildResponseHeaderMap(); return responseHeaderMap; } public List getResponseHeaderNameList() { - buildResponseHeaderMap(); - return new ArrayList(responseHeaderMap.keySet()); + return new ArrayList(getResponseHeaderMap().keySet()); + } + + @Override + public Object getSessionAttribute(String key) { + return serverAdapter.getSessionAttribute(key); } public void prepareForDeferredProcessing() { diff --git a/logback-access/src/main/java/ch/qos/logback/access/spi/IAccessEvent.java b/logback-access/src/main/java/ch/qos/logback/access/spi/IAccessEvent.java index 89c93aa2ca..435202f062 100644 --- a/logback-access/src/main/java/ch/qos/logback/access/spi/IAccessEvent.java +++ b/logback-access/src/main/java/ch/qos/logback/access/spi/IAccessEvent.java @@ -43,7 +43,9 @@ public interface IAccessEvent extends DeferredProcessingAware { * value will be null. * * @return + * @deprecated Don't rely on a HttpServletRequest being available */ + @Deprecated HttpServletRequest getRequest(); /** @@ -51,7 +53,9 @@ public interface IAccessEvent extends DeferredProcessingAware { * value will be null. * * @return + * @deprecated Don't rely on a HttpServletResponse being available */ + @Deprecated HttpServletResponse getResponse(); /** @@ -101,6 +105,8 @@ public interface IAccessEvent extends DeferredProcessingAware { String getSessionID(); + Object getSessionAttribute(String key); + void setThreadName(String threadName); String getThreadName(); @@ -133,6 +139,11 @@ public interface IAccessEvent extends DeferredProcessingAware { int getLocalPort(); + /** + * Access to internal adapter is deprecated + * @deprecated do not access the internal adapter but use the matching properties instead + */ + @Deprecated ServerAdapter getServerAdapter(); String getResponseHeader(String key); diff --git a/logback-access/src/main/java/ch/qos/logback/access/spi/ServerAdapter.java b/logback-access/src/main/java/ch/qos/logback/access/spi/ServerAdapter.java index 4031b61e08..d485cb42f5 100644 --- a/logback-access/src/main/java/ch/qos/logback/access/spi/ServerAdapter.java +++ b/logback-access/src/main/java/ch/qos/logback/access/spi/ServerAdapter.java @@ -13,7 +13,11 @@ */ package ch.qos.logback.access.spi; -import java.util.Map; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.Enumeration; /** * An interface to access server-specific methods from the server-independent @@ -26,9 +30,57 @@ public interface ServerAdapter { long getRequestTimestamp(); - long getContentLength(); + long getResponseContentLength(); int getStatusCode(); - Map buildResponseHeaderMap(); + String getContentType(); + + String getRequestURI(); + + String getQueryString(); + + String getMethod(); + + String getProtocol(); + + String getRemoteHost(); + + String getRemoteUser(); + + String getSessionId(); + + Object getSessionAttribute(String key); + + int getLocalPort(); + + String getServerName(); + + String getRemoteAddr(); + + Enumeration getHeaderNames(); + + String getHeader(String key); + + Enumeration getParameterNames(); + + String[] getParameterValues(String key); + + Enumeration getAttributeNames(); + + Object getAttribute(String key); + + Cookie[] getCookies(); + + String getResponseType(); + + /** + * Will be null for some server implementations. Don't rely on it being available! + */ + HttpServletRequest getRequest(); + + /** + * Will be null for some server implementations. Don't rely on it being available! + */ + HttpServletResponse getResponse(); } diff --git a/logback-access/src/main/java/ch/qos/logback/access/spi/ServletApiServerAdapter.java b/logback-access/src/main/java/ch/qos/logback/access/spi/ServletApiServerAdapter.java new file mode 100644 index 0000000000..0f33058ffa --- /dev/null +++ b/logback-access/src/main/java/ch/qos/logback/access/spi/ServletApiServerAdapter.java @@ -0,0 +1,181 @@ +/** + * Logback: the reliable, generic, fast and flexible logging framework. + * Copyright (C) 1999-2024, QOS.ch. All rights reserved. + *

+ * This program and the accompanying materials are dual-licensed under + * either the terms of the Eclipse Public License v1.0 as published by + * the Eclipse Foundation + *

+ * or (per the licensee's choosing) + *

+ * under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation. + */ +package ch.qos.logback.access.spi; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; + +import java.util.Collections; +import java.util.Enumeration; + +/** + * Base class for ServerAdapter implementations where the server provides access to + * HttpServletRequest and HttpServletResponse + */ +public abstract class ServletApiServerAdapter implements ServerAdapter { + + private final HttpServletRequest request; + private final HttpServletResponse response; + + protected ServletApiServerAdapter(HttpServletRequest servletRequest, HttpServletResponse servletResponse) { + this.request = servletRequest; + this.response = servletResponse; + } + + @Override + public int getStatusCode() { + return response.getStatus(); + } + + @Override + public String getContentType() { + return request.getContentType(); + } + + @Override + public String getRequestURI() { + return request.getRequestURI(); + } + + @Override + public String getQueryString() { + return request.getQueryString(); + } + + @Override + public String getMethod() { + return request.getMethod(); + } + + @Override + public String getProtocol() { + return request.getProtocol(); + } + + @Override + public String getRemoteHost() { + return request.getRemoteHost(); + } + + @Override + public String getRemoteUser() { + return request.getRemoteUser(); + } + + @Override + public String getSessionId() { + final HttpSession session = request.getSession(false); + if (session != null) { + return session.getId(); + } + return null; + } + + @Override + public Object getSessionAttribute(String key) { + final HttpSession session = request.getSession(false); + if (session != null) { + return session.getId(); + } + return null; + } + + @Override + public String getServerName() { + return request.getServerName(); + } + + @Override + public String getRemoteAddr() { + return request.getRemoteAddr(); + } + + @Override + public Enumeration getHeaderNames() { + Enumeration headerNames = request.getHeaderNames(); + if (headerNames == null) { + headerNames = Collections.emptyEnumeration(); + } + return headerNames; + } + + @Override + public String getHeader(String key) { + return request.getHeader(key); + } + + @Override + public Enumeration getParameterNames() { + try { + Enumeration parameterNames = request.getParameterNames(); + if (parameterNames != null) { + return parameterNames; + } + } catch (Exception t) { + // The use of HttpServletRequest.getParameterNames() can cause + // a READ of the Request body content. This can fail with various + // Throwable failures depending on the state of the Request + // at the time this method is called. + // We don't want to fail the logging due to these types of requests + t.printStackTrace(); + } + return Collections.emptyEnumeration(); + } + + @Override + public String[] getParameterValues(String key) { + return request.getParameterValues(key); + } + + @Override + public Enumeration getAttributeNames() { + Enumeration attributeNames = request.getAttributeNames(); + if (attributeNames == null) { + attributeNames = Collections.emptyEnumeration(); + } + return attributeNames; + } + + @Override + public Object getAttribute(String key) { + return request.getAttribute(key); + } + + @Override + public Cookie[] getCookies() { + return request.getCookies(); + } + + @Override + public int getLocalPort() { + return request.getLocalPort(); + } + + @Override + public String getResponseType() { + return response.getContentType(); + } + + @Override + public HttpServletRequest getRequest() { + return request; + } + + @Override + public HttpServletResponse getResponse() { + return response; + } +} diff --git a/logback-access/src/main/java/ch/qos/logback/access/tomcat/LogbackValve.java b/logback-access/src/main/java/ch/qos/logback/access/tomcat/LogbackValve.java index bc5b00aafd..c2a8220df3 100644 --- a/logback-access/src/main/java/ch/qos/logback/access/tomcat/LogbackValve.java +++ b/logback-access/src/main/java/ch/qos/logback/access/tomcat/LogbackValve.java @@ -267,7 +267,7 @@ public void invoke(Request request, Response response) throws IOException, Servl getNext().invoke(request, response); TomcatServerAdapter adapter = new TomcatServerAdapter(request, response); - IAccessEvent accessEvent = new AccessEvent(this, request, response, adapter); + IAccessEvent accessEvent = new AccessEvent(this, adapter); addThreadName(accessEvent); diff --git a/logback-access/src/main/java/ch/qos/logback/access/tomcat/TomcatServerAdapter.java b/logback-access/src/main/java/ch/qos/logback/access/tomcat/TomcatServerAdapter.java index a08f572c94..d623c1eb92 100644 --- a/logback-access/src/main/java/ch/qos/logback/access/tomcat/TomcatServerAdapter.java +++ b/logback-access/src/main/java/ch/qos/logback/access/tomcat/TomcatServerAdapter.java @@ -15,49 +15,33 @@ import ch.qos.logback.access.spi.ServerAdapter; +import ch.qos.logback.access.spi.ServletApiServerAdapter; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; -import java.util.HashMap; -import java.util.Map; - /** * A tomcat specific implementation of the {@link ServerAdapter} interface. * * @author Sébastien Pennec */ -public class TomcatServerAdapter implements ServerAdapter { +public class TomcatServerAdapter extends ServletApiServerAdapter { Request request; Response response; public TomcatServerAdapter(Request tomcatRequest, Response tomcatResponse) { + super(tomcatRequest, tomcatResponse); this.request = tomcatRequest; this.response = tomcatResponse; } @Override - public long getContentLength() { + public long getResponseContentLength() { return response.getContentLength(); } - @Override - public int getStatusCode() { - return response.getStatus(); - } - @Override public long getRequestTimestamp() { return request.getCoyoteRequest().getStartTime(); } - - @Override - public Map buildResponseHeaderMap() { - Map responseHeaderMap = new HashMap(); - for (String key : response.getHeaderNames()) { - String value = response.getHeader(key); - responseHeaderMap.put(key, value); - } - return responseHeaderMap; - } } diff --git a/logback-access/src/test/java/ch/qos/logback/access/boolex/JaninoEventEvaluatorTest.java b/logback-access/src/test/java/ch/qos/logback/access/boolex/JaninoEventEvaluatorTest.java index 6f01773882..abac970504 100644 --- a/logback-access/src/test/java/ch/qos/logback/access/boolex/JaninoEventEvaluatorTest.java +++ b/logback-access/src/test/java/ch/qos/logback/access/boolex/JaninoEventEvaluatorTest.java @@ -50,7 +50,7 @@ public void setUp() throws Exception { public void smoke() throws EvaluationException { evaluator.setExpression("event.getProtocol().equals(\"testProtocol\")"); evaluator.start(); - IAccessEvent ae = new AccessEvent(accessContext, request, response, serverAdapter); + IAccessEvent ae = new AccessEvent(accessContext, serverAdapter); assertTrue(evaluator.evaluate(ae)); } @@ -58,7 +58,7 @@ public void smoke() throws EvaluationException { public void block() throws EvaluationException { evaluator.setExpression("String protocol = event.getProtocol();" + "return protocol.equals(\"testProtocol\");"); evaluator.start(); - IAccessEvent ae = new AccessEvent(accessContext, request, response, serverAdapter); + IAccessEvent ae = new AccessEvent(accessContext, serverAdapter); assertTrue(evaluator.evaluate(ae)); } @@ -66,7 +66,7 @@ public void block() throws EvaluationException { public void invalidExpression() throws EvaluationException { evaluator.setExpression("return true"); evaluator.start(); - IAccessEvent ae = new AccessEvent(accessContext, request, response, serverAdapter); + IAccessEvent ae = new AccessEvent(accessContext, serverAdapter); try { evaluator.evaluate(ae); fail("Was expecting an exception"); diff --git a/logback-access/src/test/java/ch/qos/logback/access/dummy/DummyAccessEventBuilder.java b/logback-access/src/test/java/ch/qos/logback/access/dummy/DummyAccessEventBuilder.java index a63fb4e5b8..1f358de171 100644 --- a/logback-access/src/test/java/ch/qos/logback/access/dummy/DummyAccessEventBuilder.java +++ b/logback-access/src/test/java/ch/qos/logback/access/dummy/DummyAccessEventBuilder.java @@ -25,7 +25,7 @@ static public IAccessEvent buildNewAccessEvent() { DummyServerAdapter adapter = new DummyServerAdapter(request, response); AccessContext accessContext = new AccessContext(); - return new AccessEvent(accessContext, request, response, adapter); + return new AccessEvent(accessContext, adapter); } } diff --git a/logback-access/src/test/java/ch/qos/logback/access/dummy/DummyServerAdapter.java b/logback-access/src/test/java/ch/qos/logback/access/dummy/DummyServerAdapter.java index 7af921da30..5b1db720d0 100644 --- a/logback-access/src/test/java/ch/qos/logback/access/dummy/DummyServerAdapter.java +++ b/logback-access/src/test/java/ch/qos/logback/access/dummy/DummyServerAdapter.java @@ -13,21 +13,18 @@ */ package ch.qos.logback.access.dummy; -import ch.qos.logback.access.spi.ServerAdapter; +import ch.qos.logback.access.spi.ServletApiServerAdapter; -import java.util.Map; +public class DummyServerAdapter extends ServletApiServerAdapter { -public class DummyServerAdapter implements ServerAdapter { - - DummyRequest request; DummyResponse response; public DummyServerAdapter(DummyRequest dummyRequest, DummyResponse dummyResponse) { - this.request = dummyRequest; + super(dummyRequest, dummyResponse); this.response = dummyResponse; } - public long getContentLength() { + public long getResponseContentLength() { return response.getContentCount(); } @@ -38,9 +35,4 @@ public int getStatusCode() { public long getRequestTimestamp() { return -1; } - - public Map buildResponseHeaderMap() { - return response.headerMap; - } - } diff --git a/logback-access/src/test/java/ch/qos/logback/access/jetty/JettyFixtureBase.java b/logback-access/src/test/java/ch/qos/logback/access/jetty/JettyFixtureBase.java index 0e546d6da7..1edb8058cc 100644 --- a/logback-access/src/test/java/ch/qos/logback/access/jetty/JettyFixtureBase.java +++ b/logback-access/src/test/java/ch/qos/logback/access/jetty/JettyFixtureBase.java @@ -13,17 +13,15 @@ */ package ch.qos.logback.access.jetty; -import java.io.IOException; -import java.io.Writer; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.handler.AbstractHandler; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; +import org.eclipse.jetty.util.Callback; public class JettyFixtureBase { final protected RequestLogImpl requestLogImpl; @@ -69,14 +67,12 @@ protected Handler getRequestHandler() { return handler; } - class BasicHandler extends AbstractHandler { - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - response.setCharacterEncoding("UTF-8"); - response.setContentType("text/plain"); - Writer writer = response.getWriter(); - writer.write("hello world"); - writer.flush(); - baseRequest.setHandled(true); + static class BasicHandler extends Handler.Wrapper { + @Override + public boolean handle(Request request, Response response, Callback callback) { + response.write(true, ByteBuffer.wrap("hello world".getBytes(StandardCharsets.UTF_8)), callback); + callback.succeeded(); + return true; } } } diff --git a/logback-access/src/test/java/ch/qos/logback/access/net/URLEvaluatorTest.java b/logback-access/src/test/java/ch/qos/logback/access/net/URLEvaluatorTest.java index 64f330a3b4..93bbca6204 100644 --- a/logback-access/src/test/java/ch/qos/logback/access/net/URLEvaluatorTest.java +++ b/logback-access/src/test/java/ch/qos/logback/access/net/URLEvaluatorTest.java @@ -61,14 +61,14 @@ public void tearDown() throws Exception { @Test public void testExpectFalse() throws EvaluationException { request.setRequestUri("test"); - IAccessEvent ae = new AccessEvent(accessContext, request, response, serverAdapter); + IAccessEvent ae = new AccessEvent(accessContext, serverAdapter); assertFalse(evaluator.evaluate(ae)); } @Test public void testExpectTrue() throws EvaluationException { request.setRequestUri(expectedURL1); - IAccessEvent ae = new AccessEvent(accessContext, request, response, serverAdapter); + IAccessEvent ae = new AccessEvent(accessContext, serverAdapter); assertTrue(evaluator.evaluate(ae)); } @@ -76,7 +76,7 @@ public void testExpectTrue() throws EvaluationException { public void testExpectTrueMultiple() throws EvaluationException { evaluator.addURL(expectedURL2); request.setRequestUri(expectedURL2); - IAccessEvent ae = new AccessEvent(accessContext, request, response, serverAdapter); + IAccessEvent ae = new AccessEvent(accessContext, serverAdapter); assertTrue(evaluator.evaluate(ae)); } } diff --git a/logback-access/src/test/java/ch/qos/logback/access/pattern/ConverterTest.java b/logback-access/src/test/java/ch/qos/logback/access/pattern/ConverterTest.java index 07a4875f73..c9547c55f7 100644 --- a/logback-access/src/test/java/ch/qos/logback/access/pattern/ConverterTest.java +++ b/logback-access/src/test/java/ch/qos/logback/access/pattern/ConverterTest.java @@ -19,9 +19,7 @@ import ch.qos.logback.access.dummy.DummyServerAdapter; import ch.qos.logback.access.spi.AccessContext; import ch.qos.logback.access.spi.AccessEvent; -import ch.qos.logback.access.spi.IAccessEvent; import ch.qos.logback.core.CoreConstants; -import ch.qos.logback.core.model.TimestampModel; import jakarta.servlet.http.Cookie; import org.assertj.core.util.Lists; import org.junit.jupiter.api.AfterEach; @@ -62,7 +60,7 @@ public void testContentLengthConverter() { ContentLengthConverter converter = new ContentLengthConverter(); converter.start(); String result = converter.convert(event); - assertEquals(Long.toString(event.getServerAdapter().getContentLength()), result); + assertEquals(Long.toString(event.getServerAdapter().getResponseContentLength()), result); } @Test @@ -220,7 +218,7 @@ public void testStatusCodeConverter() { private AccessEvent createEvent() { DummyServerAdapter dummyAdapter = new DummyServerAdapter(request, response); - return new AccessEvent(accessContext, request, response, dummyAdapter); + return new AccessEvent(accessContext, dummyAdapter); } } diff --git a/logback-access/src/test/java/ch/qos/logback/access/spi/AccessEventSerializationTest.java b/logback-access/src/test/java/ch/qos/logback/access/spi/AccessEventSerializationTest.java index 93dbbfa0d7..4a10bb9b16 100644 --- a/logback-access/src/test/java/ch/qos/logback/access/spi/AccessEventSerializationTest.java +++ b/logback-access/src/test/java/ch/qos/logback/access/spi/AccessEventSerializationTest.java @@ -81,7 +81,7 @@ public void testAttributesAreNotTakenFromRecycledRequestWhenProcessingDeferred() DummyServerAdapter adapter = new DummyServerAdapter(request, response); AccessContext accessContext = new AccessContext(); - IAccessEvent event = new AccessEvent(accessContext, request, response, adapter); + IAccessEvent event = new AccessEvent(accessContext, adapter); request.setAttribute("testKey", "ORIGINAL"); diff --git a/pom.xml b/pom.xml index f6ff7d3f0a..e46527c06d 100755 --- a/pom.xml +++ b/pom.xml @@ -76,7 +76,7 @@ 0.8.1 1.1.0 10.0.10 - 11.0.12 + 12.0.5 2.15.0