Merge branch 'jetty-9.4.x' into jetty-10.0.x
This commit is contained in:
commit
5e8a7403d1
|
@ -108,7 +108,7 @@ public class HttpRequest implements Request
|
|||
headers.put(userAgentField);
|
||||
}
|
||||
|
||||
protected HttpConversation getConversation()
|
||||
public HttpConversation getConversation()
|
||||
{
|
||||
return conversation;
|
||||
}
|
||||
|
|
|
@ -110,12 +110,12 @@ public class HttpChannelOverHTTP extends HttpChannel
|
|||
|
||||
// Upgrade Response
|
||||
HttpRequest request = exchange.getRequest();
|
||||
if (request instanceof HttpConnectionUpgrader)
|
||||
HttpConnectionUpgrader upgrader = (HttpConnectionUpgrader) request.getConversation().getAttribute(HttpConnectionUpgrader.class.getName());
|
||||
if (upgrader != null)
|
||||
{
|
||||
HttpConnectionUpgrader listener = (HttpConnectionUpgrader)request;
|
||||
try
|
||||
{
|
||||
listener.upgrade(response,getHttpConnection());
|
||||
upgrader.upgrade(response, getHttpConnection());
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<!--
|
||||
|
@ -73,73 +74,6 @@
|
|||
<excludes>META-INF/**</excludes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>populate distribution from home</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<copy todir="${assembly-directory}">
|
||||
<fileset dir="${home-directory}/jetty-home-${project.version}/" />
|
||||
</copy>
|
||||
</tasks>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>set jetty.sh</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<chmod dir="${assembly-directory}/bin" perm="755" includes="**/*.sh" />
|
||||
</tasks>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>removeKeystore</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<delete file="${assembly-directory}/etc/keystore" />
|
||||
</tasks>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-remote-resources-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>process</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<resourceBundles>
|
||||
<resourceBundle>org.eclipse.jetty.toolchain:jetty-distribution-remote-resources:1.2</resourceBundle>
|
||||
</resourceBundles>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy</id>
|
||||
<phase>prepare-package</phase>
|
||||
|
@ -321,6 +255,68 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>populate distribution from home</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<copy todir="${assembly-directory}">
|
||||
<fileset dir="${home-directory}/jetty-home-${project.version}/" />
|
||||
</copy>
|
||||
</tasks>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>set jetty.sh</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<chmod dir="${assembly-directory}/bin" perm="755" includes="**/*.sh" />
|
||||
</tasks>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>removeKeystore</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<delete file="${assembly-directory}/etc/keystore" />
|
||||
</tasks>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-remote-resources-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>process</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<resourceBundles>
|
||||
<resourceBundle>org.eclipse.jetty.toolchain:jetty-distribution-remote-resources:1.2</resourceBundle>
|
||||
</resourceBundles>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
|
|
|
@ -45,12 +45,15 @@
|
|||
<artifactId>pax-exam-junit4</artifactId>
|
||||
<version>${exam.version}</version>
|
||||
<scope>test</scope>
|
||||
<!-- not anymore as others tests use junit 5 -->
|
||||
<!--
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
-->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ops4j.pax.exam</groupId>
|
||||
|
|
|
@ -42,7 +42,7 @@ import java.io.StringReader;
|
|||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
|
||||
public class CookiePatternRuleTest
|
||||
|
|
|
@ -21,12 +21,12 @@ package org.eclipse.jetty.server.handler;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -2610,35 +2610,25 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
|
||||
// no security manager just return the classloader
|
||||
if (!_usingSecurityManager)
|
||||
{
|
||||
return _classLoader;
|
||||
}
|
||||
else
|
||||
{
|
||||
// check to see if the classloader of the caller is the same as the context
|
||||
// classloader, or a parent of it
|
||||
try
|
||||
{
|
||||
Class<?> reflect = Loader.loadClass("sun.reflect.Reflection");
|
||||
Method getCallerClass = reflect.getMethod("getCallerClass",Integer.TYPE);
|
||||
Class<?> caller = (Class<?>)getCallerClass.invoke(null,2);
|
||||
// classloader, or a parent of it, as required by the javadoc specification.
|
||||
|
||||
boolean ok = false;
|
||||
ClassLoader callerLoader = caller.getClassLoader();
|
||||
while (!ok && callerLoader != null)
|
||||
// Wrap in a PrivilegedAction so that only Jetty code will require the
|
||||
// "createSecurityManager" permission, not also application code that calls this method.
|
||||
Caller caller = AccessController.doPrivileged((PrivilegedAction<Caller>)Caller::new);
|
||||
ClassLoader callerLoader = caller.getCallerClassLoader(2);
|
||||
while (callerLoader != null)
|
||||
{
|
||||
if (callerLoader == _classLoader)
|
||||
ok = true;
|
||||
return _classLoader;
|
||||
else
|
||||
callerLoader = callerLoader.getParent();
|
||||
}
|
||||
|
||||
if (ok)
|
||||
return _classLoader;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to check classloader of caller",e);
|
||||
}
|
||||
|
||||
AccessController.checkPermission(new RuntimePermission("getClassLoader"));
|
||||
return _classLoader;
|
||||
}
|
||||
|
@ -3161,4 +3151,17 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
*/
|
||||
void exitScope(Context context, Request request);
|
||||
}
|
||||
|
||||
private static class Caller extends SecurityManager
|
||||
{
|
||||
public ClassLoader getCallerClassLoader(int depth)
|
||||
{
|
||||
if (depth < 0)
|
||||
return null;
|
||||
Class<?>[] classContext = getClassContext();
|
||||
if (classContext.length <= depth)
|
||||
return null;
|
||||
return classContext[depth].getClassLoader();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,12 +31,7 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.CompressedContentFormat;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.PreEncodedHttpField;
|
||||
import org.eclipse.jetty.http.*;
|
||||
import org.eclipse.jetty.http.pathmap.PathSpecSet;
|
||||
import org.eclipse.jetty.server.DeflaterPool;
|
||||
import org.eclipse.jetty.server.HttpOutput;
|
||||
|
@ -156,6 +151,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
|
|||
public static final int COMPRESSION_LEVEL = Deflater.DEFAULT_COMPRESSION;
|
||||
private static final Logger LOG = Log.getLogger(GzipHandler.class);
|
||||
private static final HttpField X_CE_GZIP = new PreEncodedHttpField("X-Content-Encoding","gzip");
|
||||
private static final HttpField TE_CHUNKED = new PreEncodedHttpField(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED.asString());
|
||||
private static final Pattern COMMA_GZIP = Pattern.compile(".*, *gzip");
|
||||
|
||||
private int POOL_CAPACITY = -1;
|
||||
|
@ -602,16 +598,17 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
|
|||
// Handle request inflation
|
||||
if (_inflateBufferSize>0)
|
||||
{
|
||||
boolean inflate = false;
|
||||
for (ListIterator<HttpField> i = baseRequest.getHttpFields().listIterator(); i.hasNext();)
|
||||
{
|
||||
HttpField field = i.next();
|
||||
if (field.getHeader()!=HttpHeader.CONTENT_ENCODING)
|
||||
continue;
|
||||
|
||||
if (field.getHeader()==HttpHeader.CONTENT_ENCODING)
|
||||
{
|
||||
if (field.getValue().equalsIgnoreCase("gzip"))
|
||||
{
|
||||
i.set(X_CE_GZIP);
|
||||
baseRequest.getHttpInput().addInterceptor(new GzipHttpInputInterceptor(baseRequest.getHttpChannel().getByteBufferPool(),_inflateBufferSize));
|
||||
inflate = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -621,12 +618,28 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
|
|||
v = v.substring(0, v.lastIndexOf(','));
|
||||
i.set(new HttpField(HttpHeader.CONTENT_ENCODING, v));
|
||||
i.add(X_CE_GZIP);
|
||||
baseRequest.getHttpInput().addInterceptor(new GzipHttpInputInterceptor(baseRequest.getHttpChannel().getByteBufferPool(),_inflateBufferSize));
|
||||
inflate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inflate)
|
||||
{
|
||||
baseRequest.getHttpInput().addInterceptor(new GzipHttpInputInterceptor(baseRequest.getHttpChannel().getByteBufferPool(), _inflateBufferSize));
|
||||
|
||||
for (ListIterator<HttpField> i = baseRequest.getHttpFields().listIterator(); i.hasNext();)
|
||||
{
|
||||
HttpField field = i.next();
|
||||
if (field.getHeader()==HttpHeader.CONTENT_LENGTH)
|
||||
{
|
||||
i.set(new HttpField("X-Content-Length", field.getValue()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Are we already being gzipped?
|
||||
HttpOutput out = baseRequest.getResponse().getHttpOutput();
|
||||
HttpOutput.Interceptor interceptor = out.getInterceptor();
|
||||
|
|
|
@ -27,7 +27,6 @@ import org.junit.jupiter.api.AfterEach;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.Socket;
|
||||
|
@ -38,7 +37,8 @@ import java.util.List;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class CustomResourcesMonitorTest
|
||||
{
|
||||
|
@ -111,28 +111,14 @@ public class CustomResourcesMonitorTest
|
|||
InputStream input1 = socket1.getInputStream();
|
||||
|
||||
assertTrue(_fileOnDirectoryMonitor.isLowOnResources());
|
||||
try
|
||||
{
|
||||
input1.read();
|
||||
fail();
|
||||
}
|
||||
catch (SocketTimeoutException expected)
|
||||
{
|
||||
}
|
||||
assertThrows(SocketTimeoutException.class, () -> input1.read());
|
||||
|
||||
// Wait a couple of lowResources idleTimeouts.
|
||||
Thread.sleep(2 * lowResourcesIdleTimeout);
|
||||
|
||||
// Verify the new socket is still open.
|
||||
assertTrue(_fileOnDirectoryMonitor.isLowOnResources());
|
||||
try
|
||||
{
|
||||
input1.read();
|
||||
fail();
|
||||
}
|
||||
catch (SocketTimeoutException expected)
|
||||
{
|
||||
}
|
||||
assertThrows(SocketTimeoutException.class, () -> input1.read());
|
||||
|
||||
Files.delete( tmpFile );
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
|||
import org.eclipse.jetty.util.thread.TimerScheduler;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -38,7 +39,6 @@ import java.util.concurrent.CountDownLatch;
|
|||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class LowResourcesMonitorTest
|
||||
|
@ -248,28 +248,15 @@ public class LowResourcesMonitorTest
|
|||
InputStream input1 = socket1.getInputStream();
|
||||
|
||||
assertTrue(_lowResourcesMonitor.isLowOnResources());
|
||||
try
|
||||
{
|
||||
input1.read();
|
||||
fail();
|
||||
}
|
||||
catch (SocketTimeoutException expected)
|
||||
{
|
||||
}
|
||||
assertThrows( SocketTimeoutException.class, () -> input1.read());
|
||||
|
||||
// Wait a couple of lowResources idleTimeouts.
|
||||
Thread.sleep(2 * lowResourcesIdleTimeout);
|
||||
|
||||
// Verify the new socket is still open.
|
||||
assertTrue(_lowResourcesMonitor.isLowOnResources());
|
||||
try
|
||||
{
|
||||
input1.read();
|
||||
fail();
|
||||
}
|
||||
catch (SocketTimeoutException expected)
|
||||
{
|
||||
}
|
||||
assertThrows( SocketTimeoutException.class, () -> input1.read());
|
||||
|
||||
// Let the maxLowResourcesTime elapse.
|
||||
Thread.sleep(maxLowResourcesTime);
|
||||
|
||||
|
|
|
@ -18,32 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.servlet;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalToIgnoringCase;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpTester;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
@ -54,6 +28,33 @@ import org.junit.jupiter.api.AfterEach;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class GzipHandlerTest
|
||||
{
|
||||
|
@ -104,6 +105,7 @@ public class GzipHandlerTest
|
|||
servlets.addServletWithMapping(IncludeServlet.class,"/include");
|
||||
servlets.addServletWithMapping(EchoServlet.class,"/echo/*");
|
||||
servlets.addServletWithMapping(DumpServlet.class,"/dump/*");
|
||||
servlets.addFilterWithMapping(CheckFilter.class,"/*", EnumSet.of(DispatcherType.REQUEST));
|
||||
|
||||
_server.start();
|
||||
}
|
||||
|
@ -510,6 +512,38 @@ public class GzipHandlerTest
|
|||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGzipRequestChunked() throws Exception
|
||||
{
|
||||
String data = "Hello Nice World! ";
|
||||
for (int i = 0; i < 10; ++i)
|
||||
data += data;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
GZIPOutputStream output = new GZIPOutputStream(baos);
|
||||
output.write(data.getBytes(StandardCharsets.UTF_8));
|
||||
output.close();
|
||||
byte[] bytes = baos.toByteArray();
|
||||
|
||||
// generated and parsed test
|
||||
HttpTester.Request request = HttpTester.newRequest();
|
||||
HttpTester.Response response;
|
||||
|
||||
request.setMethod("POST");
|
||||
request.setURI("/ctx/echo");
|
||||
request.setVersion("HTTP/1.1");
|
||||
request.setHeader("Host","tester");
|
||||
request.setHeader("Content-Type","text/plain");
|
||||
request.setHeader("Content-Encoding","gzip");
|
||||
request.add("Transfer-Encoding", "chunked");
|
||||
request.setContent(bytes);
|
||||
response = HttpTester.parseResponse(_connector.getResponse(request.generate()));
|
||||
|
||||
assertThat(response.getStatus(),is(200));
|
||||
assertThat(response.getContent(),is(data));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGzipFormRequest() throws Exception
|
||||
{
|
||||
|
@ -569,4 +603,26 @@ public class GzipHandlerTest
|
|||
assertThat(response.getContentBytes().length,is(512*1024));
|
||||
}
|
||||
|
||||
public static class CheckFilter implements Filter
|
||||
{
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
|
||||
{
|
||||
if (request.getParameter("X-Content-Encoding")!=null)
|
||||
assertEquals(-1,request.getContentLength());
|
||||
else if (request.getContentLength()>=0)
|
||||
assertThat(request.getParameter("X-Content-Encoding"),Matchers.nullValue());
|
||||
chain.doFilter(request,response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,10 +21,10 @@ package org.eclipse.jetty.util;
|
|||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
|
|
@ -24,7 +24,8 @@ import org.hamcrest.Matchers;
|
|||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -411,9 +411,9 @@ public class WebSocketUpgradeRequest extends HttpRequest implements CompleteList
|
|||
{
|
||||
throw new IllegalStateException("Unable to start WebSocketClient", e);
|
||||
}
|
||||
|
||||
this.localEndpoint = localEndpoint;
|
||||
this.fut = new CompletableFuture<>();
|
||||
|
||||
}
|
||||
|
||||
private final String genRandomKey()
|
||||
|
@ -503,6 +503,7 @@ public class WebSocketUpgradeRequest extends HttpRequest implements CompleteList
|
|||
}
|
||||
|
||||
Throwable failure = result.getFailure();
|
||||
|
||||
if ( (failure instanceof java.net.SocketException) ||
|
||||
(failure instanceof java.io.InterruptedIOException) ||
|
||||
(failure instanceof HttpResponseException) ||
|
||||
|
|
|
@ -845,7 +845,6 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
|
|||
endpointFunctions.getLog().warn("Error during OPEN", t);
|
||||
onError(new CloseException(StatusCode.SERVER_ERROR, t));
|
||||
}
|
||||
|
||||
/* Perform fillInterested outside of onConnected / onOpen.
|
||||
*
|
||||
* This is to allow for 2 specific scenarios.
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
import org.eclipse.jetty.server.SecureRequestCustomizer;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.SslConnectionFactory;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
import org.eclipse.jetty.server.handler.SecuredRedirectHandler;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.server.helper.EchoServlet;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class RedirectWebSocketClientTest
|
||||
{
|
||||
public static Server server;
|
||||
public static URI serverWsUri;
|
||||
public static URI serverWssUri;
|
||||
|
||||
@BeforeAll
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
|
||||
HttpConfiguration http_config = new HttpConfiguration();
|
||||
http_config.setSecureScheme("https");
|
||||
http_config.setSecurePort(0);
|
||||
http_config.setOutputBufferSize(32768);
|
||||
http_config.setRequestHeaderSize(8192);
|
||||
http_config.setResponseHeaderSize(8192);
|
||||
http_config.setSendServerVersion(true);
|
||||
http_config.setSendDateHeader(false);
|
||||
|
||||
SslContextFactory sslContextFactory = newSslContextFactory();
|
||||
|
||||
// SSL HTTP Configuration
|
||||
HttpConfiguration https_config = new HttpConfiguration(http_config);
|
||||
https_config.addCustomizer(new SecureRequestCustomizer());
|
||||
|
||||
// SSL Connector
|
||||
ServerConnector sslConnector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), new HttpConnectionFactory(https_config));
|
||||
sslConnector.setPort(0);
|
||||
server.addConnector(sslConnector);
|
||||
|
||||
// Normal Connector
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(0);
|
||||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler contextHandler = new ServletContextHandler();
|
||||
contextHandler.setContextPath("/");
|
||||
contextHandler.addServlet(EchoServlet.class, "/echo");
|
||||
|
||||
HandlerList handlers = new HandlerList();
|
||||
|
||||
handlers.addHandler(new SecuredRedirectHandler());
|
||||
handlers.addHandler(contextHandler);
|
||||
handlers.addHandler(new DefaultHandler());
|
||||
|
||||
server.setHandler(handlers);
|
||||
|
||||
server.start();
|
||||
|
||||
serverWsUri = URI.create("ws://localhost:" + connector.getLocalPort() + "/");
|
||||
serverWssUri = URI.create("wss://localhost:" + sslConnector.getLocalPort() + "/");
|
||||
|
||||
// adjust HttpConfiguration in connector
|
||||
HttpConnectionFactory connectionFactory = connector.getConnectionFactory(HttpConnectionFactory.class);
|
||||
connectionFactory.getHttpConfiguration().setSecurePort(sslConnector.getLocalPort());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
||||
private static SslContextFactory newSslContextFactory()
|
||||
{
|
||||
SslContextFactory ssl = new SslContextFactory();
|
||||
ssl.setKeyStorePath(MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath());
|
||||
ssl.setKeyStorePassword("storepwd");
|
||||
ssl.setKeyManagerPassword("keypwd");
|
||||
return ssl;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirect() throws Exception
|
||||
{
|
||||
SslContextFactory ssl = newSslContextFactory();
|
||||
ssl.setTrustAll(false);
|
||||
ssl.setEndpointIdentificationAlgorithm(null);
|
||||
HttpClient httpClient = new HttpClient(ssl);
|
||||
|
||||
WebSocketClient client = new WebSocketClient(httpClient);
|
||||
client.addBean(httpClient, true);
|
||||
client.start();
|
||||
|
||||
try
|
||||
{
|
||||
URI wsUri = serverWsUri.resolve("/echo");
|
||||
|
||||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
Future<Session> sessionFuture = client.connect(new EmptyWebSocket(), wsUri, request);
|
||||
Session session = sessionFuture.get();
|
||||
assertThat(session, is(notNullValue()));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@WebSocket
|
||||
public static class EmptyWebSocket {
|
||||
|
||||
}
|
||||
}
|
6
pom.xml
6
pom.xml
|
@ -38,6 +38,8 @@
|
|||
<weld.version>2.4.5.Final</weld.version>
|
||||
<jetty.perf-helper.version>1.0.5</jetty.perf-helper.version>
|
||||
<unix.socket.tmp></unix.socket.tmp>
|
||||
<!-- enable or not TestTracker junit5 extension i.e log message when test method is starting -->
|
||||
<jetty.testtracker.log>false</jetty.testtracker.log>
|
||||
|
||||
<!-- some maven plugins versions -->
|
||||
<maven.surefire.version>2.22.0</maven.surefire.version>
|
||||
|
@ -50,7 +52,7 @@
|
|||
|
||||
|
||||
<!-- testing -->
|
||||
<jetty.test.version>5.0</jetty.test.version>
|
||||
<jetty.test.version>5.1</jetty.test.version>
|
||||
</properties>
|
||||
|
||||
<licenses>
|
||||
|
@ -647,6 +649,8 @@
|
|||
<systemPropertyVariables>
|
||||
<java.io.tmpdir>${project.build.directory}</java.io.tmpdir>
|
||||
<unix.socket.tmp>${unix.socket.tmp}</unix.socket.tmp>
|
||||
<junit.jupiter.extensions.autodetection.enabled>true</junit.jupiter.extensions.autodetection.enabled>
|
||||
<jetty.testtracker.log>${jetty.testtracker.log}</jetty.testtracker.log>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -258,7 +258,7 @@ public class JettyDistro
|
|||
*/
|
||||
public JettyDistro(Class<?> clazz, String artifact) throws IOException
|
||||
{
|
||||
this.jettyHomeDir = MavenTestingUtils.getTargetTestingDir(clazz,"jettyHome");
|
||||
this.jettyHomeDir = MavenTestingUtils.getTargetTestingPath(clazz,"jettyHome").toFile();
|
||||
if (artifact != null)
|
||||
{
|
||||
this.artifactName = artifact;
|
||||
|
|
|
@ -22,6 +22,7 @@ package org.eclipse.jetty.gcloud.session;
|
|||
import org.eclipse.jetty.server.session.AbstractClusteredOrphanedSessionTest;
|
||||
import org.eclipse.jetty.server.session.SessionDataStoreFactory;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
|
@ -32,10 +33,25 @@ import org.junit.jupiter.api.Test;
|
|||
public class ClusteredOrphanedSessionTest extends AbstractClusteredOrphanedSessionTest
|
||||
{
|
||||
|
||||
public static GCloudSessionTestSupport __testSupport;
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp () throws Exception
|
||||
{
|
||||
__testSupport = new GCloudSessionTestSupport();
|
||||
__testSupport.setUp();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDown () throws Exception
|
||||
{
|
||||
__testSupport.tearDown();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void teardown () throws Exception
|
||||
{
|
||||
GCloudTestSuite.__testSupport.deleteSessions();
|
||||
__testSupport.deleteSessions();
|
||||
}
|
||||
|
||||
|
||||
|
@ -46,7 +62,7 @@ public class ClusteredOrphanedSessionTest extends AbstractClusteredOrphanedSessi
|
|||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore());
|
||||
return GCloudSessionTestSupport.newSessionDataStoreFactory(__testSupport.getDatastore());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ package org.eclipse.jetty.gcloud.session;
|
|||
import org.eclipse.jetty.server.session.AbstractClusteredSessionScavengingTest;
|
||||
import org.eclipse.jetty.server.session.SessionDataStoreFactory;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
/**
|
||||
* ClusteredSessionScavengingTest
|
||||
|
@ -31,10 +32,25 @@ import org.junit.jupiter.api.AfterAll;
|
|||
public class ClusteredSessionScavengingTest extends AbstractClusteredSessionScavengingTest
|
||||
{
|
||||
|
||||
public static GCloudSessionTestSupport __testSupport;
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp () throws Exception
|
||||
{
|
||||
__testSupport = new GCloudSessionTestSupport();
|
||||
__testSupport.setUp();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDown () throws Exception
|
||||
{
|
||||
__testSupport.tearDown();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void teardown () throws Exception
|
||||
{
|
||||
GCloudTestSuite.__testSupport.deleteSessions();
|
||||
__testSupport.deleteSessions();
|
||||
}
|
||||
|
||||
|
||||
|
@ -44,7 +60,7 @@ public class ClusteredSessionScavengingTest extends AbstractClusteredSessionScav
|
|||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore());
|
||||
return GCloudSessionTestSupport.newSessionDataStoreFactory(__testSupport.getDatastore());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -22,7 +22,9 @@ package org.eclipse.jetty.gcloud.session;
|
|||
import org.eclipse.jetty.server.session.AbstractSessionDataStoreTest;
|
||||
import org.eclipse.jetty.server.session.SessionData;
|
||||
import org.eclipse.jetty.server.session.SessionDataStoreFactory;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
/**
|
||||
* GCloudSessionDataStoreTest
|
||||
|
@ -32,24 +34,39 @@ import org.junit.jupiter.api.AfterEach;
|
|||
public class GCloudSessionDataStoreTest extends AbstractSessionDataStoreTest
|
||||
{
|
||||
|
||||
public static GCloudSessionTestSupport __testSupport;
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp () throws Exception
|
||||
{
|
||||
__testSupport = new GCloudSessionTestSupport();
|
||||
__testSupport.setUp();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDown () throws Exception
|
||||
{
|
||||
__testSupport.tearDown();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void teardown () throws Exception
|
||||
{
|
||||
GCloudTestSuite.__testSupport.deleteSessions();
|
||||
__testSupport.deleteSessions();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore());
|
||||
return GCloudSessionTestSupport.newSessionDataStoreFactory(__testSupport.getDatastore());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void persistSession(SessionData data) throws Exception
|
||||
{
|
||||
GCloudTestSuite.__testSupport.createSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), data.getCreated(),
|
||||
__testSupport.createSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), data.getCreated(),
|
||||
data.getAccessed(), data.getLastAccessed(), data.getMaxInactiveMs(), data.getExpiry(),
|
||||
data.getCookieSet(), data.getLastSaved(), data.getAllAttributes());
|
||||
|
||||
|
@ -60,7 +77,7 @@ public class GCloudSessionDataStoreTest extends AbstractSessionDataStoreTest
|
|||
public void persistUnreadableSession(SessionData data) throws Exception
|
||||
{
|
||||
|
||||
GCloudTestSuite.__testSupport.createSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), data.getCreated(),
|
||||
__testSupport.createSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), data.getCreated(),
|
||||
data.getAccessed(), data.getLastAccessed(), data.getMaxInactiveMs(), data.getExpiry(),
|
||||
data.getCookieSet(), data.getLastSaved(), null);
|
||||
}
|
||||
|
@ -69,7 +86,7 @@ public class GCloudSessionDataStoreTest extends AbstractSessionDataStoreTest
|
|||
@Override
|
||||
public boolean checkSessionExists(SessionData data) throws Exception
|
||||
{
|
||||
return GCloudTestSuite.__testSupport.checkSessionExists(data.getId());
|
||||
return __testSupport.checkSessionExists(data.getId());
|
||||
}
|
||||
|
||||
|
||||
|
@ -79,7 +96,7 @@ public class GCloudSessionDataStoreTest extends AbstractSessionDataStoreTest
|
|||
@Override
|
||||
public boolean checkSessionPersisted(SessionData data) throws Exception
|
||||
{
|
||||
return GCloudTestSuite.__testSupport.checkSessionPersisted(data);
|
||||
return __testSupport.checkSessionPersisted(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.gcloud.session;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
|
||||
/**
|
||||
* GCloudTestSuite
|
||||
*
|
||||
* Sets up the gcloud emulator once before running all tests.
|
||||
*
|
||||
*/
|
||||
@RunWith(Suite.class)
|
||||
@Suite.SuiteClasses({
|
||||
GCloudSessionDataStoreTest.class,
|
||||
InvalidationSessionTest.class,
|
||||
ClusteredSessionScavengingTest.class,
|
||||
ClusteredOrphanedSessionTest.class
|
||||
})
|
||||
public class GCloudTestSuite
|
||||
{
|
||||
public static GCloudSessionTestSupport __testSupport;
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp () throws Exception
|
||||
{
|
||||
__testSupport = new GCloudSessionTestSupport();
|
||||
__testSupport.setUp();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDown () throws Exception
|
||||
{
|
||||
__testSupport.tearDown();
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ package org.eclipse.jetty.gcloud.session;
|
|||
import org.eclipse.jetty.server.session.AbstractClusteredInvalidationSessionTest;
|
||||
import org.eclipse.jetty.server.session.SessionDataStoreFactory;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
/**
|
||||
* InvalidationSessionTest
|
||||
|
@ -32,10 +33,25 @@ import org.junit.jupiter.api.AfterAll;
|
|||
public class InvalidationSessionTest extends AbstractClusteredInvalidationSessionTest
|
||||
{
|
||||
|
||||
public static GCloudSessionTestSupport __testSupport;
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp () throws Exception
|
||||
{
|
||||
__testSupport = new GCloudSessionTestSupport();
|
||||
__testSupport.setUp();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDown () throws Exception
|
||||
{
|
||||
__testSupport.tearDown();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void teardown () throws Exception
|
||||
{
|
||||
GCloudTestSuite.__testSupport.deleteSessions();
|
||||
__testSupport.deleteSessions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -44,6 +60,6 @@ public class InvalidationSessionTest extends AbstractClusteredInvalidationSessio
|
|||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore());
|
||||
return GCloudSessionTestSupport.newSessionDataStoreFactory(__testSupport.getDatastore());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue