Re-enable RequestLog tests.
Re-implemented features that were commented out. Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
parent
48c085d082
commit
557696653d
|
@ -37,6 +37,7 @@ import org.eclipse.jetty.util.StringUtil;
|
|||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -318,11 +319,13 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
@ManagedObject("Custom format request log")
|
||||
public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
||||
{
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(CustomRequestLog.class);
|
||||
|
||||
public static final String DEFAULT_DATE_FORMAT = "dd/MMM/yyyy:HH:mm:ss ZZZ";
|
||||
public static final String NCSA_FORMAT = "%{client}a - %u %t \"%r\" %s %O";
|
||||
public static final String EXTENDED_NCSA_FORMAT = NCSA_FORMAT + " \"%{Referer}i\" \"%{User-Agent}i\"";
|
||||
public static final String HANDLER_NAME = CustomRequestLog.class.getName() + ".handlerName";
|
||||
public static final String REAL_PATH = CustomRequestLog.class.getName() + ".realPath";
|
||||
public static final String USER_NAME = CustomRequestLog.class.getName() + ".userPrincipal";
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CustomRequestLog.class);
|
||||
private static final ThreadLocal<StringBuilder> _buffers = ThreadLocal.withInitial(() -> new StringBuilder(256));
|
||||
|
||||
private final RequestLog.Writer _requestLogWriter;
|
||||
|
@ -379,11 +382,6 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
return _requestLogWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the request and response information to the output stream.
|
||||
*
|
||||
* @see org.eclipse.jetty.server.RequestLog#log(Request, Response)
|
||||
*/
|
||||
@Override
|
||||
public void log(Request request, Response response)
|
||||
{
|
||||
|
@ -409,27 +407,6 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the user authentication
|
||||
*
|
||||
* @param request The request to extract from
|
||||
* @param checkDeferred Whether to check for deferred authentication
|
||||
* @return The string to log for authenticated user.
|
||||
*/
|
||||
protected static String getAuthentication(Request request, boolean checkDeferred)
|
||||
{
|
||||
// TODO
|
||||
// Authentication authentication = request.getAuthentication();
|
||||
// if (checkDeferred && authentication instanceof Authentication.Deferred)
|
||||
// authentication = ((Authentication.Deferred)authentication).authenticate(request);
|
||||
|
||||
String name = null;
|
||||
// if (authentication instanceof Authentication.User)
|
||||
// name = ((Authentication.User)authentication).getUserIdentity().getUserPrincipal().getName();
|
||||
//
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set request paths that will not be logged.
|
||||
*
|
||||
|
@ -1046,8 +1023,7 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
@SuppressWarnings("unused")
|
||||
private static void logResponseSize(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
long written = Response.getContentBytesWritten(response);
|
||||
b.append(written);
|
||||
b.append(Response.getContentBytesWritten(response));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -1123,7 +1099,6 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
b.append('-');
|
||||
}
|
||||
|
||||
|
@ -1132,7 +1107,9 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
{
|
||||
List<HttpCookie> cookies = Request.getCookies(request);
|
||||
if (cookies == null || cookies.size() == 0)
|
||||
{
|
||||
b.append('-');
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < cookies.size(); i++)
|
||||
|
@ -1155,17 +1132,25 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
@SuppressWarnings("unused")
|
||||
private static void logFilename(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
b.append('-');
|
||||
// TODO UserIdentity.Scope scope = request.getUserIdentityScope();
|
||||
// if (scope == null || scope.getContextHandler() == null)
|
||||
// b.append('-');
|
||||
// else
|
||||
// {
|
||||
// ContextHandler context = scope.getContextHandler();
|
||||
// int lengthToStrip = scope.getContextPath().length() > 1 ? scope.getContextPath().length() : 0;
|
||||
// String filename = context.getServletContext().getRealPath(request.getPathInfo().substring(lengthToStrip));
|
||||
// append(b, filename);
|
||||
// }
|
||||
String realPath = (String)request.getAttribute(REAL_PATH);
|
||||
if (realPath == null)
|
||||
{
|
||||
Context context = request.getContext();
|
||||
Resource baseResource = context.getBaseResource();
|
||||
if (baseResource != null)
|
||||
{
|
||||
String fileName = baseResource.resolve(request.getPathInContext()).getName();
|
||||
append(b, fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
b.append("-");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
b.append(realPath);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -1221,8 +1206,7 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
@SuppressWarnings("unused")
|
||||
private static void logRequestHandler(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
b.append('-');
|
||||
// TODO append(b, request.getServletName());
|
||||
append(b, (String)request.getAttribute(HANDLER_NAME));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -1242,39 +1226,38 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
@SuppressWarnings("unused")
|
||||
private static void logLatencyMicroseconds(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
long currentTime = System.currentTimeMillis();
|
||||
long requestTime = request.getTimeStamp();
|
||||
|
||||
long latencyMs = currentTime - requestTime;
|
||||
long latencyUs = TimeUnit.MILLISECONDS.toMicros(latencyMs);
|
||||
|
||||
b.append(latencyUs);
|
||||
logLatency(b, request, TimeUnit.MICROSECONDS);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static void logLatencyMilliseconds(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
long latency = System.currentTimeMillis() - request.getTimeStamp();
|
||||
b.append(latency);
|
||||
logLatency(b, request, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static void logLatencySeconds(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
logLatency(b, request, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private static void logLatency(StringBuilder b, Request request, TimeUnit unit)
|
||||
{
|
||||
long latency = System.currentTimeMillis() - request.getTimeStamp();
|
||||
b.append(TimeUnit.MILLISECONDS.toSeconds(latency));
|
||||
b.append(unit.convert(latency, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static void logRequestAuthentication(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
append(b, getAuthentication(request, false));
|
||||
append(b, (String)request.getAttribute(USER_NAME));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static void logRequestAuthenticationWithDeferred(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
append(b, getAuthentication(request, true));
|
||||
// TODO: deferred to be implemented.
|
||||
logRequestAuthentication(b, request, response);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -29,8 +29,8 @@ import java.util.function.Consumer;
|
|||
|
||||
import jakarta.servlet.DispatcherType;
|
||||
import jakarta.servlet.RequestDispatcher;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletRequestState.Action;
|
||||
import org.eclipse.jetty.ee10.servlet.security.Authentication;
|
||||
import org.eclipse.jetty.http.BadMessageException;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
@ -41,6 +41,7 @@ import org.eclipse.jetty.io.Connection;
|
|||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.QuietException;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.CustomRequestLog;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
|
@ -781,14 +782,27 @@ public class ServletChannel implements Runnable
|
|||
|
||||
public void onCompleted()
|
||||
{
|
||||
HttpServletRequest httpServletRequest = _request.getHttpServletRequest();
|
||||
ServletContextRequest.ServletApiRequest apiRequest = _request.getServletApiRequest();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onCompleted for {} written={}", httpServletRequest.getRequestURI(), getBytesWritten());
|
||||
LOG.debug("onCompleted for {} written={}", apiRequest.getRequestURI(), getBytesWritten());
|
||||
|
||||
long idleTO = _configuration.getIdleTimeout();
|
||||
if (idleTO >= 0 && getIdleTimeout() != _oldIdleTimeout)
|
||||
setIdleTimeout(_oldIdleTimeout);
|
||||
|
||||
if (getServer().getRequestLog() != null)
|
||||
{
|
||||
Authentication authentication = apiRequest.getAuthentication();
|
||||
if (authentication instanceof Authentication.User userAuthentication)
|
||||
_request.setAttribute(CustomRequestLog.USER_NAME, userAuthentication.getUserIdentity().getUserPrincipal().getName());
|
||||
|
||||
String realPath = apiRequest.getServletContext().getRealPath(_request.getPathInContext());
|
||||
_request.setAttribute(CustomRequestLog.REAL_PATH, realPath);
|
||||
|
||||
String servletName = _request.getServletName();
|
||||
_request.setAttribute(CustomRequestLog.HANDLER_NAME, servletName);
|
||||
}
|
||||
|
||||
// Callback will either be succeeded here or failed in abort().
|
||||
if (_state.completeResponse())
|
||||
_callback.succeeded();
|
||||
|
|
|
@ -1,141 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.servlet;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.server.CustomRequestLog;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
@Disabled
|
||||
public class CustomRequestLogServletTest
|
||||
{
|
||||
RequestLog _log;
|
||||
Server _server;
|
||||
LocalConnector _connector;
|
||||
BlockingQueue<String> _entries = new BlockingArrayQueue<>();
|
||||
String _tmpDir;
|
||||
|
||||
@BeforeEach
|
||||
public void before() throws Exception
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new LocalConnector(_server);
|
||||
_server.addConnector(_connector);
|
||||
_tmpDir = new File(System.getProperty("java.io.tmpdir")).getCanonicalPath();
|
||||
}
|
||||
|
||||
void testHandlerServerStart(String formatString) throws Exception
|
||||
{
|
||||
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
context.setContextPath("/context");
|
||||
context.setBaseResource(Paths.get(_tmpDir));
|
||||
context.addServlet(TestServlet.class, "/servlet/*");
|
||||
|
||||
TestRequestLogWriter writer = new TestRequestLogWriter();
|
||||
_log = new CustomRequestLog(writer, formatString);
|
||||
_server.setRequestLog(_log);
|
||||
_server.setHandler(context);
|
||||
_server.start();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after() throws Exception
|
||||
{
|
||||
_server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogFilename() throws Exception
|
||||
{
|
||||
testHandlerServerStart("Filename: %f");
|
||||
|
||||
_connector.getResponse("GET /context/servlet/info HTTP/1.0\n\n");
|
||||
String log = _entries.poll(5, TimeUnit.SECONDS);
|
||||
String expected = new File(_tmpDir + File.separator + "servlet" + File.separator + "info").getCanonicalPath();
|
||||
assertThat(log, is("Filename: " + expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogRequestHandler() throws Exception
|
||||
{
|
||||
testHandlerServerStart("RequestHandler: %R");
|
||||
|
||||
_connector.getResponse("GET /context/servlet/ HTTP/1.0\n\n");
|
||||
String log = _entries.poll(5, TimeUnit.SECONDS);
|
||||
assertThat(log, Matchers.containsString("TestServlet"));
|
||||
}
|
||||
|
||||
class TestRequestLogWriter implements RequestLog.Writer
|
||||
{
|
||||
@Override
|
||||
public void write(String requestEntry)
|
||||
{
|
||||
try
|
||||
{
|
||||
_entries.add(requestEntry);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestServlet extends HttpServlet
|
||||
{
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
if (request.getRequestURI().contains("error404"))
|
||||
{
|
||||
response.setStatus(404);
|
||||
}
|
||||
else if (request.getRequestURI().contains("error301"))
|
||||
{
|
||||
response.setStatus(301);
|
||||
}
|
||||
else if (request.getHeader("echo") != null)
|
||||
{
|
||||
ServletOutputStream outputStream = response.getOutputStream();
|
||||
outputStream.print(request.getHeader("echo"));
|
||||
}
|
||||
else if (request.getRequestURI().contains("responseHeaders"))
|
||||
{
|
||||
response.addHeader("Header1", "value1");
|
||||
response.addHeader("Header2", "value2");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.servlet;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.security.HashLoginService;
|
||||
import org.eclipse.jetty.ee10.servlet.security.UserStore;
|
||||
import org.eclipse.jetty.ee10.servlet.security.authentication.BasicAuthenticator;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.server.CustomRequestLog;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.util.security.Credential;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class CustomRequestLogTest
|
||||
{
|
||||
private final BlockingQueue<String> _logs = new BlockingArrayQueue<>();
|
||||
private Server _server;
|
||||
private LocalConnector _connector;
|
||||
private Path _tmpDir;
|
||||
|
||||
private void start(String formatString, HttpServlet servlet) throws Exception
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new LocalConnector(_server);
|
||||
_server.addConnector(_connector);
|
||||
|
||||
TestRequestLogWriter writer = new TestRequestLogWriter();
|
||||
RequestLog requestLog = new CustomRequestLog(writer, formatString);
|
||||
_server.setRequestLog(requestLog);
|
||||
|
||||
_tmpDir = Path.of(System.getProperty("java.io.tmpdir")).toRealPath();
|
||||
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
context.setBaseResource(_tmpDir);
|
||||
context.setContextPath("/context");
|
||||
context.addServlet(new ServletHolder(servlet), "/servlet/*");
|
||||
|
||||
HashLoginService loginService = new HashLoginService();
|
||||
UserStore userStore = new UserStore();
|
||||
userStore.addUser("username", Credential.getCredential("password"), new String[]{"user"});
|
||||
loginService.setUserStore(userStore);
|
||||
loginService.setName("realm");
|
||||
|
||||
Constraint constraint = new Constraint();
|
||||
constraint.setName("auth");
|
||||
constraint.setAuthenticate(true);
|
||||
constraint.setRoles(new String[]{"**"});
|
||||
|
||||
ConstraintMapping mapping = new ConstraintMapping();
|
||||
mapping.setPathSpec("/secure/*");
|
||||
mapping.setConstraint(constraint);
|
||||
|
||||
ConstraintSecurityHandler security = new ConstraintSecurityHandler();
|
||||
security.addConstraintMapping(mapping);
|
||||
security.setAuthenticator(new BasicAuthenticator());
|
||||
security.setLoginService(loginService);
|
||||
|
||||
context.setSecurityHandler(security);
|
||||
|
||||
_server.setHandler(context);
|
||||
|
||||
_server.start();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after()
|
||||
{
|
||||
LifeCycle.stop(_server);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogFilename() throws Exception
|
||||
{
|
||||
start("Filename: %f", new SimpleServlet());
|
||||
|
||||
_connector.getResponse("GET /context/servlet/info HTTP/1.0\n\n");
|
||||
String log = _logs.poll(5, TimeUnit.SECONDS);
|
||||
String expected = new File(_tmpDir + File.separator + "servlet" + File.separator + "info").getCanonicalPath();
|
||||
assertThat(log, is("Filename: " + expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogRequestHandler() throws Exception
|
||||
{
|
||||
start("RequestHandler: %R", new SimpleServlet());
|
||||
|
||||
_connector.getResponse("GET /context/servlet/ HTTP/1.0\n\n");
|
||||
String log = _logs.poll(5, TimeUnit.SECONDS);
|
||||
assertThat(log, Matchers.containsString(SimpleServlet.class.getSimpleName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogRemoteUser() throws Exception
|
||||
{
|
||||
String authHeader = HttpHeader.AUTHORIZATION + ": Basic " + Base64.getEncoder().encodeToString("username:password".getBytes());
|
||||
start("%u", new SimpleServlet());
|
||||
|
||||
_connector.getResponse("GET /context/servlet/unsecure HTTP/1.0\n\n");
|
||||
String log = _logs.poll(5, TimeUnit.SECONDS);
|
||||
assertThat(log, is("-"));
|
||||
|
||||
_connector.getResponse("GET /context/servlet/secure HTTP/1.0\n" + authHeader + "\n\n");
|
||||
log = _logs.poll(5, TimeUnit.SECONDS);
|
||||
assertThat(log, is("username"));
|
||||
}
|
||||
|
||||
private class TestRequestLogWriter implements RequestLog.Writer
|
||||
{
|
||||
@Override
|
||||
public void write(String requestEntry)
|
||||
{
|
||||
_logs.add(requestEntry);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SimpleServlet extends HttpServlet
|
||||
{
|
||||
@Override
|
||||
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
// Trigger the authentication.
|
||||
request.getRemoteUser();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -50,6 +50,7 @@ import org.eclipse.jetty.io.QuietException;
|
|||
import org.eclipse.jetty.server.AbstractConnector;
|
||||
import org.eclipse.jetty.server.ConnectionMetaData;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.CustomRequestLog;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
|
@ -945,12 +946,25 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
|||
public void onCompleted()
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onCompleted for {} written={}", getRequest().getRequestURI(), getBytesWritten());
|
||||
LOG.debug("onCompleted for {} written={}", _request.getRequestURI(), getBytesWritten());
|
||||
|
||||
long idleTO = _configuration.getIdleTimeout();
|
||||
if (idleTO >= 0 && getIdleTimeout() != _oldIdleTimeout)
|
||||
setIdleTimeout(_oldIdleTimeout);
|
||||
|
||||
if (getServer().getRequestLog() != null)
|
||||
{
|
||||
Authentication authentication = _request.getAuthentication();
|
||||
if (authentication instanceof Authentication.User userAuthentication)
|
||||
_request.setAttribute(CustomRequestLog.USER_NAME, userAuthentication.getUserIdentity().getUserPrincipal().getName());
|
||||
|
||||
String realPath = _request.getServletContext().getRealPath(_request.getPathInContext());
|
||||
_request.setAttribute(CustomRequestLog.REAL_PATH, realPath);
|
||||
|
||||
String servletName = _request.getServletName();
|
||||
_request.setAttribute(CustomRequestLog.HANDLER_NAME, servletName);
|
||||
}
|
||||
|
||||
_request.onCompleted();
|
||||
_combinedListener.onComplete(_request);
|
||||
Callback callback = _coreCallback;
|
||||
|
|
|
@ -15,73 +15,99 @@ package org.eclipse.jetty.ee9.servlet;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.ee9.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee9.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.ee9.security.HashLoginService;
|
||||
import org.eclipse.jetty.ee9.security.UserStore;
|
||||
import org.eclipse.jetty.ee9.security.authentication.BasicAuthenticator;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.server.CustomRequestLog;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.util.security.Credential;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
@Disabled // TODO
|
||||
public class CustomRequestLogTest
|
||||
{
|
||||
RequestLog _log;
|
||||
Server _server;
|
||||
LocalConnector _connector;
|
||||
BlockingQueue<String> _entries = new BlockingArrayQueue<>();
|
||||
String _tmpDir;
|
||||
private final BlockingQueue<String> _logs = new BlockingArrayQueue<>();
|
||||
private Server _server;
|
||||
private LocalConnector _connector;
|
||||
private Path _tmpDir;
|
||||
|
||||
@BeforeEach
|
||||
public void before() throws Exception
|
||||
private void start(String formatString, HttpServlet servlet) throws Exception
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new LocalConnector(_server);
|
||||
_server.addConnector(_connector);
|
||||
_tmpDir = new File(System.getProperty("java.io.tmpdir")).getCanonicalPath();
|
||||
}
|
||||
|
||||
void testHandlerServerStart(String formatString) throws Exception
|
||||
{
|
||||
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
context.setContextPath("/context");
|
||||
context.setResourceBase(_tmpDir);
|
||||
context.addServlet(TestServlet.class, "/servlet/*");
|
||||
|
||||
TestRequestLogWriter writer = new TestRequestLogWriter();
|
||||
_log = new CustomRequestLog(writer, formatString);
|
||||
_server.setRequestLog(_log);
|
||||
RequestLog requestLog = new CustomRequestLog(writer, formatString);
|
||||
_server.setRequestLog(requestLog);
|
||||
|
||||
_tmpDir = Path.of(System.getProperty("java.io.tmpdir")).toRealPath();
|
||||
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
context.setBaseResource(_tmpDir);
|
||||
context.setContextPath("/context");
|
||||
context.addServlet(new ServletHolder(servlet), "/servlet/*");
|
||||
|
||||
HashLoginService loginService = new HashLoginService();
|
||||
UserStore userStore = new UserStore();
|
||||
userStore.addUser("username", Credential.getCredential("password"), new String[]{"user"});
|
||||
loginService.setUserStore(userStore);
|
||||
loginService.setName("realm");
|
||||
|
||||
Constraint constraint = new Constraint();
|
||||
constraint.setName("auth");
|
||||
constraint.setAuthenticate(true);
|
||||
constraint.setRoles(new String[]{"**"});
|
||||
|
||||
ConstraintMapping mapping = new ConstraintMapping();
|
||||
mapping.setPathSpec("/secure/*");
|
||||
mapping.setConstraint(constraint);
|
||||
|
||||
ConstraintSecurityHandler security = new ConstraintSecurityHandler();
|
||||
security.addConstraintMapping(mapping);
|
||||
security.setAuthenticator(new BasicAuthenticator());
|
||||
security.setLoginService(loginService);
|
||||
|
||||
context.setSecurityHandler(security);
|
||||
|
||||
_server.setHandler(context);
|
||||
|
||||
_server.start();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after() throws Exception
|
||||
public void after()
|
||||
{
|
||||
_server.stop();
|
||||
LifeCycle.stop(_server);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogFilename() throws Exception
|
||||
{
|
||||
testHandlerServerStart("Filename: %f");
|
||||
start("Filename: %f", new SimpleServlet());
|
||||
|
||||
_connector.getResponse("GET /context/servlet/info HTTP/1.0\n\n");
|
||||
String log = _entries.poll(5, TimeUnit.SECONDS);
|
||||
String log = _logs.poll(5, TimeUnit.SECONDS);
|
||||
String expected = new File(_tmpDir + File.separator + "servlet" + File.separator + "info").getCanonicalPath();
|
||||
assertThat(log, is("Filename: " + expected));
|
||||
}
|
||||
|
@ -89,52 +115,44 @@ public class CustomRequestLogTest
|
|||
@Test
|
||||
public void testLogRequestHandler() throws Exception
|
||||
{
|
||||
testHandlerServerStart("RequestHandler: %R");
|
||||
start("RequestHandler: %R", new SimpleServlet());
|
||||
|
||||
_connector.getResponse("GET /context/servlet/ HTTP/1.0\n\n");
|
||||
String log = _entries.poll(5, TimeUnit.SECONDS);
|
||||
assertThat(log, Matchers.containsString("TestServlet"));
|
||||
String log = _logs.poll(5, TimeUnit.SECONDS);
|
||||
assertThat(log, Matchers.containsString(SimpleServlet.class.getSimpleName()));
|
||||
}
|
||||
|
||||
class TestRequestLogWriter implements RequestLog.Writer
|
||||
@Test
|
||||
public void testLogRemoteUser() throws Exception
|
||||
{
|
||||
String authHeader = HttpHeader.AUTHORIZATION + ": Basic " + Base64.getEncoder().encodeToString("username:password".getBytes());
|
||||
start("%u", new SimpleServlet());
|
||||
|
||||
_connector.getResponse("GET /context/servlet/unsecure HTTP/1.0\n\n");
|
||||
String log = _logs.poll(5, TimeUnit.SECONDS);
|
||||
assertThat(log, is("-"));
|
||||
|
||||
_connector.getResponse("GET /context/servlet/secure HTTP/1.0\n" + authHeader + "\n\n");
|
||||
log = _logs.poll(5, TimeUnit.SECONDS);
|
||||
assertThat(log, is("username"));
|
||||
}
|
||||
|
||||
private class TestRequestLogWriter implements RequestLog.Writer
|
||||
{
|
||||
@Override
|
||||
public void write(String requestEntry)
|
||||
{
|
||||
try
|
||||
{
|
||||
_entries.add(requestEntry);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
_logs.add(requestEntry);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestServlet extends HttpServlet
|
||||
private static class SimpleServlet extends HttpServlet
|
||||
{
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
if (request.getRequestURI().contains("error404"))
|
||||
{
|
||||
response.setStatus(404);
|
||||
}
|
||||
else if (request.getRequestURI().contains("error301"))
|
||||
{
|
||||
response.setStatus(301);
|
||||
}
|
||||
else if (request.getHeader("echo") != null)
|
||||
{
|
||||
ServletOutputStream outputStream = response.getOutputStream();
|
||||
outputStream.print(request.getHeader("echo"));
|
||||
}
|
||||
else if (request.getRequestURI().contains("responseHeaders"))
|
||||
{
|
||||
response.addHeader("Header1", "value1");
|
||||
response.addHeader("Header2", "value2");
|
||||
}
|
||||
// Trigger the authentication.
|
||||
request.getRemoteUser();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue