Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-10.0.x-3428-decoderLists
This commit is contained in:
commit
2c1c25d5a7
28
VERSION.txt
28
VERSION.txt
|
@ -1,5 +1,31 @@
|
|||
jetty-10.0.0-SNAPSHOT
|
||||
|
||||
jetty-9.4.29.v20200521 - 21 May 2020
|
||||
+ 2188 Lock contention creating HTTP/2 streams
|
||||
+ 4235 communicate the reason of failure to the OpenID error page
|
||||
+ 4695 HttpChannel recycling in h2
|
||||
+ 4764 HTTP2 Jetty Server does not send back content-length
|
||||
+ 4778 Enforcing SNI when there are only non-wildcards certificates
|
||||
+ 4787 Make org.eclipse.jetty.client.HttpRequest's host name writable
|
||||
+ 4789 org.eclipse.jetty.util.thread.ShutdownThread should use an appropriate
|
||||
name to identify itself in Thread dump
|
||||
+ 4798 Better handling of fatal Selector failures
|
||||
+ 4814 Allow a ConnectionFactory (eg SslConnectionFactory) to automatically
|
||||
add a Customizer
|
||||
+ 4820 Jetty OSGi DefaultJettyAtJettyHomeHelper refers to non-existent
|
||||
config file
|
||||
+ 4824 WebSocket server outgoing message queue memory growth
|
||||
+ 4828 NIO ByteBuffer corruption in embedded Jetty server
|
||||
+ 4835 GzipHandler and GzipHttpOutputInterceptor do not flush response when
|
||||
body is empty
|
||||
+ 4860 org.eclipse.jetty.server.HttpChannel busyloop on HttpFields
|
||||
NullPointerException
|
||||
+ 4861 Combine `AttributesMap` and `Attributes.Wrapper`
|
||||
+ 4868 Update to asm 7.3.1
|
||||
+ 4892 Non-blocking JSON parser
|
||||
+ 4895 AbstractSessionCache.setFlushOnResponseCommit(true) can write an
|
||||
invalid session to the backing store
|
||||
|
||||
jetty-10.0.0.alpha1 - 26 November 2019
|
||||
+ 97 Permanent UnavailableException thrown during servlet request handling
|
||||
should cause servlet destroy
|
||||
|
@ -363,7 +389,7 @@ jetty-9.4.28.v20200408 - 08 April 2020
|
|||
+ 4529 ErrorHandler showing servlet info, can not be disabled unless
|
||||
overriding most of its functionality
|
||||
+ 4542 servlet context root mapping incorrect
|
||||
+ 4619 Inconsistent library versions notice.
|
||||
+ 4619 Inconsistent library versions notice
|
||||
+ 4620 Using console-capture with StdErrLog results in empty log file
|
||||
+ 4621 jetty-jaspi in jetty-all uber aggregate artifact requires
|
||||
javax.security.auth.message.AuthException which cannot be included
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-slf4j-impl</artifactId>
|
||||
<scope>test</scope>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -61,6 +61,7 @@ import org.eclipse.jetty.servlet.ServletHolder;
|
|||
import org.eclipse.jetty.servlets.PushCacheFilter;
|
||||
import org.eclipse.jetty.util.resource.PathResource;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Http2Server
|
||||
{
|
||||
|
@ -74,6 +75,8 @@ public class Http2Server
|
|||
ManagementFactory.getPlatformMBeanServer());
|
||||
server.addBean(mbContainer);
|
||||
|
||||
server.addBean(LoggerFactory.getILoggerFactory());
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS);
|
||||
Path docroot = Paths.get("src/main/resources/docroot");
|
||||
if (!Files.exists(docroot))
|
||||
|
|
|
@ -211,7 +211,7 @@ public class WebServletAnnotation extends DiscoveredAnnotation
|
|||
for (String p : urlPatternList)
|
||||
{
|
||||
ServletMapping existingMapping = _context.getServletHandler().getServletMapping(p);
|
||||
if (existingMapping != null && existingMapping.isDefault())
|
||||
if (existingMapping != null && existingMapping.isFromDefaultDescriptor())
|
||||
{
|
||||
String[] updatedPaths = ArrayUtil.removeFromArray(existingMapping.getPathSpecs(), p);
|
||||
//if we removed the last path from a servletmapping, delete the servletmapping
|
||||
|
@ -264,7 +264,7 @@ public class WebServletAnnotation extends DiscoveredAnnotation
|
|||
return false;
|
||||
for (ServletMapping m : mappings)
|
||||
{
|
||||
if (!m.isDefault())
|
||||
if (!m.isFromDefaultDescriptor())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -117,7 +117,7 @@ public class TestServletAnnotations
|
|||
ServletMapping m = new ServletMapping();
|
||||
m.setPathSpec("/");
|
||||
m.setServletName("default");
|
||||
m.setDefault(true); //this mapping will be from a default descriptor
|
||||
m.setFromDefaultDescriptor(true); //this mapping will be from a default descriptor
|
||||
wac.getServletHandler().addServletMapping(m);
|
||||
|
||||
WebServletAnnotation annotation = new WebServletAnnotation(wac, "org.eclipse.jetty.annotations.ServletD", null);
|
||||
|
@ -150,13 +150,13 @@ public class TestServletAnnotations
|
|||
ServletMapping m = new ServletMapping();
|
||||
m.setPathSpec("/");
|
||||
m.setServletName("default");
|
||||
m.setDefault(true); //this mapping will be from a default descriptor
|
||||
m.setFromDefaultDescriptor(true); //this mapping will be from a default descriptor
|
||||
wac.getServletHandler().addServletMapping(m);
|
||||
|
||||
ServletMapping m2 = new ServletMapping();
|
||||
m2.setPathSpec("/other");
|
||||
m2.setServletName("default");
|
||||
m2.setDefault(true); //this mapping will be from a default descriptor
|
||||
m2.setFromDefaultDescriptor(true); //this mapping will be from a default descriptor
|
||||
wac.getServletHandler().addServletMapping(m2);
|
||||
|
||||
WebServletAnnotation annotation = new WebServletAnnotation(wac, "org.eclipse.jetty.annotations.ServletD", null);
|
||||
|
@ -235,7 +235,7 @@ public class TestServletAnnotations
|
|||
|
||||
ServletMapping m = new ServletMapping();
|
||||
m.setPathSpec("/default");
|
||||
m.setDefault(true);
|
||||
m.setFromDefaultDescriptor(true);
|
||||
m.setServletName("DServlet");
|
||||
wac.getServletHandler().addServletMapping(m);
|
||||
|
||||
|
|
|
@ -381,7 +381,17 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-core</artifactId>
|
||||
<artifactId>websocket-core-common</artifactId>
|
||||
<version>10.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-core-client</artifactId>
|
||||
<version>10.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-core-server</artifactId>
|
||||
<version>10.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -93,4 +93,10 @@ public class HttpAuthenticationStore implements AuthenticationStore
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAuthenticationResults()
|
||||
{
|
||||
return !results.isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1113,7 +1113,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
|
||||
protected String normalizeHost(String host)
|
||||
{
|
||||
if (host != null && host.matches("\\[.*]"))
|
||||
if (host != null && host.startsWith("[") && host.endsWith("]"))
|
||||
return host.substring(1, host.length() - 1);
|
||||
return host;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jetty.client.api.Authentication;
|
||||
import org.eclipse.jetty.client.api.AuthenticationStore;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.util.BytesRequestContent;
|
||||
|
@ -138,13 +139,15 @@ public abstract class HttpConnection implements IConnection
|
|||
request.path(path);
|
||||
}
|
||||
|
||||
URI uri = request.getURI();
|
||||
|
||||
ProxyConfiguration.Proxy proxy = destination.getProxy();
|
||||
if (proxy instanceof HttpProxy && !HttpClient.isSchemeSecure(request.getScheme()) && uri != null)
|
||||
if (proxy instanceof HttpProxy && !HttpClient.isSchemeSecure(request.getScheme()))
|
||||
{
|
||||
path = uri.toString();
|
||||
request.path(path);
|
||||
URI uri = request.getURI();
|
||||
if (uri != null)
|
||||
{
|
||||
path = uri.toString();
|
||||
request.path(path);
|
||||
}
|
||||
}
|
||||
|
||||
// If we are HTTP 1.1, add the Host header
|
||||
|
@ -185,9 +188,10 @@ public abstract class HttpConnection implements IConnection
|
|||
|
||||
// Cookies
|
||||
CookieStore cookieStore = getHttpClient().getCookieStore();
|
||||
if (cookieStore != null)
|
||||
if (cookieStore != null && cookieStore.getClass() != HttpCookieStore.Empty.class)
|
||||
{
|
||||
StringBuilder cookies = null;
|
||||
URI uri = request.getURI();
|
||||
if (uri != null)
|
||||
cookies = convertCookies(HttpCookieStore.matchPath(uri, cookieStore.get(uri)), null);
|
||||
cookies = convertCookies(request.getCookies(), cookies);
|
||||
|
@ -199,8 +203,8 @@ public abstract class HttpConnection implements IConnection
|
|||
}
|
||||
|
||||
// Authentication
|
||||
applyAuthentication(request, proxy != null ? proxy.getURI() : null);
|
||||
applyAuthentication(request, uri);
|
||||
applyProxyAuthentication(request, proxy);
|
||||
applyRequestAuthentication(request);
|
||||
}
|
||||
|
||||
private StringBuilder convertCookies(List<HttpCookie> cookies, StringBuilder builder)
|
||||
|
@ -216,16 +220,31 @@ public abstract class HttpConnection implements IConnection
|
|||
return builder;
|
||||
}
|
||||
|
||||
private void applyAuthentication(Request request, URI uri)
|
||||
private void applyProxyAuthentication(Request request, ProxyConfiguration.Proxy proxy)
|
||||
{
|
||||
if (uri != null)
|
||||
if (proxy != null)
|
||||
{
|
||||
Authentication.Result result = getHttpClient().getAuthenticationStore().findAuthenticationResult(uri);
|
||||
Authentication.Result result = getHttpClient().getAuthenticationStore().findAuthenticationResult(proxy.getURI());
|
||||
if (result != null)
|
||||
result.apply(request);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyRequestAuthentication(Request request)
|
||||
{
|
||||
AuthenticationStore authenticationStore = getHttpClient().getAuthenticationStore();
|
||||
if (authenticationStore.hasAuthenticationResults())
|
||||
{
|
||||
URI uri = request.getURI();
|
||||
if (uri != null)
|
||||
{
|
||||
Authentication.Result result = authenticationStore.findAuthenticationResult(uri);
|
||||
if (result != null)
|
||||
result.apply(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onIdleTimeout(long idleTimeout)
|
||||
{
|
||||
synchronized (this)
|
||||
|
|
|
@ -117,9 +117,9 @@ public class HttpConversation extends AttributesMap
|
|||
// will notify a listener that may send a new request and trigger
|
||||
// another call to this method which will build different listeners
|
||||
// which may be iterated over when the iteration continues.
|
||||
List<Response.ResponseListener> listeners = new ArrayList<>();
|
||||
HttpExchange firstExchange = exchanges.peekFirst();
|
||||
HttpExchange lastExchange = exchanges.peekLast();
|
||||
List<Response.ResponseListener> listeners = new ArrayList<>(firstExchange.getResponseListeners().size() + lastExchange.getResponseListeners().size());
|
||||
if (firstExchange == lastExchange)
|
||||
{
|
||||
// We don't have a conversation, just a single request.
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.client;
|
|||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
@ -31,7 +32,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.LongConsumer;
|
||||
import java.util.function.LongUnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
|
@ -693,10 +693,11 @@ public abstract class HttpReceiver
|
|||
|
||||
private ContentListeners(List<Response.ResponseListener> responseListeners)
|
||||
{
|
||||
listeners = responseListeners.stream()
|
||||
listeners = new ArrayList<>(responseListeners.size());
|
||||
responseListeners.stream()
|
||||
.filter(Response.DemandedContentListener.class::isInstance)
|
||||
.map(Response.DemandedContentListener.class::cast)
|
||||
.collect(Collectors.toList());
|
||||
.forEach(listeners::add);
|
||||
}
|
||||
|
||||
private boolean isEmpty()
|
||||
|
|
|
@ -75,4 +75,12 @@ public interface AuthenticationStore
|
|||
* @return the {@link Authentication.Result} that matches the given URI, or null
|
||||
*/
|
||||
public Authentication.Result findAuthenticationResult(URI uri);
|
||||
|
||||
/**
|
||||
* @return false if there are no stored authentication results, true if there may be some.
|
||||
*/
|
||||
public default boolean hasAuthenticationResults()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,10 @@ public interface Request
|
|||
* @param host the URI host of this request, such as "127.0.0.1" or "google.com"
|
||||
* @return this request object
|
||||
*/
|
||||
Request host(String host);
|
||||
default Request host(String host)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the URI port of this request such as 80 or 443
|
||||
|
@ -81,11 +84,13 @@ public interface Request
|
|||
int getPort();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param port the URI port of this request such as 80 or 443
|
||||
* @return this request object
|
||||
*/
|
||||
Request port(int port);
|
||||
default Request port(int port)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the method of this request, such as GET or POST, as a String
|
||||
|
|
|
@ -67,6 +67,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler;
|
|||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
|
@ -88,8 +89,9 @@ import static org.junit.jupiter.api.Assertions.fail;
|
|||
import static org.junit.jupiter.api.condition.OS.LINUX;
|
||||
import static org.junit.jupiter.api.condition.OS.WINDOWS;
|
||||
|
||||
// This whole test is very specific to how TLS < 1.3 works.
|
||||
@EnabledOnJre({JRE.JAVA_8, JRE.JAVA_9, JRE.JAVA_10})
|
||||
// Other JREs have slight differences in how TLS work
|
||||
// and this test expects a very specific TLS behavior.
|
||||
@EnabledOnJre(JRE.JAVA_11)
|
||||
public class SslBytesServerTest extends SslBytesTest
|
||||
{
|
||||
private final AtomicInteger sslFills = new AtomicInteger();
|
||||
|
@ -108,9 +110,9 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
@BeforeEach
|
||||
public void init() throws Exception
|
||||
{
|
||||
|
||||
threadPool = Executors.newCachedThreadPool();
|
||||
server = new Server();
|
||||
QueuedThreadPool serverThreads = new QueuedThreadPool();
|
||||
serverThreads.setName("server");
|
||||
server = new Server(serverThreads);
|
||||
|
||||
sslFills.set(0);
|
||||
sslFlushes.set(0);
|
||||
|
@ -119,6 +121,8 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
|
||||
File keyStore = MavenTestingUtils.getTestResourceFile("keystore.p12");
|
||||
sslContextFactory = new SslContextFactory.Server();
|
||||
// This whole test is very specific to how TLS < 1.3 works.
|
||||
sslContextFactory.setIncludeProtocols("TLSv1.2");
|
||||
sslContextFactory.setKeyStorePath(keyStore.getAbsolutePath());
|
||||
sslContextFactory.setKeyStorePassword("storepwd");
|
||||
|
||||
|
@ -238,6 +242,7 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
|
||||
sslContext = sslContextFactory.getSslContext();
|
||||
|
||||
threadPool = Executors.newCachedThreadPool();
|
||||
proxy = new SimpleProxy(threadPool, "localhost", serverPort);
|
||||
proxy.start();
|
||||
logger.info("proxy:{} <==> server:{}", proxy.getPort(), serverPort);
|
||||
|
@ -1128,6 +1133,66 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
client.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestResponseServerIdleTimeoutClientResets() throws Exception
|
||||
{
|
||||
SSLSocket client = newClient();
|
||||
|
||||
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
|
||||
client.startHandshake();
|
||||
assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
|
||||
|
||||
Future<Object> request = threadPool.submit(() ->
|
||||
{
|
||||
OutputStream clientOutput = client.getOutputStream();
|
||||
clientOutput.write((
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n").getBytes(StandardCharsets.UTF_8));
|
||||
clientOutput.flush();
|
||||
return null;
|
||||
});
|
||||
|
||||
// Application data
|
||||
TLSRecord record = proxy.readFromClient();
|
||||
proxy.flushToServer(record);
|
||||
assertNull(request.get(5, TimeUnit.SECONDS));
|
||||
|
||||
// Application data
|
||||
record = proxy.readFromServer();
|
||||
assertEquals(TLSRecord.Type.APPLICATION, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), StandardCharsets.UTF_8));
|
||||
String line = reader.readLine();
|
||||
assertNotNull(line);
|
||||
assertTrue(line.startsWith("HTTP/1.1 200 "));
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.trim().length() == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait for the server idle timeout.
|
||||
Thread.sleep(idleTimeout);
|
||||
|
||||
// We expect that the server sends the TLS Alert.
|
||||
record = proxy.readFromServer();
|
||||
assertNotNull(record);
|
||||
assertEquals(TLSRecord.Type.ALERT, record.getType());
|
||||
|
||||
// Send a RST to the server.
|
||||
proxy.sendRSTToServer();
|
||||
|
||||
// Wait for the RST to be processed by the server.
|
||||
Thread.sleep(1000);
|
||||
|
||||
// The server EndPoint must be closed.
|
||||
assertFalse(serverEndPoint.get().isOpen());
|
||||
|
||||
client.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledOnOs(LINUX) // see message below
|
||||
public void testRequestWithCloseAlertWithSplitBoundary() throws Exception
|
||||
|
|
|
@ -234,6 +234,7 @@ public abstract class SslBytesTest
|
|||
|
||||
public void flushToServer(TLSRecord record, long sleep) throws Exception
|
||||
{
|
||||
logger.debug("P --> S {}", record);
|
||||
if (record == null)
|
||||
{
|
||||
server.shutdownOutput();
|
||||
|
@ -272,6 +273,7 @@ public abstract class SslBytesTest
|
|||
|
||||
public void flushToClient(TLSRecord record) throws Exception
|
||||
{
|
||||
logger.debug("C <-- P {}", record);
|
||||
if (record == null)
|
||||
{
|
||||
client.shutdownOutput();
|
||||
|
|
|
@ -85,6 +85,16 @@ db-connection-type=datasource
|
|||
#jetty.session.jdbc.schema.maxIntervalColumn=maxInterval
|
||||
#jetty.session.jdbc.schema.mapColumn=map
|
||||
#jetty.session.jdbc.schema.table=JettySessions
|
||||
# Optional name of the schema used to identify where the session table is defined in the database:
|
||||
# "" - empty string, no schema name
|
||||
# "INFERRED" - special string meaning infer from the current db connection
|
||||
# name - a string defined by the user
|
||||
#jetty.session.jdbc.schema.schemaName
|
||||
# Optional name of the catalog used to identify where the session table is defined in the database:
|
||||
# "" - empty string, no catalog name
|
||||
# "INFERRED" - special string meaning infer from the current db connection
|
||||
# name - a string defined by the user
|
||||
#jetty.session.jdbc.schema.catalogName
|
||||
----
|
||||
|
||||
jetty.session.gracePeriod.seconds::
|
||||
|
@ -111,4 +121,14 @@ jetty.session.jdbc.driverUrl::
|
|||
Url of the database which includes the driver type, host name and port, service name and any specific attributes unique to the database, such as a username.
|
||||
As an example, here is a mysql connection with the username appended: `jdbc:mysql://127.0.0.1:3306/sessions?user=sessionsadmin`.
|
||||
|
||||
The `jetty.sessionTableSchema` values represent the names for the columns in the JDBC database and can be changed to suit your environment.
|
||||
The `jetty.session.jdbc.schema.*` values represent the names of the table and columns in the JDBC database used to store sessions and can be changed to suit your environment.
|
||||
|
||||
There are also two special, optional properties: `jetty.session.jdbc.schema.schemaName` and `jetty.session.jdbc.schema.catalogName`.
|
||||
The exact meaning of these two properties is dependent on your database vendor, but can broadly be described as further scoping for the session table name.
|
||||
See https://en.wikipedia.org/wiki/Database_schema and https://en.wikipedia.org/wiki/Database_catalog.
|
||||
These extra scoping names can come into play at startup time when jetty determines if the session table already exists, or otherwise creates it on-the-fly.
|
||||
If you have employed either of these concepts when you pre-created the session table, or you want to ensure that jetty uses them when it auto-creates the session table, then you have two options: either set them explicitly, or let jetty infer them from a database connection (obtained using either a Datasource or Driver according to the `db-connection-type` you have configured).
|
||||
To set them explicitly, uncomment and supply appropriate values for the `jetty.session.jdbc.schema.schemaName` and/or `jetty.session.jdbc.schema.catalogName` properties.
|
||||
To allow jetty to infer them from a database connection, use the special string `INFERRED` instead.
|
||||
If you leave them blank or commented out, then the sessions table will not be scoped by schema or catalog name.
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ You *must also install the Apache Aries SPI Fly bundles* as many parts of Jetty
|
|||
[cols=",,",options="header",]
|
||||
|=======================================================================
|
||||
|Jar |Bundle Symbolic Name |Location
|
||||
|org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle-1.2.jar |org.apache.aries.spifly.dynamic.bundle
|
||||
|org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle-1.2.4.jar |org.apache.aries.spifly.dynamic.bundle
|
||||
|https://repo1.maven.org/maven2/org/apache/aries/spifly/org.apache.aries.spifly.dynamic.bundle/[Maven central]
|
||||
|=======================================================================
|
||||
|
||||
|
|
|
@ -4,5 +4,7 @@ org.eclipse.jetty.LEVEL=INFO
|
|||
#com.example.LEVEL=INFO
|
||||
## Configure a level for specific logger
|
||||
#com.example.MyComponent.LEVEL=INFO
|
||||
## Configure JMX Context Name
|
||||
# org.eclipse.jetty.logging.jmx.context=JettyServer
|
||||
## Hide stacks traces in an arbitrary logger tree
|
||||
#com.example.STACKS=false
|
||||
|
|
|
@ -43,7 +43,7 @@ public class HttpField
|
|||
if (_header != null && name == null)
|
||||
_name = _header.asString();
|
||||
else
|
||||
_name = Objects.requireNonNull(name);
|
||||
_name = Objects.requireNonNull(name, "name");
|
||||
_value = value;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.ToIntFunction;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -855,6 +856,8 @@ public interface HttpFields extends Iterable<HttpField>
|
|||
*/
|
||||
public Mutable put(String name, List<String> list)
|
||||
{
|
||||
Objects.requireNonNull(name, "name must not be null");
|
||||
Objects.requireNonNull(list, "list must not be null");
|
||||
remove(name);
|
||||
for (String v : list)
|
||||
{
|
||||
|
@ -1018,6 +1021,9 @@ public interface HttpFields extends Iterable<HttpField>
|
|||
@Override
|
||||
public void add(HttpField field)
|
||||
{
|
||||
if (field == null)
|
||||
return;
|
||||
|
||||
_fields = Arrays.copyOf(_fields, _fields.length + 1);
|
||||
System.arraycopy(_fields, _cursor, _fields, _cursor + 1, _size++);
|
||||
_fields[_cursor++] = field;
|
||||
|
@ -1083,7 +1089,10 @@ public interface HttpFields extends Iterable<HttpField>
|
|||
{
|
||||
if (_current < 0)
|
||||
throw new IllegalStateException();
|
||||
_fields[_current] = field;
|
||||
if (field == null)
|
||||
remove();
|
||||
else
|
||||
_fields[_current] = field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import static org.hamcrest.Matchers.is;
|
|||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class HttpFieldTest
|
||||
|
@ -165,6 +166,12 @@ public class HttpFieldTest
|
|||
assertEquals("c", values[2]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFieldNameNull()
|
||||
{
|
||||
assertThrows(NullPointerException.class, () -> new HttpField((String)null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCachedField()
|
||||
{
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.http;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Enumeration;
|
||||
|
@ -49,7 +50,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
public class HttpFieldsTest
|
||||
{
|
||||
@Test
|
||||
public void testPut() throws Exception
|
||||
public void testPut()
|
||||
{
|
||||
HttpFields.Mutable header = HttpFields.build()
|
||||
.put("name0", "value:0")
|
||||
|
@ -73,13 +74,13 @@ public class HttpFieldsTest
|
|||
assertEquals(2, matches);
|
||||
|
||||
e = header.getValues("name0");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value:0");
|
||||
assertEquals(false, e.hasMoreElements());
|
||||
assertFalse(e.hasMoreElements());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPutTo() throws Exception
|
||||
public void testPutTo()
|
||||
{
|
||||
HttpFields.Mutable header = HttpFields.build()
|
||||
.put("name0", "value0")
|
||||
|
@ -99,7 +100,7 @@ public class HttpFieldsTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testImmutable() throws Exception
|
||||
public void testImmutable()
|
||||
{
|
||||
HttpFields header = HttpFields.build()
|
||||
.put("name0", "value0")
|
||||
|
@ -109,24 +110,21 @@ public class HttpFieldsTest
|
|||
assertEquals("value0", header.get("Name0"));
|
||||
assertEquals("value1", header.get("name1"));
|
||||
assertEquals("value1", header.get("Name1"));
|
||||
assertEquals(null, header.get("Name2"));
|
||||
assertNull(header.get("Name2"));
|
||||
|
||||
assertEquals("value0", header.getField("name0").getValue());
|
||||
assertEquals("value0", header.getField("Name0").getValue());
|
||||
assertEquals("value1", header.getField("name1").getValue());
|
||||
assertEquals("value1", header.getField("Name1").getValue());
|
||||
assertEquals(null, header.getField("Name2"));
|
||||
assertNull(header.getField("Name2"));
|
||||
|
||||
assertEquals("value0", header.getField(0).getValue());
|
||||
assertEquals("value1", header.getField(1).getValue());
|
||||
assertThrows(NoSuchElementException.class, () ->
|
||||
{
|
||||
header.getField(2);
|
||||
});
|
||||
assertThrows(NoSuchElementException.class, () -> header.getField(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMutable() throws Exception
|
||||
public void testMutable()
|
||||
{
|
||||
HttpFields headers = HttpFields.build()
|
||||
.add(HttpHeader.ETAG, "tag")
|
||||
|
@ -147,20 +145,20 @@ public class HttpFieldsTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testMap() throws Exception
|
||||
public void testMap()
|
||||
{
|
||||
Map<HttpFields.Immutable,String> map = new HashMap<>();
|
||||
map.put(HttpFields.build().add("X","1").add(HttpHeader.ETAG,"tag").asImmutable(),"1");
|
||||
map.put(HttpFields.build().add("X","2").add(HttpHeader.ETAG,"other").asImmutable(),"2");
|
||||
Map<HttpFields.Immutable, String> map = new HashMap<>();
|
||||
map.put(HttpFields.build().add("X", "1").add(HttpHeader.ETAG, "tag").asImmutable(), "1");
|
||||
map.put(HttpFields.build().add("X", "2").add(HttpHeader.ETAG, "other").asImmutable(), "2");
|
||||
|
||||
assertThat(map.get(HttpFields.build().add("X","1").add(HttpHeader.ETAG,"tag").asImmutable()), is("1"));
|
||||
assertThat(map.get(HttpFields.build().add("X","2").add(HttpHeader.ETAG,"other").asImmutable()), is("2"));
|
||||
assertThat(map.get(HttpFields.build().add("X","2").asImmutable()), nullValue());
|
||||
assertThat(map.get(HttpFields.build().add("X","2").add(HttpHeader.ETAG,"tag").asImmutable()), nullValue());
|
||||
assertThat(map.get(HttpFields.build().add("X", "1").add(HttpHeader.ETAG, "tag").asImmutable()), is("1"));
|
||||
assertThat(map.get(HttpFields.build().add("X", "2").add(HttpHeader.ETAG, "other").asImmutable()), is("2"));
|
||||
assertThat(map.get(HttpFields.build().add("X", "2").asImmutable()), nullValue());
|
||||
assertThat(map.get(HttpFields.build().add("X", "2").add(HttpHeader.ETAG, "tag").asImmutable()), nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet() throws Exception
|
||||
public void testGet()
|
||||
{
|
||||
HttpFields header = HttpFields.build()
|
||||
.put("name0", "value0")
|
||||
|
@ -170,24 +168,21 @@ public class HttpFieldsTest
|
|||
assertEquals("value0", header.get("Name0"));
|
||||
assertEquals("value1", header.get("name1"));
|
||||
assertEquals("value1", header.get("Name1"));
|
||||
assertEquals(null, header.get("Name2"));
|
||||
assertNull(header.get("Name2"));
|
||||
|
||||
assertEquals("value0", header.getField("name0").getValue());
|
||||
assertEquals("value0", header.getField("Name0").getValue());
|
||||
assertEquals("value1", header.getField("name1").getValue());
|
||||
assertEquals("value1", header.getField("Name1").getValue());
|
||||
assertEquals(null, header.getField("Name2"));
|
||||
assertNull(header.getField("Name2"));
|
||||
|
||||
assertEquals("value0", header.getField(0).getValue());
|
||||
assertEquals("value1", header.getField(1).getValue());
|
||||
assertThrows(NoSuchElementException.class, () ->
|
||||
{
|
||||
header.getField(2);
|
||||
});
|
||||
assertThrows(NoSuchElementException.class, () -> header.getField(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetKnown() throws Exception
|
||||
public void testGetKnown()
|
||||
{
|
||||
HttpFields.Mutable header = HttpFields.build();
|
||||
|
||||
|
@ -200,12 +195,12 @@ public class HttpFieldsTest
|
|||
assertEquals("value0", header.getField(HttpHeader.CONNECTION).getValue());
|
||||
assertEquals("value1", header.getField(HttpHeader.ACCEPT).getValue());
|
||||
|
||||
assertEquals(null, header.getField(HttpHeader.AGE));
|
||||
assertEquals(null, header.get(HttpHeader.AGE));
|
||||
assertNull(header.getField(HttpHeader.AGE));
|
||||
assertNull(header.get(HttpHeader.AGE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCRLF() throws Exception
|
||||
public void testCRLF()
|
||||
{
|
||||
HttpFields.Mutable header = HttpFields.build();
|
||||
|
||||
|
@ -224,7 +219,7 @@ public class HttpFieldsTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testCachedPut() throws Exception
|
||||
public void testCachedPut()
|
||||
{
|
||||
HttpFields.Mutable header = HttpFields.build();
|
||||
|
||||
|
@ -244,7 +239,7 @@ public class HttpFieldsTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testRePut() throws Exception
|
||||
public void testRePut()
|
||||
{
|
||||
HttpFields.Mutable header = HttpFields.build();
|
||||
|
||||
|
@ -278,13 +273,13 @@ public class HttpFieldsTest
|
|||
assertEquals(3, matches);
|
||||
|
||||
e = header.getValues("name1");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value1");
|
||||
assertEquals(false, e.hasMoreElements());
|
||||
assertFalse(e.hasMoreElements());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemove() throws Exception
|
||||
public void testRemove()
|
||||
{
|
||||
HttpFields.Mutable header = HttpFields.build(1)
|
||||
.put("name0", "value0")
|
||||
|
@ -326,11 +321,11 @@ public class HttpFieldsTest
|
|||
assertEquals(2, matches);
|
||||
|
||||
e = header.getValues("name1");
|
||||
assertEquals(false, e.hasMoreElements());
|
||||
assertFalse(e.hasMoreElements());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdd() throws Exception
|
||||
public void testAdd()
|
||||
{
|
||||
HttpFields.Mutable fields = HttpFields.build();
|
||||
|
||||
|
@ -364,11 +359,11 @@ public class HttpFieldsTest
|
|||
assertEquals(3, matches);
|
||||
|
||||
e = fields.getValues("name1");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "valueA");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "valueB");
|
||||
assertEquals(false, e.hasMoreElements());
|
||||
assertFalse(e.hasMoreElements());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -412,7 +407,7 @@ public class HttpFieldsTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testGetValues() throws Exception
|
||||
public void testGetValues()
|
||||
{
|
||||
HttpFields.Mutable fields = HttpFields.build();
|
||||
|
||||
|
@ -422,37 +417,37 @@ public class HttpFieldsTest
|
|||
fields.add("name1", "\"value1C\",\tvalue1D");
|
||||
|
||||
Enumeration<String> e = fields.getValues("name0");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value0A,value0B");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value0C,value0D");
|
||||
assertEquals(false, e.hasMoreElements());
|
||||
assertFalse(e.hasMoreElements());
|
||||
|
||||
e = Collections.enumeration(fields.getCSV("name0", false));
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value0A");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value0B");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value0C");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value0D");
|
||||
assertEquals(false, e.hasMoreElements());
|
||||
assertFalse(e.hasMoreElements());
|
||||
|
||||
e = Collections.enumeration(fields.getCSV("name1", false));
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value1A");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value\t, 1B");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value1C");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value1D");
|
||||
assertEquals(false, e.hasMoreElements());
|
||||
assertFalse(e.hasMoreElements());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCSV() throws Exception
|
||||
public void testGetCSV()
|
||||
{
|
||||
HttpFields.Mutable fields = HttpFields.build();
|
||||
|
||||
|
@ -462,37 +457,37 @@ public class HttpFieldsTest
|
|||
fields.add("name1", "\"value1C\",\tvalue1D");
|
||||
|
||||
Enumeration<String> e = fields.getValues("name0");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value0A,value0B");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value0C,value0D");
|
||||
assertEquals(false, e.hasMoreElements());
|
||||
assertFalse(e.hasMoreElements());
|
||||
|
||||
e = Collections.enumeration(fields.getCSV("name0", false));
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value0A");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value0B");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value0C");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value0D");
|
||||
assertEquals(false, e.hasMoreElements());
|
||||
assertFalse(e.hasMoreElements());
|
||||
|
||||
e = Collections.enumeration(fields.getCSV("name1", false));
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value1A");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value\t, 1B");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value1C");
|
||||
assertEquals(true, e.hasMoreElements());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals(e.nextElement(), "value1D");
|
||||
assertEquals(false, e.hasMoreElements());
|
||||
assertFalse(e.hasMoreElements());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddQuotedCSV() throws Exception
|
||||
public void testAddQuotedCSV()
|
||||
{
|
||||
HttpFields.Mutable fields = HttpFields.build();
|
||||
|
||||
|
@ -540,7 +535,7 @@ public class HttpFieldsTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testGetQualityCSV() throws Exception
|
||||
public void testGetQualityCSV()
|
||||
{
|
||||
HttpFields.Mutable fields = HttpFields.build();
|
||||
|
||||
|
@ -562,7 +557,7 @@ public class HttpFieldsTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testGetQualityCSVHeader() throws Exception
|
||||
public void testGetQualityCSVHeader()
|
||||
{
|
||||
HttpFields.Mutable fields = HttpFields.build();
|
||||
|
||||
|
@ -584,7 +579,7 @@ public class HttpFieldsTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDateFields() throws Exception
|
||||
public void testDateFields()
|
||||
{
|
||||
HttpFields.Mutable fields = HttpFields.build();
|
||||
|
||||
|
@ -626,7 +621,7 @@ public class HttpFieldsTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testNegDateFields() throws Exception
|
||||
public void testNegDateFields()
|
||||
{
|
||||
HttpFields.Mutable fields = HttpFields.build();
|
||||
|
||||
|
@ -644,7 +639,7 @@ public class HttpFieldsTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testLongFields() throws Exception
|
||||
public void testLongFields()
|
||||
{
|
||||
HttpFields.Mutable header = HttpFields.build();
|
||||
|
||||
|
@ -656,47 +651,12 @@ public class HttpFieldsTest
|
|||
header.put("N2", "xx");
|
||||
|
||||
long i1 = header.getLongField("I1");
|
||||
try
|
||||
{
|
||||
header.getLongField("I2");
|
||||
assertTrue(false);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
assertThrows(NumberFormatException.class, () -> header.getLongField("I2"));
|
||||
long i3 = header.getLongField("I3");
|
||||
|
||||
try
|
||||
{
|
||||
header.getLongField("I4");
|
||||
assertTrue(false);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
header.getLongField("N1");
|
||||
assertTrue(false);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
header.getLongField("N2");
|
||||
assertTrue(false);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
assertTrue(true);
|
||||
}
|
||||
assertThrows(NumberFormatException.class, () -> header.getLongField("I4"));
|
||||
assertThrows(NumberFormatException.class, () -> header.getLongField("N1"));
|
||||
assertThrows(NumberFormatException.class, () -> header.getLongField("N2"));
|
||||
|
||||
assertEquals(42, i1);
|
||||
assertEquals(-44, i3);
|
||||
|
@ -708,7 +668,7 @@ public class HttpFieldsTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testContains() throws Exception
|
||||
public void testContains()
|
||||
{
|
||||
HttpFields.Mutable header = HttpFields.build();
|
||||
|
||||
|
@ -768,6 +728,73 @@ public class HttpFieldsTest
|
|||
assertFalse(fields.contains(keyName), "containsKey('" + keyName + "')");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddNullName()
|
||||
{
|
||||
HttpFields.Mutable fields = HttpFields.build();
|
||||
assertThrows(NullPointerException.class, () -> fields.add((String)null, "bogus"));
|
||||
assertThat(fields.size(), is(0));
|
||||
|
||||
assertThrows(NullPointerException.class, () -> fields.add((HttpHeader)null, "bogus"));
|
||||
assertThat(fields.size(), is(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPutNullName()
|
||||
{
|
||||
HttpFields.Mutable fields = HttpFields.build();
|
||||
assertThrows(NullPointerException.class, () -> fields.put((String)null, "bogus"));
|
||||
assertThat(fields.size(), is(0));
|
||||
|
||||
assertThrows(NullPointerException.class, () -> fields.put(null, (List<String>)null));
|
||||
assertThat(fields.size(), is(0));
|
||||
|
||||
List<String> emptyList = new ArrayList<>();
|
||||
assertThrows(NullPointerException.class, () -> fields.put(null, emptyList));
|
||||
assertThat(fields.size(), is(0));
|
||||
|
||||
assertThrows(NullPointerException.class, () -> fields.put((HttpHeader)null, "bogus"));
|
||||
assertThat(fields.size(), is(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPutNullValueList()
|
||||
{
|
||||
HttpFields.Mutable fields = HttpFields.build();
|
||||
|
||||
assertThrows(NullPointerException.class, () -> fields.put("name", (List<String>)null));
|
||||
assertThat(fields.size(), is(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreventNullFieldEntry()
|
||||
{
|
||||
// Attempt various ways that may have put a null field in the array that
|
||||
// previously caused a NPE in put.
|
||||
HttpFields.Mutable fields = HttpFields.build();
|
||||
fields.add((HttpField)null); // should not result in field being added
|
||||
assertThat(fields.size(), is(0));
|
||||
fields.put(null); // should not result in field being added
|
||||
assertThat(fields.size(), is(0));
|
||||
fields.put("something", "else");
|
||||
assertThat(fields.size(), is(1));
|
||||
ListIterator<HttpField> iter = fields.listIterator();
|
||||
iter.next();
|
||||
iter.set(null); // set field to null - should result in noop
|
||||
assertThat(fields.size(), is(0));
|
||||
iter.add(null); // attempt to add null entry
|
||||
assertThat(fields.size(), is(0));
|
||||
fields.put("something", "other");
|
||||
assertThat(fields.size(), is(1));
|
||||
iter = fields.listIterator();
|
||||
iter.next();
|
||||
iter.remove(); // remove only entry
|
||||
assertThat(fields.size(), is(0));
|
||||
fields.put("something", "other");
|
||||
assertThat(fields.size(), is(1));
|
||||
fields.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreventNullField()
|
||||
{
|
||||
|
@ -780,7 +807,7 @@ public class HttpFieldsTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testIteration() throws Exception
|
||||
public void testIteration()
|
||||
{
|
||||
HttpFields.Mutable header = HttpFields.build();
|
||||
Iterator<HttpField> i = header.iterator();
|
||||
|
|
|
@ -21,6 +21,8 @@ package org.eclipse.jetty.http2;
|
|||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Deque;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
@ -47,7 +49,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
private final Queue<WindowEntry> windows = new ArrayDeque<>();
|
||||
private final Deque<Entry> entries = new ArrayDeque<>();
|
||||
private final Queue<Entry> pendingEntries = new ArrayDeque<>();
|
||||
private final Set<Entry> processedEntries = new HashSet<>();
|
||||
private final Collection<Entry> processedEntries = new ArrayList<>();
|
||||
private final HTTP2Session session;
|
||||
private final ByteBufferPool.Lease lease;
|
||||
private Throwable terminated;
|
||||
|
@ -192,7 +194,10 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
|
||||
progress = true;
|
||||
|
||||
processedEntries.add(entry);
|
||||
// We use ArrayList contains() + add() instead of HashSet add()
|
||||
// because that is faster for collections of size up to 250 entries.
|
||||
if (!processedEntries.contains(entry))
|
||||
processedEntries.add(entry);
|
||||
|
||||
if (entry.getDataBytesRemaining() == 0)
|
||||
pending.remove();
|
||||
|
|
|
@ -395,12 +395,15 @@ public class HpackContext
|
|||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(String.format("HdrTbl[%x] evictAll", HpackContext.this.hashCode()));
|
||||
_fieldMap.clear();
|
||||
_nameMap.clear();
|
||||
_offset = 0;
|
||||
_size = 0;
|
||||
_dynamicTableSizeInBytes = 0;
|
||||
Arrays.fill(_entries, null);
|
||||
if (size() > 0)
|
||||
{
|
||||
_fieldMap.clear();
|
||||
_nameMap.clear();
|
||||
_offset = 0;
|
||||
_size = 0;
|
||||
_dynamicTableSizeInBytes = 0;
|
||||
Arrays.fill(_entries, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>infinispan-remote-query</artifactId>
|
||||
<name>Jetty :: Infinispan Session Manager Remote with Querying</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.infinispan.remote.query</bundle-symbolic-name>
|
||||
<infinispan.docker.image.version>9.4.8.Final</infinispan.docker.image.version>
|
||||
</properties>
|
||||
<build>
|
||||
<defaultGoal>install</defaultGoal>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
@ -127,10 +126,20 @@
|
|||
<artifactId>infinispan-remote-query-client</artifactId>
|
||||
<version>${infinispan.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>remote</id>
|
||||
<id>remote-session-tests</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>hotrod.enabled</name>
|
||||
|
@ -144,6 +153,9 @@
|
|||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skipTests>false</skipTests>
|
||||
<systemPropertyVariables>
|
||||
<infinispan.docker.image.version>${infinispan.docker.image.version}</infinispan.docker.image.version>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.Random;
|
|||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.server.session.SessionData;
|
||||
import org.eclipse.jetty.session.infinispan.InfinispanSessionData;
|
||||
import org.eclipse.jetty.session.infinispan.QueryManager;
|
||||
import org.eclipse.jetty.session.infinispan.RemoteQueryManager;
|
||||
import org.eclipse.jetty.session.infinispan.SessionDataMarshaller;
|
||||
|
@ -35,11 +36,19 @@ import org.hibernate.search.cfg.Environment;
|
|||
import org.hibernate.search.cfg.SearchMapping;
|
||||
import org.infinispan.client.hotrod.RemoteCache;
|
||||
import org.infinispan.client.hotrod.RemoteCacheManager;
|
||||
import org.infinispan.client.hotrod.configuration.ClientIntelligence;
|
||||
import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
|
||||
import org.infinispan.client.hotrod.marshall.ProtoStreamMarshaller;
|
||||
import org.infinispan.protostream.FileDescriptorSource;
|
||||
import org.infinispan.protostream.SerializationContext;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.output.Slf4jLogConsumer;
|
||||
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
@ -49,8 +58,45 @@ public class RemoteQueryManagerTest
|
|||
{
|
||||
public static final String DEFAULT_CACHE_NAME = "remote-session-test";
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RemoteQueryManagerTest.class);
|
||||
|
||||
private static final Logger INFINISPAN_LOG =
|
||||
LoggerFactory.getLogger("org.eclipse.jetty.server.session.infinispan.infinispanLogs");
|
||||
|
||||
private String host;
|
||||
private int port;
|
||||
|
||||
GenericContainer infinispan =
|
||||
new GenericContainer(System.getProperty("infinispan.docker.image.name", "jboss/infinispan-server") +
|
||||
":" + System.getProperty("infinispan.docker.image.version", "9.4.8.Final"))
|
||||
.withEnv("APP_USER","theuser")
|
||||
.withEnv("APP_PASS","foobar")
|
||||
.withEnv("MGMT_USER", "admin")
|
||||
.withEnv("MGMT_PASS", "admin")
|
||||
.waitingFor(new LogMessageWaitStrategy()
|
||||
.withRegEx(".*Infinispan Server.*started in.*\\s"))
|
||||
.withExposedPorts(4712,4713,8088,8089,8443,9990,9993,11211,11222,11223,11224)
|
||||
.withLogConsumer(new Slf4jLogConsumer(INFINISPAN_LOG));
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws Exception
|
||||
{
|
||||
long start = System.currentTimeMillis();
|
||||
infinispan.start();
|
||||
host = infinispan.getContainerIpAddress();
|
||||
port = infinispan.getMappedPort(11222);
|
||||
LOG.info("Infinispan container started for {}:{} - {}ms", host, port,
|
||||
System.currentTimeMillis() - start);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void stop() throws Exception
|
||||
{
|
||||
infinispan.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception
|
||||
public void testQuery() throws Exception
|
||||
{
|
||||
SearchMapping mapping = new SearchMapping();
|
||||
mapping.entity(SessionData.class).indexed().providedId().property("expiry", ElementType.FIELD).field();
|
||||
|
@ -59,9 +105,13 @@ public class RemoteQueryManagerTest
|
|||
properties.put(Environment.MODEL_MAPPING, mapping);
|
||||
|
||||
ConfigurationBuilder clientBuilder = new ConfigurationBuilder();
|
||||
clientBuilder.withProperties(properties).addServer().host("127.0.0.1").marshaller(new ProtoStreamMarshaller());
|
||||
clientBuilder.withProperties(properties).addServer()
|
||||
.host(this.host).port(this.port)
|
||||
.clientIntelligence(ClientIntelligence.BASIC)
|
||||
.marshaller(new ProtoStreamMarshaller());
|
||||
|
||||
RemoteCacheManager remoteCacheManager = new RemoteCacheManager(clientBuilder.build());
|
||||
remoteCacheManager.administration().getOrCreateCache("remote-session-test", (String)null);
|
||||
|
||||
FileDescriptorSource fds = new FileDescriptorSource();
|
||||
fds.addProtoFiles("/session.proto");
|
||||
|
@ -70,20 +120,17 @@ public class RemoteQueryManagerTest
|
|||
serCtx.registerProtoFiles(fds);
|
||||
serCtx.registerMarshaller(new SessionDataMarshaller());
|
||||
|
||||
RemoteCache<String, SessionData> cache = remoteCacheManager.getCache(DEFAULT_CACHE_NAME);
|
||||
|
||||
ByteArrayOutputStream baos;
|
||||
try (InputStream is = RemoteQueryManagerTest.class.getClassLoader().getResourceAsStream("session.proto"))
|
||||
try (InputStream is = RemoteQueryManagerTest.class.getClassLoader().getResourceAsStream("session.proto");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream())
|
||||
{
|
||||
if (is == null)
|
||||
throw new IllegalStateException("inputstream is null");
|
||||
|
||||
baos = new ByteArrayOutputStream();
|
||||
IO.copy(is, baos);
|
||||
String content = baos.toString("UTF-8");
|
||||
remoteCacheManager.getCache("___protobuf_metadata").put("session.proto", content);
|
||||
}
|
||||
|
||||
String content = baos.toString("UTF-8");
|
||||
remoteCacheManager.getCache("___protobuf_metadata").put("session.proto", content);
|
||||
RemoteCache<String, SessionData> cache = remoteCacheManager.getCache(DEFAULT_CACHE_NAME);
|
||||
|
||||
//put some sessions into the remote cache
|
||||
int numSessions = 10;
|
||||
|
@ -97,7 +144,7 @@ public class RemoteQueryManagerTest
|
|||
String id = "sd" + i;
|
||||
//create new sessiondata with random expiry time
|
||||
long expiryTime = r.nextInt(maxExpiryTime);
|
||||
SessionData sd = new SessionData(id, "", "", 0, 0, 0, 0);
|
||||
InfinispanSessionData sd = new InfinispanSessionData(id, "", "", 0, 0, 0, 0);
|
||||
sd.setLastNode("lastNode");
|
||||
sd.setExpiry(expiryTime);
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
org.slf4j.simpleLogger.defaultLogLevel=info
|
||||
org.slf4j.simpleLogger.log.org.eclipse.jetty.server.session.infinispan.infinispanLogs=debug
|
||||
org.slf4j.simpleLogger.log.org.eclipse.jetty.server.session.infinispan.RemoteQueryManagerTest=debug
|
|
@ -30,10 +30,12 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MXBean;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.modelmbean.ModelMBean;
|
||||
|
||||
|
@ -151,6 +153,25 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable, De
|
|||
{
|
||||
if (o == null)
|
||||
return null;
|
||||
if (o instanceof DynamicMBean)
|
||||
return o;
|
||||
Class<?> klass = o.getClass();
|
||||
while (klass != Object.class)
|
||||
{
|
||||
MXBean mxbean = klass.getAnnotation(MXBean.class);
|
||||
if (mxbean != null && mxbean.value())
|
||||
return o;
|
||||
String mbeanName = klass.getName() + "MBean";
|
||||
String mxbeanName = klass.getName() + "MXBean";
|
||||
Class<?>[] interfaces = klass.getInterfaces();
|
||||
for (Class<?> type : interfaces)
|
||||
{
|
||||
String name = type.getName();
|
||||
if (name.equals(mbeanName) || name.equals(mxbeanName))
|
||||
return o;
|
||||
}
|
||||
klass = klass.getSuperclass();
|
||||
}
|
||||
Object mbean = findMetaData(container, o.getClass()).newInstance(o);
|
||||
if (mbean instanceof ObjectMBean)
|
||||
((ObjectMBean)mbean).setMBeanContainer(container);
|
||||
|
@ -338,7 +359,9 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable, De
|
|||
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
String context = (mbean instanceof ObjectMBean) ? makeName(((ObjectMBean)mbean).getObjectContextBasis()) : null;
|
||||
String context = (mbean instanceof ObjectMBean)
|
||||
? makeName(((ObjectMBean)mbean).getObjectContextBasis())
|
||||
: makeName(reflectContextBasis(mbean));
|
||||
if (context == null && parentObjectName != null)
|
||||
context = parentObjectName.getKeyProperty("context");
|
||||
|
||||
|
@ -347,7 +370,9 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable, De
|
|||
|
||||
buf.append("type=").append(type);
|
||||
|
||||
String name = (mbean instanceof ObjectMBean) ? makeName(((ObjectMBean)mbean).getObjectNameBasis()) : context;
|
||||
String name = (mbean instanceof ObjectMBean)
|
||||
? makeName(((ObjectMBean)mbean).getObjectNameBasis())
|
||||
: makeName(reflectNameBasis(mbean));
|
||||
if (name != null && name.length() > 1)
|
||||
buf.append(",").append("name=").append(name);
|
||||
|
||||
|
@ -394,6 +419,28 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable, De
|
|||
}
|
||||
}
|
||||
|
||||
private String reflectContextBasis(Object mbean)
|
||||
{
|
||||
return reflectBasis(mbean, "jmxContext");
|
||||
}
|
||||
|
||||
private String reflectNameBasis(Object mbean)
|
||||
{
|
||||
return reflectBasis(mbean, "jmxName");
|
||||
}
|
||||
|
||||
private String reflectBasis(Object mbean, String methodName)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (String)mbean.getClass().getMethod(methodName).invoke(mbean);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param basis name to strip of special characters.
|
||||
* @return normalized name
|
||||
|
|
|
@ -19,21 +19,11 @@
|
|||
package org.eclipse.jetty.osgi.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.io.ClientConnector;
|
||||
import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
|
||||
import org.eclipse.jetty.toolchain.test.FS;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
@ -43,16 +33,12 @@ import org.ops4j.pax.exam.Option;
|
|||
import org.ops4j.pax.exam.options.WrappedUrlProvisionOption.OverwriteMode;
|
||||
import org.ops4j.pax.tinybundles.core.TinyBundle;
|
||||
import org.ops4j.pax.tinybundles.core.TinyBundles;
|
||||
import org.ops4j.pax.url.mvn.internal.AetherBasedResolver;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.Constants;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.service.http.HttpService;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
|
||||
|
@ -195,7 +181,9 @@ public class TestOSGiUtil
|
|||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-jndi").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-plus").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-annotations").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-core").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-core-server").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-core-client").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-core-common").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-util").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-util-server").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-jetty-api").versionAsInProject().start());
|
||||
|
|
|
@ -106,7 +106,7 @@ public class QuickStartDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
{
|
||||
String origin = node.getAttribute(_originAttributeName);
|
||||
if (!StringUtil.isBlank(origin) && origin.startsWith(DefaultsDescriptor.class.getSimpleName()))
|
||||
mapping.setDefault(true);
|
||||
mapping.setFromDefaultDescriptor(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ public class TestQuickStart
|
|||
server.dumpStdErr();
|
||||
|
||||
//verify that FooServlet is now mapped to / and not the DefaultServlet
|
||||
ServletHolder sh = webapp.getServletHandler().getMappedServlet("/").getResource();
|
||||
ServletHolder sh = webapp.getServletHandler().getMappedServlet("/").getServletHolder();
|
||||
assertNotNull(sh);
|
||||
assertEquals("foo", sh.getName());
|
||||
}
|
||||
|
|
|
@ -54,6 +54,12 @@
|
|||
<Set name="mapColumn">
|
||||
<Property name="jetty.session.jdbc.schema.mapColumn" default="map" />
|
||||
</Set>
|
||||
<Set name="schemaName">
|
||||
<Property name="jetty.session.jdbc.schema.schemaName" />
|
||||
</Set>
|
||||
<Set name="catalogName">
|
||||
<Property name="jetty.session.jdbc.schema.catalogName" />
|
||||
</Set>
|
||||
<Set name="tableName">
|
||||
<Property name="jetty.session.jdbc.schema.table" default="JettySessions" />
|
||||
</Set>
|
||||
|
|
|
@ -55,3 +55,14 @@ db-connection-type=datasource
|
|||
#jetty.session.jdbc.schema.maxIntervalColumn=maxInterval
|
||||
#jetty.session.jdbc.schema.mapColumn=map
|
||||
#jetty.session.jdbc.schema.table=JettySessions
|
||||
# Optional name of the schema used to identify where the session table is defined in the database:
|
||||
# "" - empty string, no schema name
|
||||
# "INFERRED" - special string meaning infer from the current db connection
|
||||
# name - a string defined by the user
|
||||
#jetty.session.jdbc.schema.schemaName
|
||||
# Optional name of the catalog used to identify where the session table is defined in the database:
|
||||
# "" - empty string, no catalog name
|
||||
# "INFERRED" - special string meaning infer from the current db connection
|
||||
# name - a string defined by the user
|
||||
#jetty.session.jdbc.schema.catalogName
|
||||
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.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.server;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.servlet.AsyncContext;
|
||||
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
|
||||
class AsyncAttributes extends Attributes.Wrapper
|
||||
{
|
||||
private final String _requestURI;
|
||||
private final String _contextPath;
|
||||
private final String _pathInContext;
|
||||
private ServletPathMapping _mapping;
|
||||
private final String _queryString;
|
||||
|
||||
public AsyncAttributes(Attributes attributes, String requestUri, String contextPath, String pathInContext, ServletPathMapping mapping, String queryString)
|
||||
{
|
||||
super(attributes);
|
||||
_requestURI = requestUri;
|
||||
_contextPath = contextPath;
|
||||
_pathInContext = pathInContext;
|
||||
_mapping = mapping;
|
||||
_queryString = queryString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case AsyncContext.ASYNC_REQUEST_URI:
|
||||
return _requestURI;
|
||||
case AsyncContext.ASYNC_CONTEXT_PATH:
|
||||
return _contextPath;
|
||||
case AsyncContext.ASYNC_SERVLET_PATH:
|
||||
return _mapping == null ? null : _mapping.getServletPath();
|
||||
case AsyncContext.ASYNC_PATH_INFO:
|
||||
return _mapping == null ? _pathInContext : _mapping.getPathInfo();
|
||||
case AsyncContext.ASYNC_QUERY_STRING:
|
||||
return _queryString;
|
||||
case AsyncContext.ASYNC_MAPPING:
|
||||
return _mapping;
|
||||
default:
|
||||
return super.getAttribute(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAttributeNameSet()
|
||||
{
|
||||
Set<String> set = new HashSet<>(super.getAttributeNameSet());
|
||||
set.add(AsyncContext.ASYNC_REQUEST_URI);
|
||||
set.add(AsyncContext.ASYNC_CONTEXT_PATH);
|
||||
set.add(AsyncContext.ASYNC_SERVLET_PATH);
|
||||
set.add(AsyncContext.ASYNC_PATH_INFO);
|
||||
set.add(AsyncContext.ASYNC_QUERY_STRING);
|
||||
set.add(AsyncContext.ASYNC_MAPPING);
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String key, Object value)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case AsyncContext.ASYNC_REQUEST_URI:
|
||||
case AsyncContext.ASYNC_CONTEXT_PATH:
|
||||
case AsyncContext.ASYNC_SERVLET_PATH:
|
||||
case AsyncContext.ASYNC_PATH_INFO:
|
||||
case AsyncContext.ASYNC_QUERY_STRING:
|
||||
case AsyncContext.ASYNC_MAPPING:
|
||||
// Ignore sets for these reserved names as this class is applied
|
||||
// we will always override these particular attributes.
|
||||
break;
|
||||
default:
|
||||
super.setAttribute(key, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,7 +34,7 @@ public class AsyncContextEvent extends AsyncEvent implements Runnable
|
|||
private final Context _context;
|
||||
private final AsyncContextState _asyncContext;
|
||||
private final HttpURI _baseURI;
|
||||
private volatile HttpChannelState _state;
|
||||
private final HttpChannelState _state;
|
||||
private ServletContext _dispatchContext;
|
||||
private String _dispatchPath;
|
||||
private volatile Scheduler.Task _timeoutTask;
|
||||
|
@ -53,33 +53,9 @@ public class AsyncContextEvent extends AsyncEvent implements Runnable
|
|||
_state = state;
|
||||
_baseURI = baseURI;
|
||||
|
||||
// If we haven't been async dispatched before
|
||||
if (baseRequest.getAttribute(AsyncContext.ASYNC_REQUEST_URI) == null)
|
||||
{
|
||||
// We are setting these attributes during startAsync, when the spec implies that
|
||||
// they are only available after a call to AsyncContext.dispatch(...);
|
||||
|
||||
// have we been forwarded before?
|
||||
String uri = (String)baseRequest.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
|
||||
if (uri != null)
|
||||
{
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_REQUEST_URI, uri);
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH, baseRequest.getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH));
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_SERVLET_PATH, baseRequest.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH));
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_PATH_INFO, baseRequest.getAttribute(RequestDispatcher.FORWARD_PATH_INFO));
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_QUERY_STRING, baseRequest.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING));
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_MAPPING, baseRequest.getAttribute(RequestDispatcher.FORWARD_MAPPING));
|
||||
}
|
||||
else
|
||||
{
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_REQUEST_URI, baseRequest.getRequestURI());
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH, baseRequest.getContextPath());
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_SERVLET_PATH, baseRequest.getServletPath());
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_PATH_INFO, baseRequest.getPathInfo());
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_QUERY_STRING, baseRequest.getQueryString());
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_MAPPING, baseRequest.getHttpServletMapping());
|
||||
}
|
||||
}
|
||||
// We are setting these attributes during startAsync, when the spec implies that
|
||||
// they are only available after a call to AsyncContext.dispatch(...);
|
||||
baseRequest.setAsyncAttributes();
|
||||
}
|
||||
|
||||
public HttpURI getBaseURI()
|
||||
|
|
|
@ -26,7 +26,6 @@ import javax.servlet.RequestDispatcher;
|
|||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletMapping;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
@ -101,14 +100,7 @@ public class Dispatcher implements RequestDispatcher
|
|||
}
|
||||
else
|
||||
{
|
||||
IncludeAttributes attr = new IncludeAttributes(old_attr);
|
||||
|
||||
attr._requestURI = _uri.getPath();
|
||||
attr._contextPath = _contextHandler.getContextPath();
|
||||
attr._servletPath = null; // set by ServletHandler
|
||||
attr._pathInfo = _pathInContext;
|
||||
attr._query = _uri.getQuery();
|
||||
attr._mapping = null; //set by ServletHandler
|
||||
IncludeAttributes attr = new IncludeAttributes(old_attr, _uri.getPath(), _contextHandler.getContextPath(), _pathInContext, _uri.getQuery());
|
||||
if (attr._query != null)
|
||||
baseRequest.mergeQueryParameters(baseRequest.getQueryString(), attr._query);
|
||||
baseRequest.setAttributes(attr);
|
||||
|
@ -147,7 +139,7 @@ public class Dispatcher implements RequestDispatcher
|
|||
final String old_context_path = baseRequest.getContextPath();
|
||||
final String old_servlet_path = baseRequest.getServletPath();
|
||||
final String old_path_info = baseRequest.getPathInfo();
|
||||
final HttpServletMapping old_mapping = baseRequest.getHttpServletMapping();
|
||||
final ServletPathMapping old_mapping = baseRequest.getServletPathMapping();
|
||||
|
||||
final MultiMap<String> old_query_params = baseRequest.getQueryParameters();
|
||||
final Attributes old_attr = baseRequest.getAttributes();
|
||||
|
@ -163,30 +155,26 @@ public class Dispatcher implements RequestDispatcher
|
|||
}
|
||||
else
|
||||
{
|
||||
ForwardAttributes attr = new ForwardAttributes(old_attr);
|
||||
|
||||
//If we have already been forwarded previously, then keep using the established
|
||||
//original value. Otherwise, this is the first forward and we need to establish the values.
|
||||
//Note: the established value on the original request for pathInfo and
|
||||
//for queryString is allowed to be null, but cannot be null for the other values.
|
||||
if (old_attr.getAttribute(FORWARD_REQUEST_URI) != null)
|
||||
{
|
||||
attr._pathInfo = (String)old_attr.getAttribute(FORWARD_PATH_INFO);
|
||||
attr._query = (String)old_attr.getAttribute(FORWARD_QUERY_STRING);
|
||||
attr._requestURI = (String)old_attr.getAttribute(FORWARD_REQUEST_URI);
|
||||
attr._contextPath = (String)old_attr.getAttribute(FORWARD_CONTEXT_PATH);
|
||||
attr._servletPath = (String)old_attr.getAttribute(FORWARD_SERVLET_PATH);
|
||||
attr._mapping = (HttpServletMapping)old_attr.getAttribute(FORWARD_MAPPING);
|
||||
}
|
||||
else
|
||||
{
|
||||
attr._pathInfo = old_path_info;
|
||||
attr._query = old_uri.getQuery();
|
||||
attr._requestURI = old_uri.getPath();
|
||||
attr._contextPath = old_context_path;
|
||||
attr._servletPath = old_servlet_path;
|
||||
attr._mapping = old_mapping;
|
||||
}
|
||||
// If we have already been forwarded previously, then keep using the established
|
||||
// original value. Otherwise, this is the first forward and we need to establish the values.
|
||||
// Note: the established value on the original request for pathInfo and
|
||||
// for queryString is allowed to be null, but cannot be null for the other values.
|
||||
// Note: the pathInfo is passed as the pathInContext since it is only used when there is
|
||||
// no mapping, and when there is no mapping the pathInfo is the pathInContext.
|
||||
// TODO Ultimately it is intended for the request to carry the pathInContext for easy access
|
||||
ForwardAttributes attr = old_attr.getAttribute(FORWARD_REQUEST_URI) != null
|
||||
? new ForwardAttributes(old_attr,
|
||||
(String)old_attr.getAttribute(FORWARD_REQUEST_URI),
|
||||
(String)old_attr.getAttribute(FORWARD_CONTEXT_PATH),
|
||||
(String)old_attr.getAttribute(FORWARD_PATH_INFO),
|
||||
(ServletPathMapping)old_attr.getAttribute(FORWARD_MAPPING),
|
||||
(String)old_attr.getAttribute(FORWARD_QUERY_STRING))
|
||||
: new ForwardAttributes(old_attr,
|
||||
old_uri.getPath(),
|
||||
old_context_path,
|
||||
baseRequest.getPathInfo(), // TODO replace with pathInContext
|
||||
old_mapping,
|
||||
old_uri.getQuery());
|
||||
|
||||
String query = _uri.getQuery();
|
||||
if (query == null)
|
||||
|
@ -194,6 +182,7 @@ public class Dispatcher implements RequestDispatcher
|
|||
|
||||
baseRequest.setHttpURI(HttpURI.build(old_uri, _uri.getPath(), _uri.getParam(), query));
|
||||
baseRequest.setContextPath(_contextHandler.getContextPath());
|
||||
baseRequest.setServletPathMapping(null);
|
||||
baseRequest.setServletPath(null);
|
||||
baseRequest.setPathInfo(_pathInContext);
|
||||
|
||||
|
@ -257,16 +246,20 @@ public class Dispatcher implements RequestDispatcher
|
|||
|
||||
private class ForwardAttributes extends Attributes.Wrapper
|
||||
{
|
||||
String _requestURI;
|
||||
String _contextPath;
|
||||
String _servletPath;
|
||||
String _pathInfo;
|
||||
String _query;
|
||||
HttpServletMapping _mapping;
|
||||
private final String _requestURI;
|
||||
private final String _contextPath;
|
||||
private final String _pathInContext;
|
||||
private final ServletPathMapping _servletPathMapping;
|
||||
private final String _query;
|
||||
|
||||
ForwardAttributes(Attributes attributes)
|
||||
public ForwardAttributes(Attributes attributes, String requestURI, String contextPath, String pathInContext, ServletPathMapping mapping, String query)
|
||||
{
|
||||
super(attributes);
|
||||
_requestURI = requestURI;
|
||||
_contextPath = contextPath;
|
||||
_pathInContext = pathInContext;
|
||||
_servletPathMapping = mapping;
|
||||
_query = query;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -277,22 +270,23 @@ public class Dispatcher implements RequestDispatcher
|
|||
switch (key)
|
||||
{
|
||||
case FORWARD_PATH_INFO:
|
||||
return _pathInfo;
|
||||
return _servletPathMapping == null ? _pathInContext : _servletPathMapping.getPathInfo();
|
||||
case FORWARD_REQUEST_URI:
|
||||
return _requestURI;
|
||||
case FORWARD_SERVLET_PATH:
|
||||
return _servletPath;
|
||||
return _servletPathMapping == null ? null : _servletPathMapping.getServletPath();
|
||||
case FORWARD_CONTEXT_PATH:
|
||||
return _contextPath;
|
||||
case FORWARD_QUERY_STRING:
|
||||
return _query;
|
||||
case FORWARD_MAPPING:
|
||||
return _mapping;
|
||||
return _servletPathMapping;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we are forwarded then we hide include attributes
|
||||
if (key.startsWith(__INCLUDE_PREFIX))
|
||||
return null;
|
||||
|
||||
|
@ -312,18 +306,12 @@ public class Dispatcher implements RequestDispatcher
|
|||
|
||||
if (_named == null)
|
||||
{
|
||||
if (_pathInfo != null)
|
||||
set.add(FORWARD_PATH_INFO);
|
||||
else
|
||||
set.remove(FORWARD_PATH_INFO);
|
||||
set.add(FORWARD_PATH_INFO);
|
||||
set.add(FORWARD_REQUEST_URI);
|
||||
set.add(FORWARD_SERVLET_PATH);
|
||||
set.add(FORWARD_CONTEXT_PATH);
|
||||
set.add(FORWARD_MAPPING);
|
||||
if (_query != null)
|
||||
set.add(FORWARD_QUERY_STRING);
|
||||
else
|
||||
set.remove(FORWARD_QUERY_STRING);
|
||||
set.add(FORWARD_QUERY_STRING);
|
||||
}
|
||||
|
||||
return set;
|
||||
|
@ -332,39 +320,11 @@ public class Dispatcher implements RequestDispatcher
|
|||
@Override
|
||||
public void setAttribute(String key, Object value)
|
||||
{
|
||||
if (_named == null && key.startsWith("javax.servlet."))
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case FORWARD_PATH_INFO:
|
||||
_pathInfo = (String)value;
|
||||
return;
|
||||
case FORWARD_REQUEST_URI:
|
||||
_requestURI = (String)value;
|
||||
return;
|
||||
case FORWARD_SERVLET_PATH:
|
||||
_servletPath = (String)value;
|
||||
return;
|
||||
case FORWARD_CONTEXT_PATH:
|
||||
_contextPath = (String)value;
|
||||
return;
|
||||
case FORWARD_QUERY_STRING:
|
||||
_query = (String)value;
|
||||
return;
|
||||
case FORWARD_MAPPING:
|
||||
_mapping = (HttpServletMapping)value;
|
||||
return;
|
||||
default:
|
||||
if (value == null)
|
||||
_attributes.removeAttribute(key);
|
||||
else
|
||||
_attributes.setAttribute(key, value);
|
||||
}
|
||||
}
|
||||
else if (value == null)
|
||||
_attributes.removeAttribute(key);
|
||||
else
|
||||
_attributes.setAttribute(key, value);
|
||||
// Allow any attribute to be set, even if a reserved name. If a reserved
|
||||
// name is set here, it will be hidden by this class during the forward,
|
||||
// but revealed after the forward is complete just as if the reserved name
|
||||
// attribute had be set by the application before the forward.
|
||||
_attributes.setAttribute(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -388,16 +348,19 @@ public class Dispatcher implements RequestDispatcher
|
|||
|
||||
private class IncludeAttributes extends Attributes.Wrapper
|
||||
{
|
||||
String _requestURI;
|
||||
String _contextPath;
|
||||
String _servletPath;
|
||||
String _pathInfo;
|
||||
String _query;
|
||||
HttpServletMapping _mapping;
|
||||
private final String _requestURI;
|
||||
private final String _contextPath;
|
||||
private final String _pathInContext;
|
||||
private ServletPathMapping _servletPathMapping; // Set later by ServletHandler
|
||||
private final String _query;
|
||||
|
||||
IncludeAttributes(Attributes attributes)
|
||||
public IncludeAttributes(Attributes attributes, String requestURI, String contextPath, String pathInContext, String query)
|
||||
{
|
||||
super(attributes);
|
||||
_requestURI = requestURI;
|
||||
_contextPath = contextPath;
|
||||
_pathInContext = pathInContext;
|
||||
_query = query;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -408,9 +371,9 @@ public class Dispatcher implements RequestDispatcher
|
|||
switch (key)
|
||||
{
|
||||
case INCLUDE_PATH_INFO:
|
||||
return _pathInfo;
|
||||
return _servletPathMapping == null ? _pathInContext : _servletPathMapping.getPathInfo();
|
||||
case INCLUDE_SERVLET_PATH:
|
||||
return _servletPath;
|
||||
return _servletPathMapping == null ? null : _servletPathMapping.getServletPath();
|
||||
case INCLUDE_CONTEXT_PATH:
|
||||
return _contextPath;
|
||||
case INCLUDE_QUERY_STRING:
|
||||
|
@ -418,13 +381,11 @@ public class Dispatcher implements RequestDispatcher
|
|||
case INCLUDE_REQUEST_URI:
|
||||
return _requestURI;
|
||||
case INCLUDE_MAPPING:
|
||||
return _mapping;
|
||||
return _servletPathMapping;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (key.startsWith(__INCLUDE_PREFIX))
|
||||
return null;
|
||||
|
||||
return _attributes.getAttribute(key);
|
||||
}
|
||||
|
@ -441,18 +402,12 @@ public class Dispatcher implements RequestDispatcher
|
|||
|
||||
if (_named == null)
|
||||
{
|
||||
if (_pathInfo != null)
|
||||
set.add(INCLUDE_PATH_INFO);
|
||||
else
|
||||
set.remove(INCLUDE_PATH_INFO);
|
||||
set.add(INCLUDE_PATH_INFO);
|
||||
set.add(INCLUDE_REQUEST_URI);
|
||||
set.add(INCLUDE_SERVLET_PATH);
|
||||
set.add(INCLUDE_CONTEXT_PATH);
|
||||
set.add(INCLUDE_MAPPING);
|
||||
if (_query != null)
|
||||
set.add(INCLUDE_QUERY_STRING);
|
||||
else
|
||||
set.remove(INCLUDE_QUERY_STRING);
|
||||
set.add(INCLUDE_QUERY_STRING);
|
||||
}
|
||||
|
||||
return set;
|
||||
|
@ -461,38 +416,11 @@ public class Dispatcher implements RequestDispatcher
|
|||
@Override
|
||||
public void setAttribute(String key, Object value)
|
||||
{
|
||||
if (_named == null && key.startsWith("javax.servlet."))
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case INCLUDE_PATH_INFO:
|
||||
_pathInfo = (String)value;
|
||||
return;
|
||||
case INCLUDE_REQUEST_URI:
|
||||
_requestURI = (String)value;
|
||||
return;
|
||||
case INCLUDE_SERVLET_PATH:
|
||||
_servletPath = (String)value;
|
||||
return;
|
||||
case INCLUDE_CONTEXT_PATH:
|
||||
_contextPath = (String)value;
|
||||
return;
|
||||
case INCLUDE_QUERY_STRING:
|
||||
_query = (String)value;
|
||||
return;
|
||||
case INCLUDE_MAPPING:
|
||||
_mapping = (HttpServletMapping)value;
|
||||
return;
|
||||
default:
|
||||
if (value == null)
|
||||
_attributes.removeAttribute(key);
|
||||
else
|
||||
_attributes.setAttribute(key, value);
|
||||
}
|
||||
}
|
||||
else if (value == null)
|
||||
_attributes.removeAttribute(key);
|
||||
if (_servletPathMapping == null && _named == null && INCLUDE_MAPPING.equals(key))
|
||||
_servletPathMapping = (ServletPathMapping)value;
|
||||
else
|
||||
// Allow any attribute to be set, even if a reserved name. If a reserved
|
||||
// name is set here, it will be revealed after the include is complete.
|
||||
_attributes.setAttribute(key, value);
|
||||
}
|
||||
|
||||
|
|
|
@ -419,8 +419,17 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
|||
abort(x);
|
||||
else
|
||||
{
|
||||
_response.resetContent();
|
||||
sendResponseAndComplete();
|
||||
try
|
||||
{
|
||||
_response.resetContent();
|
||||
sendResponseAndComplete();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
if (x != t)
|
||||
x.addSuppressed(t);
|
||||
abort(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
|
|
@ -475,8 +475,8 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
synchronized (_channelState)
|
||||
{
|
||||
_state = State.CLOSED;
|
||||
releaseBuffer();
|
||||
}
|
||||
releaseBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -601,10 +601,13 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
|
||||
public ByteBuffer getBuffer()
|
||||
{
|
||||
return _aggregate;
|
||||
synchronized (_channelState)
|
||||
{
|
||||
return acquireBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
public ByteBuffer acquireBuffer()
|
||||
private ByteBuffer acquireBuffer()
|
||||
{
|
||||
if (_aggregate == null)
|
||||
_aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), _channel.isUseOutputDirectByteBuffers());
|
||||
|
@ -1362,10 +1365,13 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
|
||||
public void resetBuffer()
|
||||
{
|
||||
_interceptor.resetBuffer();
|
||||
if (BufferUtil.hasContent(_aggregate))
|
||||
BufferUtil.clear(_aggregate);
|
||||
_written = 0;
|
||||
synchronized (_channelState)
|
||||
{
|
||||
_interceptor.resetBuffer();
|
||||
if (BufferUtil.hasContent(_aggregate))
|
||||
BufferUtil.clear(_aggregate);
|
||||
_written = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -63,7 +63,6 @@ import javax.servlet.http.HttpServletRequestWrapper;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.HttpUpgradeHandler;
|
||||
import javax.servlet.http.MappingMatch;
|
||||
import javax.servlet.http.Part;
|
||||
import javax.servlet.http.PushBuilder;
|
||||
|
||||
|
@ -83,8 +82,6 @@ import org.eclipse.jetty.http.HttpURI;
|
|||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.http.pathmap.ServletPathSpec;
|
||||
import org.eclipse.jetty.io.RuntimeIOException;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler.Context;
|
||||
|
@ -193,85 +190,6 @@ public class Request implements HttpServletRequest
|
|||
return null;
|
||||
}
|
||||
|
||||
public static HttpServletMapping getServletMapping(PathSpec pathSpec, String servletPath, String servletName)
|
||||
{
|
||||
final MappingMatch match;
|
||||
final String mapping;
|
||||
if (pathSpec instanceof ServletPathSpec)
|
||||
{
|
||||
switch (pathSpec.getGroup())
|
||||
{
|
||||
case ROOT:
|
||||
match = MappingMatch.CONTEXT_ROOT;
|
||||
mapping = "";
|
||||
break;
|
||||
case DEFAULT:
|
||||
match = MappingMatch.DEFAULT;
|
||||
mapping = "/";
|
||||
break;
|
||||
case EXACT:
|
||||
match = MappingMatch.EXACT;
|
||||
mapping = servletPath.startsWith("/") ? servletPath.substring(1) : servletPath;
|
||||
break;
|
||||
case SUFFIX_GLOB:
|
||||
match = MappingMatch.EXTENSION;
|
||||
int dot = servletPath.lastIndexOf('.');
|
||||
mapping = servletPath.substring(0, dot);
|
||||
break;
|
||||
case PREFIX_GLOB:
|
||||
match = MappingMatch.PATH;
|
||||
mapping = servletPath;
|
||||
break;
|
||||
default:
|
||||
match = null;
|
||||
mapping = servletPath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
match = null;
|
||||
mapping = servletPath;
|
||||
}
|
||||
|
||||
return new HttpServletMapping()
|
||||
{
|
||||
@Override
|
||||
public String getMatchValue()
|
||||
{
|
||||
return (mapping == null ? "" : mapping);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPattern()
|
||||
{
|
||||
if (pathSpec != null)
|
||||
return pathSpec.getDeclaration();
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServletName()
|
||||
{
|
||||
return (servletName == null ? "" : servletName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingMatch getMappingMatch()
|
||||
{
|
||||
return match;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "HttpServletMapping{matchValue=" + getMatchValue() +
|
||||
", pattern=" + getPattern() + ", servletName=" + getServletName() +
|
||||
", mappingMatch=" + getMappingMatch() + "}";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private final HttpChannel _channel;
|
||||
private final List<ServletRequestAttributeListener> _requestAttributeListeners = new ArrayList<>();
|
||||
private final HttpInput _input;
|
||||
|
@ -283,7 +201,7 @@ public class Request implements HttpServletRequest
|
|||
private String _contextPath;
|
||||
private String _servletPath;
|
||||
private String _pathInfo;
|
||||
private PathSpec _pathSpec;
|
||||
private ServletPathMapping _servletPathMapping;
|
||||
private boolean _secure;
|
||||
private String _asyncNotSupportedSource = null;
|
||||
private boolean _newContext;
|
||||
|
@ -739,7 +657,7 @@ public class Request implements HttpServletRequest
|
|||
public Attributes getAttributes()
|
||||
{
|
||||
if (_attributes == null)
|
||||
_attributes = new AttributesMap();
|
||||
_attributes = new ServletAttributes();
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
|
@ -1752,7 +1670,7 @@ public class Request implements HttpServletRequest
|
|||
// TODO this is not really right for CONNECT
|
||||
path = _uri.isAbsolute() ? "/" : null;
|
||||
else if (encoded.startsWith("/"))
|
||||
path = (encoded.length() == 1) ? "/" : URIUtil.canonicalPath(URIUtil.decodePath(encoded));
|
||||
path = (encoded.length() == 1) ? "/" : _uri.getDecodedPath();
|
||||
else if ("*".equals(encoded) || HttpMethod.CONNECT.is(getMethod()))
|
||||
path = encoded;
|
||||
else
|
||||
|
@ -1815,7 +1733,7 @@ public class Request implements HttpServletRequest
|
|||
_attributes = Attributes.unwrap(_attributes);
|
||||
if (_attributes != null)
|
||||
{
|
||||
if (AttributesMap.class.equals(_attributes.getClass()))
|
||||
if (ServletAttributes.class.equals(_attributes.getClass()))
|
||||
_attributes.clearAttributes();
|
||||
else
|
||||
_attributes = null;
|
||||
|
@ -1841,7 +1759,6 @@ public class Request implements HttpServletRequest
|
|||
_queryParameters = null;
|
||||
_contentParameters = null;
|
||||
_parameters = null;
|
||||
_pathSpec = null;
|
||||
_contentParamsExtracted = false;
|
||||
_inputState = INPUT_NONE;
|
||||
_multiParts = null;
|
||||
|
@ -1896,7 +1813,7 @@ public class Request implements HttpServletRequest
|
|||
LOG.warn("Deprecated: org.eclipse.jetty.server.sendContent");
|
||||
|
||||
if (_attributes == null)
|
||||
_attributes = new AttributesMap();
|
||||
_attributes = new ServletAttributes();
|
||||
_attributes.setAttribute(name, value);
|
||||
|
||||
if (!_requestAttributeListeners.isEmpty())
|
||||
|
@ -1919,6 +1836,76 @@ public class Request implements HttpServletRequest
|
|||
_attributes = attributes;
|
||||
}
|
||||
|
||||
public void setAsyncAttributes()
|
||||
{
|
||||
// Return if we have been async dispatched before.
|
||||
if (getAttribute(AsyncContext.ASYNC_REQUEST_URI) != null)
|
||||
return;
|
||||
|
||||
// Unwrap the _attributes to get the base attributes instance.
|
||||
Attributes baseAttributes;
|
||||
if (_attributes == null)
|
||||
baseAttributes = _attributes = new ServletAttributes();
|
||||
else
|
||||
baseAttributes = Attributes.unwrap(_attributes);
|
||||
|
||||
// We cannot use a apply AsyncAttribute via #setAttributes as that
|
||||
// will wrap over any dispatch specific attribute wrappers (eg.
|
||||
// Dispatcher#ForwardAttributes). Async attributes must persist
|
||||
// after the current dispatch, so they must be set under any other
|
||||
// wrappers.
|
||||
|
||||
String fwdRequestURI = (String)getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
|
||||
if (fwdRequestURI == null)
|
||||
{
|
||||
if (baseAttributes instanceof ServletAttributes)
|
||||
{
|
||||
// The baseAttributes map is our ServletAttributes, so we can set the async
|
||||
// attributes there, under any other wrappers.
|
||||
((ServletAttributes)baseAttributes).setAsyncAttributes(getRequestURI(),
|
||||
getContextPath(),
|
||||
getPathInfo(), // TODO change to pathInContext when cheaply available
|
||||
getServletPathMapping(),
|
||||
getQueryString());
|
||||
}
|
||||
else
|
||||
{
|
||||
// We cannot find our ServletAttributes instance, so just set directly and hope
|
||||
// whatever non jetty wrappers that have been applied will do the right thing.
|
||||
_attributes.setAttribute(AsyncContext.ASYNC_REQUEST_URI, getRequestURI());
|
||||
_attributes.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH, getContextPath());
|
||||
_attributes.setAttribute(AsyncContext.ASYNC_SERVLET_PATH, getServletPath());
|
||||
_attributes.setAttribute(AsyncContext.ASYNC_PATH_INFO, getPathInfo());
|
||||
_attributes.setAttribute(AsyncContext.ASYNC_QUERY_STRING, getQueryString());
|
||||
_attributes.setAttribute(AsyncContext.ASYNC_MAPPING, getHttpServletMapping());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (baseAttributes instanceof ServletAttributes)
|
||||
{
|
||||
// The baseAttributes map is our ServletAttributes, so we can set the async
|
||||
// attributes there, under any other wrappers.
|
||||
((ServletAttributes)baseAttributes).setAsyncAttributes(fwdRequestURI,
|
||||
(String)getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH),
|
||||
(String)getAttribute(RequestDispatcher.FORWARD_PATH_INFO),
|
||||
(ServletPathMapping)getAttribute(RequestDispatcher.FORWARD_MAPPING),
|
||||
(String)getAttribute(RequestDispatcher.FORWARD_QUERY_STRING));
|
||||
}
|
||||
else
|
||||
{
|
||||
// We cannot find our ServletAttributes instance, so just set directly and hope
|
||||
// whatever non jetty wrappers that have been applied will do the right thing.
|
||||
_attributes.setAttribute(AsyncContext.ASYNC_REQUEST_URI, fwdRequestURI);
|
||||
_attributes.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH, getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH));
|
||||
_attributes.setAttribute(AsyncContext.ASYNC_SERVLET_PATH, getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH));
|
||||
_attributes.setAttribute(AsyncContext.ASYNC_PATH_INFO, getAttribute(RequestDispatcher.FORWARD_PATH_INFO));
|
||||
_attributes.setAttribute(AsyncContext.ASYNC_QUERY_STRING, getAttribute(RequestDispatcher.FORWARD_QUERY_STRING));
|
||||
_attributes.setAttribute(AsyncContext.ASYNC_MAPPING, getAttribute(RequestDispatcher.FORWARD_MAPPING));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the authentication.
|
||||
*
|
||||
|
@ -2358,19 +2345,34 @@ public class Request implements HttpServletRequest
|
|||
throw new ServletException("HttpServletRequest.upgrade() not supported in Jetty");
|
||||
}
|
||||
|
||||
public void setPathSpec(PathSpec pathSpec)
|
||||
/**
|
||||
* Set the servletPathMapping, the servletPath and the pathInfo.
|
||||
* TODO remove the side effect on servletPath and pathInfo by removing those fields.
|
||||
* @param servletPathMapping The mapping used to return from {@link #getHttpServletMapping()}
|
||||
*/
|
||||
public void setServletPathMapping(ServletPathMapping servletPathMapping)
|
||||
{
|
||||
_pathSpec = pathSpec;
|
||||
_servletPathMapping = servletPathMapping;
|
||||
if (servletPathMapping == null)
|
||||
{
|
||||
// TODO reset the servletPath and pathInfo, but currently cannot do that
|
||||
// as we don't know the pathInContext.
|
||||
}
|
||||
else
|
||||
{
|
||||
_servletPath = servletPathMapping.getServletPath();
|
||||
_pathInfo = servletPathMapping.getPathInfo();
|
||||
}
|
||||
}
|
||||
|
||||
public PathSpec getPathSpec()
|
||||
public ServletPathMapping getServletPathMapping()
|
||||
{
|
||||
return _pathSpec;
|
||||
return _servletPathMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpServletMapping getHttpServletMapping()
|
||||
{
|
||||
return Request.getServletMapping(_pathSpec, _servletPath, getServletName());
|
||||
return _servletPathMapping;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.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.server;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.util.AttributesMap;
|
||||
|
||||
/**
|
||||
* An implementation of Attributes that supports the standard async attributes.
|
||||
*
|
||||
* This implementation delegates to an internal {@link AttributesMap} instance, which
|
||||
* can optionally be wrapped with a {@link AsyncAttributes} instance. This allows async
|
||||
* attributes to be applied underneath any other attribute wrappers.
|
||||
*/
|
||||
public class ServletAttributes implements Attributes
|
||||
{
|
||||
private final Attributes _attributes = new AttributesMap();
|
||||
private AsyncAttributes _asyncAttributes;
|
||||
|
||||
public void setAsyncAttributes(String requestURI, String contextPath, String pathInContext, ServletPathMapping servletPathMapping, String queryString)
|
||||
{
|
||||
_asyncAttributes = new AsyncAttributes(_attributes, requestURI, contextPath, pathInContext, servletPathMapping, queryString);
|
||||
}
|
||||
|
||||
private Attributes getAttributes()
|
||||
{
|
||||
return (_asyncAttributes == null) ? _attributes : _asyncAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name)
|
||||
{
|
||||
getAttributes().removeAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, Object attribute)
|
||||
{
|
||||
getAttributes().setAttribute(name, attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String name)
|
||||
{
|
||||
return getAttributes().getAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAttributeNameSet()
|
||||
{
|
||||
return getAttributes().getAttributeNameSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAttributes()
|
||||
{
|
||||
getAttributes().clearAttributes();
|
||||
_asyncAttributes = null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.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.server;
|
||||
|
||||
import javax.servlet.http.HttpServletMapping;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.MappingMatch;
|
||||
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.http.pathmap.ServletPathSpec;
|
||||
|
||||
/**
|
||||
* Implementation of HttpServletMapping.
|
||||
*
|
||||
* Represents the application of a {@link ServletPathSpec} to a specific path
|
||||
* that resulted in a mapping to a {@link javax.servlet.Servlet}.
|
||||
* As well as supporting the standard {@link HttpServletMapping} methods, this
|
||||
* class also carries fields, which can be precomputed for the implementation
|
||||
* of {@link HttpServletRequest#getServletPath()} and
|
||||
* {@link HttpServletRequest#getPathInfo()}
|
||||
*/
|
||||
public class ServletPathMapping implements HttpServletMapping
|
||||
{
|
||||
private final MappingMatch _mappingMatch;
|
||||
private final String _matchValue;
|
||||
private final String _pattern;
|
||||
private final String _servletName;
|
||||
private final String _servletPath;
|
||||
private final String _pathInfo;
|
||||
|
||||
public ServletPathMapping(PathSpec pathSpec, String servletName, String pathInContext)
|
||||
{
|
||||
_servletName = (servletName == null ? "" : servletName);
|
||||
_pattern = pathSpec == null ? null : pathSpec.getDeclaration();
|
||||
|
||||
if (pathSpec instanceof ServletPathSpec && pathInContext != null)
|
||||
{
|
||||
switch (pathSpec.getGroup())
|
||||
{
|
||||
case ROOT:
|
||||
_mappingMatch = MappingMatch.CONTEXT_ROOT;
|
||||
_matchValue = "";
|
||||
_servletPath = "";
|
||||
_pathInfo = "/";
|
||||
break;
|
||||
|
||||
case DEFAULT:
|
||||
_mappingMatch = MappingMatch.DEFAULT;
|
||||
_matchValue = "";
|
||||
_servletPath = pathInContext;
|
||||
_pathInfo = null;
|
||||
break;
|
||||
|
||||
case EXACT:
|
||||
_mappingMatch = MappingMatch.EXACT;
|
||||
_matchValue = _pattern.startsWith("/") ? _pattern.substring(1) : _pattern;
|
||||
_servletPath = _pattern;
|
||||
_pathInfo = null;
|
||||
break;
|
||||
|
||||
case PREFIX_GLOB:
|
||||
_mappingMatch = MappingMatch.PATH;
|
||||
_servletPath = pathSpec.getPrefix();
|
||||
// TODO avoid the substring on the known servletPath!
|
||||
_matchValue = _servletPath.startsWith("/") ? _servletPath.substring(1) : _servletPath;
|
||||
_pathInfo = pathSpec.getPathInfo(pathInContext);
|
||||
break;
|
||||
|
||||
case SUFFIX_GLOB:
|
||||
_mappingMatch = MappingMatch.EXTENSION;
|
||||
int dot = pathInContext.lastIndexOf('.');
|
||||
_matchValue = pathInContext.substring(pathInContext.startsWith("/") ? 1 : 0, dot);
|
||||
_servletPath = pathInContext;
|
||||
_pathInfo = null;
|
||||
break;
|
||||
|
||||
case MIDDLE_GLOB:
|
||||
_mappingMatch = null;
|
||||
_matchValue = "";
|
||||
_servletPath = pathInContext;
|
||||
_pathInfo = null;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_mappingMatch = null;
|
||||
_matchValue = "";
|
||||
_servletPath = pathInContext;
|
||||
_pathInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMatchValue()
|
||||
{
|
||||
return _matchValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPattern()
|
||||
{
|
||||
return _pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServletName()
|
||||
{
|
||||
return _servletName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingMatch getMappingMatch()
|
||||
{
|
||||
return _mappingMatch;
|
||||
}
|
||||
|
||||
public String getServletPath()
|
||||
{
|
||||
return _servletPath;
|
||||
}
|
||||
|
||||
public String getPathInfo()
|
||||
{
|
||||
return _pathInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "ServletPathMapping{" +
|
||||
"matchValue=" + _matchValue +
|
||||
", pattern=" + _pattern +
|
||||
", servletName=" + _servletName +
|
||||
", mappingMatch=" + _mappingMatch +
|
||||
", servletPath=" + _servletPath +
|
||||
", pathInfo=" + _pathInfo +
|
||||
"}";
|
||||
}
|
||||
}
|
|
@ -173,11 +173,23 @@ public class ContextHandlerCollection extends HandlerCollection
|
|||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
Handlers handlers = _handlers.get();
|
||||
if (handlers == null)
|
||||
Mapping mapping = (Mapping)_handlers.get();
|
||||
|
||||
// Handle no contexts
|
||||
if (mapping == null)
|
||||
return;
|
||||
Handler[] handlers = mapping.getHandlers();
|
||||
if (handlers == null || handlers.length == 0)
|
||||
return;
|
||||
|
||||
Mapping mapping = (Mapping)handlers;
|
||||
// handle only a single context.
|
||||
if (handlers.length == 1)
|
||||
{
|
||||
handlers[0].handle(target, baseRequest, request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
// handle async dispatch to specific context
|
||||
HttpChannelState async = baseRequest.getHttpChannelState();
|
||||
if (async.isAsync())
|
||||
{
|
||||
|
@ -194,6 +206,7 @@ public class ContextHandlerCollection extends HandlerCollection
|
|||
}
|
||||
}
|
||||
|
||||
// handle many contexts
|
||||
if (target.startsWith("/"))
|
||||
{
|
||||
Trie<Map.Entry<String, Branch[]>> pathBranches = mapping._pathBranches;
|
||||
|
@ -226,11 +239,9 @@ public class ContextHandlerCollection extends HandlerCollection
|
|||
}
|
||||
else
|
||||
{
|
||||
if (mapping.getHandlers() == null)
|
||||
return;
|
||||
for (int i = 0; i < mapping.getHandlers().length; i++)
|
||||
for (Handler handler : handlers)
|
||||
{
|
||||
mapping.getHandlers()[i].handle(target, baseRequest, request, response);
|
||||
handler.handle(target, baseRequest, request, response);
|
||||
if (baseRequest.isHandled())
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -298,7 +298,7 @@ public class ErrorHandler extends AbstractHandler
|
|||
// TODO error page may cause a BufferOverflow. In which case we try
|
||||
// TODO again with stacks disabled. If it still overflows, it is
|
||||
// TODO written without a body.
|
||||
ByteBuffer buffer = baseRequest.getResponse().getHttpOutput().acquireBuffer();
|
||||
ByteBuffer buffer = baseRequest.getResponse().getHttpOutput().getBuffer();
|
||||
ByteBufferOutputStream out = new ByteBufferOutputStream(buffer);
|
||||
PrintWriter writer = new PrintWriter(new OutputStreamWriter(out, charset));
|
||||
|
||||
|
|
|
@ -467,7 +467,7 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
|
|||
{
|
||||
//only write the session out at this point if the attributes changed. If only
|
||||
//the lastAccess/expiry time changed defer the write until the last request exits
|
||||
if (session.getSessionData().isDirty() && _flushOnResponseCommit)
|
||||
if (session.isValid() && session.getSessionData().isDirty() && _flushOnResponseCommit)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Flush session {} on response commit", session);
|
||||
|
|
|
@ -66,9 +66,11 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
public static class SessionTableSchema
|
||||
{
|
||||
public static final int MAX_INTERVAL_NOT_SET = -999;
|
||||
public static final String INFERRED = "INFERRED";
|
||||
|
||||
protected DatabaseAdaptor _dbAdaptor;
|
||||
protected String _schemaName = null;
|
||||
protected String _catalogName = null;
|
||||
protected String _tableName = "JettySessions";
|
||||
protected String _idColumn = "sessionId";
|
||||
protected String _contextPathColumn = "contextPath";
|
||||
|
@ -87,7 +89,20 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
{
|
||||
_dbAdaptor = dbadaptor;
|
||||
}
|
||||
|
||||
public void setCatalogName(String catalogName)
|
||||
{
|
||||
if (catalogName != null && StringUtil.isBlank(catalogName))
|
||||
_catalogName = null;
|
||||
else
|
||||
_catalogName = catalogName;
|
||||
}
|
||||
|
||||
public String getCatalogName()
|
||||
{
|
||||
return _catalogName;
|
||||
}
|
||||
|
||||
public String getSchemaName()
|
||||
{
|
||||
return _schemaName;
|
||||
|
@ -95,8 +110,10 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
|
||||
public void setSchemaName(String schemaName)
|
||||
{
|
||||
checkNotNull(schemaName);
|
||||
_schemaName = schemaName;
|
||||
if (schemaName != null && StringUtil.isBlank(schemaName))
|
||||
_schemaName = null;
|
||||
else
|
||||
_schemaName = schemaName;
|
||||
}
|
||||
|
||||
public String getTableName()
|
||||
|
@ -484,28 +501,48 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
|
||||
//make the session table if necessary
|
||||
String tableName = _dbAdaptor.convertIdentifier(getTableName());
|
||||
|
||||
String schemaName = _dbAdaptor.convertIdentifier(getSchemaName());
|
||||
try (ResultSet result = metaData.getTables(null, schemaName, tableName, null))
|
||||
if (INFERRED.equalsIgnoreCase(schemaName))
|
||||
{
|
||||
//use the value from the connection -
|
||||
//NOTE that this value will also now be prepended to ALL
|
||||
//table names in queries/updates.
|
||||
schemaName = connection.getSchema();
|
||||
setSchemaName(schemaName);
|
||||
}
|
||||
String catalogName = _dbAdaptor.convertIdentifier(getCatalogName());
|
||||
if (INFERRED.equalsIgnoreCase(catalogName))
|
||||
{
|
||||
//use the value from the connection
|
||||
catalogName = connection.getCatalog();
|
||||
setCatalogName(catalogName);
|
||||
}
|
||||
|
||||
try (ResultSet result = metaData.getTables(catalogName, schemaName, tableName, null))
|
||||
{
|
||||
if (!result.next())
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Creating table {} schema={} catalog={}", tableName, schemaName, catalogName);
|
||||
//table does not exist, so create it
|
||||
statement.executeUpdate(getCreateStatementAsString());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Not creating table {} schema={} catalog={}", tableName, schemaName, catalogName);
|
||||
//session table exists, check it has maxinterval column
|
||||
ResultSet colResult = null;
|
||||
try
|
||||
{
|
||||
colResult = metaData.getColumns(null, schemaName, tableName,
|
||||
colResult = metaData.getColumns(catalogName, schemaName, tableName,
|
||||
_dbAdaptor.convertIdentifier(getMaxIntervalColumn()));
|
||||
}
|
||||
catch (SQLException sqlEx)
|
||||
{
|
||||
LOG.warn("Problem checking if " + getTableName() +
|
||||
" table contains " + getMaxIntervalColumn() + " column. Ensure table contains column definition: \"" +
|
||||
getMaxIntervalColumn() + " long not null default -999\"");
|
||||
LOG.warn("Problem checking if {} table contains {} column. Ensure table contains column with definition: long not null default -999",
|
||||
getTableName(), getMaxIntervalColumn());
|
||||
throw sqlEx;
|
||||
}
|
||||
try
|
||||
|
@ -519,9 +556,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
}
|
||||
catch (SQLException sqlEx)
|
||||
{
|
||||
LOG.warn("Problem adding " + getMaxIntervalColumn() +
|
||||
" column. Ensure table contains column definition: \"" + getMaxIntervalColumn() +
|
||||
" long not null default -999\"");
|
||||
LOG.warn("Problem adding {} column. Ensure table contains column definition: long not null default -999", getMaxIntervalColumn());
|
||||
throw sqlEx;
|
||||
}
|
||||
}
|
||||
|
@ -538,7 +573,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
|
||||
boolean index1Exists = false;
|
||||
boolean index2Exists = false;
|
||||
try (ResultSet result = metaData.getIndexInfo(null, schemaName, tableName, false, true))
|
||||
try (ResultSet result = metaData.getIndexInfo(catalogName, schemaName, tableName, false, true))
|
||||
{
|
||||
while (result.next())
|
||||
{
|
||||
|
@ -559,8 +594,8 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s[%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s]", super.toString(),
|
||||
_schemaName, _tableName, _idColumn, _contextPathColumn, _virtualHostColumn, _cookieTimeColumn, _createTimeColumn,
|
||||
return String.format("%s[%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s]", super.toString(),
|
||||
_catalogName, _schemaName, _tableName, _idColumn, _contextPathColumn, _virtualHostColumn, _cookieTimeColumn, _createTimeColumn,
|
||||
_expiryTimeColumn, _accessTimeColumn, _lastAccessTimeColumn, _lastNodeColumn, _lastSavedTimeColumn, _maxIntervalColumn);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ import javax.servlet.http.HttpServletMapping;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.MappingMatch;
|
||||
import javax.servlet.http.Part;
|
||||
import javax.servlet.http.PushBuilder;
|
||||
|
||||
|
@ -86,6 +87,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
@ -1427,69 +1429,6 @@ public class RequestTest
|
|||
assertThat(response, containsString("Hello World"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpServletMapping() throws Exception
|
||||
{
|
||||
String request = "GET / HTTP/1.1\n" +
|
||||
"Host: whatever\n" +
|
||||
"Connection: close\n" +
|
||||
"\n";
|
||||
|
||||
_server.stop();
|
||||
PathMappingHandler handler = new PathMappingHandler(null, null, null);
|
||||
_server.setHandler(handler);
|
||||
_server.start();
|
||||
String response = _connector.getResponse(request);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat("Response body content", response, containsString("HttpServletMapping{matchValue=, pattern=, servletName=, mappingMatch=null}"));
|
||||
_server.stop();
|
||||
|
||||
ServletPathSpec spec = new ServletPathSpec("");
|
||||
handler = new PathMappingHandler(spec, spec.getPathMatch("foo"), "Something");
|
||||
_server.setHandler(handler);
|
||||
_server.start();
|
||||
response = _connector.getResponse(request);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat("Response body content", response, containsString("HttpServletMapping{matchValue=, pattern=, servletName=Something, mappingMatch=CONTEXT_ROOT}"));
|
||||
_server.stop();
|
||||
|
||||
spec = new ServletPathSpec("/");
|
||||
handler = new PathMappingHandler(spec, "", "Default");
|
||||
_server.setHandler(handler);
|
||||
_server.start();
|
||||
response = _connector.getResponse(request);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat("Response body content", response, containsString("HttpServletMapping{matchValue=/, pattern=/, servletName=Default, mappingMatch=DEFAULT}"));
|
||||
_server.stop();
|
||||
|
||||
spec = new ServletPathSpec("/foo/*");
|
||||
handler = new PathMappingHandler(spec, spec.getPathMatch("/foo/bar"), "BarServlet");
|
||||
_server.setHandler(handler);
|
||||
_server.start();
|
||||
response = _connector.getResponse(request);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat("Response body content", response, containsString("HttpServletMapping{matchValue=/foo, pattern=/foo/*, servletName=BarServlet, mappingMatch=PATH}"));
|
||||
_server.stop();
|
||||
|
||||
spec = new ServletPathSpec("*.jsp");
|
||||
handler = new PathMappingHandler(spec, spec.getPathMatch("/foo/bar.jsp"), "JspServlet");
|
||||
_server.setHandler(handler);
|
||||
_server.start();
|
||||
response = _connector.getResponse(request);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat("Response body content", response, containsString("HttpServletMapping{matchValue=/foo/bar, pattern=*.jsp, servletName=JspServlet, mappingMatch=EXTENSION}"));
|
||||
_server.stop();
|
||||
|
||||
spec = new ServletPathSpec("/catalog");
|
||||
handler = new PathMappingHandler(spec, spec.getPathMatch("/catalog"), "CatalogServlet");
|
||||
_server.setHandler(handler);
|
||||
_server.start();
|
||||
response = _connector.getResponse(request);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat("Response body content", response, containsString("HttpServletMapping{matchValue=catalog, pattern=/catalog, servletName=CatalogServlet, mappingMatch=EXACT}"));
|
||||
_server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCookies() throws Exception
|
||||
{
|
||||
|
@ -1935,6 +1874,92 @@ public class RequestTest
|
|||
assertThat(builder.getHeader("Cookie"), not(containsString("bad")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServletPathMapping() throws Exception
|
||||
{
|
||||
ServletPathSpec spec;
|
||||
String uri;
|
||||
ServletPathMapping m;
|
||||
|
||||
spec = null;
|
||||
uri = null;
|
||||
m = new ServletPathMapping(spec, null, uri);
|
||||
assertThat(m.getMappingMatch(), nullValue());
|
||||
assertThat(m.getMatchValue(), is(""));
|
||||
assertThat(m.getPattern(), nullValue());
|
||||
assertThat(m.getServletName(), is(""));
|
||||
assertThat(m.getServletPath(), nullValue());
|
||||
assertThat(m.getPathInfo(), nullValue());
|
||||
|
||||
spec = new ServletPathSpec("");
|
||||
uri = "/";
|
||||
m = new ServletPathMapping(spec, "Something", uri);
|
||||
assertThat(m.getMappingMatch(), is(MappingMatch.CONTEXT_ROOT));
|
||||
assertThat(m.getMatchValue(), is(""));
|
||||
assertThat(m.getPattern(), is(""));
|
||||
assertThat(m.getServletName(), is("Something"));
|
||||
assertThat(m.getServletPath(), is(spec.getPathMatch(uri)));
|
||||
assertThat(m.getPathInfo(), is(spec.getPathInfo(uri)));
|
||||
|
||||
spec = new ServletPathSpec("/");
|
||||
uri = "/some/path";
|
||||
m = new ServletPathMapping(spec, "Default", uri);
|
||||
assertThat(m.getMappingMatch(), is(MappingMatch.DEFAULT));
|
||||
assertThat(m.getMatchValue(), is(""));
|
||||
assertThat(m.getPattern(), is("/"));
|
||||
assertThat(m.getServletName(), is("Default"));
|
||||
assertThat(m.getServletPath(), is(spec.getPathMatch(uri)));
|
||||
assertThat(m.getPathInfo(), is(spec.getPathInfo(uri)));
|
||||
|
||||
spec = new ServletPathSpec("/foo/*");
|
||||
uri = "/foo/bar";
|
||||
m = new ServletPathMapping(spec, "FooServlet", uri);
|
||||
assertThat(m.getMappingMatch(), is(MappingMatch.PATH));
|
||||
assertThat(m.getMatchValue(), is("foo"));
|
||||
assertThat(m.getPattern(), is("/foo/*"));
|
||||
assertThat(m.getServletName(), is("FooServlet"));
|
||||
assertThat(m.getServletPath(), is(spec.getPathMatch(uri)));
|
||||
assertThat(m.getPathInfo(), is(spec.getPathInfo(uri)));
|
||||
|
||||
uri = "/foo/";
|
||||
m = new ServletPathMapping(spec, "FooServlet", uri);
|
||||
assertThat(m.getMappingMatch(), is(MappingMatch.PATH));
|
||||
assertThat(m.getMatchValue(), is("foo"));
|
||||
assertThat(m.getPattern(), is("/foo/*"));
|
||||
assertThat(m.getServletName(), is("FooServlet"));
|
||||
assertThat(m.getServletPath(), is(spec.getPathMatch(uri)));
|
||||
assertThat(m.getPathInfo(), is(spec.getPathInfo(uri)));
|
||||
|
||||
uri = "/foo";
|
||||
m = new ServletPathMapping(spec, "FooServlet", uri);
|
||||
assertThat(m.getMappingMatch(), is(MappingMatch.PATH));
|
||||
assertThat(m.getMatchValue(), is("foo"));
|
||||
assertThat(m.getPattern(), is("/foo/*"));
|
||||
assertThat(m.getServletName(), is("FooServlet"));
|
||||
assertThat(m.getServletPath(), is(spec.getPathMatch(uri)));
|
||||
assertThat(m.getPathInfo(), is(spec.getPathInfo(uri)));
|
||||
|
||||
spec = new ServletPathSpec("*.jsp");
|
||||
uri = "/foo/bar.jsp";
|
||||
m = new ServletPathMapping(spec, "JspServlet", uri);
|
||||
assertThat(m.getMappingMatch(), is(MappingMatch.EXTENSION));
|
||||
assertThat(m.getMatchValue(), is("foo/bar"));
|
||||
assertThat(m.getPattern(), is("*.jsp"));
|
||||
assertThat(m.getServletName(), is("JspServlet"));
|
||||
assertThat(m.getServletPath(), is(spec.getPathMatch(uri)));
|
||||
assertThat(m.getPathInfo(), is(spec.getPathInfo(uri)));
|
||||
|
||||
spec = new ServletPathSpec("/catalog");
|
||||
uri = "/catalog";
|
||||
m = new ServletPathMapping(spec, "CatalogServlet", uri);
|
||||
assertThat(m.getMappingMatch(), is(MappingMatch.EXACT));
|
||||
assertThat(m.getMatchValue(), is("catalog"));
|
||||
assertThat(m.getPattern(), is("/catalog"));
|
||||
assertThat(m.getServletName(), is("CatalogServlet"));
|
||||
assertThat(m.getServletPath(), is(spec.getPathMatch(uri)));
|
||||
assertThat(m.getPathInfo(), is(spec.getPathInfo(uri)));
|
||||
}
|
||||
|
||||
interface RequestTester
|
||||
{
|
||||
boolean check(HttpServletRequest request, HttpServletResponse response) throws IOException;
|
||||
|
@ -2169,7 +2194,6 @@ public class RequestTest
|
|||
{
|
||||
((Request)request).setHandled(true);
|
||||
baseRequest.setServletPath(_servletPath);
|
||||
baseRequest.setPathSpec(_spec);
|
||||
if (_servletName != null)
|
||||
baseRequest.setUserIdentityScope(new TestUserIdentityScope(null, null, _servletName));
|
||||
HttpServletMapping mapping = baseRequest.getHttpServletMapping();
|
||||
|
|
|
@ -35,7 +35,6 @@ import org.eclipse.jetty.http.HttpContent;
|
|||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.PreEncodedHttpField;
|
||||
import org.eclipse.jetty.http.pathmap.MappedResource;
|
||||
import org.eclipse.jetty.server.CachedContentFactory;
|
||||
import org.eclipse.jetty.server.ResourceContentFactory;
|
||||
import org.eclipse.jetty.server.ResourceService;
|
||||
|
@ -500,9 +499,9 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
|
|||
|
||||
if ((_welcomeServlets || _welcomeExactServlets) && welcomeServlet == null)
|
||||
{
|
||||
MappedResource<ServletHolder> entry = _servletHandler.getMappedServlet(welcomeInContext);
|
||||
ServletHandler.MappedServlet entry = _servletHandler.getMappedServlet(welcomeInContext);
|
||||
@SuppressWarnings("ReferenceEquality")
|
||||
boolean isDefaultHolder = (entry.getResource() != _defaultHolder);
|
||||
boolean isDefaultHolder = (entry.getServletHolder() != _defaultHolder);
|
||||
if (entry != null && isDefaultHolder &&
|
||||
(_welcomeServlets || (_welcomeExactServlets && entry.getPathSpec().getDeclaration().equals(welcomeInContext))))
|
||||
welcomeServlet = welcomeInContext;
|
||||
|
|
|
@ -31,7 +31,6 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.pathmap.MappedResource;
|
||||
import org.eclipse.jetty.server.Dispatcher;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
|
@ -71,7 +70,7 @@ public class Invoker extends HttpServlet
|
|||
|
||||
private ContextHandler _contextHandler;
|
||||
private ServletHandler _servletHandler;
|
||||
private MappedResource<ServletHolder> _invokerEntry;
|
||||
private ServletHandler.MappedServlet _invokerEntry;
|
||||
private Map<String, String> _parameters;
|
||||
private boolean _nonContextServlets;
|
||||
private boolean _verbose;
|
||||
|
@ -171,12 +170,12 @@ public class Invoker extends HttpServlet
|
|||
|
||||
// Check for existing mapping (avoid threaded race).
|
||||
String path = URIUtil.addPaths(servletPath, servlet);
|
||||
MappedResource<ServletHolder> entry = _servletHandler.getMappedServlet(path);
|
||||
ServletHandler.MappedServlet entry = _servletHandler.getMappedServlet(path);
|
||||
|
||||
if (entry != null && !entry.equals(_invokerEntry))
|
||||
{
|
||||
// Use the holder
|
||||
holder = (ServletHolder)entry.getResource();
|
||||
holder = (ServletHolder)entry.getServletHolder();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.util.EnumSet;
|
|||
import java.util.EventListener;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
@ -57,6 +56,7 @@ import org.eclipse.jetty.http.pathmap.ServletPathSpec;
|
|||
import org.eclipse.jetty.security.IdentityService;
|
||||
import org.eclipse.jetty.security.SecurityHandler;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.ServletPathMapping;
|
||||
import org.eclipse.jetty.server.ServletRequestHttpWrapper;
|
||||
import org.eclipse.jetty.server.ServletResponseHttpWrapper;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
|
@ -92,8 +92,6 @@ public class ServletHandler extends ScopedHandler
|
|||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ServletHandler.class);
|
||||
|
||||
public static final String __DEFAULT_SERVLET = "default";
|
||||
|
||||
private ServletContextHandler _contextHandler;
|
||||
private ServletContext _servletContext;
|
||||
private FilterHolder[] _filters = new FilterHolder[0];
|
||||
|
@ -113,8 +111,8 @@ public class ServletHandler extends ScopedHandler
|
|||
private List<FilterMapping> _filterPathMappings;
|
||||
private MultiMap<FilterMapping> _filterNameMappings;
|
||||
|
||||
private final Map<String, ServletHolder> _servletNameMap = new HashMap<>();
|
||||
private PathMappings<ServletHolder> _servletPathMap;
|
||||
private final Map<String, MappedServlet> _servletNameMap = new HashMap<>();
|
||||
private PathMappings<MappedServlet> _servletPathMap;
|
||||
|
||||
private ListenerHolder[] _listeners = new ListenerHolder[0];
|
||||
private boolean _initialized = false;
|
||||
|
@ -167,7 +165,7 @@ public class ServletHandler extends ScopedHandler
|
|||
LOG.debug("Adding Default404Servlet to {}", this);
|
||||
addServletWithMapping(Default404Servlet.class, "/");
|
||||
updateMappings();
|
||||
getServletMapping("/").setDefault(true);
|
||||
getServletMapping("/").setFromDefaultDescriptor(true);
|
||||
}
|
||||
|
||||
if (isFilterChainsCached())
|
||||
|
@ -247,13 +245,7 @@ public class ServletHandler extends ScopedHandler
|
|||
//remove all of the mappings that were for non-embedded filters
|
||||
_filterNameMap.remove(filter.getName());
|
||||
//remove any mappings associated with this filter
|
||||
ListIterator<FilterMapping> fmitor = filterMappings.listIterator();
|
||||
while (fmitor.hasNext())
|
||||
{
|
||||
FilterMapping fm = fmitor.next();
|
||||
if (fm.getFilterName().equals(filter.getName()))
|
||||
fmitor.remove();
|
||||
}
|
||||
filterMappings.removeIf(fm -> fm.getFilterName().equals(filter.getName()));
|
||||
}
|
||||
else
|
||||
filterHolders.add(filter); //only retain embedded
|
||||
|
@ -261,10 +253,8 @@ public class ServletHandler extends ScopedHandler
|
|||
}
|
||||
|
||||
//Retain only filters and mappings that were added using jetty api (ie Source.EMBEDDED)
|
||||
FilterHolder[] fhs = (FilterHolder[])LazyList.toArray(filterHolders, FilterHolder.class);
|
||||
_filters = fhs;
|
||||
FilterMapping[] fms = (FilterMapping[])LazyList.toArray(filterMappings, FilterMapping.class);
|
||||
_filterMappings = fms;
|
||||
_filters = (FilterHolder[])LazyList.toArray(filterHolders, FilterHolder.class);
|
||||
_filterMappings = (FilterMapping[])LazyList.toArray(filterMappings, FilterMapping.class);
|
||||
|
||||
_matchAfterIndex = (_filterMappings == null || _filterMappings.length == 0 ? -1 : _filterMappings.length - 1);
|
||||
_matchBeforeIndex = -1;
|
||||
|
@ -291,13 +281,7 @@ public class ServletHandler extends ScopedHandler
|
|||
//remove from servlet name map
|
||||
_servletNameMap.remove(servlet.getName());
|
||||
//remove any mappings associated with this servlet
|
||||
ListIterator<ServletMapping> smitor = servletMappings.listIterator();
|
||||
while (smitor.hasNext())
|
||||
{
|
||||
ServletMapping sm = smitor.next();
|
||||
if (sm.getServletName().equals(servlet.getName()))
|
||||
smitor.remove();
|
||||
}
|
||||
servletMappings.removeIf(sm -> sm.getServletName().equals(servlet.getName()));
|
||||
}
|
||||
else
|
||||
servletHolders.add(servlet); //only retain embedded
|
||||
|
@ -305,10 +289,8 @@ public class ServletHandler extends ScopedHandler
|
|||
}
|
||||
|
||||
//Retain only Servlets and mappings added via jetty apis (ie Source.EMBEDDED)
|
||||
ServletHolder[] shs = (ServletHolder[])LazyList.toArray(servletHolders, ServletHolder.class);
|
||||
_servlets = shs;
|
||||
ServletMapping[] sms = (ServletMapping[])LazyList.toArray(servletMappings, ServletMapping.class);
|
||||
_servletMappings = sms;
|
||||
_servlets = (ServletHolder[])LazyList.toArray(servletHolders, ServletHolder.class);
|
||||
_servletMappings = (ServletMapping[])LazyList.toArray(servletMappings, ServletMapping.class);
|
||||
|
||||
if (_contextHandler != null)
|
||||
_contextHandler.contextDestroyed();
|
||||
|
@ -332,8 +314,7 @@ public class ServletHandler extends ScopedHandler
|
|||
listenerHolders.add(listener);
|
||||
}
|
||||
}
|
||||
ListenerHolder[] listeners = (ListenerHolder[])LazyList.toArray(listenerHolders, ListenerHolder.class);
|
||||
_listeners = listeners;
|
||||
_listeners = (ListenerHolder[])LazyList.toArray(listenerHolders, ListenerHolder.class);
|
||||
|
||||
//will be regenerated on next start
|
||||
_filterPathMappings = null;
|
||||
|
@ -425,50 +406,40 @@ public class ServletHandler extends ScopedHandler
|
|||
|
||||
public ServletHolder getServlet(String name)
|
||||
{
|
||||
return _servletNameMap.get(name);
|
||||
MappedServlet mapped = _servletNameMap.get(name);
|
||||
if (mapped != null)
|
||||
return mapped.getServletHolder();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
// Get the base requests
|
||||
final String old_servlet_path = baseRequest.getServletPath();
|
||||
final String old_path_info = baseRequest.getPathInfo();
|
||||
final PathSpec old_path_spec = baseRequest.getPathSpec();
|
||||
final ServletPathMapping old_servlet_path_mapping = baseRequest.getServletPathMapping();
|
||||
|
||||
DispatcherType type = baseRequest.getDispatcherType();
|
||||
|
||||
ServletHolder servletHolder = null;
|
||||
UserIdentity.Scope oldScope = null;
|
||||
|
||||
MappedResource<ServletHolder> mapping = getMappedServlet(target);
|
||||
if (mapping != null)
|
||||
MappedServlet mappedServlet = getMappedServlet(target);
|
||||
if (mappedServlet != null)
|
||||
{
|
||||
servletHolder = mapping.getResource();
|
||||
|
||||
if (mapping.getPathSpec() != null)
|
||||
servletHolder = mappedServlet.getServletHolder();
|
||||
ServletPathMapping servletPathMapping = mappedServlet.getServletPathMapping(target);
|
||||
if (servletPathMapping != null)
|
||||
{
|
||||
PathSpec pathSpec = mapping.getPathSpec();
|
||||
String servletPath = pathSpec.getPathMatch(target);
|
||||
String pathInfo = pathSpec.getPathInfo(target);
|
||||
|
||||
// Setting the servletPathMapping also provides the servletPath and pathInfo
|
||||
if (DispatcherType.INCLUDE.equals(type))
|
||||
{
|
||||
baseRequest.setAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH, servletPath);
|
||||
baseRequest.setAttribute(RequestDispatcher.INCLUDE_PATH_INFO, pathInfo);
|
||||
baseRequest.setAttribute(RequestDispatcher.INCLUDE_MAPPING, Request.getServletMapping(pathSpec, servletPath, servletHolder.getName()));
|
||||
}
|
||||
baseRequest.setAttribute(RequestDispatcher.INCLUDE_MAPPING, servletPathMapping);
|
||||
else
|
||||
{
|
||||
baseRequest.setPathSpec(pathSpec);
|
||||
baseRequest.setServletPath(servletPath);
|
||||
baseRequest.setPathInfo(pathInfo);
|
||||
}
|
||||
baseRequest.setServletPathMapping(servletPathMapping);
|
||||
}
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("servlet {}|{}|{} -> {}", baseRequest.getContextPath(), baseRequest.getServletPath(), baseRequest.getPathInfo(), servletHolder);
|
||||
LOG.debug("servlet {}|{}|{}|{} -> {}", baseRequest.getContextPath(), baseRequest.getServletPath(), baseRequest.getPathInfo(), baseRequest.getHttpServletMapping(), servletHolder);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -484,11 +455,7 @@ public class ServletHandler extends ScopedHandler
|
|||
baseRequest.setUserIdentityScope(oldScope);
|
||||
|
||||
if (!(DispatcherType.INCLUDE.equals(type)))
|
||||
{
|
||||
baseRequest.setServletPath(old_servlet_path);
|
||||
baseRequest.setPathInfo(old_path_info);
|
||||
baseRequest.setPathSpec(old_path_spec);
|
||||
}
|
||||
baseRequest.setServletPathMapping(old_servlet_path_mapping);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -550,34 +517,33 @@ public class ServletHandler extends ScopedHandler
|
|||
}
|
||||
|
||||
/**
|
||||
* ServletHolder matching path.
|
||||
* Get MappedServlet for target.
|
||||
*
|
||||
* @param target Path within _context or servlet name
|
||||
* @return MappedResource to the ServletHolder. Named servlets have a null PathSpec
|
||||
* @return MappedServlet matched by path or name. Named servlets have a null PathSpec
|
||||
*/
|
||||
public MappedResource<ServletHolder> getMappedServlet(String target)
|
||||
public MappedServlet getMappedServlet(String target)
|
||||
{
|
||||
if (target.startsWith("/"))
|
||||
{
|
||||
if (_servletPathMap == null)
|
||||
return null;
|
||||
return _servletPathMap.getMatch(target);
|
||||
|
||||
MappedResource<MappedServlet> match = _servletPathMap.getMatch(target);
|
||||
if (match == null)
|
||||
return null;
|
||||
return match.getResource();
|
||||
}
|
||||
|
||||
if (_servletNameMap == null)
|
||||
return null;
|
||||
ServletHolder holder = _servletNameMap.get(target);
|
||||
if (holder == null)
|
||||
return null;
|
||||
return new MappedResource<>(null, holder);
|
||||
return _servletNameMap.get(target);
|
||||
}
|
||||
|
||||
protected FilterChain getFilterChain(Request baseRequest, String pathInContext, ServletHolder servletHolder)
|
||||
private FilterChain getFilterChain(Request baseRequest, String pathInContext, ServletHolder servletHolder)
|
||||
{
|
||||
String key = pathInContext == null ? servletHolder.getName() : pathInContext;
|
||||
int dispatch = FilterMapping.dispatch(baseRequest.getDispatcherType());
|
||||
|
||||
if (_filterChainsCached && _chainCache != null)
|
||||
if (_filterChainsCached)
|
||||
{
|
||||
FilterChain chain = _chainCache[dispatch].get(key);
|
||||
if (chain != null)
|
||||
|
@ -624,8 +590,7 @@ public class ServletHandler extends ScopedHandler
|
|||
FilterChain chain = null;
|
||||
if (_filterChainsCached)
|
||||
{
|
||||
if (!filters.isEmpty())
|
||||
chain = newCachedChain(filters, servletHolder);
|
||||
chain = newCachedChain(filters, servletHolder);
|
||||
|
||||
final Map<String, FilterChain> cache = _chainCache[dispatch];
|
||||
final Queue<String> lru = _chainLRU[dispatch];
|
||||
|
@ -648,7 +613,7 @@ public class ServletHandler extends ScopedHandler
|
|||
cache.put(key, chain);
|
||||
lru.add(key);
|
||||
}
|
||||
else if (!filters.isEmpty())
|
||||
else
|
||||
chain = new Chain(baseRequest, filters, servletHolder);
|
||||
|
||||
return chain;
|
||||
|
@ -1133,7 +1098,7 @@ public class ServletHandler extends ScopedHandler
|
|||
if (mappings == null || mappings.length == 0)
|
||||
{
|
||||
setFilterMappings(insertFilterMapping(mapping, 0, false));
|
||||
if (source != null && source == Source.JAVAX_API)
|
||||
if (source == Source.JAVAX_API)
|
||||
_matchAfterIndex = 0;
|
||||
}
|
||||
else
|
||||
|
@ -1141,7 +1106,7 @@ public class ServletHandler extends ScopedHandler
|
|||
//there are existing entries. If this is a programmatic filtermapping, it is added at the end of the list.
|
||||
//If this is a normal filtermapping, it is inserted after all the other filtermappings (matchBefores and normals),
|
||||
//but before the first matchAfter filtermapping.
|
||||
if (source != null && Source.JAVAX_API == source)
|
||||
if (Source.JAVAX_API == source)
|
||||
{
|
||||
setFilterMappings(insertFilterMapping(mapping, mappings.length - 1, false));
|
||||
if (_matchAfterIndex < 0)
|
||||
|
@ -1177,12 +1142,12 @@ public class ServletHandler extends ScopedHandler
|
|||
if (mappings == null || mappings.length == 0)
|
||||
{
|
||||
setFilterMappings(insertFilterMapping(mapping, 0, false));
|
||||
if (source != null && Source.JAVAX_API == source)
|
||||
if (Source.JAVAX_API == source)
|
||||
_matchBeforeIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (source != null && Source.JAVAX_API == source)
|
||||
if (Source.JAVAX_API == source)
|
||||
{
|
||||
//programmatically defined filter mappings are prepended to mapping list in the order
|
||||
//in which they were defined. In other words, insert this mapping at the tail of the
|
||||
|
@ -1281,7 +1246,7 @@ public class ServletHandler extends ScopedHandler
|
|||
// update the maps
|
||||
for (ServletHolder servlet : _servlets)
|
||||
{
|
||||
_servletNameMap.put(servlet.getName(), servlet);
|
||||
_servletNameMap.put(servlet.getName(), new MappedServlet(null, servlet));
|
||||
servlet.setServletHandler(this);
|
||||
}
|
||||
}
|
||||
|
@ -1321,13 +1286,13 @@ public class ServletHandler extends ScopedHandler
|
|||
}
|
||||
|
||||
// Map servlet paths to holders
|
||||
if (_servletMappings == null || _servletNameMap == null)
|
||||
if (_servletMappings == null)
|
||||
{
|
||||
_servletPathMap = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
PathMappings<ServletHolder> pm = new PathMappings<>();
|
||||
PathMappings<MappedServlet> pm = new PathMappings<>();
|
||||
|
||||
//create a map of paths to set of ServletMappings that define that mapping
|
||||
HashMap<String, List<ServletMapping>> sms = new HashMap<>();
|
||||
|
@ -1338,12 +1303,7 @@ public class ServletHandler extends ScopedHandler
|
|||
{
|
||||
for (String pathSpec : pathSpecs)
|
||||
{
|
||||
List<ServletMapping> mappings = sms.get(pathSpec);
|
||||
if (mappings == null)
|
||||
{
|
||||
mappings = new ArrayList<>();
|
||||
sms.put(pathSpec, mappings);
|
||||
}
|
||||
List<ServletMapping> mappings = sms.computeIfAbsent(pathSpec, k -> new ArrayList<>());
|
||||
mappings.add(servletMapping);
|
||||
}
|
||||
}
|
||||
|
@ -1360,7 +1320,7 @@ public class ServletHandler extends ScopedHandler
|
|||
for (ServletMapping mapping : mappings)
|
||||
{
|
||||
//Get servlet associated with the mapping and check it is enabled
|
||||
ServletHolder servletHolder = _servletNameMap.get(mapping.getServletName());
|
||||
ServletHolder servletHolder = getServlet(mapping.getServletName());
|
||||
if (servletHolder == null)
|
||||
throw new IllegalStateException("No such servlet: " + mapping.getServletName());
|
||||
//if the servlet related to the mapping is not enabled, skip it from consideration
|
||||
|
@ -1374,7 +1334,7 @@ public class ServletHandler extends ScopedHandler
|
|||
{
|
||||
//already have a candidate - only accept another one
|
||||
//if the candidate is a default, or we're allowing duplicate mappings
|
||||
if (finalMapping.isDefault())
|
||||
if (finalMapping.isFromDefaultDescriptor())
|
||||
finalMapping = mapping;
|
||||
else if (isAllowDuplicateMappings())
|
||||
{
|
||||
|
@ -1384,9 +1344,9 @@ public class ServletHandler extends ScopedHandler
|
|||
else
|
||||
{
|
||||
//existing candidate isn't a default, if the one we're looking at isn't a default either, then its an error
|
||||
if (!mapping.isDefault())
|
||||
if (!mapping.isFromDefaultDescriptor())
|
||||
{
|
||||
ServletHolder finalMappedServlet = _servletNameMap.get(finalMapping.getServletName());
|
||||
ServletHolder finalMappedServlet = getServlet(finalMapping.getServletName());
|
||||
throw new IllegalStateException("Multiple servlets map to path " +
|
||||
pathSpec + ": " +
|
||||
finalMappedServlet.getName() + "[mapped:" + finalMapping.getSource() + "]," +
|
||||
|
@ -1403,22 +1363,21 @@ public class ServletHandler extends ScopedHandler
|
|||
pathSpec,
|
||||
finalMapping.getSource(),
|
||||
finalMapping.getServletName(),
|
||||
_servletNameMap.get(finalMapping.getServletName()).getSource());
|
||||
getServlet(finalMapping.getServletName()).getSource());
|
||||
|
||||
pm.put(new ServletPathSpec(pathSpec), _servletNameMap.get(finalMapping.getServletName()));
|
||||
ServletPathSpec servletPathSpec = new ServletPathSpec(pathSpec);
|
||||
MappedServlet mappedServlet = new MappedServlet(servletPathSpec, getServlet(finalMapping.getServletName()));
|
||||
pm.put(servletPathSpec, mappedServlet);
|
||||
}
|
||||
|
||||
_servletPathMap = pm;
|
||||
}
|
||||
|
||||
// flush filter chain cache
|
||||
if (_chainCache != null)
|
||||
for (int i = _chainCache.length; i-- > 0; )
|
||||
{
|
||||
for (int i = _chainCache.length; i-- > 0; )
|
||||
{
|
||||
if (_chainCache[i] != null)
|
||||
_chainCache[i].clear();
|
||||
}
|
||||
if (_chainCache[i] != null)
|
||||
_chainCache[i].clear();
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
|
@ -1453,28 +1412,26 @@ public class ServletHandler extends ScopedHandler
|
|||
{
|
||||
if (_filters == null)
|
||||
return false;
|
||||
boolean found = false;
|
||||
for (FilterHolder f : _filters)
|
||||
{
|
||||
if (f == holder)
|
||||
found = true;
|
||||
return true;
|
||||
}
|
||||
return found;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected synchronized boolean containsServletHolder(ServletHolder holder)
|
||||
{
|
||||
if (_servlets == null)
|
||||
return false;
|
||||
boolean found = false;
|
||||
for (ServletHolder s : _servlets)
|
||||
{
|
||||
@SuppressWarnings("ReferenceEquality")
|
||||
boolean foundServletHolder = (s == holder);
|
||||
if (foundServletHolder)
|
||||
found = true;
|
||||
return true;
|
||||
}
|
||||
return found;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1731,6 +1688,68 @@ public class ServletHandler extends ScopedHandler
|
|||
_contextHandler.destroyListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* A mapping of a servlet by pathSpec or by name
|
||||
*/
|
||||
public static class MappedServlet
|
||||
{
|
||||
private final PathSpec _pathSpec;
|
||||
private final ServletHolder _servletHolder;
|
||||
private final ServletPathMapping _servletPathMapping;
|
||||
|
||||
MappedServlet(PathSpec pathSpec, ServletHolder servletHolder)
|
||||
{
|
||||
_pathSpec = pathSpec;
|
||||
_servletHolder = servletHolder;
|
||||
|
||||
// Create the HttpServletMapping only once if possible.
|
||||
if (pathSpec instanceof ServletPathSpec)
|
||||
{
|
||||
switch (pathSpec.getGroup())
|
||||
{
|
||||
case EXACT:
|
||||
case ROOT:
|
||||
_servletPathMapping = new ServletPathMapping(_pathSpec, _servletHolder.getName(), _pathSpec.getPrefix());
|
||||
break;
|
||||
default:
|
||||
_servletPathMapping = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_servletPathMapping = null;
|
||||
}
|
||||
}
|
||||
|
||||
public PathSpec getPathSpec()
|
||||
{
|
||||
return _pathSpec;
|
||||
}
|
||||
|
||||
public ServletHolder getServletHolder()
|
||||
{
|
||||
return _servletHolder;
|
||||
}
|
||||
|
||||
public ServletPathMapping getServletPathMapping(String pathInContext)
|
||||
{
|
||||
if (_servletPathMapping != null)
|
||||
return _servletPathMapping;
|
||||
if (_pathSpec != null)
|
||||
return new ServletPathMapping(_pathSpec, _servletHolder.getName(), pathInContext);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("MappedServlet%x{%s->%s}",
|
||||
hashCode(), _pathSpec == null ? null : _pathSpec.getDeclaration(), _servletHolder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class Default404Servlet extends HttpServlet
|
||||
{
|
||||
|
|
|
@ -918,7 +918,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
|
|||
if (mapping != null)
|
||||
{
|
||||
//if the servlet mapping was from a default descriptor, then allow it to be overridden
|
||||
if (!mapping.isDefault())
|
||||
if (!mapping.isFromDefaultDescriptor())
|
||||
{
|
||||
if (clash == null)
|
||||
clash = new HashSet<>();
|
||||
|
|
|
@ -104,12 +104,12 @@ public class ServletMapping
|
|||
}
|
||||
|
||||
@ManagedAttribute(value = "default", readonly = true)
|
||||
public boolean isDefault()
|
||||
public boolean isFromDefaultDescriptor()
|
||||
{
|
||||
return _default;
|
||||
}
|
||||
|
||||
public void setDefault(boolean fromDefault)
|
||||
public void setFromDefaultDescriptor(boolean fromDefault)
|
||||
{
|
||||
_default = fromDefault;
|
||||
}
|
||||
|
|
|
@ -257,7 +257,7 @@ public class AsyncContextTest
|
|||
assertThat("async run attr query string", responseBody, containsString("async:run:attr:queryString:dispatch=true"));
|
||||
assertThat("async run context path", responseBody, containsString("async:run:attr:contextPath:/ctx"));
|
||||
assertThat("async run request uri has correct encoding", responseBody, containsString("async:run:attr:requestURI:/ctx/test/hello%2fthere"));
|
||||
assertThat("http servlet mapping matchValue is correct", responseBody, containsString("async:run:attr:mapping:matchValue:/test"));
|
||||
assertThat("http servlet mapping matchValue is correct", responseBody, containsString("async:run:attr:mapping:matchValue:test"));
|
||||
assertThat("http servlet mapping pattern is correct", responseBody, containsString("async:run:attr:mapping:pattern:/test/*"));
|
||||
assertThat("http servlet mapping servletName is correct", responseBody, containsString("async:run:attr:mapping:servletName:"));
|
||||
assertThat("http servlet mapping mappingMatch is correct", responseBody, containsString("async:run:attr:mapping:mappingMatch:PATH"));
|
||||
|
|
|
@ -170,6 +170,43 @@ public class DispatcherTest
|
|||
assertEquals(expected, responses);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNamedForward() throws Exception
|
||||
{
|
||||
_contextHandler.addServlet(NamedForwardServlet.class, "/forward/*");
|
||||
String echo = _contextHandler.addServlet(EchoURIServlet.class, "/echo/*").getName();
|
||||
|
||||
String expected =
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Type: text/plain\r\n" +
|
||||
"Content-Length: 62\r\n" +
|
||||
"\r\n" +
|
||||
"/context\r\n" +
|
||||
"/forward\r\n" +
|
||||
"/info\r\n" +
|
||||
"/context/forward/info;param=value\r\n";
|
||||
String responses = _connector.getResponse("GET /context/forward/info;param=value?name=" + echo + " HTTP/1.0\n\n");
|
||||
assertEquals(expected, responses);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNamedInclude() throws Exception
|
||||
{
|
||||
_contextHandler.addServlet(NamedIncludeServlet.class, "/include/*");
|
||||
String echo = _contextHandler.addServlet(EchoURIServlet.class, "/echo/*").getName();
|
||||
|
||||
String expected =
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Length: 62\r\n" +
|
||||
"\r\n" +
|
||||
"/context\r\n" +
|
||||
"/include\r\n" +
|
||||
"/info\r\n" +
|
||||
"/context/include/info;param=value\r\n";
|
||||
String responses = _connector.getResponse("GET /context/include/info;param=value?name=" + echo + " HTTP/1.0\n\n");
|
||||
assertEquals(expected, responses);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForwardWithBadParams() throws Exception
|
||||
{
|
||||
|
@ -507,6 +544,24 @@ public class DispatcherTest
|
|||
}
|
||||
}
|
||||
|
||||
public static class NamedForwardServlet extends HttpServlet implements Servlet
|
||||
{
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
getServletContext().getNamedDispatcher(request.getParameter("name")).forward(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
public static class NamedIncludeServlet extends HttpServlet implements Servlet
|
||||
{
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
getServletContext().getNamedDispatcher(request.getParameter("name")).include(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ForwardNonUTF8Servlet extends HttpServlet implements Servlet
|
||||
{
|
||||
@Override
|
||||
|
@ -734,7 +789,7 @@ public class DispatcherTest
|
|||
assertEquals("do=assertforward&do=more&test=1", request.getAttribute(Dispatcher.FORWARD_QUERY_STRING));
|
||||
HttpServletMapping fwdMapping = (HttpServletMapping)request.getAttribute(Dispatcher.FORWARD_MAPPING);
|
||||
assertNotNull(fwdMapping);
|
||||
assertEquals("/ForwardServlet", fwdMapping.getMatchValue());
|
||||
assertEquals("ForwardServlet", fwdMapping.getMatchValue());
|
||||
|
||||
List<String> expectedAttributeNames = Arrays.asList(Dispatcher.FORWARD_REQUEST_URI, Dispatcher.FORWARD_CONTEXT_PATH,
|
||||
Dispatcher.FORWARD_SERVLET_PATH, Dispatcher.FORWARD_QUERY_STRING, Dispatcher.FORWARD_MAPPING);
|
||||
|
@ -769,7 +824,7 @@ public class DispatcherTest
|
|||
assertEquals("do=assertforward&foreign=%d2%e5%ec%ef%e5%f0%e0%f2%f3%f0%e0&test=1", request.getAttribute(Dispatcher.FORWARD_QUERY_STRING));
|
||||
HttpServletMapping fwdMapping = (HttpServletMapping)request.getAttribute(Dispatcher.FORWARD_MAPPING);
|
||||
assertNotNull(fwdMapping);
|
||||
assertEquals("/ForwardServlet", fwdMapping.getMatchValue());
|
||||
assertEquals("ForwardServlet", fwdMapping.getMatchValue());
|
||||
|
||||
List<String> expectedAttributeNames = Arrays.asList(Dispatcher.FORWARD_REQUEST_URI, Dispatcher.FORWARD_CONTEXT_PATH,
|
||||
Dispatcher.FORWARD_SERVLET_PATH, Dispatcher.FORWARD_QUERY_STRING, Dispatcher.FORWARD_MAPPING);
|
||||
|
@ -818,7 +873,7 @@ public class DispatcherTest
|
|||
assertEquals("do=end&do=the", request.getAttribute(Dispatcher.INCLUDE_QUERY_STRING));
|
||||
HttpServletMapping incMapping = (HttpServletMapping)request.getAttribute(Dispatcher.INCLUDE_MAPPING);
|
||||
assertNotNull(incMapping);
|
||||
assertEquals("/AssertIncludeServlet", incMapping.getMatchValue());
|
||||
assertEquals("AssertIncludeServlet", incMapping.getMatchValue());
|
||||
|
||||
List expectedAttributeNames = Arrays.asList(Dispatcher.INCLUDE_REQUEST_URI, Dispatcher.INCLUDE_CONTEXT_PATH,
|
||||
Dispatcher.INCLUDE_SERVLET_PATH, Dispatcher.INCLUDE_QUERY_STRING, Dispatcher.INCLUDE_MAPPING);
|
||||
|
@ -851,7 +906,7 @@ public class DispatcherTest
|
|||
assertEquals("do=include", request.getAttribute(Dispatcher.FORWARD_QUERY_STRING));
|
||||
HttpServletMapping fwdMapping = (HttpServletMapping)request.getAttribute(Dispatcher.FORWARD_MAPPING);
|
||||
assertNotNull(fwdMapping);
|
||||
assertEquals("/ForwardServlet", fwdMapping.getMatchValue());
|
||||
assertEquals("ForwardServlet", fwdMapping.getMatchValue());
|
||||
|
||||
assertEquals("/context/AssertForwardIncludeServlet/assertpath", request.getAttribute(Dispatcher.INCLUDE_REQUEST_URI));
|
||||
assertEquals("/context", request.getAttribute(Dispatcher.INCLUDE_CONTEXT_PATH));
|
||||
|
@ -860,7 +915,7 @@ public class DispatcherTest
|
|||
assertEquals("do=end", request.getAttribute(Dispatcher.INCLUDE_QUERY_STRING));
|
||||
HttpServletMapping incMapping = (HttpServletMapping)request.getAttribute(Dispatcher.INCLUDE_MAPPING);
|
||||
assertNotNull(incMapping);
|
||||
assertEquals("/AssertForwardIncludeServlet", incMapping.getMatchValue());
|
||||
assertEquals("AssertForwardIncludeServlet", incMapping.getMatchValue());
|
||||
|
||||
List expectedAttributeNames = Arrays.asList(Dispatcher.FORWARD_REQUEST_URI, Dispatcher.FORWARD_CONTEXT_PATH, Dispatcher.FORWARD_SERVLET_PATH,
|
||||
Dispatcher.FORWARD_PATH_INFO, Dispatcher.FORWARD_QUERY_STRING, Dispatcher.FORWARD_MAPPING,
|
||||
|
@ -902,7 +957,7 @@ public class DispatcherTest
|
|||
assertEquals("do=forward", request.getAttribute(Dispatcher.FORWARD_QUERY_STRING));
|
||||
HttpServletMapping fwdMapping = (HttpServletMapping)request.getAttribute(Dispatcher.FORWARD_MAPPING);
|
||||
assertNotNull(fwdMapping);
|
||||
assertEquals("/IncludeServlet", fwdMapping.getMatchValue());
|
||||
assertEquals("IncludeServlet", fwdMapping.getMatchValue());
|
||||
|
||||
List expectedAttributeNames = Arrays.asList(Dispatcher.FORWARD_REQUEST_URI, Dispatcher.FORWARD_CONTEXT_PATH, Dispatcher.FORWARD_SERVLET_PATH,
|
||||
Dispatcher.FORWARD_PATH_INFO, Dispatcher.FORWARD_QUERY_STRING, Dispatcher.FORWARD_MAPPING);
|
||||
|
|
|
@ -62,7 +62,6 @@ import javax.servlet.http.HttpSessionEvent;
|
|||
import javax.servlet.http.HttpSessionIdListener;
|
||||
import javax.servlet.http.HttpSessionListener;
|
||||
|
||||
import org.eclipse.jetty.http.pathmap.MappedResource;
|
||||
import org.eclipse.jetty.logging.StacklessLogging;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.RoleInfo;
|
||||
|
@ -1376,9 +1375,9 @@ public class ServletContextHandlerTest
|
|||
|
||||
root.addBean(new MySCIStarter(root.getServletContext(), new JSPAddingSCI()), true);
|
||||
_server.start();
|
||||
MappedResource<ServletHolder> mappedServlet = root.getServletHandler().getMappedServlet("/somejsp/xxx");
|
||||
assertNotNull(mappedServlet.getResource());
|
||||
assertEquals("some.jsp", mappedServlet.getResource().getName());
|
||||
ServletHandler.MappedServlet mappedServlet = root.getServletHandler().getMappedServlet("/somejsp/xxx");
|
||||
assertNotNull(mappedServlet.getServletHolder());
|
||||
assertEquals("some.jsp", mappedServlet.getServletHolder().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1452,9 +1451,9 @@ public class ServletContextHandlerTest
|
|||
|
||||
root.addBean(new MySCIStarter(root.getServletContext(), new JSPAddingSCI()), true);
|
||||
_server.start();
|
||||
MappedResource<ServletHolder> mappedServlet = root.getServletHandler().getMappedServlet("/bar/xxx");
|
||||
assertNotNull(mappedServlet.getResource());
|
||||
assertEquals("some.jsp", mappedServlet.getResource().getName());
|
||||
ServletHandler.MappedServlet mappedServlet = root.getServletHandler().getMappedServlet("/bar/xxx");
|
||||
assertNotNull(mappedServlet.getServletHolder());
|
||||
assertEquals("some.jsp", mappedServlet.getServletHolder().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -21,7 +21,6 @@ package org.eclipse.jetty.servlet;
|
|||
import java.util.EnumSet;
|
||||
import javax.servlet.DispatcherType;
|
||||
|
||||
import org.eclipse.jetty.http.pathmap.MappedResource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -79,17 +78,17 @@ public class ServletHandlerTest
|
|||
fm5.setFilterHolder(fh5);
|
||||
|
||||
sh1.setName("s1");
|
||||
sm1.setDefault(false);
|
||||
sm1.setFromDefaultDescriptor(false);
|
||||
sm1.setPathSpec("/foo/*");
|
||||
sm1.setServletName("s1");
|
||||
|
||||
sh2.setName("s2");
|
||||
sm2.setDefault(false);
|
||||
sm2.setFromDefaultDescriptor(false);
|
||||
sm2.setPathSpec("/foo/*");
|
||||
sm2.setServletName("s2");
|
||||
|
||||
sh3.setName("s3");
|
||||
sm3.setDefault(true);
|
||||
sm3.setFromDefaultDescriptor(true);
|
||||
sm3.setPathSpec("/foo/*");
|
||||
sm3.setServletName("s3");
|
||||
}
|
||||
|
@ -251,9 +250,9 @@ public class ServletHandlerTest
|
|||
|
||||
handler.updateMappings();
|
||||
|
||||
MappedResource<ServletHolder> entry = handler.getMappedServlet("/foo/*");
|
||||
ServletHandler.MappedServlet entry = handler.getMappedServlet("/foo/*");
|
||||
assertNotNull(entry);
|
||||
assertEquals("s1", entry.getResource().getName());
|
||||
assertEquals("s1", entry.getServletHolder().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -292,9 +291,9 @@ public class ServletHandlerTest
|
|||
handler.addServletMapping(sm2);
|
||||
handler.updateMappings();
|
||||
|
||||
MappedResource<ServletHolder> entry = handler.getMappedServlet("/foo/*");
|
||||
ServletHandler.MappedServlet entry = handler.getMappedServlet("/foo/*");
|
||||
assertNotNull(entry);
|
||||
assertEquals("s2", entry.getResource().getName());
|
||||
assertEquals("s2", entry.getServletHolder().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -4,16 +4,35 @@
|
|||
<artifactId>jetty-project</artifactId>
|
||||
<version>10.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-slf4j-impl</artifactId>
|
||||
<name>Jetty :: Slf4j Implementation</name>
|
||||
<description>Slf4j Logging Implementation based on Jetty's older StdErrLog</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.logging</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<compilerArgs>
|
||||
<arg>--add-modules</arg>
|
||||
<arg>java.management</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>
|
||||
@{argLine} ${jetty.surefire.argLine} --add-reads org.eclipse.jetty.logging=java.management
|
||||
</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
|
@ -29,15 +48,17 @@
|
|||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.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.logging;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.slf4j.event.Level;
|
||||
|
||||
public enum JettyLevel
|
||||
{
|
||||
// Intentionally sorted incrementally by level int
|
||||
ALL(Level.TRACE.toInt() - 10),
|
||||
TRACE(Level.TRACE),
|
||||
DEBUG(Level.DEBUG),
|
||||
INFO(Level.INFO),
|
||||
WARN(Level.WARN),
|
||||
ERROR(Level.ERROR),
|
||||
OFF(Level.ERROR.toInt() + 1);
|
||||
|
||||
private final Level level;
|
||||
private final int levelInt;
|
||||
|
||||
JettyLevel(Level level)
|
||||
{
|
||||
this.level = level;
|
||||
this.levelInt = level.toInt();
|
||||
}
|
||||
|
||||
JettyLevel(int i)
|
||||
{
|
||||
this.level = null;
|
||||
this.levelInt = i;
|
||||
}
|
||||
|
||||
public static JettyLevel fromLevel(Level slf4jLevel)
|
||||
{
|
||||
for (JettyLevel level : JettyLevel.values())
|
||||
{
|
||||
if (slf4jLevel.toInt() == level.levelInt)
|
||||
return level;
|
||||
}
|
||||
return OFF;
|
||||
}
|
||||
|
||||
public int toInt()
|
||||
{
|
||||
return levelInt;
|
||||
}
|
||||
|
||||
public Level toLevel()
|
||||
{
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a provided level is included by the level value of this level.
|
||||
*
|
||||
* @param testLevel the level to test against.
|
||||
* @return true if includes this includes the test level.
|
||||
*/
|
||||
public boolean includes(JettyLevel testLevel)
|
||||
{
|
||||
return (this.levelInt <= testLevel.levelInt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return name();
|
||||
}
|
||||
|
||||
public static JettyLevel intToLevel(int levelInt)
|
||||
{
|
||||
for (JettyLevel level : JettyLevel.values())
|
||||
{
|
||||
if (levelInt <= level.levelInt)
|
||||
return level;
|
||||
}
|
||||
return OFF;
|
||||
}
|
||||
|
||||
public static JettyLevel strToLevel(String levelStr)
|
||||
{
|
||||
if (levelStr == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
String levelName = levelStr.trim().toUpperCase(Locale.ENGLISH);
|
||||
for (JettyLevel level : JettyLevel.values())
|
||||
{
|
||||
if (level.name().equals(levelName))
|
||||
return level;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.logging;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.Marker;
|
||||
import org.slf4j.event.Level;
|
||||
|
@ -29,37 +27,130 @@ import org.slf4j.spi.LocationAwareLogger;
|
|||
|
||||
public class JettyLogger implements LocationAwareLogger, Logger
|
||||
{
|
||||
/**
|
||||
* The Level to set if you want this logger to be "OFF"
|
||||
*/
|
||||
public static final int OFF = 999;
|
||||
/**
|
||||
* The Level to set if you want this logger to show all events from all levels.
|
||||
*/
|
||||
public static final int ALL = -1;
|
||||
|
||||
private final JettyLoggerFactory factory;
|
||||
private final String name;
|
||||
private final String condensedName;
|
||||
private final JettyAppender appender;
|
||||
private int level;
|
||||
private boolean hideStacks = false;
|
||||
private JettyLevel level;
|
||||
private boolean hideStacks;
|
||||
|
||||
public JettyLogger(JettyLoggerFactory factory, String name, JettyAppender appender)
|
||||
{
|
||||
this(factory, name, appender, Level.INFO.toInt(), false);
|
||||
this(factory, name, appender, JettyLevel.INFO, false);
|
||||
}
|
||||
|
||||
public JettyLogger(JettyLoggerFactory factory, String name, JettyAppender appender, int level, boolean hideStacks)
|
||||
public JettyLogger(JettyLoggerFactory factory, String name, JettyAppender appender, JettyLevel level, boolean hideStacks)
|
||||
{
|
||||
this.factory = factory;
|
||||
this.name = name;
|
||||
this.condensedName = JettyLoggerFactory.condensePackageString(name);
|
||||
this.condensedName = condensePackageString(name);
|
||||
this.appender = appender;
|
||||
this.level = level;
|
||||
this.hideStacks = hideStacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Condenses a classname by stripping down the package name to just the first character of each package name
|
||||
* segment.Configured
|
||||
*
|
||||
* <pre>
|
||||
* Examples:
|
||||
* "org.eclipse.jetty.test.FooTest" = "oejt.FooTest"
|
||||
* "org.eclipse.jetty.server.logging.LogTest" = "orjsl.LogTest"
|
||||
* </pre>
|
||||
*
|
||||
* @param classname the fully qualified class name
|
||||
* @return the condensed name
|
||||
*/
|
||||
private static String condensePackageString(String classname)
|
||||
{
|
||||
if (classname == null || classname.isEmpty())
|
||||
return "";
|
||||
|
||||
int rawLen = classname.length();
|
||||
StringBuilder dense = new StringBuilder(rawLen);
|
||||
boolean foundStart = false;
|
||||
boolean hasPackage = false;
|
||||
int startIdx = -1;
|
||||
int endIdx = -1;
|
||||
for (int i = 0; i < rawLen; i++)
|
||||
{
|
||||
char c = classname.charAt(i);
|
||||
if (!foundStart)
|
||||
{
|
||||
foundStart = Character.isJavaIdentifierStart(c);
|
||||
if (foundStart)
|
||||
{
|
||||
if (startIdx >= 0)
|
||||
{
|
||||
dense.append(classname.charAt(startIdx));
|
||||
hasPackage = true;
|
||||
}
|
||||
startIdx = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundStart)
|
||||
{
|
||||
if (Character.isJavaIdentifierPart(c))
|
||||
endIdx = i;
|
||||
else
|
||||
foundStart = false;
|
||||
}
|
||||
}
|
||||
// append remaining from startIdx
|
||||
if ((startIdx >= 0) && (endIdx >= startIdx))
|
||||
{
|
||||
if (hasPackage)
|
||||
dense.append('.');
|
||||
dense.append(classname, startIdx, endIdx + 1);
|
||||
}
|
||||
|
||||
return dense.toString();
|
||||
}
|
||||
|
||||
public JettyAppender getAppender()
|
||||
{
|
||||
return appender;
|
||||
}
|
||||
|
||||
String getCondensedName()
|
||||
{
|
||||
return condensedName;
|
||||
}
|
||||
|
||||
public JettyLevel getLevel()
|
||||
{
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(JettyLevel level)
|
||||
{
|
||||
this.level = level;
|
||||
|
||||
// apply setLevel to children too.
|
||||
factory.walkChildrenLoggers(this.getName(), (logger) -> logger.setLevel(level));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isHideStacks()
|
||||
{
|
||||
return hideStacks;
|
||||
}
|
||||
|
||||
public void setHideStacks(boolean hideStacks)
|
||||
{
|
||||
this.hideStacks = hideStacks;
|
||||
|
||||
// apply setHideStacks to children too.
|
||||
factory.walkChildrenLoggers(this.getName(), (logger) -> logger.setHideStacks(hideStacks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg)
|
||||
{
|
||||
|
@ -105,12 +196,6 @@ public class JettyLogger implements LocationAwareLogger, Logger
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled(Marker marker)
|
||||
{
|
||||
return isDebugEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String msg)
|
||||
{
|
||||
|
@ -146,6 +231,18 @@ public class JettyLogger implements LocationAwareLogger, Logger
|
|||
debug(msg, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled()
|
||||
{
|
||||
return level.includes(JettyLevel.DEBUG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled(Marker marker)
|
||||
{
|
||||
return isDebugEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String msg)
|
||||
{
|
||||
|
@ -191,12 +288,6 @@ public class JettyLogger implements LocationAwareLogger, Logger
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorEnabled(Marker marker)
|
||||
{
|
||||
return isErrorEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String msg)
|
||||
{
|
||||
|
@ -232,66 +323,16 @@ public class JettyLogger implements LocationAwareLogger, Logger
|
|||
error(msg, t);
|
||||
}
|
||||
|
||||
public JettyAppender getAppender()
|
||||
{
|
||||
return appender;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point for {@link LocationAwareLogger}
|
||||
*/
|
||||
@Override
|
||||
public void log(Marker marker, String fqcn, int levelInt, String message, Object[] argArray, Throwable throwable)
|
||||
public boolean isErrorEnabled()
|
||||
{
|
||||
if (this.level <= levelInt)
|
||||
{
|
||||
long timestamp = System.currentTimeMillis();
|
||||
String threadName = Thread.currentThread().getName();
|
||||
getAppender().emit(this, intToLevel(levelInt), timestamp, threadName, throwable, message, argArray);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamic (via Reflection) entry point for {@link SubstituteLogger} usage.
|
||||
*
|
||||
* @param event the logging event
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public void log(LoggingEvent event)
|
||||
{
|
||||
// TODO: do we want to support org.sfl4j.Marker?
|
||||
// TODO: do we want to support org.sfl4j.even.KeyValuePair?
|
||||
getAppender().emit(this, event.getLevel(), event.getTimeStamp(), event.getThreadName(), event.getThrowable(), event.getMessage(), event.getArgumentArray());
|
||||
}
|
||||
|
||||
public String getCondensedName()
|
||||
{
|
||||
return condensedName;
|
||||
}
|
||||
|
||||
public int getLevel()
|
||||
{
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(Level level)
|
||||
{
|
||||
Objects.requireNonNull(level, "Level");
|
||||
setLevel(level.toInt());
|
||||
}
|
||||
|
||||
public void setLevel(int lvlInt)
|
||||
{
|
||||
this.level = lvlInt;
|
||||
|
||||
// apply setLevel to children too.
|
||||
factory.walkChildLoggers(this.getName(), (logger) -> logger.setLevel(lvlInt));
|
||||
return level.includes(JettyLevel.ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
public boolean isErrorEnabled(Marker marker)
|
||||
{
|
||||
return name;
|
||||
return isErrorEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -339,12 +380,6 @@ public class JettyLogger implements LocationAwareLogger, Logger
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfoEnabled(Marker marker)
|
||||
{
|
||||
return isInfoEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String msg)
|
||||
{
|
||||
|
@ -380,47 +415,16 @@ public class JettyLogger implements LocationAwareLogger, Logger
|
|||
info(msg, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled()
|
||||
{
|
||||
return level <= Level.DEBUG.toInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorEnabled()
|
||||
{
|
||||
return level <= Level.ERROR.toInt();
|
||||
}
|
||||
|
||||
public boolean isHideStacks()
|
||||
{
|
||||
return hideStacks;
|
||||
}
|
||||
|
||||
public void setHideStacks(boolean hideStacks)
|
||||
{
|
||||
this.hideStacks = hideStacks;
|
||||
|
||||
// apply setHideStacks to children too.
|
||||
factory.walkChildLoggers(this.getName(), (logger) -> logger.setHideStacks(hideStacks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfoEnabled()
|
||||
{
|
||||
return level <= Level.INFO.toInt();
|
||||
return level.includes(JettyLevel.INFO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTraceEnabled()
|
||||
public boolean isInfoEnabled(Marker marker)
|
||||
{
|
||||
return level <= Level.TRACE.toInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled()
|
||||
{
|
||||
return level <= Level.WARN.toInt();
|
||||
return isInfoEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -468,12 +472,6 @@ public class JettyLogger implements LocationAwareLogger, Logger
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTraceEnabled(Marker marker)
|
||||
{
|
||||
return isTraceEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String msg)
|
||||
{
|
||||
|
@ -509,6 +507,18 @@ public class JettyLogger implements LocationAwareLogger, Logger
|
|||
trace(msg, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTraceEnabled()
|
||||
{
|
||||
return level.includes(JettyLevel.TRACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTraceEnabled(Marker marker)
|
||||
{
|
||||
return isTraceEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg)
|
||||
{
|
||||
|
@ -554,12 +564,6 @@ public class JettyLogger implements LocationAwareLogger, Logger
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled(Marker marker)
|
||||
{
|
||||
return isWarnEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String msg)
|
||||
{
|
||||
|
@ -595,6 +599,18 @@ public class JettyLogger implements LocationAwareLogger, Logger
|
|||
warn(msg, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled()
|
||||
{
|
||||
return level.includes(JettyLevel.WARN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled(Marker marker)
|
||||
{
|
||||
return isWarnEnabled();
|
||||
}
|
||||
|
||||
private void emit(Level level, String msg)
|
||||
{
|
||||
long timestamp = System.currentTimeMillis();
|
||||
|
@ -636,43 +652,36 @@ public class JettyLogger implements LocationAwareLogger, Logger
|
|||
getAppender().emit(this, level, timestamp, threadName, throwable, msg);
|
||||
}
|
||||
|
||||
public static Level intToLevel(int level)
|
||||
/**
|
||||
* Entry point for {@link LocationAwareLogger}
|
||||
*/
|
||||
@Override
|
||||
public void log(Marker marker, String fqcn, int levelInt, String message, Object[] argArray, Throwable throwable)
|
||||
{
|
||||
if (level >= JettyLogger.OFF)
|
||||
return Level.ERROR;
|
||||
if (level >= Level.ERROR.toInt())
|
||||
return Level.ERROR;
|
||||
if (level >= Level.WARN.toInt())
|
||||
return Level.WARN;
|
||||
if (level >= Level.INFO.toInt())
|
||||
return Level.INFO;
|
||||
if (level >= Level.DEBUG.toInt())
|
||||
return Level.DEBUG;
|
||||
if (level >= Level.TRACE.toInt())
|
||||
return Level.TRACE;
|
||||
return Level.TRACE; // everything else
|
||||
if (this.level.toInt() <= levelInt)
|
||||
{
|
||||
long timestamp = System.currentTimeMillis();
|
||||
String threadName = Thread.currentThread().getName();
|
||||
getAppender().emit(this, JettyLevel.intToLevel(levelInt).toLevel(), timestamp, threadName, throwable, message, argArray);
|
||||
}
|
||||
}
|
||||
|
||||
public static String levelToString(int level)
|
||||
/**
|
||||
* Dynamic (via Reflection) entry point for {@link SubstituteLogger} usage.
|
||||
*
|
||||
* @param event the logging event
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public void log(LoggingEvent event)
|
||||
{
|
||||
if (level >= JettyLogger.OFF)
|
||||
return "OFF";
|
||||
if (level >= Level.ERROR.toInt())
|
||||
return "ERROR";
|
||||
if (level >= Level.WARN.toInt())
|
||||
return "WARN";
|
||||
if (level >= Level.INFO.toInt())
|
||||
return "INFO";
|
||||
if (level >= Level.DEBUG.toInt())
|
||||
return "DEBUG";
|
||||
if (level >= Level.TRACE.toInt())
|
||||
return "TRACE";
|
||||
return "OFF"; // everything else
|
||||
// TODO: do we want to support org.sfl4j.Marker?
|
||||
// TODO: do we want to support org.sfl4j.even.KeyValuePair?
|
||||
getAppender().emit(this, event.getLevel(), event.getTimeStamp(), event.getThreadName(), event.getThrowable(), event.getMessage(), event.getArgumentArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s:%s:LEVEL=%s", JettyLogger.class.getSimpleName(), name, levelToString(level));
|
||||
return String.format("%s:%s:LEVEL=%s", JettyLogger.class.getSimpleName(), name, level.name());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,12 +23,10 @@ import java.io.InputStream;
|
|||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.TimeZone;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.slf4j.event.Level;
|
||||
|
||||
/**
|
||||
* JettyLogger specific configuration:
|
||||
|
@ -39,7 +37,7 @@ import org.slf4j.event.Level;
|
|||
*/
|
||||
public class JettyLoggerConfiguration
|
||||
{
|
||||
private static final int DEFAULT_LEVEL = Level.INFO.toInt();
|
||||
private static final JettyLevel DEFAULT_LEVEL = JettyLevel.INFO;
|
||||
private static final boolean DEFAULT_HIDE_STACKS = false;
|
||||
private static final String SUFFIX_LEVEL = ".LEVEL";
|
||||
private static final String SUFFIX_STACKS = ".STACKS";
|
||||
|
@ -78,76 +76,77 @@ public class JettyLoggerConfiguration
|
|||
|
||||
// strip ".STACKS" suffix (if present)
|
||||
if (startName.endsWith(SUFFIX_STACKS))
|
||||
{
|
||||
startName = startName.substring(0, startName.length() - SUFFIX_STACKS.length());
|
||||
}
|
||||
|
||||
Boolean hideStacks = walkParentLoggerNames(startName, (key) ->
|
||||
Boolean hideStacks = JettyLoggerFactory.walkParentLoggerNames(startName, key ->
|
||||
{
|
||||
String stacksBool = properties.getProperty(key + SUFFIX_STACKS);
|
||||
if (stacksBool != null)
|
||||
{
|
||||
return Boolean.parseBoolean(stacksBool);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
if (hideStacks != null)
|
||||
return hideStacks;
|
||||
|
||||
return DEFAULT_HIDE_STACKS;
|
||||
return hideStacks != null ? hideStacks : DEFAULT_HIDE_STACKS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Logging Level for the provided log name. Using the FQCN first, then each package segment from longest to
|
||||
* shortest.
|
||||
* <p>Returns the Logging Level for the provided log name.</p>
|
||||
* <p>Uses the FQCN first, then each package segment from longest to shortest.</p>
|
||||
*
|
||||
* @param name the name to get log for
|
||||
* @return the logging level int
|
||||
*/
|
||||
public int getLevel(String name)
|
||||
public JettyLevel getLevel(String name)
|
||||
{
|
||||
if (properties.isEmpty())
|
||||
return DEFAULT_LEVEL;
|
||||
|
||||
String startName = name != null ? name : "";
|
||||
|
||||
// strip trailing dot
|
||||
// Strip trailing dot.
|
||||
while (startName.endsWith("."))
|
||||
{
|
||||
startName = startName.substring(0, startName.length() - 1);
|
||||
}
|
||||
|
||||
// strip ".LEVEL" suffix (if present)
|
||||
// Strip ".LEVEL" suffix (if present).
|
||||
if (startName.endsWith(SUFFIX_LEVEL))
|
||||
{
|
||||
startName = startName.substring(0, startName.length() - SUFFIX_LEVEL.length());
|
||||
}
|
||||
|
||||
Integer level = walkParentLoggerNames(startName, (key) ->
|
||||
JettyLevel level = JettyLoggerFactory.walkParentLoggerNames(startName, key ->
|
||||
{
|
||||
String levelStr = properties.getProperty(key + SUFFIX_LEVEL);
|
||||
if (levelStr != null)
|
||||
{
|
||||
return getLevelInt(key, levelStr);
|
||||
}
|
||||
return null;
|
||||
return toJettyLevel(key, levelStr);
|
||||
});
|
||||
|
||||
if (level == null)
|
||||
{
|
||||
// try legacy root logging config
|
||||
String levelStr = properties.getProperty("log" + SUFFIX_LEVEL);
|
||||
if (levelStr != null)
|
||||
{
|
||||
level = getLevelInt("log", levelStr);
|
||||
}
|
||||
// Try slf4j root logging config.
|
||||
String levelStr = properties.getProperty(JettyLogger.ROOT_LOGGER_NAME + SUFFIX_LEVEL);
|
||||
level = toJettyLevel(JettyLogger.ROOT_LOGGER_NAME, levelStr);
|
||||
}
|
||||
|
||||
if (level != null)
|
||||
return level;
|
||||
if (level == null)
|
||||
{
|
||||
// Try legacy root logging config.
|
||||
String levelStr = properties.getProperty("log" + SUFFIX_LEVEL);
|
||||
level = toJettyLevel("log", levelStr);
|
||||
}
|
||||
|
||||
return DEFAULT_LEVEL;
|
||||
return level != null ? level : DEFAULT_LEVEL;
|
||||
}
|
||||
|
||||
static JettyLevel toJettyLevel(String loggerName, String levelStr)
|
||||
{
|
||||
if (levelStr == null)
|
||||
return null;
|
||||
JettyLevel level = JettyLevel.strToLevel(levelStr);
|
||||
if (level == null)
|
||||
{
|
||||
System.err.printf("Unknown JettyLogger/SLF4J Level [%s]=[%s], expecting only %s as values.%n",
|
||||
loggerName, levelStr, Arrays.toString(JettyLevel.values()));
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
public TimeZone getTimeZone(String key)
|
||||
|
@ -155,7 +154,6 @@ public class JettyLoggerConfiguration
|
|||
String zoneIdStr = properties.getProperty(key);
|
||||
if (zoneIdStr == null)
|
||||
return null;
|
||||
|
||||
return TimeZone.getTimeZone(zoneIdStr);
|
||||
}
|
||||
|
||||
|
@ -193,6 +191,11 @@ public class JettyLoggerConfiguration
|
|||
});
|
||||
}
|
||||
|
||||
public String getString(String key, String defValue)
|
||||
{
|
||||
return properties.getProperty(key, defValue);
|
||||
}
|
||||
|
||||
public boolean getBoolean(String key, boolean defValue)
|
||||
{
|
||||
String val = properties.getProperty(key, Boolean.toString(defValue));
|
||||
|
@ -203,9 +206,7 @@ public class JettyLoggerConfiguration
|
|||
{
|
||||
String val = properties.getProperty(key, Integer.toString(defValue));
|
||||
if (val == null)
|
||||
{
|
||||
return defValue;
|
||||
}
|
||||
try
|
||||
{
|
||||
return Integer.parseInt(val);
|
||||
|
@ -216,46 +217,12 @@ public class JettyLoggerConfiguration
|
|||
}
|
||||
}
|
||||
|
||||
private Integer getLevelInt(String levelSegment, String levelStr)
|
||||
{
|
||||
if (levelStr == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
String levelName = levelStr.trim().toUpperCase(Locale.ENGLISH);
|
||||
switch (levelName)
|
||||
{
|
||||
case "ALL":
|
||||
return JettyLogger.ALL;
|
||||
case "TRACE":
|
||||
return Level.TRACE.toInt();
|
||||
case "DEBUG":
|
||||
return Level.DEBUG.toInt();
|
||||
case "INFO":
|
||||
return Level.INFO.toInt();
|
||||
case "WARN":
|
||||
return Level.WARN.toInt();
|
||||
case "ERROR":
|
||||
return Level.ERROR.toInt();
|
||||
case "OFF":
|
||||
return JettyLogger.OFF;
|
||||
default:
|
||||
System.err.println("Unknown JettyLogger/Slf4J Level [" + levelSegment + "]=[" + levelName + "], expecting only [ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF] as values.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private URL getResource(ClassLoader loader, String resourceName)
|
||||
{
|
||||
if (loader == null)
|
||||
{
|
||||
return ClassLoader.getSystemResource(resourceName);
|
||||
}
|
||||
else
|
||||
{
|
||||
return loader.getResource(resourceName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -286,9 +253,7 @@ public class JettyLoggerConfiguration
|
|||
{
|
||||
URL propsUrl = getResource(loader, resourceName);
|
||||
if (propsUrl == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try (InputStream in = propsUrl.openStream())
|
||||
{
|
||||
|
@ -303,30 +268,4 @@ public class JettyLoggerConfiguration
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private <T> T walkParentLoggerNames(String startName, Function<String, T> nameFunction)
|
||||
{
|
||||
String nameSegment = startName;
|
||||
|
||||
// Checking with FQCN first, then each package segment from longest to shortest.
|
||||
while ((nameSegment != null) && (nameSegment.length() > 0))
|
||||
{
|
||||
T ret = nameFunction.apply(nameSegment);
|
||||
if (ret != null)
|
||||
return ret;
|
||||
|
||||
// Trim and try again.
|
||||
int idx = nameSegment.lastIndexOf('.');
|
||||
if (idx >= 0)
|
||||
{
|
||||
nameSegment = nameSegment.substring(0, idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
nameSegment = null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,19 +19,20 @@
|
|||
package org.eclipse.jetty.logging;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.slf4j.ILoggerFactory;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public class JettyLoggerFactory implements ILoggerFactory
|
||||
public class JettyLoggerFactory implements ILoggerFactory, JettyLoggerFactoryMBean
|
||||
{
|
||||
private static final String ROOT_LOGGER_NAME = "";
|
||||
private final JettyLoggerConfiguration configuration;
|
||||
private final JettyLogger rootLogger;
|
||||
private ConcurrentMap<String, JettyLogger> loggerMap;
|
||||
private final ConcurrentMap<String, JettyLogger> loggerMap;
|
||||
|
||||
public JettyLoggerFactory(JettyLoggerConfiguration config)
|
||||
{
|
||||
|
@ -41,9 +42,16 @@ public class JettyLoggerFactory implements ILoggerFactory
|
|||
|
||||
StdErrAppender appender = new StdErrAppender(configuration);
|
||||
|
||||
rootLogger = new JettyLogger(this, ROOT_LOGGER_NAME, appender);
|
||||
loggerMap.put(ROOT_LOGGER_NAME, rootLogger);
|
||||
rootLogger.setLevel(configuration.getLevel(ROOT_LOGGER_NAME));
|
||||
rootLogger = new JettyLogger(this, Logger.ROOT_LOGGER_NAME, appender);
|
||||
loggerMap.put(Logger.ROOT_LOGGER_NAME, rootLogger);
|
||||
rootLogger.setLevel(configuration.getLevel(Logger.ROOT_LOGGER_NAME));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public String jmxContext()
|
||||
{
|
||||
// Used to build the ObjectName.
|
||||
return configuration.getString("org.eclipse.jetty.logging.jmx.context", null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -54,11 +62,8 @@ public class JettyLoggerFactory implements ILoggerFactory
|
|||
*/
|
||||
public JettyLogger getJettyLogger(String name)
|
||||
{
|
||||
if (name.equals(ROOT_LOGGER_NAME))
|
||||
{
|
||||
if (name.equals(Logger.ROOT_LOGGER_NAME))
|
||||
return getRootLogger();
|
||||
}
|
||||
|
||||
return loggerMap.computeIfAbsent(name, this::createLogger);
|
||||
}
|
||||
|
||||
|
@ -74,109 +79,96 @@ public class JettyLoggerFactory implements ILoggerFactory
|
|||
return getJettyLogger(name);
|
||||
}
|
||||
|
||||
protected void walkChildLoggers(String parentName, Consumer<JettyLogger> childConsumer)
|
||||
void walkChildrenLoggers(String parentName, Consumer<JettyLogger> childConsumer)
|
||||
{
|
||||
String prefix = parentName;
|
||||
if (parentName.length() > 0 && !prefix.endsWith("."))
|
||||
{
|
||||
prefix += ".";
|
||||
}
|
||||
|
||||
for (JettyLogger logger : loggerMap.values())
|
||||
{
|
||||
// Skip self.
|
||||
if (logger.getName().equals(parentName))
|
||||
{
|
||||
// skip self
|
||||
continue;
|
||||
}
|
||||
|
||||
// is child, and is not itself
|
||||
// It is a child, and is not itself.
|
||||
if (logger.getName().startsWith(prefix))
|
||||
{
|
||||
childConsumer.accept(logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public JettyLogger getRootLogger()
|
||||
JettyLogger getRootLogger()
|
||||
{
|
||||
return rootLogger;
|
||||
}
|
||||
|
||||
private JettyLogger createLogger(String name)
|
||||
{
|
||||
// or is that handled by slf4j itself?
|
||||
JettyAppender appender = rootLogger.getAppender();
|
||||
int level = this.configuration.getLevel(name);
|
||||
JettyLevel level = this.configuration.getLevel(name);
|
||||
boolean hideStacks = this.configuration.getHideStacks(name);
|
||||
return new JettyLogger(this, name, appender, level, hideStacks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Condenses a classname by stripping down the package name to just the first character of each package name
|
||||
* segment.Configured
|
||||
*
|
||||
* <pre>
|
||||
* Examples:
|
||||
* "org.eclipse.jetty.test.FooTest" = "oejt.FooTest"
|
||||
* "org.eclipse.jetty.server.logging.LogTest" = "orjsl.LogTest"
|
||||
* </pre>
|
||||
*
|
||||
* @param classname the fully qualified class name
|
||||
* @return the condensed name
|
||||
*/
|
||||
protected static String condensePackageString(String classname)
|
||||
static <T> T walkParentLoggerNames(String startName, Function<String, T> nameFunction)
|
||||
{
|
||||
if (classname == null || classname.isEmpty())
|
||||
if (startName == null)
|
||||
return null;
|
||||
|
||||
// Checking with FQCN first, then each package segment from longest to shortest.
|
||||
String nameSegment = startName;
|
||||
while (nameSegment.length() > 0)
|
||||
{
|
||||
return "";
|
||||
T ret = nameFunction.apply(nameSegment);
|
||||
if (ret != null)
|
||||
return ret;
|
||||
|
||||
// Trim and try again.
|
||||
int idx = nameSegment.lastIndexOf('.');
|
||||
if (idx >= 0)
|
||||
nameSegment = nameSegment.substring(0, idx);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
int rawLen = classname.length();
|
||||
StringBuilder dense = new StringBuilder(rawLen);
|
||||
boolean foundStart = false;
|
||||
boolean hasPackage = false;
|
||||
int startIdx = -1;
|
||||
int endIdx = -1;
|
||||
for (int i = 0; i < rawLen; i++)
|
||||
{
|
||||
char c = classname.charAt(i);
|
||||
if (!foundStart)
|
||||
{
|
||||
foundStart = Character.isJavaIdentifierStart(c);
|
||||
if (foundStart)
|
||||
{
|
||||
if (startIdx >= 0)
|
||||
{
|
||||
dense.append(classname.charAt(startIdx));
|
||||
hasPackage = true;
|
||||
}
|
||||
startIdx = i;
|
||||
}
|
||||
}
|
||||
return nameFunction.apply(Logger.ROOT_LOGGER_NAME);
|
||||
}
|
||||
|
||||
if (foundStart)
|
||||
{
|
||||
if (!Character.isJavaIdentifierPart(c))
|
||||
{
|
||||
foundStart = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
endIdx = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
// append remaining from startIdx
|
||||
if ((startIdx >= 0) && (endIdx >= startIdx))
|
||||
{
|
||||
if (hasPackage)
|
||||
{
|
||||
dense.append('.');
|
||||
}
|
||||
dense.append(classname, startIdx, endIdx + 1);
|
||||
}
|
||||
@Override
|
||||
public String[] getLoggerNames()
|
||||
{
|
||||
TreeSet<String> names = new TreeSet<>(loggerMap.keySet());
|
||||
return names.toArray(new String[0]);
|
||||
}
|
||||
|
||||
return dense.toString();
|
||||
@Override
|
||||
public int getLoggerCount()
|
||||
{
|
||||
return loggerMap.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLoggerLevel(String loggerName)
|
||||
{
|
||||
return walkParentLoggerNames(loggerName, key ->
|
||||
{
|
||||
JettyLogger logger = loggerMap.get(key);
|
||||
if (logger != null)
|
||||
return logger.getLevel().name();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setLoggerLevel(String loggerName, String levelName)
|
||||
{
|
||||
JettyLevel level = JettyLoggerConfiguration.toJettyLevel(loggerName, levelName);
|
||||
if (level == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
JettyLogger jettyLogger = getJettyLogger(loggerName);
|
||||
jettyLogger.setLevel(level);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.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.logging;
|
||||
|
||||
public interface JettyLoggerFactoryMBean
|
||||
{
|
||||
int getLoggerCount();
|
||||
|
||||
String[] getLoggerNames();
|
||||
|
||||
boolean setLoggerLevel(String loggerName, String levelName);
|
||||
|
||||
String getLoggerLevel(String loggerName);
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.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.logging;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import javax.management.JMX;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class JMXTest
|
||||
{
|
||||
@Test
|
||||
public void testJMX() throws Exception
|
||||
{
|
||||
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
|
||||
Properties props = new Properties();
|
||||
JettyLoggerConfiguration config = new JettyLoggerConfiguration(props);
|
||||
JettyLoggerFactory loggerFactory = new JettyLoggerFactory(config);
|
||||
|
||||
ObjectName objectName = ObjectName.getInstance("org.eclipse.jetty.logging", "type", JettyLoggerFactory.class.getSimpleName().toLowerCase(Locale.ENGLISH));
|
||||
mbeanServer.registerMBean(loggerFactory, objectName);
|
||||
|
||||
JettyLoggerFactoryMBean mbean = JMX.newMBeanProxy(mbeanServer, objectName, JettyLoggerFactoryMBean.class);
|
||||
|
||||
// Only the root logger.
|
||||
assertEquals(1, mbean.getLoggerCount());
|
||||
|
||||
JettyLogger child = loggerFactory.getJettyLogger("org.eclipse.jetty.logging");
|
||||
JettyLogger parent = loggerFactory.getJettyLogger("org.eclipse.jetty");
|
||||
assertEquals(3, mbean.getLoggerCount());
|
||||
|
||||
// Names are sorted.
|
||||
List<String> expected = new ArrayList<>(Arrays.asList(JettyLogger.ROOT_LOGGER_NAME, parent.getName(), child.getName()));
|
||||
expected.sort(String::compareTo);
|
||||
String[] loggerNames = mbean.getLoggerNames();
|
||||
assertEquals(expected, Arrays.asList(loggerNames));
|
||||
|
||||
// Setting the parent level should propagate to the children.
|
||||
parent.setLevel(JettyLevel.DEBUG);
|
||||
assertEquals(parent.getLevel().toString(), mbean.getLoggerLevel(child.getName()));
|
||||
|
||||
// Setting the level via JMX affects the logger.
|
||||
assertTrue(mbean.setLoggerLevel(child.getName(), "INFO"));
|
||||
assertEquals(JettyLevel.INFO, child.getLevel());
|
||||
}
|
||||
}
|
|
@ -21,7 +21,6 @@ package org.eclipse.jetty.logging;
|
|||
import java.util.Properties;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.event.Level;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
@ -46,8 +45,8 @@ public class JettyLoggerConfigurationTest
|
|||
assertFalse(appender.isCondensedNames());
|
||||
assertEquals(appender.getThreadPadding(), 10);
|
||||
|
||||
int level = config.getLevel("com.mortbay");
|
||||
assertEquals(Level.WARN.toInt(), level);
|
||||
JettyLevel level = config.getLevel("com.mortbay");
|
||||
assertEquals(JettyLevel.WARN, level);
|
||||
|
||||
boolean stacks = config.getHideStacks("com.mortbay.Foo");
|
||||
assertFalse(stacks);
|
||||
|
@ -59,8 +58,8 @@ public class JettyLoggerConfigurationTest
|
|||
Properties props = new Properties();
|
||||
props.setProperty("com.mortbay.LEVEL", "WARN");
|
||||
JettyLoggerConfiguration config = new JettyLoggerConfiguration(props);
|
||||
int level = config.getLevel("com.mortbay");
|
||||
assertEquals(Level.WARN.toInt(), level);
|
||||
JettyLevel level = config.getLevel("com.mortbay");
|
||||
assertEquals(JettyLevel.WARN, level);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -70,8 +69,8 @@ public class JettyLoggerConfigurationTest
|
|||
props.setProperty("com.mortbay.LEVEL", "WARN");
|
||||
JettyLoggerConfiguration config = new JettyLoggerConfiguration(props);
|
||||
// extra trailing dot "."
|
||||
int level = config.getLevel("com.mortbay.");
|
||||
assertEquals(Level.WARN.toInt(), level);
|
||||
JettyLevel level = config.getLevel("com.mortbay.");
|
||||
assertEquals(JettyLevel.WARN, level);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -81,8 +80,8 @@ public class JettyLoggerConfigurationTest
|
|||
props.setProperty("com.mortbay.LEVEL", "WARN");
|
||||
JettyLoggerConfiguration config = new JettyLoggerConfiguration(props);
|
||||
// asking for name with ".LEVEL"
|
||||
int level = config.getLevel("com.mortbay.Bar.LEVEL");
|
||||
assertEquals(Level.WARN.toInt(), level);
|
||||
JettyLevel level = config.getLevel("com.mortbay.Bar.LEVEL");
|
||||
assertEquals(JettyLevel.WARN, level);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -91,8 +90,8 @@ public class JettyLoggerConfigurationTest
|
|||
Properties props = new Properties();
|
||||
props.setProperty("com.mortbay.LEVEL", "WARN");
|
||||
JettyLoggerConfiguration config = new JettyLoggerConfiguration(props);
|
||||
int level = config.getLevel("com.mortbay.Foo");
|
||||
assertEquals(Level.WARN.toInt(), level);
|
||||
JettyLevel level = config.getLevel("com.mortbay.Foo");
|
||||
assertEquals(JettyLevel.WARN, level);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -102,8 +101,8 @@ public class JettyLoggerConfigurationTest
|
|||
props.setProperty("com.mortbay.LEVEL", "WARN");
|
||||
JettyLoggerConfiguration config = new JettyLoggerConfiguration(props);
|
||||
// asking for name that isn't configured, returns default value
|
||||
int level = config.getLevel("org.eclipse.jetty");
|
||||
assertEquals(Level.INFO.toInt(), level);
|
||||
JettyLevel level = config.getLevel("org.eclipse.jetty");
|
||||
assertEquals(JettyLevel.INFO, level);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -163,41 +162,41 @@ public class JettyLoggerConfigurationTest
|
|||
public void testGetLoggingLevelBad()
|
||||
{
|
||||
Properties props = new Properties();
|
||||
props.setProperty("log.LEVEL", "WARN");
|
||||
props.setProperty("ROOT.LEVEL", "WARN");
|
||||
props.setProperty("org.eclipse.jetty.bad.LEVEL", "EXPECTED_BAD_LEVEL");
|
||||
JettyLoggerConfiguration config = new JettyLoggerConfiguration(props);
|
||||
|
||||
// Default Level (because of bad level value)
|
||||
assertEquals(Level.WARN.toInt(), config.getLevel("org.eclipse.jetty.bad"));
|
||||
assertEquals(JettyLevel.WARN, config.getLevel("org.eclipse.jetty.bad"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLoggingLevelLowercase()
|
||||
{
|
||||
Properties props = new Properties();
|
||||
props.setProperty("log.LEVEL", "warn");
|
||||
props.setProperty("ROOT.LEVEL", "warn");
|
||||
props.setProperty("org.eclipse.jetty.util.LEVEL", "info");
|
||||
JettyLoggerConfiguration config = new JettyLoggerConfiguration(props);
|
||||
|
||||
// Default Level
|
||||
assertEquals(Level.WARN.toInt(), config.getLevel("org.eclipse.jetty"));
|
||||
assertEquals(JettyLevel.WARN, config.getLevel("org.eclipse.jetty"));
|
||||
// Specific Level
|
||||
assertEquals(Level.INFO.toInt(), config.getLevel("org.eclipse.jetty.util"));
|
||||
assertEquals(JettyLevel.INFO, config.getLevel("org.eclipse.jetty.util"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLoggingLevelRoot()
|
||||
{
|
||||
Properties props = new Properties();
|
||||
props.setProperty("log.LEVEL", "DEBUG");
|
||||
props.setProperty("ROOT.LEVEL", "DEBUG");
|
||||
JettyLoggerConfiguration config = new JettyLoggerConfiguration(props);
|
||||
|
||||
// Default Levels
|
||||
assertEquals(Level.DEBUG.toInt(), config.getLevel(null));
|
||||
assertEquals(Level.DEBUG.toInt(), config.getLevel(""));
|
||||
assertEquals(Level.DEBUG.toInt(), config.getLevel("org.eclipse.jetty"));
|
||||
assertEquals(JettyLevel.DEBUG, config.getLevel(null));
|
||||
assertEquals(JettyLevel.DEBUG, config.getLevel(""));
|
||||
assertEquals(JettyLevel.DEBUG, config.getLevel("org.eclipse.jetty"));
|
||||
String name = JettyLoggerConfigurationTest.class.getName();
|
||||
assertEquals(Level.DEBUG.toInt(), config.getLevel(name), "Default Logging Level - " + name + " name");
|
||||
assertEquals(JettyLevel.DEBUG, config.getLevel(name), "Default Logging Level - " + name + " name");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -209,12 +208,12 @@ public class JettyLoggerConfigurationTest
|
|||
JettyLoggerConfiguration config = new JettyLoggerConfiguration(props);
|
||||
|
||||
// Default Levels
|
||||
assertEquals(Level.INFO.toInt(), config.getLevel(null));
|
||||
assertEquals(Level.INFO.toInt(), config.getLevel(""));
|
||||
assertEquals(Level.INFO.toInt(), config.getLevel("org.eclipse.jetty"));
|
||||
assertEquals(JettyLevel.INFO, config.getLevel(null));
|
||||
assertEquals(JettyLevel.INFO, config.getLevel(""));
|
||||
assertEquals(JettyLevel.INFO, config.getLevel("org.eclipse.jetty"));
|
||||
|
||||
// Specified Level
|
||||
assertEquals(JettyLogger.ALL, config.getLevel(name));
|
||||
assertEquals(JettyLevel.ALL, config.getLevel(name));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -225,40 +224,40 @@ public class JettyLoggerConfigurationTest
|
|||
JettyLoggerConfiguration config = new JettyLoggerConfiguration(props);
|
||||
|
||||
// Default Levels
|
||||
assertEquals(Level.INFO.toInt(), config.getLevel(null));
|
||||
assertEquals(Level.INFO.toInt(), config.getLevel(""));
|
||||
assertEquals(Level.INFO.toInt(), config.getLevel("org.eclipse.jetty"));
|
||||
assertEquals(Level.INFO.toInt(), config.getLevel("org.eclipse.jetty.server.BogusObject"));
|
||||
assertEquals(Level.INFO.toInt(), config.getLevel(JettyLoggerConfigurationTest.class.getName()));
|
||||
assertEquals(JettyLevel.INFO, config.getLevel(null));
|
||||
assertEquals(JettyLevel.INFO, config.getLevel(""));
|
||||
assertEquals(JettyLevel.INFO, config.getLevel("org.eclipse.jetty"));
|
||||
assertEquals(JettyLevel.INFO, config.getLevel("org.eclipse.jetty.server.BogusObject"));
|
||||
assertEquals(JettyLevel.INFO, config.getLevel(JettyLoggerConfigurationTest.class.getName()));
|
||||
|
||||
// Configured Level
|
||||
assertEquals(Level.DEBUG.toInt(), config.getLevel("org.eclipse.jetty.util.Bogus"));
|
||||
assertEquals(Level.DEBUG.toInt(), config.getLevel("org.eclipse.jetty.util"));
|
||||
assertEquals(Level.DEBUG.toInt(), config.getLevel("org.eclipse.jetty.util.resource.PathResource"));
|
||||
assertEquals(JettyLevel.DEBUG, config.getLevel("org.eclipse.jetty.util.Bogus"));
|
||||
assertEquals(JettyLevel.DEBUG, config.getLevel("org.eclipse.jetty.util"));
|
||||
assertEquals(JettyLevel.DEBUG, config.getLevel("org.eclipse.jetty.util.resource.PathResource"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLoggingLevelMixedLevels()
|
||||
{
|
||||
Properties props = new Properties();
|
||||
props.setProperty("log.LEVEL", "DEBUG");
|
||||
props.setProperty("ROOT.LEVEL", "DEBUG");
|
||||
props.setProperty("org.eclipse.jetty.util.LEVEL", "WARN");
|
||||
props.setProperty("org.eclipse.jetty.util.ConcurrentHashMap.LEVEL", "ALL");
|
||||
|
||||
JettyLoggerConfiguration config = new JettyLoggerConfiguration(props);
|
||||
|
||||
// Default Levels
|
||||
assertEquals(Level.DEBUG.toInt(), config.getLevel(null));
|
||||
assertEquals(Level.DEBUG.toInt(), config.getLevel(""));
|
||||
assertEquals(Level.DEBUG.toInt(), config.getLevel("org.eclipse.jetty"));
|
||||
assertEquals(Level.DEBUG.toInt(), config.getLevel("org.eclipse.jetty.server.BogusObject"));
|
||||
assertEquals(Level.DEBUG.toInt(), config.getLevel(JettyLoggerConfigurationTest.class.getName()));
|
||||
assertEquals(JettyLevel.DEBUG, config.getLevel(null));
|
||||
assertEquals(JettyLevel.DEBUG, config.getLevel(""));
|
||||
assertEquals(JettyLevel.DEBUG, config.getLevel("org.eclipse.jetty"));
|
||||
assertEquals(JettyLevel.DEBUG, config.getLevel("org.eclipse.jetty.server.BogusObject"));
|
||||
assertEquals(JettyLevel.DEBUG, config.getLevel(JettyLoggerConfigurationTest.class.getName()));
|
||||
|
||||
// Configured Level
|
||||
assertEquals(Level.WARN.toInt(), config.getLevel("org.eclipse.jetty.util.MagicUtil"));
|
||||
assertEquals(Level.WARN.toInt(), config.getLevel("org.eclipse.jetty.util"));
|
||||
assertEquals(Level.WARN.toInt(), config.getLevel("org.eclipse.jetty.util.resource.PathResource"));
|
||||
assertEquals(JettyLevel.WARN, config.getLevel("org.eclipse.jetty.util.MagicUtil"));
|
||||
assertEquals(JettyLevel.WARN, config.getLevel("org.eclipse.jetty.util"));
|
||||
assertEquals(JettyLevel.WARN, config.getLevel("org.eclipse.jetty.util.resource.PathResource"));
|
||||
|
||||
assertEquals(JettyLogger.ALL, config.getLevel("org.eclipse.jetty.util.ConcurrentHashMap"));
|
||||
assertEquals(JettyLevel.ALL, config.getLevel("org.eclipse.jetty.util.ConcurrentHashMap"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,11 +91,11 @@ public class JettyLoggerTest
|
|||
|
||||
JettyLogger log = factory.getJettyLogger("xxx");
|
||||
|
||||
log.setLevel(Level.DEBUG);
|
||||
log.setLevel(JettyLevel.DEBUG);
|
||||
log.debug("testing {} {}", "test", "debug");
|
||||
log.info("testing {} {}", "test", "info");
|
||||
log.warn("testing {} {}", "test", "warn");
|
||||
log.setLevel(Level.INFO);
|
||||
log.setLevel(JettyLevel.INFO);
|
||||
log.debug("YOU SHOULD NOT SEE THIS!");
|
||||
|
||||
output.assertContains("DEBUG:xxx:tname: testing test debug");
|
||||
|
@ -177,7 +177,7 @@ public class JettyLoggerTest
|
|||
appender.setStream(output);
|
||||
|
||||
JettyLogger log = factory.getJettyLogger(JettyLoggerTest.class.getName());
|
||||
log.setLevel(Level.DEBUG);
|
||||
log.setLevel(JettyLevel.DEBUG);
|
||||
|
||||
String nullMsg = null;
|
||||
try (StacklessLogging ignored = new StacklessLogging(log))
|
||||
|
@ -234,11 +234,11 @@ public class JettyLoggerTest
|
|||
log.warn("See Me");
|
||||
|
||||
// Set to debug level
|
||||
log.setLevel(Level.DEBUG);
|
||||
log.setLevel(JettyLevel.DEBUG);
|
||||
log.warn("Hear Me");
|
||||
|
||||
// Set to warn level
|
||||
log.setLevel(Level.WARN);
|
||||
log.setLevel(JettyLevel.WARN);
|
||||
log.warn("Cheer Me");
|
||||
|
||||
log.warn("<zoom>", new Throwable("out of focus"));
|
||||
|
@ -279,18 +279,18 @@ public class JettyLoggerTest
|
|||
log.info("I will not buy");
|
||||
|
||||
// Level Debug
|
||||
log.setLevel(Level.DEBUG);
|
||||
log.setLevel(JettyLevel.DEBUG);
|
||||
log.info("this record");
|
||||
|
||||
// Level All
|
||||
log.setLevel(Level.TRACE);
|
||||
log.setLevel(JettyLevel.TRACE);
|
||||
log.info("it is scratched.");
|
||||
|
||||
log.info("<zoom>", new Throwable("out of focus"));
|
||||
log.info("shot issue", new Throwable("scene lost"));
|
||||
|
||||
// Level Warn
|
||||
log.setLevel(Level.WARN);
|
||||
log.setLevel(JettyLevel.WARN);
|
||||
log.info("sorry?");
|
||||
log.info("<spoken line>", new Throwable("on editing room floor"));
|
||||
|
||||
|
@ -326,7 +326,7 @@ public class JettyLoggerTest
|
|||
JettyLogger log = factory.getJettyLogger(JettyLoggerTest.class.getName());
|
||||
try (StacklessLogging ignored = new StacklessLogging(log))
|
||||
{
|
||||
log.setLevel(Level.ERROR);
|
||||
log.setLevel(JettyLevel.ERROR);
|
||||
|
||||
// Various logging events
|
||||
log.debug("Squelch");
|
||||
|
@ -359,7 +359,7 @@ public class JettyLoggerTest
|
|||
|
||||
try (StacklessLogging ignored = new StacklessLogging(log))
|
||||
{
|
||||
log.setLevel(JettyLogger.OFF);
|
||||
log.setLevel(JettyLevel.OFF);
|
||||
|
||||
// Various logging events
|
||||
log.debug("Squelch");
|
||||
|
@ -399,18 +399,18 @@ public class JettyLoggerTest
|
|||
log.debug("<spoken line>", new Throwable("on editing room floor"));
|
||||
|
||||
// Level Debug
|
||||
log.setLevel(Level.DEBUG);
|
||||
log.setLevel(JettyLevel.DEBUG);
|
||||
log.debug("my hovercraft is");
|
||||
|
||||
log.debug("<zoom>", new Throwable("out of focus"));
|
||||
log.debug("shot issue", new Throwable("scene lost"));
|
||||
|
||||
// Level All
|
||||
log.setLevel(Level.TRACE);
|
||||
log.setLevel(JettyLevel.TRACE);
|
||||
log.debug("full of eels.");
|
||||
|
||||
// Level Warn
|
||||
log.setLevel(Level.WARN);
|
||||
log.setLevel(JettyLevel.WARN);
|
||||
log.debug("what?");
|
||||
|
||||
// Validate Output
|
||||
|
@ -444,22 +444,22 @@ public class JettyLoggerTest
|
|||
|
||||
try (StacklessLogging ignored = new StacklessLogging(log))
|
||||
{
|
||||
log.setLevel(Level.TRACE);
|
||||
log.setLevel(JettyLevel.TRACE);
|
||||
assertThat("log.level(trace).isDebugEnabled", log.isDebugEnabled(), is(true));
|
||||
|
||||
log.setLevel(Level.DEBUG);
|
||||
log.setLevel(JettyLevel.DEBUG);
|
||||
assertThat("log.level(debug).isDebugEnabled", log.isDebugEnabled(), is(true));
|
||||
|
||||
log.setLevel(Level.INFO);
|
||||
log.setLevel(JettyLevel.INFO);
|
||||
assertThat("log.level(info).isDebugEnabled", log.isDebugEnabled(), is(false));
|
||||
|
||||
log.setLevel(Level.WARN);
|
||||
log.setLevel(JettyLevel.WARN);
|
||||
assertThat("log.level(warn).isDebugEnabled", log.isDebugEnabled(), is(false));
|
||||
|
||||
log.setLevel(Level.ERROR);
|
||||
log.setLevel(JettyLevel.ERROR);
|
||||
assertThat("log.level(error).isDebugEnabled", log.isDebugEnabled(), is(false));
|
||||
|
||||
log.setLevel(JettyLogger.OFF);
|
||||
log.setLevel(JettyLevel.OFF);
|
||||
assertThat("log.level(null).isDebugEnabled", log.isDebugEnabled(), is(false));
|
||||
}
|
||||
}
|
||||
|
@ -478,23 +478,23 @@ public class JettyLoggerTest
|
|||
|
||||
try (StacklessLogging ignored = new StacklessLogging(log))
|
||||
{
|
||||
log.setLevel(Level.TRACE);
|
||||
assertThat("log.level(trace).getLevel()", log.getLevel(), is(Level.TRACE.toInt()));
|
||||
log.setLevel(JettyLevel.TRACE);
|
||||
assertThat("log.level(trace).getLevel()", log.getLevel(), is(JettyLevel.TRACE));
|
||||
|
||||
log.setLevel(Level.DEBUG);
|
||||
assertThat("log.level(debug).getLevel()", log.getLevel(), is(Level.DEBUG.toInt()));
|
||||
log.setLevel(JettyLevel.DEBUG);
|
||||
assertThat("log.level(debug).getLevel()", log.getLevel(), is(JettyLevel.DEBUG));
|
||||
|
||||
log.setLevel(Level.INFO);
|
||||
assertThat("log.level(info).getLevel()", log.getLevel(), is(Level.INFO.toInt()));
|
||||
log.setLevel(JettyLevel.INFO);
|
||||
assertThat("log.level(info).getLevel()", log.getLevel(), is(JettyLevel.INFO));
|
||||
|
||||
log.setLevel(Level.WARN);
|
||||
assertThat("log.level(warn).getLevel()", log.getLevel(), is(Level.WARN.toInt()));
|
||||
log.setLevel(JettyLevel.WARN);
|
||||
assertThat("log.level(warn).getLevel()", log.getLevel(), is(JettyLevel.WARN));
|
||||
|
||||
log.setLevel(Level.ERROR);
|
||||
assertThat("log.level(error).getLevel()", log.getLevel(), is(Level.ERROR.toInt()));
|
||||
log.setLevel(JettyLevel.ERROR);
|
||||
assertThat("log.level(error).getLevel()", log.getLevel(), is(JettyLevel.ERROR));
|
||||
|
||||
log.setLevel(888);
|
||||
assertThat("log.level(888).getLevel()", log.getLevel(), is(888));
|
||||
log.setLevel(JettyLevel.OFF);
|
||||
assertThat("log.level(off).getLevel()", log.getLevel(), is(JettyLevel.OFF));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -510,22 +510,22 @@ public class JettyLoggerTest
|
|||
|
||||
JettyLogger log = factory.getJettyLogger("xxx");
|
||||
|
||||
log.setLevel(Level.TRACE);
|
||||
log.setLevel(JettyLevel.TRACE);
|
||||
assertThat("Logger.toString", log.toString(), is("JettyLogger:xxx:LEVEL=TRACE"));
|
||||
|
||||
log.setLevel(Level.DEBUG);
|
||||
log.setLevel(JettyLevel.DEBUG);
|
||||
assertThat("Logger.toString", log.toString(), is("JettyLogger:xxx:LEVEL=DEBUG"));
|
||||
|
||||
log.setLevel(Level.INFO);
|
||||
log.setLevel(JettyLevel.INFO);
|
||||
assertThat("Logger.toString", log.toString(), is("JettyLogger:xxx:LEVEL=INFO"));
|
||||
|
||||
log.setLevel(Level.WARN);
|
||||
log.setLevel(JettyLevel.WARN);
|
||||
assertThat("Logger.toString", log.toString(), is("JettyLogger:xxx:LEVEL=WARN"));
|
||||
|
||||
log.setLevel(Level.ERROR);
|
||||
log.setLevel(JettyLevel.ERROR);
|
||||
assertThat("Logger.toString", log.toString(), is("JettyLogger:xxx:LEVEL=ERROR"));
|
||||
|
||||
log.setLevel(JettyLogger.OFF);
|
||||
log.setLevel(JettyLevel.OFF);
|
||||
assertThat("Logger.toString", log.toString(), is("JettyLogger:xxx:LEVEL=OFF"));
|
||||
}
|
||||
|
||||
|
@ -544,25 +544,25 @@ public class JettyLoggerTest
|
|||
appender.setStream(output);
|
||||
|
||||
JettyLogger root = factory.getJettyLogger("");
|
||||
assertLevel(root, Level.INFO); // default
|
||||
assertLevel(root, JettyLevel.INFO); // default
|
||||
|
||||
JettyLogger log = factory.getJettyLogger("org.eclipse.jetty.util.Foo");
|
||||
assertThat("Log.isDebugEnabled()", log.isDebugEnabled(), is(false));
|
||||
assertLevel(log, Level.WARN); // as configured
|
||||
assertLevel(log, JettyLevel.WARN); // as configured
|
||||
|
||||
// Boot stomp it all to debug
|
||||
root.setLevel(Level.DEBUG);
|
||||
root.setLevel(JettyLevel.DEBUG);
|
||||
assertThat("Log.isDebugEnabled()", log.isDebugEnabled(), is(true));
|
||||
assertLevel(log, Level.DEBUG); // as stomped
|
||||
assertLevel(log, JettyLevel.DEBUG); // as stomped
|
||||
|
||||
// Restore configured
|
||||
factory.walkChildLoggers(root.getName(), (logger) ->
|
||||
factory.walkChildrenLoggers(root.getName(), (logger) ->
|
||||
{
|
||||
int configuredLevel = config.getLevel(logger.getName());
|
||||
JettyLevel configuredLevel = config.getLevel(logger.getName());
|
||||
logger.setLevel(configuredLevel);
|
||||
});
|
||||
assertThat("Log.isDebugEnabled()", log.isDebugEnabled(), is(false));
|
||||
assertLevel(log, Level.WARN); // as configured
|
||||
assertLevel(log, JettyLevel.WARN); // as configured
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -606,9 +606,9 @@ public class JettyLoggerTest
|
|||
output.assertContains("\t|\t|java.lang.Exception: branch0");
|
||||
}
|
||||
|
||||
private void assertLevel(JettyLogger log, Level expectedLevel)
|
||||
private void assertLevel(JettyLogger log, JettyLevel expectedLevel)
|
||||
{
|
||||
assertThat("Log[" + log.getName() + "].level",
|
||||
JettyLogger.levelToString(log.getLevel()), is(expectedLevel.toString()));
|
||||
log.getLevel(), is(expectedLevel));
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,528 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.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.util.ajax;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class AsyncJSONTest
|
||||
{
|
||||
private static AsyncJSON newAsyncJSON()
|
||||
{
|
||||
AsyncJSON.Factory factory = new AsyncJSON.Factory();
|
||||
factory.setDetailedParseException(true);
|
||||
return factory.newAsyncJSON();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"|", "}", "]", "{]", "[}", "+", ".", "{} []"})
|
||||
public void testParseInvalidJSON(String json)
|
||||
{
|
||||
byte[] bytes = json.getBytes(UTF_8);
|
||||
AsyncJSON parser = newAsyncJSON();
|
||||
|
||||
// Parse the whole input.
|
||||
assertThrows(IllegalArgumentException.class, () -> parser.parse(bytes));
|
||||
assertTrue(parser.isEmpty());
|
||||
|
||||
// Parse byte by byte.
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
{
|
||||
for (byte b : bytes)
|
||||
{
|
||||
parser.parse(new byte[]{b});
|
||||
}
|
||||
});
|
||||
assertTrue(parser.isEmpty());
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "[{index}] ''{0}'' -> ''{1}''")
|
||||
@MethodSource("validStrings")
|
||||
public void testParseString(String string, String expected)
|
||||
{
|
||||
String json = "\"${value}\"".replace("${value}", string);
|
||||
byte[] bytes = json.getBytes(UTF_8);
|
||||
AsyncJSON parser = newAsyncJSON();
|
||||
|
||||
// Parse the whole input.
|
||||
assertTrue(parser.parse(bytes));
|
||||
assertEquals(expected, parser.complete());
|
||||
assertTrue(parser.isEmpty());
|
||||
|
||||
// Parse byte by byte.
|
||||
for (int i = 0; i < bytes.length; ++i)
|
||||
{
|
||||
byte b = bytes[i];
|
||||
if (i == bytes.length - 1)
|
||||
assertTrue(parser.parse(new byte[]{b}));
|
||||
else
|
||||
assertFalse(parser.parse(new byte[]{b}));
|
||||
}
|
||||
assertEquals(expected, parser.complete());
|
||||
assertTrue(parser.isEmpty());
|
||||
}
|
||||
|
||||
public static List<Object[]> validStrings()
|
||||
{
|
||||
List<Object[]> result = new ArrayList<>();
|
||||
result.add(new Object[]{"", ""});
|
||||
result.add(new Object[]{" \t\r\n", " \t\r\n"});
|
||||
result.add(new Object[]{"\u20AC", "\u20AC"}); // euro symbol
|
||||
result.add(new Object[]{"\\u20AC", "\u20AC"}); // euro symbol
|
||||
result.add(new Object[]{"/foo", "/foo"});
|
||||
result.add(new Object[]{"123E+01", "123E+01"});
|
||||
result.add(new Object[]{"A\\u20AC/foo\\t\\n", "A\u20AC/foo\t\n"}); // euro symbol
|
||||
result.add(new Object[]{" ABC ", " ABC "});
|
||||
return result;
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"\\u", "\\u0", "\\x"})
|
||||
public void testParseInvalidString(String value)
|
||||
{
|
||||
String json = "\"${value}\"".replace("${value}", value);
|
||||
byte[] bytes = json.getBytes(UTF_8);
|
||||
AsyncJSON parser = newAsyncJSON();
|
||||
|
||||
// Parse the whole input.
|
||||
assertThrows(IllegalArgumentException.class, () -> parser.parse(bytes));
|
||||
assertTrue(parser.isEmpty());
|
||||
|
||||
// Parse byte by byte.
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
{
|
||||
for (byte b : bytes)
|
||||
{
|
||||
parser.parse(new byte[]{b});
|
||||
}
|
||||
});
|
||||
assertTrue(parser.isEmpty());
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "[{index}] {0} -> {1}")
|
||||
@MethodSource("validArrays")
|
||||
public void testParseArray(String json, List<?> expected)
|
||||
{
|
||||
byte[] bytes = json.getBytes(UTF_8);
|
||||
AsyncJSON parser = newAsyncJSON();
|
||||
|
||||
// Parse the whole input.
|
||||
assertTrue(parser.parse(bytes));
|
||||
assertEquals(expected, parser.complete());
|
||||
assertTrue(parser.isEmpty());
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
assertTrue(parser.parse(buffer));
|
||||
assertFalse(buffer.hasRemaining());
|
||||
assertEquals(expected, parser.complete());
|
||||
assertTrue(parser.isEmpty());
|
||||
|
||||
// Parse byte by byte.
|
||||
for (byte b : bytes)
|
||||
{
|
||||
parser.parse(new byte[]{b});
|
||||
}
|
||||
assertEquals(expected, parser.complete());
|
||||
assertTrue(parser.isEmpty());
|
||||
}
|
||||
|
||||
public static List<Object[]> validArrays()
|
||||
{
|
||||
List<Object[]> result = new ArrayList<>();
|
||||
|
||||
List<Object> expected = Collections.emptyList();
|
||||
result.add(new Object[]{"[]", expected});
|
||||
result.add(new Object[]{"[] \n", expected});
|
||||
|
||||
expected = new ArrayList<>();
|
||||
expected.add(Collections.emptyList());
|
||||
result.add(new Object[]{"[[]]", expected});
|
||||
|
||||
expected = new ArrayList<>();
|
||||
expected.add("first");
|
||||
expected.add(5D);
|
||||
expected.add(null);
|
||||
expected.add(true);
|
||||
expected.add(false);
|
||||
expected.add(new HashMap<>());
|
||||
HashMap<String, Object> last = new HashMap<>();
|
||||
last.put("a", new ArrayList<>());
|
||||
expected.add(last);
|
||||
result.add(new Object[]{"[\"first\", 5E+0, null, true, false, {}, {\"a\":[]}]", expected});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"[", "]", "[[,]", " [ 1,2,[ "})
|
||||
public void testParseInvalidArray(String json)
|
||||
{
|
||||
byte[] bytes = json.getBytes(UTF_8);
|
||||
AsyncJSON parser = newAsyncJSON();
|
||||
|
||||
// Parse the whole input.
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
{
|
||||
parser.parse(bytes);
|
||||
parser.complete();
|
||||
});
|
||||
assertTrue(parser.isEmpty());
|
||||
|
||||
// Parse byte by byte.
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
{
|
||||
for (byte b : bytes)
|
||||
{
|
||||
parser.parse(new byte[]{b});
|
||||
}
|
||||
parser.complete();
|
||||
});
|
||||
assertTrue(parser.isEmpty());
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "[{index}] {0} -> {1}")
|
||||
@MethodSource("validObjects")
|
||||
public void testParseObject(String json, Object expected)
|
||||
{
|
||||
byte[] bytes = json.getBytes(UTF_8);
|
||||
AsyncJSON parser = newAsyncJSON();
|
||||
|
||||
// Parse the whole input.
|
||||
assertTrue(parser.parse(bytes));
|
||||
assertEquals(expected, parser.complete());
|
||||
assertTrue(parser.isEmpty());
|
||||
|
||||
// Parse byte by byte.
|
||||
for (int i = 0; i < bytes.length; ++i)
|
||||
{
|
||||
byte b = bytes[i];
|
||||
if (i == bytes.length - 1)
|
||||
{
|
||||
assertTrue(parser.parse(new byte[]{b}));
|
||||
}
|
||||
else
|
||||
{
|
||||
assertFalse(parser.parse(new byte[]{b}));
|
||||
}
|
||||
}
|
||||
assertEquals(expected, parser.complete());
|
||||
assertTrue(parser.isEmpty());
|
||||
}
|
||||
|
||||
public static List<Object[]> validObjects()
|
||||
{
|
||||
List<Object[]> result = new ArrayList<>();
|
||||
|
||||
HashMap<String, Object> expected = new HashMap<>();
|
||||
result.add(new Object[]{"{}", expected});
|
||||
|
||||
expected = new HashMap<>();
|
||||
expected.put("", 0L);
|
||||
result.add(new Object[]{"{\"\":0}", expected});
|
||||
|
||||
expected = new HashMap<>();
|
||||
expected.put("name", "value");
|
||||
result.add(new Object[]{"{ \"name\": \"value\" }", expected});
|
||||
|
||||
expected = new HashMap<>();
|
||||
expected.put("name", null);
|
||||
expected.put("valid", true);
|
||||
expected.put("secure", false);
|
||||
expected.put("value", 42L);
|
||||
result.add(new Object[]{
|
||||
"{, \"name\": null, \"valid\": true\n , \"secure\": false\r\n,\n \"value\":42, }", expected
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"{", "}", "{{,}", "{:\"s\"}", "{[]:0}", "{1:0}", " {\": 0} ", "{\"a: \"b\"}"})
|
||||
public void testParseInvalidObject(String json)
|
||||
{
|
||||
byte[] bytes = json.getBytes(UTF_8);
|
||||
AsyncJSON parser = newAsyncJSON();
|
||||
|
||||
// Parse the whole input.
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
{
|
||||
parser.parse(bytes);
|
||||
parser.complete();
|
||||
});
|
||||
assertTrue(parser.isEmpty());
|
||||
|
||||
// Parse byte by byte.
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
{
|
||||
for (byte b : bytes)
|
||||
{
|
||||
parser.parse(new byte[]{b});
|
||||
}
|
||||
parser.complete();
|
||||
});
|
||||
assertTrue(parser.isEmpty());
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "[{index}] {0} -> {1}")
|
||||
@MethodSource("validNumbers")
|
||||
public void testParseNumber(String json, Number expected)
|
||||
{
|
||||
byte[] bytes = json.getBytes(UTF_8);
|
||||
AsyncJSON parser = newAsyncJSON();
|
||||
|
||||
// Parse the whole input.
|
||||
parser.parse(bytes);
|
||||
assertEquals(expected, parser.complete());
|
||||
assertTrue(parser.isEmpty());
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
parser.parse(buffer);
|
||||
assertEquals(expected, parser.complete());
|
||||
assertFalse(buffer.hasRemaining());
|
||||
assertTrue(parser.isEmpty());
|
||||
|
||||
// Parse byte by byte.
|
||||
for (byte b : bytes)
|
||||
{
|
||||
parser.parse(new byte[]{b});
|
||||
}
|
||||
assertEquals(expected, parser.complete());
|
||||
assertTrue(parser.isEmpty());
|
||||
}
|
||||
|
||||
public static List<Object[]> validNumbers()
|
||||
{
|
||||
List<Object[]> result = new ArrayList<>();
|
||||
|
||||
result.add(new Object[]{"0", 0L});
|
||||
result.add(new Object[]{"-0", -0L});
|
||||
result.add(new Object[]{"13\n", 13L});
|
||||
result.add(new Object[]{"-42", -42L});
|
||||
result.add(new Object[]{"123.456", 123.456D});
|
||||
result.add(new Object[]{"-234.567", -234.567D});
|
||||
result.add(new Object[]{"9e0", 9D});
|
||||
result.add(new Object[]{"8E+1\t", 80D});
|
||||
result.add(new Object[]{"-7E-2 ", -0.07D});
|
||||
result.add(new Object[]{"70.5E-1", 7.05D});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"--", "--1", ".5", "e0", "1a1", "3-7", "1+2", "1e0e1", "1.2.3"})
|
||||
public void testParseInvalidNumber(String json)
|
||||
{
|
||||
byte[] bytes = json.getBytes(UTF_8);
|
||||
AsyncJSON parser = newAsyncJSON();
|
||||
|
||||
// Parse the whole input.
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
{
|
||||
parser.parse(bytes);
|
||||
parser.complete();
|
||||
});
|
||||
assertTrue(parser.isEmpty());
|
||||
|
||||
// Parse byte by byte.
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
{
|
||||
for (byte b : bytes)
|
||||
{
|
||||
parser.parse(new byte[]{b});
|
||||
}
|
||||
parser.complete();
|
||||
});
|
||||
assertTrue(parser.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseObjectWithConvertor()
|
||||
{
|
||||
AsyncJSON.Factory factory = new AsyncJSON.Factory();
|
||||
CustomConvertor convertor = new CustomConvertor();
|
||||
factory.putConvertor(CustomConvertor.class.getName(), convertor);
|
||||
|
||||
String json = "{" +
|
||||
"\"f1\": {\"class\":\"" + CustomConvertible.class.getName() + "\", \"field\": \"value\"}," +
|
||||
"\"f2\": {\"class\":\"" + CustomConvertor.class.getName() + "\"}" +
|
||||
"}";
|
||||
|
||||
AsyncJSON parser = factory.newAsyncJSON();
|
||||
assertTrue(parser.parse(UTF_8.encode(json)));
|
||||
Map<String, Object> result = parser.complete();
|
||||
|
||||
Object value1 = result.get("f1");
|
||||
assertTrue(value1 instanceof CustomConvertible);
|
||||
assertEquals("value", ((CustomConvertible)value1).field);
|
||||
Object value2 = result.get("f2");
|
||||
assertTrue(value2 instanceof CustomConvertor.Custom);
|
||||
|
||||
assertSame(convertor, factory.removeConvertor(CustomConvertor.class.getName()));
|
||||
assertTrue(parser.parse(UTF_8.encode(json)));
|
||||
result = parser.complete();
|
||||
|
||||
value1 = result.get("f1");
|
||||
assertTrue(value1 instanceof CustomConvertible);
|
||||
assertEquals("value", ((CustomConvertible)value1).field);
|
||||
value2 = result.get("f2");
|
||||
assertTrue(value2 instanceof Map);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map2 = (Map<String, Object>)value2;
|
||||
assertEquals(CustomConvertor.class.getName(), map2.get("class"));
|
||||
}
|
||||
|
||||
public static class CustomConvertible implements JSON.Convertible
|
||||
{
|
||||
private Object field;
|
||||
|
||||
@Override
|
||||
public void toJSON(JSON.Output out)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(Map<String, Object> map)
|
||||
{
|
||||
this.field = map.get("field");
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomConvertor implements JSON.Convertor
|
||||
{
|
||||
@Override
|
||||
public void toJSON(Object obj, JSON.Output out)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromJSON(Map<String, Object> map)
|
||||
{
|
||||
return new Custom();
|
||||
}
|
||||
|
||||
public static class Custom
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContext()
|
||||
{
|
||||
AsyncJSON.Factory factory = new AsyncJSON.Factory()
|
||||
{
|
||||
@Override
|
||||
public AsyncJSON newAsyncJSON()
|
||||
{
|
||||
return new AsyncJSON(this)
|
||||
{
|
||||
@Override
|
||||
protected Map<String, Object> newObject(Context context)
|
||||
{
|
||||
if (context.depth() == 1)
|
||||
{
|
||||
return new CustomMap();
|
||||
}
|
||||
return super.newObject(context);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
AsyncJSON parser = factory.newAsyncJSON();
|
||||
|
||||
String json = "[{" +
|
||||
"\"channel\": \"/meta/handshake\"," +
|
||||
"\"version\": \"1.0\"," +
|
||||
"\"supportedConnectionTypes\": [\"long-polling\"]," +
|
||||
"\"advice\": {\"timeout\": 0}" +
|
||||
"}]";
|
||||
|
||||
assertTrue(parser.parse(UTF_8.encode(json)));
|
||||
List<CustomMap> messages = parser.complete();
|
||||
|
||||
for (CustomMap message : messages)
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> advice = (Map<String, Object>)message.get("advice");
|
||||
assertFalse(advice instanceof CustomMap);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomMap extends HashMap<String, Object>
|
||||
{
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCaching()
|
||||
{
|
||||
AsyncJSON.Factory factory = new AsyncJSON.Factory();
|
||||
String foo = "foo";
|
||||
factory.cache(foo);
|
||||
AsyncJSON parser = factory.newAsyncJSON();
|
||||
|
||||
String json = "{\"foo\": [\"foo\", \"foo\"]}";
|
||||
parser.parse(UTF_8.encode(json));
|
||||
Map<String, Object> object = parser.complete();
|
||||
|
||||
Map.Entry<String, Object> entry = object.entrySet().iterator().next();
|
||||
assertSame(foo, entry.getKey());
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> array = (List<String>)entry.getValue();
|
||||
for (String item : array)
|
||||
{
|
||||
assertSame(foo, item);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodedCaching()
|
||||
{
|
||||
AsyncJSON.Factory factory = new AsyncJSON.Factory();
|
||||
assertFalse(factory.cache("yèck"));
|
||||
String foo = "foo\\yuck";
|
||||
assertTrue(factory.cache(foo));
|
||||
AsyncJSON parser = factory.newAsyncJSON();
|
||||
|
||||
String json = "{\"foo\\\\yuck\": [\"foo\\\\yuck\", \"foo\\\\yuck\"]}";
|
||||
parser.parse(UTF_8.encode(json));
|
||||
Map<String, Object> object = parser.complete();
|
||||
|
||||
Map.Entry<String, Object> entry = object.entrySet().iterator().next();
|
||||
assertSame(foo, entry.getKey());
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> array = (List<String>)entry.getValue();
|
||||
for (String item : array)
|
||||
{
|
||||
assertSame(foo, item);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -614,7 +614,7 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
|
|||
boolean added = _trie.put(s, v);
|
||||
while (!added && _growby > 0)
|
||||
{
|
||||
ArrayTernaryTrie<V> bigger = new ArrayTernaryTrie<>(_trie._key.length + _growby);
|
||||
ArrayTernaryTrie<V> bigger = new ArrayTernaryTrie<>(_trie.isCaseInsensitive(), _trie._key.length + _growby);
|
||||
for (Map.Entry<String, V> entry : _trie.entrySet())
|
||||
{
|
||||
bigger.put(entry.getKey(), entry.getValue());
|
||||
|
|
|
@ -111,8 +111,7 @@ public class AttributesMap implements Attributes, Dumpable
|
|||
if (attrs instanceof AttributesMap)
|
||||
return Collections.enumeration(((AttributesMap)attrs).keySet());
|
||||
|
||||
List<String> names = new ArrayList<>();
|
||||
names.addAll(Collections.list(attrs.getAttributeNames()));
|
||||
List<String> names = new ArrayList<>(Collections.list(attrs.getAttributeNames()));
|
||||
return Collections.enumeration(names);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,11 +19,13 @@
|
|||
package org.eclipse.jetty.util.thread;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.eclipse.jetty.logging.StacklessLogging;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool.SizedThreadPool;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -36,6 +38,7 @@ import static org.hamcrest.Matchers.lessThan;
|
|||
import static org.hamcrest.core.StringContains.containsString;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
||||
|
@ -753,6 +756,24 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
|||
assertThrows(IllegalArgumentException.class, () -> new QueuedThreadPool(4, 8));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJoinWithStopTimeout() throws Exception
|
||||
{
|
||||
final long stopTimeout = 100;
|
||||
QueuedThreadPool threadPool = new QueuedThreadPool();
|
||||
threadPool.setStopTimeout(100);
|
||||
threadPool.start();
|
||||
|
||||
// Verify that join does not timeout after waiting twice the stopTimeout.
|
||||
assertThrows(Throwable.class, () ->
|
||||
assertTimeoutPreemptively(Duration.ofMillis(stopTimeout * 2), threadPool::join)
|
||||
);
|
||||
|
||||
// After stopping the ThreadPool join should unblock.
|
||||
LifeCycle.stop(threadPool);
|
||||
assertTimeoutPreemptively(Duration.ofMillis(stopTimeout), threadPool::join);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDump() throws Exception
|
||||
{
|
||||
|
|
|
@ -1200,7 +1200,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
{
|
||||
ServletMapping mapping = new ServletMapping(new Source(Source.Origin.DESCRIPTOR, descriptor.getResource().toString()));
|
||||
mapping.setServletName(servletName);
|
||||
mapping.setDefault(descriptor instanceof DefaultsDescriptor);
|
||||
mapping.setFromDefaultDescriptor(descriptor instanceof DefaultsDescriptor);
|
||||
|
||||
List<String> paths = new ArrayList<String>();
|
||||
Iterator<XmlParser.Node> iter = node.iterator("url-pattern");
|
||||
|
@ -1221,9 +1221,9 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
{
|
||||
//The same path has been mapped multiple times, either to a different servlet or the same servlet.
|
||||
//If its a different servlet, this is only valid to do if the old mapping was from a default descriptor.
|
||||
if (p.equals(ps) && (sm.isDefault() || servletName.equals(sm.getServletName())))
|
||||
if (p.equals(ps) && (sm.isFromDefaultDescriptor() || servletName.equals(sm.getServletName())))
|
||||
{
|
||||
if (sm.isDefault())
|
||||
if (sm.isFromDefaultDescriptor())
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} in mapping {} from defaults descriptor is overridden by ", ps, sm, servletName);
|
||||
|
|
|
@ -14,9 +14,11 @@
|
|||
<url>http://www.eclipse.org/jetty</url>
|
||||
|
||||
<modules>
|
||||
<module>websocket-core</module>
|
||||
<module>websocket-util</module>
|
||||
<module>websocket-util-server</module>
|
||||
<!-- WebSocket Core Implementation -->
|
||||
<module>websocket-core-common</module>
|
||||
<module>websocket-core-client</module>
|
||||
<module>websocket-core-server</module>
|
||||
<module>websocket-core-tests</module>
|
||||
<!-- Jetty WebSocket Implementation -->
|
||||
<module>websocket-jetty-api</module>
|
||||
<module>websocket-jetty-common</module>
|
||||
|
@ -28,6 +30,9 @@
|
|||
<module>websocket-javax-client</module>
|
||||
<module>websocket-javax-server</module>
|
||||
<module>websocket-javax-tests</module>
|
||||
<!-- Common WebSocket Implementation -->
|
||||
<module>websocket-util</module>
|
||||
<module>websocket-util-server</module>
|
||||
</modules>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-parent</artifactId>
|
||||
<version>10.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>websocket-core-client</artifactId>
|
||||
<name>Jetty :: Websocket :: Core :: Client</name>
|
||||
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.core.client</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-core-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-xml</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>ban-ws-apis</id>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<bannedDependencies>
|
||||
<includes>
|
||||
<include>org.eclipse.jetty.websocket:websocket-jetty-api</include>
|
||||
<include>javax.websocket</include>
|
||||
</includes>
|
||||
</bannedDependencies>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>ban-java-servlet-api</id>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<bannedDependencies>
|
||||
<includes>
|
||||
<include>javax.servlet</include>
|
||||
<include>servletapi</include>
|
||||
<include>org.eclipse.jetty.orbit:javax.servlet</include>
|
||||
<include>org.mortbay.jetty:servlet-api</include>
|
||||
<include>jetty:servlet-api</include>
|
||||
<include>jetty-servlet-api</include>
|
||||
</includes>
|
||||
</bannedDependencies>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.0 which is available at
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
module org.eclipse.jetty.websocket.core.client
|
||||
{
|
||||
exports org.eclipse.jetty.websocket.core.client;
|
||||
|
||||
requires org.slf4j;
|
||||
requires transitive org.eclipse.jetty.client;
|
||||
requires transitive org.eclipse.jetty.websocket.core.common;
|
||||
|
||||
// Only required if using XmlHttpClientProvider.
|
||||
requires static org.eclipse.jetty.xml;
|
||||
}
|
|
@ -80,8 +80,8 @@ public abstract class ClientUpgradeRequest extends HttpRequest implements Respon
|
|||
protected final CompletableFuture<CoreSession> futureCoreSession;
|
||||
private final WebSocketCoreClient wsClient;
|
||||
private FrameHandler frameHandler;
|
||||
private Configuration.ConfigurationCustomizer customizer = new Configuration.ConfigurationCustomizer();
|
||||
private List<UpgradeListener> upgradeListeners = new ArrayList<>();
|
||||
private final Configuration.ConfigurationCustomizer customizer = new Configuration.ConfigurationCustomizer();
|
||||
private final List<UpgradeListener> upgradeListeners = new ArrayList<>();
|
||||
private List<ExtensionConfig> requestedExtensions = new ArrayList<>();
|
||||
|
||||
public ClientUpgradeRequest(WebSocketCoreClient webSocketClient, URI requestURI)
|
|
@ -40,7 +40,7 @@ public class WebSocketCoreClient extends ContainerLifeCycle
|
|||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WebSocketCoreClient.class);
|
||||
private final HttpClient httpClient;
|
||||
private WebSocketComponents components;
|
||||
private final WebSocketComponents components;
|
||||
|
||||
// TODO: Things to consider for inclusion in this class (or removal if they can be set elsewhere, like HttpClient)
|
||||
// - AsyncWrite Idle Timeout
|
|
@ -0,0 +1,98 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-parent</artifactId>
|
||||
<version>10.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>websocket-core-common</artifactId>
|
||||
<name>Jetty :: Websocket :: Core :: Common</name>
|
||||
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.core.common</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-io</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>ban-ws-apis</id>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<bannedDependencies>
|
||||
<includes>
|
||||
<include>org.eclipse.jetty.websocket:websocket-jetty-api</include>
|
||||
<include>javax.websocket</include>
|
||||
</includes>
|
||||
</bannedDependencies>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>ban-java-servlet-api</id>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<bannedDependencies>
|
||||
<includes>
|
||||
<include>javax.servlet</include>
|
||||
<include>servletapi</include>
|
||||
<include>org.eclipse.jetty.orbit:javax.servlet</include>
|
||||
<include>org.mortbay.jetty:servlet-api</include>
|
||||
<include>jetty:servlet-api</include>
|
||||
<include>jetty-servlet-api</include>
|
||||
</includes>
|
||||
</bannedDependencies>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>generate-manifest</id>
|
||||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Export-Package>*,org.eclipse.jetty.websocket.core.common.internal.*</Export-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,11 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[description]
|
||||
Enable both jetty and javax websocket modules for deployed web applications.
|
||||
|
||||
[tags]
|
||||
websocket
|
||||
|
||||
[depend]
|
||||
websocket-jetty
|
||||
websocket-javax
|
|
@ -22,22 +22,16 @@ import org.eclipse.jetty.websocket.core.internal.IdentityExtension;
|
|||
import org.eclipse.jetty.websocket.core.internal.PerMessageDeflateExtension;
|
||||
import org.eclipse.jetty.websocket.core.internal.ValidationExtension;
|
||||
|
||||
module org.eclipse.jetty.websocket.core
|
||||
module org.eclipse.jetty.websocket.core.common
|
||||
{
|
||||
exports org.eclipse.jetty.websocket.core;
|
||||
exports org.eclipse.jetty.websocket.core.client;
|
||||
exports org.eclipse.jetty.websocket.core.server;
|
||||
exports org.eclipse.jetty.websocket.core.exception;
|
||||
exports org.eclipse.jetty.websocket.core.internal to org.eclipse.jetty.util;
|
||||
exports org.eclipse.jetty.websocket.core.internal to org.eclipse.jetty.websocket.core.client, org.eclipse.jetty.websocket.core.server, org.eclipse.jetty.util;
|
||||
|
||||
requires jetty.servlet.api;
|
||||
requires transitive org.eclipse.jetty.client;
|
||||
requires transitive org.eclipse.jetty.server;
|
||||
requires org.eclipse.jetty.http;
|
||||
requires org.eclipse.jetty.io;
|
||||
requires org.slf4j;
|
||||
|
||||
// Only required if using XmlHttpClientProvider.
|
||||
requires static org.eclipse.jetty.xml;
|
||||
|
||||
uses Extension;
|
||||
|
||||
provides Extension with
|
|
@ -306,15 +306,12 @@ public class CloseStatus
|
|||
}
|
||||
|
||||
// Reserved / not yet allocated
|
||||
if ((statusCode == 1004) || // Reserved in RFC6455 (might be defined in the future)
|
||||
((statusCode >= 1016) && (statusCode <= 2999)) || // Reserved in RFC6455 (for future revisions, and extensions)
|
||||
(statusCode >= 5000)) // RFC6455 Not allowed to be used for any purpose
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// RFC6455 Not allowed to be used for any purpose
|
||||
return (statusCode != 1004) && // Reserved in RFC6455 (might be defined in the future)
|
||||
((statusCode < 1016) || (statusCode > 2999)) && // Reserved in RFC6455 (for future revisions, and extensions)
|
||||
(statusCode < 5000);
|
||||
|
||||
// All others are allowed
|
||||
return true;
|
||||
}
|
||||
|
||||
public Frame toFrame()
|
|
@ -38,7 +38,7 @@ import org.eclipse.jetty.util.Trie;
|
|||
*/
|
||||
public class ExtensionConfig
|
||||
{
|
||||
private static Trie<ExtensionConfig> CACHE = new ArrayTrie<>(512);
|
||||
private static final Trie<ExtensionConfig> CACHE = new ArrayTrie<>(512);
|
||||
|
||||
static
|
||||
{
|
||||
|
@ -315,7 +315,7 @@ public class ExtensionConfig
|
|||
{
|
||||
private final String parameterizedName;
|
||||
private String name;
|
||||
private Map<String, String> params = new HashMap<>();
|
||||
private final Map<String, String> params = new HashMap<>();
|
||||
|
||||
public ParamParser(String parameterizedName)
|
||||
{
|
|
@ -193,11 +193,7 @@ public class Frame
|
|||
{
|
||||
return false;
|
||||
}
|
||||
if (!Arrays.equals(mask, other.mask))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return Arrays.equals(mask, other.mask);
|
||||
}
|
||||
|
||||
public byte[] getMask()
|
|
@ -19,8 +19,6 @@
|
|||
package org.eclipse.jetty.websocket.core;
|
||||
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.core.server.Negotiation;
|
||||
|
||||
/**
|
||||
* Interface for local WebSocket Endpoint Frame handling.
|
||||
|
@ -31,11 +29,11 @@ import org.eclipse.jetty.websocket.core.server.Negotiation;
|
|||
* is instantiated by the application, either:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>On the server, the application layer must provide a {@link org.eclipse.jetty.websocket.core.server.WebSocketNegotiator} instance
|
||||
* <li>On the server, the application layer must provide a {@code org.eclipse.jetty.websocket.core.server.WebSocketNegotiator} instance
|
||||
* to negotiate and accept websocket connections, which will return the FrameHandler instance to use from
|
||||
* {@link org.eclipse.jetty.websocket.core.server.WebSocketNegotiator#negotiate(Negotiation)}.</li>
|
||||
* <li>On the client, the application returns the FrameHandler instance to user from the {@link ClientUpgradeRequest}
|
||||
* instance that it passes to the {@link org.eclipse.jetty.websocket.core.client.WebSocketCoreClient#connect(ClientUpgradeRequest)} method/</li>
|
||||
* {@code org.eclipse.jetty.websocket.core.server.WebSocketNegotiator#negotiate(Negotiation)}.</li>
|
||||
* <li>On the client, the application returns the FrameHandler instance to user from the {@code ClientUpgradeRequest}
|
||||
* instance that it passes to the {@code org.eclipse.jetty.websocket.core.client.WebSocketCoreClient#connect(ClientUpgradeRequest)} method/</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Once instantiated the FrameHandler follows is used as follows:
|
|
@ -19,7 +19,6 @@
|
|||
package org.eclipse.jetty.websocket.core;
|
||||
|
||||
import java.util.zip.Deflater;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
|
@ -31,26 +30,14 @@ import org.eclipse.jetty.util.compression.InflaterPool;
|
|||
/**
|
||||
* A collection of components which are the resources needed for websockets such as
|
||||
* {@link ByteBufferPool}, {@link WebSocketExtensionRegistry}, and {@link DecoratedObjectFactory}.
|
||||
*
|
||||
* These components should be accessed through {@link WebSocketComponents#ensureWebSocketComponents} so that
|
||||
* the instance can be shared by being stored as a bean on the ContextHandler.
|
||||
*/
|
||||
public class WebSocketComponents
|
||||
{
|
||||
public static final String WEBSOCKET_COMPONENTS_ATTRIBUTE = WebSocketComponents.class.getName();
|
||||
|
||||
public static WebSocketComponents ensureWebSocketComponents(ServletContext servletContext)
|
||||
{
|
||||
// Ensure a mapping exists
|
||||
WebSocketComponents components = (WebSocketComponents)servletContext.getAttribute(WEBSOCKET_COMPONENTS_ATTRIBUTE);
|
||||
if (components == null)
|
||||
{
|
||||
components = new WebSocketComponents();
|
||||
servletContext.setAttribute(WEBSOCKET_COMPONENTS_ATTRIBUTE, components);
|
||||
}
|
||||
|
||||
return components;
|
||||
}
|
||||
private final DecoratedObjectFactory objectFactory;
|
||||
private final WebSocketExtensionRegistry extensionRegistry;
|
||||
private final ByteBufferPool bufferPool;
|
||||
private final InflaterPool inflaterPool;
|
||||
private final DeflaterPool deflaterPool;
|
||||
|
||||
public WebSocketComponents()
|
||||
{
|
||||
|
@ -69,12 +56,6 @@ public class WebSocketComponents
|
|||
this.inflaterPool = inflaterPool;
|
||||
}
|
||||
|
||||
private DecoratedObjectFactory objectFactory;
|
||||
private WebSocketExtensionRegistry extensionRegistry;
|
||||
private ByteBufferPool bufferPool;
|
||||
private InflaterPool inflaterPool;
|
||||
private DeflaterPool deflaterPool;
|
||||
|
||||
public ByteBufferPool getBufferPool()
|
||||
{
|
||||
return bufferPool;
|
|
@ -30,7 +30,7 @@ import org.eclipse.jetty.util.TypeUtil;
|
|||
|
||||
public class WebSocketExtensionRegistry implements Iterable<Class<? extends Extension>>
|
||||
{
|
||||
private Map<String, Class<? extends Extension>> availableExtensions = new HashMap<>();
|
||||
private final Map<String, Class<? extends Extension>> availableExtensions = new HashMap<>();
|
||||
|
||||
public WebSocketExtensionRegistry()
|
||||
{
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue