Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-10.0.x-1743-refactor-maven-plugin-redux
Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
commit
79c2b819c7
|
@ -19,6 +19,7 @@
|
||||||
package org.eclipse.jetty.alpn.java.server;
|
package org.eclipse.jetty.alpn.java.server;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -26,6 +27,7 @@ import java.nio.charset.StandardCharsets;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.SSLParameters;
|
import javax.net.ssl.SSLParameters;
|
||||||
import javax.net.ssl.SSLSocket;
|
import javax.net.ssl.SSLSocket;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
@ -85,10 +87,10 @@ public class JDK9ALPNTest
|
||||||
@Test
|
@Test
|
||||||
public void testClientNotSupportingALPNServerSpeaksDefaultProtocol() throws Exception
|
public void testClientNotSupportingALPNServerSpeaksDefaultProtocol() throws Exception
|
||||||
{
|
{
|
||||||
startServer(new AbstractHandler.ErrorDispatchHandler()
|
startServer(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
}
|
}
|
||||||
|
@ -127,10 +129,10 @@ public class JDK9ALPNTest
|
||||||
@Test
|
@Test
|
||||||
public void testClientSupportingALPNServerSpeaksNegotiatedProtocol() throws Exception
|
public void testClientSupportingALPNServerSpeaksNegotiatedProtocol() throws Exception
|
||||||
{
|
{
|
||||||
startServer(new AbstractHandler.ErrorDispatchHandler()
|
startServer(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,10 +26,10 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
|
|
||||||
public class EmptyServerHandler extends AbstractHandler.ErrorDispatchHandler
|
public class EmptyServerHandler extends AbstractHandler
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected final void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public final void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
jettyRequest.setHandled(true);
|
jettyRequest.setHandled(true);
|
||||||
service(target, jettyRequest, request, response);
|
service(target, jettyRequest, request, response);
|
||||||
|
|
|
@ -534,10 +534,10 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
||||||
@ArgumentsSource(ScenarioProvider.class)
|
@ArgumentsSource(ScenarioProvider.class)
|
||||||
public void test_ExchangeIsComplete_OnlyWhenBothRequestAndResponseAreComplete(Scenario scenario) throws Exception
|
public void test_ExchangeIsComplete_OnlyWhenBothRequestAndResponseAreComplete(Scenario scenario) throws Exception
|
||||||
{
|
{
|
||||||
start(scenario, new AbstractHandler.ErrorDispatchHandler()
|
start(scenario, new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
response.setContentLength(0);
|
response.setContentLength(0);
|
||||||
|
|
|
@ -143,6 +143,7 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
|
||||||
_scanner.setRecursive(_recursive);
|
_scanner.setRecursive(_recursive);
|
||||||
_scanner.setFilenameFilter(_filenameFilter);
|
_scanner.setFilenameFilter(_filenameFilter);
|
||||||
_scanner.setReportDirs(true);
|
_scanner.setReportDirs(true);
|
||||||
|
_scanner.setScanDepth(1); //consider direct dir children of monitored dir
|
||||||
_scanner.addListener(_scannerListener);
|
_scanner.addListener(_scannerListener);
|
||||||
|
|
||||||
addBean(_scanner);
|
addBean(_scanner);
|
||||||
|
|
|
@ -81,6 +81,11 @@ public class WebAppProvider extends ScanningAppProvider
|
||||||
String lowername = name.toLowerCase(Locale.ENGLISH);
|
String lowername = name.toLowerCase(Locale.ENGLISH);
|
||||||
|
|
||||||
File file = new File(dir, name);
|
File file = new File(dir, name);
|
||||||
|
Resource r = Resource.newResource(file);
|
||||||
|
if (getMonitoredResources().contains(r) && r.isDirectory())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// ignore hidden files
|
// ignore hidden files
|
||||||
if (lowername.startsWith("."))
|
if (lowername.startsWith("."))
|
||||||
|
|
|
@ -83,6 +83,11 @@ public class SettingsBodyParser extends BodyParser
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(ByteBuffer buffer)
|
public boolean parse(ByteBuffer buffer)
|
||||||
|
{
|
||||||
|
return parse(buffer, getStreamId(), getBodyLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean parse(ByteBuffer buffer, int streamId, int bodyLength)
|
||||||
{
|
{
|
||||||
while (buffer.hasRemaining())
|
while (buffer.hasRemaining())
|
||||||
{
|
{
|
||||||
|
@ -91,9 +96,9 @@ public class SettingsBodyParser extends BodyParser
|
||||||
case PREPARE:
|
case PREPARE:
|
||||||
{
|
{
|
||||||
// SPEC: wrong streamId is treated as connection error.
|
// SPEC: wrong streamId is treated as connection error.
|
||||||
if (getStreamId() != 0)
|
if (streamId != 0)
|
||||||
return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_settings_frame");
|
return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_settings_frame");
|
||||||
length = getBodyLength();
|
length = bodyLength;
|
||||||
settings = new HashMap<>();
|
settings = new HashMap<>();
|
||||||
state = State.SETTING_ID;
|
state = State.SETTING_ID;
|
||||||
break;
|
break;
|
||||||
|
@ -216,6 +221,13 @@ public class SettingsBodyParser extends BodyParser
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Parses the given buffer containing the whole body of a {@code SETTINGS} frame
|
||||||
|
* (without header bytes), typically from the {@code HTTP2-Settings} header.</p>
|
||||||
|
*
|
||||||
|
* @param buffer the buffer containing the body of {@code SETTINGS} frame
|
||||||
|
* @return the {@code SETTINGS} frame from the parsed body bytes
|
||||||
|
*/
|
||||||
public static SettingsFrame parseBody(final ByteBuffer buffer)
|
public static SettingsFrame parseBody(final ByteBuffer buffer)
|
||||||
{
|
{
|
||||||
AtomicReference<SettingsFrame> frameRef = new AtomicReference<>();
|
AtomicReference<SettingsFrame> frameRef = new AtomicReference<>();
|
||||||
|
@ -234,7 +246,7 @@ public class SettingsBodyParser extends BodyParser
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (buffer.hasRemaining())
|
if (buffer.hasRemaining())
|
||||||
parser.parse(buffer);
|
parser.parse(buffer, 0, buffer.remaining());
|
||||||
else
|
else
|
||||||
parser.emptyBody(buffer);
|
parser.emptyBody(buffer);
|
||||||
return frameRef.get();
|
return frameRef.get();
|
||||||
|
|
|
@ -26,10 +26,10 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
|
|
||||||
public class EmptyServerHandler extends AbstractHandler.ErrorDispatchHandler
|
public class EmptyServerHandler extends AbstractHandler
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected final void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public final void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
jettyRequest.setHandled(true);
|
jettyRequest.setHandled(true);
|
||||||
service(target, jettyRequest, request, response);
|
service(target, jettyRequest, request, response);
|
||||||
|
|
|
@ -125,7 +125,7 @@ public class HTTP2CServerTest extends AbstractServerTest
|
||||||
"Host: localhost\r\n" +
|
"Host: localhost\r\n" +
|
||||||
"Connection: something, else, upgrade, HTTP2-Settings\r\n" +
|
"Connection: something, else, upgrade, HTTP2-Settings\r\n" +
|
||||||
"Upgrade: h2c\r\n" +
|
"Upgrade: h2c\r\n" +
|
||||||
"HTTP2-Settings: \r\n" +
|
"HTTP2-Settings: AAEAAEAAAAIAAAABAAMAAABkAAQBAAAAAAUAAEAA\r\n" +
|
||||||
"\r\n").getBytes(StandardCharsets.ISO_8859_1));
|
"\r\n").getBytes(StandardCharsets.ISO_8859_1));
|
||||||
output.flush();
|
output.flush();
|
||||||
|
|
||||||
|
|
|
@ -26,9 +26,9 @@ import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.PathMatcher;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -57,7 +57,8 @@ import org.eclipse.jetty.security.LoginService;
|
||||||
import org.eclipse.jetty.server.RequestLog;
|
import org.eclipse.jetty.server.RequestLog;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
import org.eclipse.jetty.util.PathWatcher;
|
import org.eclipse.jetty.util.IncludeExcludeSet;
|
||||||
|
import org.eclipse.jetty.util.Scanner;
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -847,22 +848,18 @@ public abstract class AbstractWebAppMojo extends AbstractMojo
|
||||||
* Configure any extra files, directories or patterns thereof for the
|
* Configure any extra files, directories or patterns thereof for the
|
||||||
* scanner to watch for changes.
|
* scanner to watch for changes.
|
||||||
*
|
*
|
||||||
* @param scanner PathWatcher that notices changes in files and dirs.
|
* @param scanner Scanner that notices changes in files and dirs.
|
||||||
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
protected void configureScanTargetPatterns(PathWatcher scanner)
|
protected void configureScanTargetPatterns(Scanner scanner) throws IOException
|
||||||
{
|
{
|
||||||
//handle the extra scan patterns
|
//handle the extra scan patterns
|
||||||
if (scanTargetPatterns != null)
|
if (scanTargetPatterns != null)
|
||||||
{
|
{
|
||||||
for (ScanTargetPattern p:scanTargetPatterns)
|
for (ScanTargetPattern p : scanTargetPatterns)
|
||||||
{
|
{
|
||||||
PathWatcher.Config config = new PathWatcher.Config(p.getDirectory().toPath());
|
IncludeExcludeSet<PathMatcher, Path> includesExcludes = scanner.addDirectory(p.getDirectory().toPath());
|
||||||
config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
|
p.configureIncludesExcludeSet(includesExcludes);
|
||||||
for (String pattern:p.getExcludes())
|
|
||||||
config.addExcludeGlobRelative(pattern);
|
|
||||||
for (String pattern:p.getIncludes())
|
|
||||||
config.addIncludeGlobRelative(pattern);
|
|
||||||
scanner.watch(config);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
package org.eclipse.jetty.maven.plugin;
|
package org.eclipse.jetty.maven.plugin;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.PathMatcher;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -30,8 +32,10 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
|
||||||
import org.apache.maven.plugins.annotations.Mojo;
|
import org.apache.maven.plugins.annotations.Mojo;
|
||||||
import org.apache.maven.plugins.annotations.Parameter;
|
import org.apache.maven.plugins.annotations.Parameter;
|
||||||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||||
|
import org.eclipse.jetty.util.IncludeExcludeSet;
|
||||||
import org.eclipse.jetty.util.PathWatcher;
|
import org.eclipse.jetty.util.PathWatcher;
|
||||||
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
|
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
|
||||||
|
import org.eclipse.jetty.util.Scanner;
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
import org.eclipse.jetty.webapp.WebAppContext;
|
import org.eclipse.jetty.webapp.WebAppContext;
|
||||||
|
|
||||||
|
@ -68,7 +72,7 @@ public class JettyRunMojo extends AbstractUnassembledWebAppMojo
|
||||||
/**
|
/**
|
||||||
* Scanner to check for files changes to cause redeploy
|
* Scanner to check for files changes to cause redeploy
|
||||||
*/
|
*/
|
||||||
protected PathWatcher scanner;
|
protected Scanner scanner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only one of the following will be used, depending the mode
|
* Only one of the following will be used, depending the mode
|
||||||
|
@ -154,9 +158,11 @@ public class JettyRunMojo extends AbstractUnassembledWebAppMojo
|
||||||
// start scanning for changes, or wait for linefeed on stdin
|
// start scanning for changes, or wait for linefeed on stdin
|
||||||
if (scan > 0)
|
if (scan > 0)
|
||||||
{
|
{
|
||||||
scanner = new PathWatcher();
|
scanner = new Scanner();
|
||||||
|
scanner.setScanInterval(scan);
|
||||||
|
scanner.setScanDepth(Scanner.MAX_SCAN_DEPTH); //always fully walk directory hierarchies
|
||||||
|
scanner.setReportExistingFilesOnStartup(false);
|
||||||
configureScanner();
|
configureScanner();
|
||||||
scanner.setNotifyExistingOnStart(false);
|
|
||||||
scanner.start();
|
scanner.start();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -194,27 +200,13 @@ public class JettyRunMojo extends AbstractUnassembledWebAppMojo
|
||||||
{
|
{
|
||||||
throw new MojoExecutionException("Error forming scan list", e);
|
throw new MojoExecutionException("Error forming scan list", e);
|
||||||
}
|
}
|
||||||
|
scanner.addListener(new Scanner.BulkListener()
|
||||||
scanner.addListener(new PathWatcher.EventListListener()
|
|
||||||
{
|
{
|
||||||
@Override
|
public void filesChanged(List<String> changes)
|
||||||
public void onPathWatchEvents(List<PathWatchEvent> events)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
boolean reconfigure = false;
|
boolean reconfigure = changes.contains(project.getFile().getCanonicalPath());
|
||||||
if (events != null)
|
|
||||||
{
|
|
||||||
for (PathWatchEvent e:events)
|
|
||||||
{
|
|
||||||
if (e.getPath().equals(project.getFile().toPath()))
|
|
||||||
{
|
|
||||||
reconfigure = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
restartWebApp(reconfigure);
|
restartWebApp(reconfigure);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -230,77 +222,95 @@ public class JettyRunMojo extends AbstractUnassembledWebAppMojo
|
||||||
if (webApp.getDescriptor() != null)
|
if (webApp.getDescriptor() != null)
|
||||||
{
|
{
|
||||||
Resource r = Resource.newResource(webApp.getDescriptor());
|
Resource r = Resource.newResource(webApp.getDescriptor());
|
||||||
scanner.watch(r.getFile().toPath());
|
scanner.addFile(r.getFile().toPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webApp.getJettyEnvXml() != null)
|
if (webApp.getJettyEnvXml() != null)
|
||||||
scanner.watch(new File(webApp.getJettyEnvXml()).toPath());
|
scanner.addFile(new File(webApp.getJettyEnvXml()).toPath());
|
||||||
|
|
||||||
if (webApp.getDefaultsDescriptor() != null)
|
if (webApp.getDefaultsDescriptor() != null)
|
||||||
{
|
{
|
||||||
if (!WebAppContext.WEB_DEFAULTS_XML.equals(webApp.getDefaultsDescriptor()))
|
if (!WebAppContext.WEB_DEFAULTS_XML.equals(webApp.getDefaultsDescriptor()))
|
||||||
scanner.watch(new File(webApp.getDefaultsDescriptor()).toPath());
|
scanner.addFile(new File(webApp.getDefaultsDescriptor()).toPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webApp.getOverrideDescriptor() != null)
|
if (webApp.getOverrideDescriptor() != null)
|
||||||
{
|
{
|
||||||
scanner.watch(new File(webApp.getOverrideDescriptor()).toPath());
|
scanner.addFile(new File(webApp.getOverrideDescriptor()).toPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
File jettyWebXmlFile = findJettyWebXmlFile(new File(webAppSourceDirectory,"WEB-INF"));
|
File jettyWebXmlFile = findJettyWebXmlFile(new File(webAppSourceDirectory,"WEB-INF"));
|
||||||
if (jettyWebXmlFile != null)
|
if (jettyWebXmlFile != null)
|
||||||
{
|
{
|
||||||
scanner.watch(jettyWebXmlFile.toPath());
|
scanner.addFile(jettyWebXmlFile.toPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
//make sure each of the war artifacts is added to the scanner
|
//make sure each of the war artifacts is added to the scanner
|
||||||
for (Artifact a:mavenProjectHelper.getWarPluginInfo().getWarArtifacts())
|
for (Artifact a:mavenProjectHelper.getWarPluginInfo().getWarArtifacts())
|
||||||
{
|
{
|
||||||
scanner.watch(a.getFile().toPath());
|
File f = a.getFile();
|
||||||
|
if (a.getFile().isDirectory())
|
||||||
|
scanner.addDirectory(f.toPath());
|
||||||
|
else
|
||||||
|
scanner.addFile(f.toPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
//set up any extra files or dirs to watch
|
//set up any extra files or dirs to watch
|
||||||
configureScanTargetPatterns(scanner);
|
configureScanTargetPatterns(scanner);
|
||||||
|
|
||||||
scanner.watch(project.getFile().toPath());
|
scanner.addFile(project.getFile().toPath());
|
||||||
|
|
||||||
if (webApp.getTestClasses() != null && webApp.getTestClasses().exists())
|
if (webApp.getTestClasses() != null && webApp.getTestClasses().exists())
|
||||||
{
|
{
|
||||||
PathWatcher.Config config = new PathWatcher.Config(webApp.getTestClasses().toPath());
|
Path p = webApp.getTestClasses().toPath();
|
||||||
config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
|
IncludeExcludeSet<PathMatcher, Path> includeExcludeSet = scanner.addDirectory(p);
|
||||||
if (scanTestClassesPattern != null)
|
if (scanTestClassesPattern != null)
|
||||||
{
|
{
|
||||||
for (String p:scanTestClassesPattern.getExcludes())
|
for (String s : scanTestClassesPattern.getExcludes())
|
||||||
config.addExcludeGlobRelative(p);
|
{
|
||||||
for (String p:scanTestClassesPattern.getIncludes())
|
if (!s.startsWith("glob:"))
|
||||||
config.addIncludeGlobRelative(p);
|
s = "glob:" + s;
|
||||||
|
includeExcludeSet.exclude(p.getFileSystem().getPathMatcher(s));
|
||||||
|
}
|
||||||
|
for (String s : scanTestClassesPattern.getIncludes())
|
||||||
|
{
|
||||||
|
if (!s.startsWith("glob:"))
|
||||||
|
s = "glob:" + s;
|
||||||
|
includeExcludeSet.include(p.getFileSystem().getPathMatcher(s));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
scanner.watch(config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webApp.getClasses() != null && webApp.getClasses().exists())
|
if (webApp.getClasses() != null && webApp.getClasses().exists())
|
||||||
{
|
{
|
||||||
PathWatcher.Config config = new PathWatcher.Config(webApp.getClasses().toPath());
|
Path p = webApp.getClasses().toPath();
|
||||||
config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
|
IncludeExcludeSet<PathMatcher, Path> includeExcludes = scanner.addDirectory(p);
|
||||||
if (scanClassesPattern != null)
|
if (scanClassesPattern != null)
|
||||||
{
|
{
|
||||||
for (String p:scanClassesPattern.getExcludes())
|
for (String s : scanClassesPattern.getExcludes())
|
||||||
config.addExcludeGlobRelative(p);
|
{
|
||||||
|
if (!s.startsWith("glob:"))
|
||||||
|
s = "glob:" + s;
|
||||||
|
includeExcludes.exclude(p.getFileSystem().getPathMatcher(s));
|
||||||
|
}
|
||||||
|
|
||||||
for (String p:scanClassesPattern.getIncludes())
|
for (String s : scanClassesPattern.getIncludes())
|
||||||
config.addIncludeGlobRelative(p);
|
{
|
||||||
|
if (!s.startsWith("glob:"))
|
||||||
}
|
s = "glob:" + s;
|
||||||
scanner.watch(config);
|
includeExcludes.include(p.getFileSystem().getPathMatcher(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webApp.getWebInfLib() != null)
|
if (webApp.getWebInfLib() != null)
|
||||||
{
|
{
|
||||||
for (File f:webApp.getWebInfLib())
|
for (File f : webApp.getWebInfLib())
|
||||||
{
|
{
|
||||||
PathWatcher.Config config = new PathWatcher.Config(f.toPath());
|
if (f.isDirectory())
|
||||||
config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
|
scanner.addDirectory(f.toPath());
|
||||||
scanner.watch(config);
|
else
|
||||||
|
scanner.addFile(f.toPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.maven.plugin;
|
package org.eclipse.jetty.maven.plugin;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -29,8 +30,7 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
|
||||||
import org.apache.maven.plugins.annotations.Mojo;
|
import org.apache.maven.plugins.annotations.Mojo;
|
||||||
import org.apache.maven.plugins.annotations.Parameter;
|
import org.apache.maven.plugins.annotations.Parameter;
|
||||||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||||
import org.eclipse.jetty.util.PathWatcher;
|
import org.eclipse.jetty.util.Scanner;
|
||||||
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
|
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,7 +65,7 @@ public class JettyRunWarMojo extends AbstractWebAppMojo
|
||||||
/**
|
/**
|
||||||
* Scanner to check for files changes to cause redeploy
|
* Scanner to check for files changes to cause redeploy
|
||||||
*/
|
*/
|
||||||
protected PathWatcher scanner;
|
protected Scanner scanner;
|
||||||
protected JettyEmbedder embedder;
|
protected JettyEmbedder embedder;
|
||||||
protected JettyForker forker;
|
protected JettyForker forker;
|
||||||
protected JettyDistroForker distroForker;
|
protected JettyDistroForker distroForker;
|
||||||
|
@ -155,9 +155,11 @@ public class JettyRunWarMojo extends AbstractWebAppMojo
|
||||||
// start scanning for changes, or wait for linefeed on stdin
|
// start scanning for changes, or wait for linefeed on stdin
|
||||||
if (scan > 0)
|
if (scan > 0)
|
||||||
{
|
{
|
||||||
scanner = new PathWatcher();
|
scanner = new Scanner();
|
||||||
|
scanner.setScanInterval(scan);
|
||||||
|
scanner.setScanDepth(Scanner.MAX_SCAN_DEPTH); //always fully walk directory hierarchies
|
||||||
|
scanner.setReportExistingFilesOnStartup(false);
|
||||||
configureScanner();
|
configureScanner();
|
||||||
scanner.setNotifyExistingOnStart(false);
|
|
||||||
scanner.start();
|
scanner.start();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -186,36 +188,33 @@ public class JettyRunWarMojo extends AbstractWebAppMojo
|
||||||
|
|
||||||
public void configureScanner() throws MojoExecutionException
|
public void configureScanner() throws MojoExecutionException
|
||||||
{
|
{
|
||||||
scanner.watch(project.getFile().toPath());
|
try
|
||||||
scanner.watch(war);
|
|
||||||
|
|
||||||
//set up any extra files or dirs to watch
|
|
||||||
configureScanTargetPatterns(scanner);
|
|
||||||
|
|
||||||
scanner.addListener(new PathWatcher.EventListListener()
|
|
||||||
{
|
{
|
||||||
@Override
|
scanner.addFile(project.getFile().toPath());
|
||||||
public void onPathWatchEvents(List<PathWatchEvent> events)
|
scanner.addFile(war);
|
||||||
|
|
||||||
|
//set up any extra files or dirs to watch
|
||||||
|
configureScanTargetPatterns(scanner);
|
||||||
|
scanner.addListener(new Scanner.BulkListener()
|
||||||
{
|
{
|
||||||
try
|
public void filesChanged(List<String> changes)
|
||||||
{
|
{
|
||||||
boolean reconfigure = false;
|
try
|
||||||
for (PathWatchEvent e:events)
|
|
||||||
{
|
{
|
||||||
if (e.getPath().equals(project.getFile().toPath()))
|
boolean reconfigure = changes.contains(project.getFile().getCanonicalPath());
|
||||||
{
|
restartWebApp(reconfigure);
|
||||||
reconfigure = true;
|
}
|
||||||
break;
|
catch (Exception e)
|
||||||
}
|
{
|
||||||
|
getLog().error("Error reconfiguring/restarting webapp after change in watched files",e);
|
||||||
}
|
}
|
||||||
restartWebApp(reconfigure);
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
});
|
||||||
{
|
}
|
||||||
getLog().error("Error reconfiguring/restarting webapp after change in watched files",e);
|
catch (IOException e)
|
||||||
}
|
{
|
||||||
}
|
throw new MojoExecutionException("Error configuring scanner", e);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void restartWebApp(boolean reconfigure) throws Exception
|
public void restartWebApp(boolean reconfigure) throws Exception
|
||||||
|
@ -288,7 +287,7 @@ public class JettyRunWarMojo extends AbstractWebAppMojo
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("Unrecognized run type " +deployMode);
|
throw new IllegalStateException("Unrecognized run type " + deployMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getLog().info("Restart completed.");
|
getLog().info("Restart completed.");
|
||||||
|
|
|
@ -24,7 +24,7 @@ import java.util.List;
|
||||||
/**
|
/**
|
||||||
* ScanPattern
|
* ScanPattern
|
||||||
*
|
*
|
||||||
* A pattern of includes and excludes.
|
* Ant-style pattern of includes and excludes.
|
||||||
*/
|
*/
|
||||||
public class ScanPattern
|
public class ScanPattern
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,9 +19,13 @@
|
||||||
package org.eclipse.jetty.maven.plugin;
|
package org.eclipse.jetty.maven.plugin;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.PathMatcher;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.IncludeExcludeSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ScanTargetPattern
|
* ScanTargetPattern
|
||||||
*
|
*
|
||||||
|
@ -87,4 +91,21 @@ public class ScanTargetPattern
|
||||||
{
|
{
|
||||||
return (_pattern == null ? Collections.emptyList() : _pattern.getExcludes());
|
return (_pattern == null ? Collections.emptyList() : _pattern.getExcludes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void configureIncludesExcludeSet(IncludeExcludeSet<PathMatcher, Path> includesExcludes)
|
||||||
|
{
|
||||||
|
for (String include:getIncludes())
|
||||||
|
{
|
||||||
|
if (!include.startsWith("glob:"))
|
||||||
|
include = "glob:" + include;
|
||||||
|
includesExcludes.include(_directory.toPath().getFileSystem().getPathMatcher(include));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String exclude:getExcludes())
|
||||||
|
{
|
||||||
|
if (!exclude.startsWith("glob:"))
|
||||||
|
exclude = "glob:" + exclude;
|
||||||
|
includesExcludes.exclude(_directory.toPath().getFileSystem().getPathMatcher(exclude));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class HttpServiceErrorPageErrorHandler extends ErrorPageErrorHandler
|
||||||
@Override
|
@Override
|
||||||
public void handle(String target, Request baseRequest,
|
public void handle(String target, Request baseRequest,
|
||||||
HttpServletRequest request, HttpServletResponse response)
|
HttpServletRequest request, HttpServletResponse response)
|
||||||
throws IOException
|
throws IOException, ServletException
|
||||||
{
|
{
|
||||||
if (HttpServiceErrorHandlerHelper.getCustomErrorHandler() != null)
|
if (HttpServiceErrorHandlerHelper.getCustomErrorHandler() != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -79,6 +79,12 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-util-ajax</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory$Server">
|
<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory$Server">
|
||||||
<Set name="Provider" property="jetty.sslContext.provider"/>
|
<Set name="Provider" property="jetty.sslContext.provider"/>
|
||||||
<Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.sslContext.keyStorePath" default="etc/keystore"/></Set>
|
<Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.sslContext.keyStorePath" default="etc/keystore"/></Set>
|
||||||
<Set name="KeyStorePassword"><Property name="jetty.sslContext.keyStorePassword" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
|
<Set name="KeyStorePassword"><Property name="jetty.sslContext.keyStorePassword"/></Set>
|
||||||
<Set name="KeyStoreType" property="jetty.sslContext.keyStoreType"/>
|
<Set name="KeyStoreType" property="jetty.sslContext.keyStoreType"/>
|
||||||
<Set name="KeyStoreProvider" property="jetty.sslContext.keyStoreProvider"/>
|
<Set name="KeyStoreProvider" property="jetty.sslContext.keyStoreProvider"/>
|
||||||
<Set name="KeyManagerPassword"><Property name="jetty.sslContext.keyManagerPassword" default="OBF:1u2u1wml1z7s1z7a1wnl1u2g"/></Set>
|
<Set name="KeyManagerPassword"><Property name="jetty.sslContext.keyManagerPassword"/></Set>
|
||||||
<Set name="TrustStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.sslContext.trustStorePath" default="etc/keystore"/></Set>
|
<Set name="TrustStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.sslContext.trustStorePath" default="etc/keystore"/></Set>
|
||||||
<Set name="TrustStorePassword" property="jetty.sslContext.trustStorePassword"/>
|
<Set name="TrustStorePassword" property="jetty.sslContext.trustStorePassword"/>
|
||||||
<Set name="TrustStoreType" property="jetty.sslContext.trustStoreType"/>
|
<Set name="TrustStoreType" property="jetty.sslContext.trustStoreType"/>
|
||||||
|
@ -29,6 +29,7 @@
|
||||||
<Set name="sslSessionTimeout" property="jetty.sslContext.sslSessionTimeout"/>
|
<Set name="sslSessionTimeout" property="jetty.sslContext.sslSessionTimeout"/>
|
||||||
<Set name="RenegotiationAllowed" property="jetty.sslContext.renegotiationAllowed"/>
|
<Set name="RenegotiationAllowed" property="jetty.sslContext.renegotiationAllowed"/>
|
||||||
<Set name="RenegotiationLimit" property="jetty.sslContext.renegotiationLimit"/>
|
<Set name="RenegotiationLimit" property="jetty.sslContext.renegotiationLimit"/>
|
||||||
|
<Set name="SniRequired" property="jetty.sslContext.sniRequired"/>
|
||||||
|
|
||||||
<!-- Example of how to configure a PKIX Certificate Path revocation Checker
|
<!-- Example of how to configure a PKIX Certificate Path revocation Checker
|
||||||
<Call id="pkixPreferCrls" class="java.security.cert.PKIXRevocationChecker$Option" name="valueOf"><Arg>PREFER_CRLS</Arg></Call>
|
<Call id="pkixPreferCrls" class="java.security.cert.PKIXRevocationChecker$Option" name="valueOf"><Arg>PREFER_CRLS</Arg></Call>
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
<Call name="addCustomizer">
|
<Call name="addCustomizer">
|
||||||
<Arg>
|
<Arg>
|
||||||
<New class="org.eclipse.jetty.server.SecureRequestCustomizer">
|
<New class="org.eclipse.jetty.server.SecureRequestCustomizer">
|
||||||
|
<Arg name="sniRequired" type="boolean"><Property name="jetty.ssl.sniRequired" default="false"/></Arg>
|
||||||
<Arg name="sniHostCheck" type="boolean"><Property name="jetty.ssl.sniHostCheck" default="true"/></Arg>
|
<Arg name="sniHostCheck" type="boolean"><Property name="jetty.ssl.sniHostCheck" default="true"/></Arg>
|
||||||
<Arg name="stsMaxAgeSeconds" type="int"><Property name="jetty.ssl.stsMaxAgeSeconds" default="-1"/></Arg>
|
<Arg name="stsMaxAgeSeconds" type="int"><Property name="jetty.ssl.stsMaxAgeSeconds" default="-1"/></Arg>
|
||||||
<Arg name="stsIncludeSubdomains" type="boolean"><Property name="jetty.ssl.stsIncludeSubdomains" default="false"/></Arg>
|
<Arg name="stsIncludeSubdomains" type="boolean"><Property name="jetty.ssl.stsIncludeSubdomains" default="false"/></Arg>
|
||||||
|
|
|
@ -43,6 +43,12 @@ etc/jetty-ssl-context.xml
|
||||||
## Connect Timeout in milliseconds
|
## Connect Timeout in milliseconds
|
||||||
# jetty.ssl.connectTimeout=15000
|
# jetty.ssl.connectTimeout=15000
|
||||||
|
|
||||||
|
## Whether SNI is required for all secure connections. Rejections are in TLS handshakes.
|
||||||
|
# jetty.sslContext.sniRequired=false
|
||||||
|
|
||||||
|
## Whether SNI is required for all secure connections. Rejections are in HTTP 400 response.
|
||||||
|
# jetty.ssl.sniRequired=false
|
||||||
|
|
||||||
## Whether request host names are checked to match any SNI names
|
## Whether request host names are checked to match any SNI names
|
||||||
# jetty.ssl.sniHostCheck=true
|
# jetty.ssl.sniHostCheck=true
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,6 @@ import org.eclipse.jetty.io.QuietException;
|
||||||
import org.eclipse.jetty.server.HttpChannelState.Action;
|
import org.eclipse.jetty.server.HttpChannelState.Action;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
import org.eclipse.jetty.server.handler.ErrorHandler;
|
import org.eclipse.jetty.server.handler.ErrorHandler;
|
||||||
import org.eclipse.jetty.server.handler.ErrorHandler.ErrorPageMapper;
|
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
import org.eclipse.jetty.util.Callback;
|
import org.eclipse.jetty.util.Callback;
|
||||||
import org.eclipse.jetty.util.SharedBlockingCallback.Blocker;
|
import org.eclipse.jetty.util.SharedBlockingCallback.Blocker;
|
||||||
|
@ -365,8 +364,6 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
{
|
{
|
||||||
if (!_request.hasMetaData())
|
if (!_request.hasMetaData())
|
||||||
throw new IllegalStateException("state=" + _state);
|
throw new IllegalStateException("state=" + _state);
|
||||||
_request.setHandled(false);
|
|
||||||
_response.reopen();
|
|
||||||
|
|
||||||
dispatch(DispatcherType.REQUEST, () ->
|
dispatch(DispatcherType.REQUEST, () ->
|
||||||
{
|
{
|
||||||
|
@ -384,9 +381,6 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
|
|
||||||
case ASYNC_DISPATCH:
|
case ASYNC_DISPATCH:
|
||||||
{
|
{
|
||||||
_request.setHandled(false);
|
|
||||||
_response.reopen();
|
|
||||||
|
|
||||||
dispatch(DispatcherType.ASYNC,() -> getServer().handleAsync(this));
|
dispatch(DispatcherType.ASYNC,() -> getServer().handleAsync(this));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -400,9 +394,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Get ready to send an error response
|
// Get ready to send an error response
|
||||||
_request.setHandled(false);
|
|
||||||
_response.resetContent();
|
_response.resetContent();
|
||||||
_response.reopen();
|
|
||||||
|
|
||||||
// the following is needed as you cannot trust the response code and reason
|
// the following is needed as you cannot trust the response code and reason
|
||||||
// as those could have been modified after calling sendError
|
// as those could have been modified after calling sendError
|
||||||
|
@ -419,20 +411,11 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for an error page dispatcher
|
dispatch(DispatcherType.ERROR,() ->
|
||||||
String errorPage = (errorHandler instanceof ErrorPageMapper) ? ((ErrorPageMapper)errorHandler).getErrorPage(_request) : null;
|
|
||||||
Dispatcher errorDispatcher = errorPage != null ? (Dispatcher)context.getRequestDispatcher(errorPage) : null;
|
|
||||||
if (errorDispatcher == null)
|
|
||||||
{
|
{
|
||||||
// Allow ErrorHandler to generate response
|
|
||||||
errorHandler.handle(null, _request, _request, _response);
|
errorHandler.handle(null, _request, _request, _response);
|
||||||
_request.setHandled(true);
|
_request.setHandled(true);
|
||||||
}
|
});
|
||||||
else
|
|
||||||
{
|
|
||||||
// Do the error page dispatch
|
|
||||||
dispatch(DispatcherType.ERROR,() -> errorDispatcher.error(_request, _response));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Throwable x)
|
catch (Throwable x)
|
||||||
{
|
{
|
||||||
|
@ -570,6 +553,8 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_request.setHandled(false);
|
||||||
|
_response.reopen();
|
||||||
_request.setDispatcherType(type);
|
_request.setDispatcherType(type);
|
||||||
_combinedListener.onBeforeDispatch(_request);
|
_combinedListener.onBeforeDispatch(_request);
|
||||||
dispatchable.dispatch();
|
dispatchable.dispatch();
|
||||||
|
|
|
@ -57,6 +57,7 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
||||||
|
|
||||||
private String sslSessionAttribute = "org.eclipse.jetty.servlet.request.ssl_session";
|
private String sslSessionAttribute = "org.eclipse.jetty.servlet.request.ssl_session";
|
||||||
|
|
||||||
|
private boolean _sniRequired;
|
||||||
private boolean _sniHostCheck;
|
private boolean _sniHostCheck;
|
||||||
private long _stsMaxAge = -1;
|
private long _stsMaxAge = -1;
|
||||||
private boolean _stsIncludeSubDomains;
|
private boolean _stsIncludeSubDomains;
|
||||||
|
@ -82,6 +83,22 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
||||||
@Name("stsMaxAgeSeconds") long stsMaxAgeSeconds,
|
@Name("stsMaxAgeSeconds") long stsMaxAgeSeconds,
|
||||||
@Name("stsIncludeSubdomains") boolean stsIncludeSubdomains)
|
@Name("stsIncludeSubdomains") boolean stsIncludeSubdomains)
|
||||||
{
|
{
|
||||||
|
this(false, sniHostCheck, stsMaxAgeSeconds, stsIncludeSubdomains);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param sniRequired True if a SNI certificate is required.
|
||||||
|
* @param sniHostCheck True if the SNI Host name must match.
|
||||||
|
* @param stsMaxAgeSeconds The max age in seconds for a Strict-Transport-Security response header. If set less than zero then no header is sent.
|
||||||
|
* @param stsIncludeSubdomains If true, a include subdomain property is sent with any Strict-Transport-Security header
|
||||||
|
*/
|
||||||
|
public SecureRequestCustomizer(
|
||||||
|
@Name("sniRequired") boolean sniRequired,
|
||||||
|
@Name("sniHostCheck") boolean sniHostCheck,
|
||||||
|
@Name("stsMaxAgeSeconds") long stsMaxAgeSeconds,
|
||||||
|
@Name("stsIncludeSubdomains") boolean stsIncludeSubdomains)
|
||||||
|
{
|
||||||
|
_sniRequired = sniRequired;
|
||||||
_sniHostCheck = sniHostCheck;
|
_sniHostCheck = sniHostCheck;
|
||||||
_stsMaxAge = stsMaxAgeSeconds;
|
_stsMaxAge = stsMaxAgeSeconds;
|
||||||
_stsIncludeSubDomains = stsIncludeSubdomains;
|
_stsIncludeSubDomains = stsIncludeSubdomains;
|
||||||
|
@ -89,7 +106,7 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return True if the SNI Host name must match.
|
* @return True if the SNI Host name must match when there is an SNI certificate.
|
||||||
*/
|
*/
|
||||||
public boolean isSniHostCheck()
|
public boolean isSniHostCheck()
|
||||||
{
|
{
|
||||||
|
@ -97,13 +114,31 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param sniHostCheck True if the SNI Host name must match.
|
* @param sniHostCheck True if the SNI Host name must match when there is an SNI certificate.
|
||||||
*/
|
*/
|
||||||
public void setSniHostCheck(boolean sniHostCheck)
|
public void setSniHostCheck(boolean sniHostCheck)
|
||||||
{
|
{
|
||||||
_sniHostCheck = sniHostCheck;
|
_sniHostCheck = sniHostCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return True if SNI is required, else requests will be rejected with 400 response.
|
||||||
|
* @see SslContextFactory.Server#isSniRequired()
|
||||||
|
*/
|
||||||
|
public boolean isSniRequired()
|
||||||
|
{
|
||||||
|
return _sniRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param sniRequired True if SNI is required, else requests will be rejected with 400 response.
|
||||||
|
* @see SslContextFactory.Server#setSniRequired(boolean)
|
||||||
|
*/
|
||||||
|
public void setSniRequired(boolean sniRequired)
|
||||||
|
{
|
||||||
|
_sniRequired = sniRequired;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The max age in seconds for a Strict-Transport-Security response header. If set less than zero then no header is sent.
|
* @return The max age in seconds for a Strict-Transport-Security response header. If set less than zero then no header is sent.
|
||||||
*/
|
*/
|
||||||
|
@ -208,19 +243,23 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
||||||
{
|
{
|
||||||
SSLSession sslSession = sslEngine.getSession();
|
SSLSession sslSession = sslEngine.getSession();
|
||||||
|
|
||||||
if (_sniHostCheck)
|
if (_sniHostCheck || _sniRequired)
|
||||||
{
|
{
|
||||||
String name = request.getServerName();
|
String name = request.getServerName();
|
||||||
X509 x509 = (X509)sslSession.getValue(SniX509ExtendedKeyManager.SNI_X509);
|
X509 x509 = (X509)sslSession.getValue(SniX509ExtendedKeyManager.SNI_X509);
|
||||||
|
|
||||||
if (x509 != null && !x509.matches(name))
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Host {} with SNI {}", name, x509);
|
||||||
|
|
||||||
|
if (x509 == null)
|
||||||
|
{
|
||||||
|
if (_sniRequired)
|
||||||
|
throw new BadMessageException(400, "SNI required");
|
||||||
|
}
|
||||||
|
else if (_sniHostCheck && !x509.matches(name))
|
||||||
{
|
{
|
||||||
LOG.warn("Host {} does not match SNI {}", name, x509);
|
|
||||||
throw new BadMessageException(400, "Host does not match SNI");
|
throw new BadMessageException(400, "Host does not match SNI");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("Host {} matched SNI {}", name, x509);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
|
@ -66,11 +66,7 @@ public abstract class AbstractHandler extends ContainerLifeCycle implements Hand
|
||||||
public abstract void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException;
|
public abstract void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method to generate error page.
|
* Deprecated error page generation
|
||||||
* <p>This method can be called from {@link #handle(String, Request, HttpServletRequest, HttpServletResponse)} when an {@link DispatcherType#ERROR} dispatch
|
|
||||||
* is detected and an error page needs to be generated by calling {@link HttpServletResponse#sendError(int, String)} with the appropriate code and reason,
|
|
||||||
* which are taken from {@link HttpServletRequest#getAttribute(String)} for {@link RequestDispatcher#ERROR_STATUS_CODE} and {@link RequestDispatcher#ERROR_MESSAGE}
|
|
||||||
*
|
|
||||||
* @param target The target of the request - either a URI or a name.
|
* @param target The target of the request - either a URI or a name.
|
||||||
* @param baseRequest The original unwrapped request object.
|
* @param baseRequest The original unwrapped request object.
|
||||||
* @param request The request either as the {@link Request} object or a wrapper of that request. The
|
* @param request The request either as the {@link Request} object or a wrapper of that request. The
|
||||||
|
@ -81,16 +77,14 @@ public abstract class AbstractHandler extends ContainerLifeCycle implements Hand
|
||||||
* method can be used access the Response object if required.
|
* method can be used access the Response object if required.
|
||||||
* @throws IOException if unable to handle the request or response processing
|
* @throws IOException if unable to handle the request or response processing
|
||||||
* @throws ServletException if unable to handle the request or response due to underlying servlet issue
|
* @throws ServletException if unable to handle the request or response due to underlying servlet issue
|
||||||
* @see ErrorDispatchHandler for a convenience class that calls this method.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
protected void doError(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
protected void doError(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
Object o = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
|
Object o = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
|
||||||
int code = (o instanceof Integer) ? ((Integer)o).intValue() : (o != null ? Integer.parseInt(o.toString()) : 500);
|
int code = (o instanceof Integer) ? ((Integer)o).intValue() : (o != null ? Integer.parseInt(o.toString()) : 500);
|
||||||
o = request.getAttribute(RequestDispatcher.ERROR_MESSAGE);
|
response.setStatus(code);
|
||||||
String reason = o != null ? o.toString() : null;
|
baseRequest.setHandled(true);
|
||||||
|
|
||||||
response.sendError(code, reason);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -147,7 +141,9 @@ public abstract class AbstractHandler extends ContainerLifeCycle implements Hand
|
||||||
* {@link DispatcherType#ERROR} dispatches are handled by calling the {@link #doError(String, Request, HttpServletRequest, HttpServletResponse)}
|
* {@link DispatcherType#ERROR} dispatches are handled by calling the {@link #doError(String, Request, HttpServletRequest, HttpServletResponse)}
|
||||||
* method. All other dispatches are passed to the abstract {@link #doNonErrorHandle(String, Request, HttpServletRequest, HttpServletResponse)}
|
* method. All other dispatches are passed to the abstract {@link #doNonErrorHandle(String, Request, HttpServletRequest, HttpServletResponse)}
|
||||||
* method, which should be implemented with specific handler behavior
|
* method, which should be implemented with specific handler behavior
|
||||||
|
* @deprecated This class is no longer required as ERROR dispatch is only done if there is an error page target.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public abstract static class ErrorDispatchHandler extends AbstractHandler
|
public abstract static class ErrorDispatchHandler extends AbstractHandler
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
@ -174,6 +170,7 @@ public abstract class AbstractHandler extends ContainerLifeCycle implements Hand
|
||||||
* @throws IOException if unable to handle the request or response processing
|
* @throws IOException if unable to handle the request or response processing
|
||||||
* @throws ServletException if unable to handle the request or response due to underlying servlet issue
|
* @throws ServletException if unable to handle the request or response due to underlying servlet issue
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
protected abstract void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException;
|
protected abstract void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,14 @@ import java.nio.BufferOverflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.servlet.RequestDispatcher;
|
import javax.servlet.RequestDispatcher;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
@ -82,26 +88,38 @@ public class ErrorHandler extends AbstractHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
* @see org.eclipse.jetty.server.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
|
||||||
{
|
|
||||||
doError(target, baseRequest, request, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void doError(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
|
||||||
{
|
{
|
||||||
String cacheControl = getCacheControl();
|
String cacheControl = getCacheControl();
|
||||||
if (cacheControl != null)
|
if (cacheControl != null)
|
||||||
response.setHeader(HttpHeader.CACHE_CONTROL.asString(), cacheControl);
|
response.setHeader(HttpHeader.CACHE_CONTROL.asString(), cacheControl);
|
||||||
|
|
||||||
String message = (String)request.getAttribute(Dispatcher.ERROR_MESSAGE);
|
// Look for an error page dispatcher
|
||||||
if (message == null)
|
// This logic really should be in ErrorPageErrorHandler, but some implementations extend ErrorHandler
|
||||||
message = baseRequest.getResponse().getReason();
|
// and implement ErrorPageMapper directly, so we do this here in the base class.
|
||||||
generateAcceptableResponse(baseRequest, request, response, response.getStatus(), message);
|
String errorPage = (this instanceof ErrorPageMapper) ? ((ErrorPageMapper)this).getErrorPage(request) : null;
|
||||||
|
ContextHandler.Context context = baseRequest.getErrorContext();
|
||||||
|
Dispatcher errorDispatcher = (errorPage != null && context != null)
|
||||||
|
? (Dispatcher)context.getRequestDispatcher(errorPage) : null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (errorDispatcher != null)
|
||||||
|
{
|
||||||
|
errorDispatcher.error(request, response);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String message = (String)request.getAttribute(Dispatcher.ERROR_MESSAGE);
|
||||||
|
if (message == null)
|
||||||
|
message = baseRequest.getResponse().getReason();
|
||||||
|
generateAcceptableResponse(baseRequest, request, response, response.getStatus(), message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -429,23 +447,31 @@ public class ErrorHandler extends AbstractHandler
|
||||||
|
|
||||||
private void writeErrorJson(HttpServletRequest request, PrintWriter writer, int code, String message)
|
private void writeErrorJson(HttpServletRequest request, PrintWriter writer, int code, String message)
|
||||||
{
|
{
|
||||||
writer
|
|
||||||
.append("{\n")
|
|
||||||
.append(" url: \"").append(request.getRequestURI()).append("\",\n")
|
|
||||||
.append(" status: \"").append(Integer.toString(code)).append("\",\n")
|
|
||||||
.append(" message: ").append(QuotedStringTokenizer.quote(message)).append(",\n");
|
|
||||||
Object servlet = request.getAttribute(Dispatcher.ERROR_SERVLET_NAME);
|
|
||||||
if (servlet != null)
|
|
||||||
writer.append("servlet: \"").append(servlet.toString()).append("\",\n");
|
|
||||||
Throwable cause = (Throwable)request.getAttribute(Dispatcher.ERROR_EXCEPTION);
|
Throwable cause = (Throwable)request.getAttribute(Dispatcher.ERROR_EXCEPTION);
|
||||||
|
Object servlet = request.getAttribute(Dispatcher.ERROR_SERVLET_NAME);
|
||||||
|
Map<String,String> json = new HashMap<>();
|
||||||
|
|
||||||
|
json.put("url", request.getRequestURI());
|
||||||
|
json.put("status", Integer.toString(code));
|
||||||
|
json.put("message", message);
|
||||||
|
if (servlet != null)
|
||||||
|
{
|
||||||
|
json.put("servlet", servlet.toString());
|
||||||
|
}
|
||||||
int c = 0;
|
int c = 0;
|
||||||
while (cause != null)
|
while (cause != null)
|
||||||
{
|
{
|
||||||
writer.append(" cause").append(Integer.toString(c++)).append(": ")
|
json.put("cause" + c++, cause.toString());
|
||||||
.append(QuotedStringTokenizer.quote(cause.toString())).append(",\n");
|
|
||||||
cause = cause.getCause();
|
cause = cause.getCause();
|
||||||
}
|
}
|
||||||
writer.append("}");
|
|
||||||
|
writer.append(json.entrySet().stream()
|
||||||
|
.map(e -> QuotedStringTokenizer.quote(e.getKey()) +
|
||||||
|
":" +
|
||||||
|
QuotedStringTokenizer.quote((e.getValue())))
|
||||||
|
.collect(Collectors.joining(",\n", "{\n", "\n}")));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeErrorPageStacks(HttpServletRequest request, Writer writer)
|
protected void writeErrorPageStacks(HttpServletRequest request, Writer writer)
|
||||||
|
|
|
@ -104,7 +104,7 @@ public abstract class AbstractHttpTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class ThrowExceptionOnDemandHandler extends AbstractHandler.ErrorDispatchHandler
|
protected class ThrowExceptionOnDemandHandler extends AbstractHandler
|
||||||
{
|
{
|
||||||
private final boolean throwException;
|
private final boolean throwException;
|
||||||
private volatile Throwable failure;
|
private volatile Throwable failure;
|
||||||
|
@ -115,7 +115,7 @@ public abstract class AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
if (throwException)
|
if (throwException)
|
||||||
throw new TestCommitException();
|
throw new TestCommitException();
|
||||||
|
|
|
@ -42,7 +42,7 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
* Dumps GET and POST requests.
|
* Dumps GET and POST requests.
|
||||||
* Useful for testing and debugging.
|
* Useful for testing and debugging.
|
||||||
*/
|
*/
|
||||||
public class DumpHandler extends AbstractHandler.ErrorDispatchHandler
|
public class DumpHandler extends AbstractHandler
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(DumpHandler.class);
|
private static final Logger LOG = Log.getLogger(DumpHandler.class);
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ public class DumpHandler extends AbstractHandler.ErrorDispatchHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
if (!isStarted())
|
if (!isStarted())
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
package org.eclipse.jetty.server;
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.DispatcherType;
|
import javax.servlet.DispatcherType;
|
||||||
import javax.servlet.RequestDispatcher;
|
import javax.servlet.RequestDispatcher;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
|
@ -30,6 +32,7 @@ import org.eclipse.jetty.http.HttpField;
|
||||||
import org.eclipse.jetty.http.HttpHeader;
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
import org.eclipse.jetty.http.tools.HttpTester;
|
import org.eclipse.jetty.http.tools.HttpTester;
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
|
import org.eclipse.jetty.util.ajax.JSON;
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -302,4 +305,25 @@ public class ErrorHandlerTest
|
||||||
|
|
||||||
assertThat("Response status code", response.getStatus(), is(444));
|
assertThat("Response status code", response.getStatus(), is(444));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJsonResponse() throws Exception
|
||||||
|
{
|
||||||
|
String rawResponse = connector.getResponse(
|
||||||
|
"GET /badmessage/444 HTTP/1.1\r\n" +
|
||||||
|
"Host: Localhost\r\n" +
|
||||||
|
"Accept: text/json\r\n" +
|
||||||
|
"\r\n");
|
||||||
|
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||||
|
|
||||||
|
assertThat("Response status code", response.getStatus(), is(444));
|
||||||
|
|
||||||
|
System.out.println("response:" + response.getContent());
|
||||||
|
|
||||||
|
Map<Object,Object> jo = (Map) JSON.parse(response.getContent());
|
||||||
|
|
||||||
|
assertThat("url field null", jo.get("url"), is(notNullValue()));
|
||||||
|
assertThat("status field null", jo.get("status"), is(notNullValue()));
|
||||||
|
assertThat("message field null", jo.get("message"), is(notNullValue()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -271,10 +271,10 @@ public class HttpChannelEventTest
|
||||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TestHandler extends AbstractHandler.ErrorDispatchHandler
|
private static class TestHandler extends AbstractHandler
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected final void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public final void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
jettyRequest.setHandled(true);
|
jettyRequest.setHandled(true);
|
||||||
handle(request, response);
|
handle(request, response);
|
||||||
|
|
|
@ -1227,11 +1227,11 @@ public class HttpConnectionTest
|
||||||
final String longstr = str;
|
final String longstr = str;
|
||||||
final CountDownLatch checkError = new CountDownLatch(1);
|
final CountDownLatch checkError = new CountDownLatch(1);
|
||||||
server.stop();
|
server.stop();
|
||||||
server.setHandler(new AbstractHandler.ErrorDispatchHandler()
|
server.setHandler(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
response.setHeader(HttpHeader.CONTENT_TYPE.toString(), MimeTypes.Type.TEXT_HTML.toString());
|
response.setHeader(HttpHeader.CONTENT_TYPE.toString(), MimeTypes.Type.TEXT_HTML.toString());
|
||||||
|
|
|
@ -126,7 +126,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
if (request.getAttribute(contextAttribute) == null)
|
if (request.getAttribute(contextAttribute) == null)
|
||||||
{
|
{
|
||||||
|
@ -140,7 +140,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
asyncContext.complete();
|
asyncContext.complete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
if (request.getAttribute(contextAttribute) == null)
|
if (request.getAttribute(contextAttribute) == null)
|
||||||
{
|
{
|
||||||
|
@ -215,7 +215,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,7 +273,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
if (request.getAttribute(contextAttribute) == null)
|
if (request.getAttribute(contextAttribute) == null)
|
||||||
{
|
{
|
||||||
|
@ -296,7 +296,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,7 +354,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
if (request.getAttribute(contextAttribute) == null)
|
if (request.getAttribute(contextAttribute) == null)
|
||||||
{
|
{
|
||||||
|
@ -379,7 +379,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,7 +437,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
if (request.getAttribute(contextAttribute) == null)
|
if (request.getAttribute(contextAttribute) == null)
|
||||||
{
|
{
|
||||||
|
@ -460,7 +460,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,7 +520,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
if (request.getAttribute(contextAttribute) == null)
|
if (request.getAttribute(contextAttribute) == null)
|
||||||
{
|
{
|
||||||
|
@ -546,7 +546,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,7 +607,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
if (request.getAttribute(contextAttribute) == null)
|
if (request.getAttribute(contextAttribute) == null)
|
||||||
{
|
{
|
||||||
|
@ -632,7 +632,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,7 +689,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
if (request.getAttribute(contextAttribute) == null)
|
if (request.getAttribute(contextAttribute) == null)
|
||||||
{
|
{
|
||||||
|
@ -714,7 +714,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,7 +772,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
if (request.getAttribute(contextAttribute) == null)
|
if (request.getAttribute(contextAttribute) == null)
|
||||||
{
|
{
|
||||||
|
@ -797,7 +797,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -850,7 +850,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
if (request.getAttribute(contextAttribute) == null)
|
if (request.getAttribute(contextAttribute) == null)
|
||||||
{
|
{
|
||||||
|
@ -875,7 +875,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -930,7 +930,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
if (request.getAttribute(contextAttribute) == null)
|
if (request.getAttribute(contextAttribute) == null)
|
||||||
{
|
{
|
||||||
|
@ -955,7 +955,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,10 +84,10 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(false); // not needed, but lets be explicit about what the test does
|
baseRequest.setHandled(false); // not needed, but lets be explicit about what the test does
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,10 +125,10 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,11 +167,11 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
response.getWriter().write("foobar");
|
response.getWriter().write("foobar");
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,12 +214,12 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
response.getWriter().write("foobar");
|
response.getWriter().write("foobar");
|
||||||
response.flushBuffer();
|
response.flushBuffer();
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,11 +259,11 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
response.flushBuffer();
|
response.flushBuffer();
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,13 +305,13 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
response.getWriter().write("foo");
|
response.getWriter().write("foo");
|
||||||
response.flushBuffer();
|
response.flushBuffer();
|
||||||
response.getWriter().write("bar");
|
response.getWriter().write("bar");
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,12 +384,12 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
response.setBufferSize(4);
|
response.setBufferSize(4);
|
||||||
response.getWriter().write("foobar");
|
response.getWriter().write("foobar");
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,13 +401,13 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
response.setBufferSize(8);
|
response.setBufferSize(8);
|
||||||
response.getWriter().write("fo");
|
response.getWriter().write("fo");
|
||||||
response.getWriter().write("obarfoobar");
|
response.getWriter().write("obarfoobar");
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,7 +419,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
response.setBufferSize(8);
|
response.setBufferSize(8);
|
||||||
|
@ -429,7 +429,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
||||||
response.getWriter().write("fo");
|
response.getWriter().write("fo");
|
||||||
response.getWriter().write("ob");
|
response.getWriter().write("ob");
|
||||||
response.getWriter().write("ar");
|
response.getWriter().write("ar");
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,12 +558,12 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
response.setContentLength(3);
|
response.setContentLength(3);
|
||||||
response.getWriter().write("foo");
|
response.getWriter().write("foo");
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -603,13 +603,13 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
response.setContentLength(3);
|
response.setContentLength(3);
|
||||||
// Only "foo" will get written and "bar" will be discarded
|
// Only "foo" will get written and "bar" will be discarded
|
||||||
response.getWriter().write("foobar");
|
response.getWriter().write("foobar");
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,12 +649,12 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
response.getWriter().write("foo");
|
response.getWriter().write("foo");
|
||||||
response.setContentLength(3);
|
response.setContentLength(3);
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -694,12 +694,12 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
response.getWriter().write("foobar");
|
response.getWriter().write("foobar");
|
||||||
response.setContentLength(3);
|
response.setContentLength(3);
|
||||||
super.doNonErrorHandle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -283,10 +283,10 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
||||||
@Test
|
@Test
|
||||||
public void testExceptionThrownInHandler() throws Exception
|
public void testExceptionThrownInHandler() throws Exception
|
||||||
{
|
{
|
||||||
configureServer(new AbstractHandler.ErrorDispatchHandler()
|
configureServer(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
throw new QuietServletException("TEST handler exception");
|
throw new QuietServletException("TEST handler exception");
|
||||||
}
|
}
|
||||||
|
@ -314,10 +314,10 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
||||||
{
|
{
|
||||||
final AtomicBoolean fourBytesRead = new AtomicBoolean(false);
|
final AtomicBoolean fourBytesRead = new AtomicBoolean(false);
|
||||||
final AtomicBoolean earlyEOFException = new AtomicBoolean(false);
|
final AtomicBoolean earlyEOFException = new AtomicBoolean(false);
|
||||||
configureServer(new AbstractHandler.ErrorDispatchHandler()
|
configureServer(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
int contentLength = request.getContentLength();
|
int contentLength = request.getContentLength();
|
||||||
|
|
|
@ -26,7 +26,6 @@ import java.io.PrintWriter;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import javax.servlet.RequestDispatcher;
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
@ -211,7 +210,7 @@ public class HttpServerTestFixture
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class ReadExactHandler extends AbstractHandler.ErrorDispatchHandler
|
protected static class ReadExactHandler extends AbstractHandler
|
||||||
{
|
{
|
||||||
private int expected;
|
private int expected;
|
||||||
|
|
||||||
|
@ -226,7 +225,7 @@ public class HttpServerTestFixture
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
int len = expected < 0 ? request.getContentLength() : expected;
|
int len = expected < 0 ? request.getContentLength() : expected;
|
||||||
|
@ -246,16 +245,6 @@ public class HttpServerTestFixture
|
||||||
response.setContentLength(reply.length());
|
response.setContentLength(reply.length());
|
||||||
response.getOutputStream().write(reply.getBytes(StandardCharsets.ISO_8859_1));
|
response.getOutputStream().write(reply.getBytes(StandardCharsets.ISO_8859_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doError(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
|
||||||
{
|
|
||||||
System.err.println("ERROR: " + request.getAttribute(RequestDispatcher.ERROR_MESSAGE));
|
|
||||||
Throwable th = (Throwable)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
|
|
||||||
if (th != null)
|
|
||||||
th.printStackTrace();
|
|
||||||
super.doError(target, baseRequest, request, response);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class ReadHandler extends AbstractHandler
|
protected static class ReadHandler extends AbstractHandler
|
||||||
|
|
|
@ -204,10 +204,10 @@ public class OptionalSslConnectionTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class EmptyServerHandler extends AbstractHandler.ErrorDispatchHandler
|
private static class EmptyServerHandler extends AbstractHandler
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response)
|
public void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response)
|
||||||
{
|
{
|
||||||
jettyRequest.setHandled(true);
|
jettyRequest.setHandled(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1793,14 +1793,14 @@ public class RequestTest
|
||||||
boolean check(HttpServletRequest request, HttpServletResponse response) throws IOException;
|
boolean check(HttpServletRequest request, HttpServletResponse response) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class RequestHandler extends AbstractHandler.ErrorDispatchHandler
|
private class RequestHandler extends AbstractHandler
|
||||||
{
|
{
|
||||||
private RequestTester _checker;
|
private RequestTester _checker;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private String _content;
|
private String _content;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
((Request)request).setHandled(true);
|
((Request)request).setHandled(true);
|
||||||
|
|
||||||
|
|
|
@ -152,10 +152,10 @@ public class ServerConnectorTimeoutTest extends ConnectorTimeoutTest
|
||||||
public void testHttpWriteIdleTimeout() throws Exception
|
public void testHttpWriteIdleTimeout() throws Exception
|
||||||
{
|
{
|
||||||
_httpConfiguration.setIdleTimeout(500);
|
_httpConfiguration.setIdleTimeout(500);
|
||||||
configureServer(new AbstractHandler.ErrorDispatchHandler()
|
configureServer(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
IO.copy(request.getInputStream(), response.getOutputStream());
|
IO.copy(request.getInputStream(), response.getOutputStream());
|
||||||
|
|
|
@ -72,9 +72,9 @@ public class ServletWriterTest
|
||||||
char[] chars = new char[128 * 1024 * 1024];
|
char[] chars = new char[128 * 1024 * 1024];
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
AtomicReference<Thread> serverThreadRef = new AtomicReference<>();
|
AtomicReference<Thread> serverThreadRef = new AtomicReference<>();
|
||||||
start(chars.length, new AbstractHandler.ErrorDispatchHandler() {
|
start(chars.length, new AbstractHandler() {
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
serverThreadRef.set(Thread.currentThread());
|
serverThreadRef.set(Thread.currentThread());
|
||||||
jettyRequest.setHandled(true);
|
jettyRequest.setHandled(true);
|
||||||
|
|
|
@ -465,10 +465,10 @@ public class NcsaRequestLogTest
|
||||||
{
|
{
|
||||||
setup(logType);
|
setup(logType);
|
||||||
_server.setRequestLog(_log);
|
_server.setRequestLog(_log);
|
||||||
AbstractHandler.ErrorDispatchHandler wrapper = new AbstractHandler.ErrorDispatchHandler()
|
AbstractHandler wrapper = new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||||
throws IOException, ServletException
|
throws IOException, ServletException
|
||||||
{
|
{
|
||||||
testHandler.handle(target, baseRequest, request, response);
|
testHandler.handle(target, baseRequest, request, response);
|
||||||
|
@ -481,10 +481,11 @@ public class NcsaRequestLogTest
|
||||||
ErrorHandler errorHandler = new ErrorHandler()
|
ErrorHandler errorHandler = new ErrorHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void doError(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||||
|
throws IOException, ServletException
|
||||||
{
|
{
|
||||||
errors.add(baseRequest.getRequestURI());
|
errors.add(baseRequest.getRequestURI());
|
||||||
super.doError(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
_server.addBean(errorHandler);
|
_server.addBean(errorHandler);
|
||||||
|
@ -499,10 +500,10 @@ public class NcsaRequestLogTest
|
||||||
{
|
{
|
||||||
setup(logType);
|
setup(logType);
|
||||||
_server.setRequestLog(_log);
|
_server.setRequestLog(_log);
|
||||||
AbstractHandler.ErrorDispatchHandler wrapper = new AbstractHandler.ErrorDispatchHandler()
|
AbstractHandler wrapper = new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||||
throws IOException, ServletException
|
throws IOException, ServletException
|
||||||
{
|
{
|
||||||
testHandler.handle(target, baseRequest, request, response);
|
testHandler.handle(target, baseRequest, request, response);
|
||||||
|
|
|
@ -26,6 +26,7 @@ import java.io.OutputStream;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
@ -65,10 +66,10 @@ public class SSLReadEOFAfterResponseTest
|
||||||
|
|
||||||
String content = "the quick brown fox jumped over the lazy dog";
|
String content = "the quick brown fox jumped over the lazy dog";
|
||||||
byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
|
byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
|
||||||
server.setHandler(new AbstractHandler.ErrorDispatchHandler()
|
server.setHandler(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
// First: read the whole content.
|
// First: read the whole content.
|
||||||
InputStream input = request.getInputStream();
|
InputStream input = request.getInputStream();
|
||||||
|
|
|
@ -31,9 +31,11 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import javax.net.ssl.SNIHostName;
|
import javax.net.ssl.SNIHostName;
|
||||||
import javax.net.ssl.SNIServerName;
|
import javax.net.ssl.SNIServerName;
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
|
import javax.net.ssl.SSLHandshakeException;
|
||||||
import javax.net.ssl.SSLParameters;
|
import javax.net.ssl.SSLParameters;
|
||||||
import javax.net.ssl.SSLSession;
|
import javax.net.ssl.SSLSession;
|
||||||
import javax.net.ssl.SSLSocket;
|
import javax.net.ssl.SSLSocket;
|
||||||
|
@ -57,6 +59,7 @@ import org.eclipse.jetty.server.SslConnectionFactory;
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
import org.eclipse.jetty.server.handler.ErrorHandler;
|
import org.eclipse.jetty.server.handler.ErrorHandler;
|
||||||
import org.eclipse.jetty.util.IO;
|
import org.eclipse.jetty.util.IO;
|
||||||
|
import org.eclipse.jetty.util.ssl.SniX509ExtendedKeyManager;
|
||||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
@ -67,6 +70,8 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
public class SniSslConnectionFactoryTest
|
public class SniSslConnectionFactoryTest
|
||||||
{
|
{
|
||||||
|
@ -76,7 +81,7 @@ public class SniSslConnectionFactoryTest
|
||||||
private int _port;
|
private int _port;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void before() throws Exception
|
public void before()
|
||||||
{
|
{
|
||||||
_server = new Server();
|
_server = new Server();
|
||||||
|
|
||||||
|
@ -114,12 +119,18 @@ public class SniSslConnectionFactoryTest
|
||||||
|
|
||||||
protected void start(String keystorePath) throws Exception
|
protected void start(String keystorePath) throws Exception
|
||||||
{
|
{
|
||||||
File keystoreFile = new File(keystorePath);
|
start(ssl -> ssl.setKeyStorePath(keystorePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void start(Consumer<SslContextFactory.Server> sslConfig) throws Exception
|
||||||
|
{
|
||||||
|
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
|
||||||
|
sslConfig.accept(sslContextFactory);
|
||||||
|
|
||||||
|
File keystoreFile = sslContextFactory.getKeyStoreResource().getFile();
|
||||||
if (!keystoreFile.exists())
|
if (!keystoreFile.exists())
|
||||||
throw new FileNotFoundException(keystoreFile.getAbsolutePath());
|
throw new FileNotFoundException(keystoreFile.getAbsolutePath());
|
||||||
|
|
||||||
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
|
|
||||||
sslContextFactory.setKeyStorePath(keystoreFile.getAbsolutePath());
|
|
||||||
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||||
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||||
|
|
||||||
|
@ -128,10 +139,10 @@ public class SniSslConnectionFactoryTest
|
||||||
new HttpConnectionFactory(_httpsConfiguration));
|
new HttpConnectionFactory(_httpsConfiguration));
|
||||||
_server.addConnector(https);
|
_server.addConnector(https);
|
||||||
|
|
||||||
_server.setHandler(new AbstractHandler.ErrorDispatchHandler()
|
_server.setHandler(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
response.setStatus(200);
|
response.setStatus(200);
|
||||||
|
@ -219,6 +230,79 @@ public class SniSslConnectionFactoryTest
|
||||||
assertThat(response, Matchers.containsString("Host does not match SNI"));
|
assertThat(response, Matchers.containsString("Host does not match SNI"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWrongSNIRejectedConnection() throws Exception
|
||||||
|
{
|
||||||
|
start(ssl ->
|
||||||
|
{
|
||||||
|
ssl.setKeyStorePath("src/test/resources/keystore_sni.p12");
|
||||||
|
// Do not allow unmatched SNI.
|
||||||
|
ssl.setSniRequired(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wrong SNI host.
|
||||||
|
assertThrows(SSLHandshakeException.class, () -> getResponse("wrong.com", "wrong.com", null));
|
||||||
|
|
||||||
|
// No SNI host.
|
||||||
|
assertThrows(SSLHandshakeException.class, () -> getResponse(null, "wrong.com", null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWrongSNIRejectedBadRequest() throws Exception
|
||||||
|
{
|
||||||
|
start(ssl ->
|
||||||
|
{
|
||||||
|
ssl.setKeyStorePath("src/test/resources/keystore_sni.p12");
|
||||||
|
// Do not allow unmatched SNI.
|
||||||
|
ssl.setSniRequired(false);
|
||||||
|
_httpsConfiguration.getCustomizers().stream()
|
||||||
|
.filter(SecureRequestCustomizer.class::isInstance)
|
||||||
|
.map(SecureRequestCustomizer.class::cast)
|
||||||
|
.forEach(src -> src.setSniRequired(true));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wrong SNI host.
|
||||||
|
HttpTester.Response response = HttpTester.parseResponse(getResponse("wrong.com", "wrong.com", null));
|
||||||
|
assertNotNull(response);
|
||||||
|
assertThat(response.getStatus(), is(400));
|
||||||
|
|
||||||
|
// No SNI host.
|
||||||
|
response = HttpTester.parseResponse(getResponse(null, "wrong.com", null));
|
||||||
|
assertNotNull(response);
|
||||||
|
assertThat(response.getStatus(), is(400));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWrongSNIRejectedFunction() throws Exception
|
||||||
|
{
|
||||||
|
start(ssl ->
|
||||||
|
{
|
||||||
|
ssl.setKeyStorePath("src/test/resources/keystore_sni.p12");
|
||||||
|
// Do not allow unmatched SNI.
|
||||||
|
ssl.setSniRequired(true);
|
||||||
|
ssl.setSNISelector((keyType, issuers, session, sniHost, certificates) ->
|
||||||
|
{
|
||||||
|
if (sniHost == null)
|
||||||
|
return SniX509ExtendedKeyManager.SniSelector.DELEGATE;
|
||||||
|
return ssl.sniSelect(keyType, issuers, session, sniHost, certificates);
|
||||||
|
});
|
||||||
|
_httpsConfiguration.getCustomizers().stream()
|
||||||
|
.filter(SecureRequestCustomizer.class::isInstance)
|
||||||
|
.map(SecureRequestCustomizer.class::cast)
|
||||||
|
.forEach(src -> src.setSniRequired(true));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wrong SNI host.
|
||||||
|
assertThrows(SSLHandshakeException.class, () -> getResponse("wrong.com", "wrong.com", null));
|
||||||
|
|
||||||
|
// No SNI host.
|
||||||
|
HttpTester.Response response = HttpTester.parseResponse(getResponse(null, "wrong.com", null));
|
||||||
|
assertNotNull(response);
|
||||||
|
assertThat(response.getStatus(), is(400));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSameConnectionRequestsForManyDomains() throws Exception
|
public void testSameConnectionRequestsForManyDomains() throws Exception
|
||||||
{
|
{
|
||||||
|
@ -247,6 +331,7 @@ public class SniSslConnectionFactoryTest
|
||||||
|
|
||||||
InputStream input = sslSocket.getInputStream();
|
InputStream input = sslSocket.getInputStream();
|
||||||
HttpTester.Response response = HttpTester.parseResponse(input);
|
HttpTester.Response response = HttpTester.parseResponse(input);
|
||||||
|
assertNotNull(response);
|
||||||
assertThat(response.getStatus(), is(200));
|
assertThat(response.getStatus(), is(200));
|
||||||
|
|
||||||
// Same socket, send a request for a different domain but same alias.
|
// Same socket, send a request for a different domain but same alias.
|
||||||
|
@ -257,6 +342,7 @@ public class SniSslConnectionFactoryTest
|
||||||
output.write(request.getBytes(StandardCharsets.UTF_8));
|
output.write(request.getBytes(StandardCharsets.UTF_8));
|
||||||
output.flush();
|
output.flush();
|
||||||
response = HttpTester.parseResponse(input);
|
response = HttpTester.parseResponse(input);
|
||||||
|
assertNotNull(response);
|
||||||
assertThat(response.getStatus(), is(200));
|
assertThat(response.getStatus(), is(200));
|
||||||
|
|
||||||
// Same socket, send a request for a different domain but different alias.
|
// Same socket, send a request for a different domain but different alias.
|
||||||
|
@ -268,6 +354,7 @@ public class SniSslConnectionFactoryTest
|
||||||
output.flush();
|
output.flush();
|
||||||
|
|
||||||
response = HttpTester.parseResponse(input);
|
response = HttpTester.parseResponse(input);
|
||||||
|
assertNotNull(response);
|
||||||
assertThat(response.getStatus(), is(400));
|
assertThat(response.getStatus(), is(400));
|
||||||
assertThat(response.getContent(), containsString("Host does not match SNI"));
|
assertThat(response.getContent(), containsString("Host does not match SNI"));
|
||||||
}
|
}
|
||||||
|
@ -303,6 +390,7 @@ public class SniSslConnectionFactoryTest
|
||||||
|
|
||||||
InputStream input = sslSocket.getInputStream();
|
InputStream input = sslSocket.getInputStream();
|
||||||
HttpTester.Response response = HttpTester.parseResponse(input);
|
HttpTester.Response response = HttpTester.parseResponse(input);
|
||||||
|
assertNotNull(response);
|
||||||
assertThat(response.getStatus(), is(200));
|
assertThat(response.getStatus(), is(200));
|
||||||
|
|
||||||
// Now, on the same socket, send a request for a different valid domain.
|
// Now, on the same socket, send a request for a different valid domain.
|
||||||
|
@ -314,6 +402,7 @@ public class SniSslConnectionFactoryTest
|
||||||
output.flush();
|
output.flush();
|
||||||
|
|
||||||
response = HttpTester.parseResponse(input);
|
response = HttpTester.parseResponse(input);
|
||||||
|
assertNotNull(response);
|
||||||
assertThat(response.getStatus(), is(200));
|
assertThat(response.getStatus(), is(200));
|
||||||
|
|
||||||
// Now make a request for an invalid domain for this connection.
|
// Now make a request for an invalid domain for this connection.
|
||||||
|
@ -325,6 +414,7 @@ public class SniSslConnectionFactoryTest
|
||||||
output.flush();
|
output.flush();
|
||||||
|
|
||||||
response = HttpTester.parseResponse(input);
|
response = HttpTester.parseResponse(input);
|
||||||
|
assertNotNull(response);
|
||||||
assertThat(response.getStatus(), is(400));
|
assertThat(response.getStatus(), is(400));
|
||||||
assertThat(response.getContent(), containsString("Host does not match SNI"));
|
assertThat(response.getContent(), containsString("Host does not match SNI"));
|
||||||
}
|
}
|
||||||
|
@ -334,49 +424,6 @@ public class SniSslConnectionFactoryTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getResponse(String host, String cn) throws Exception
|
|
||||||
{
|
|
||||||
String response = getResponse(host, host, cn);
|
|
||||||
assertThat(response, Matchers.startsWith("HTTP/1.1 200 "));
|
|
||||||
assertThat(response, Matchers.containsString("X-URL: /ctx/path"));
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getResponse(String sniHost, String reqHost, String cn) throws Exception
|
|
||||||
{
|
|
||||||
SslContextFactory clientContextFactory = new SslContextFactory.Client(true);
|
|
||||||
clientContextFactory.start();
|
|
||||||
SSLSocketFactory factory = clientContextFactory.getSslContext().getSocketFactory();
|
|
||||||
try (SSLSocket sslSocket = (SSLSocket)factory.createSocket("127.0.0.1", _port))
|
|
||||||
{
|
|
||||||
if (sniHost != null)
|
|
||||||
{
|
|
||||||
SNIHostName serverName = new SNIHostName(sniHost);
|
|
||||||
List<SNIServerName> serverNames = new ArrayList<>();
|
|
||||||
serverNames.add(serverName);
|
|
||||||
|
|
||||||
SSLParameters params = sslSocket.getSSLParameters();
|
|
||||||
params.setServerNames(serverNames);
|
|
||||||
sslSocket.setSSLParameters(params);
|
|
||||||
}
|
|
||||||
sslSocket.startHandshake();
|
|
||||||
|
|
||||||
if (cn != null)
|
|
||||||
{
|
|
||||||
X509Certificate cert = ((X509Certificate)sslSocket.getSession().getPeerCertificates()[0]);
|
|
||||||
assertThat(cert.getSubjectX500Principal().getName("CANONICAL"), Matchers.startsWith("cn=" + cn));
|
|
||||||
}
|
|
||||||
|
|
||||||
String response = "GET /ctx/path HTTP/1.0\r\nHost: " + reqHost + ":" + _port + "\r\n\r\n";
|
|
||||||
sslSocket.getOutputStream().write(response.getBytes(StandardCharsets.ISO_8859_1));
|
|
||||||
return IO.toString(sslSocket.getInputStream());
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
clientContextFactory.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSocketCustomization() throws Exception
|
public void testSocketCustomization() throws Exception
|
||||||
{
|
{
|
||||||
|
@ -420,4 +467,47 @@ public class SniSslConnectionFactoryTest
|
||||||
assertEquals("customize http class org.eclipse.jetty.server.HttpConnection,true", history.poll());
|
assertEquals("customize http class org.eclipse.jetty.server.HttpConnection,true", history.poll());
|
||||||
assertEquals(0, history.size());
|
assertEquals(0, history.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getResponse(String host, String cn) throws Exception
|
||||||
|
{
|
||||||
|
String response = getResponse(host, host, cn);
|
||||||
|
assertThat(response, Matchers.startsWith("HTTP/1.1 200 "));
|
||||||
|
assertThat(response, Matchers.containsString("X-URL: /ctx/path"));
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getResponse(String sniHost, String reqHost, String cn) throws Exception
|
||||||
|
{
|
||||||
|
SslContextFactory clientContextFactory = new SslContextFactory.Client(true);
|
||||||
|
clientContextFactory.start();
|
||||||
|
SSLSocketFactory factory = clientContextFactory.getSslContext().getSocketFactory();
|
||||||
|
try (SSLSocket sslSocket = (SSLSocket)factory.createSocket("127.0.0.1", _port))
|
||||||
|
{
|
||||||
|
if (sniHost != null)
|
||||||
|
{
|
||||||
|
SNIHostName serverName = new SNIHostName(sniHost);
|
||||||
|
List<SNIServerName> serverNames = new ArrayList<>();
|
||||||
|
serverNames.add(serverName);
|
||||||
|
|
||||||
|
SSLParameters params = sslSocket.getSSLParameters();
|
||||||
|
params.setServerNames(serverNames);
|
||||||
|
sslSocket.setSSLParameters(params);
|
||||||
|
}
|
||||||
|
sslSocket.startHandshake();
|
||||||
|
|
||||||
|
if (cn != null)
|
||||||
|
{
|
||||||
|
X509Certificate cert = ((X509Certificate)sslSocket.getSession().getPeerCertificates()[0]);
|
||||||
|
assertThat(cert.getSubjectX500Principal().getName("CANONICAL"), Matchers.startsWith("cn=" + cn));
|
||||||
|
}
|
||||||
|
|
||||||
|
String response = "GET /ctx/path HTTP/1.0\r\nHost: " + reqHost + ":" + _port + "\r\n\r\n";
|
||||||
|
sslSocket.getOutputStream().write(response.getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
return IO.toString(sslSocket.getInputStream());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
clientContextFactory.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||||
org.eclipse.jetty.LEVEL=INFO
|
|
||||||
#org.eclipse.jetty.LEVEL=DEBUG
|
#org.eclipse.jetty.LEVEL=DEBUG
|
||||||
#org.eclipse.jetty.server.LEVEL=DEBUG
|
#org.eclipse.jetty.server.LEVEL=DEBUG
|
||||||
#org.eclipse.jetty.server.ConnectionLimit.LEVEL=DEBUG
|
#org.eclipse.jetty.server.ConnectionLimit.LEVEL=DEBUG
|
||||||
|
|
|
@ -103,10 +103,10 @@ public class UnixSocketTest
|
||||||
connector.setUnixSocket(sockFile.toString());
|
connector.setUnixSocket(sockFile.toString());
|
||||||
server.addConnector(connector);
|
server.addConnector(connector);
|
||||||
|
|
||||||
server.setHandler(new AbstractHandler.ErrorDispatchHandler()
|
server.setHandler(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
int l = 0;
|
int l = 0;
|
||||||
if (request.getContentLength() != 0)
|
if (request.getContentLength() != 0)
|
||||||
|
|
|
@ -49,10 +49,10 @@ public class UnixSocketProxyServer
|
||||||
if (Files.exists(socket))
|
if (Files.exists(socket))
|
||||||
Files.delete(socket);
|
Files.delete(socket);
|
||||||
|
|
||||||
server.setHandler(new AbstractHandler.ErrorDispatchHandler()
|
server.setHandler(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
int l = 0;
|
int l = 0;
|
||||||
if (request.getContentLength() != 0)
|
if (request.getContentLength() != 0)
|
||||||
|
|
|
@ -47,10 +47,10 @@ public class UnixSocketServer
|
||||||
if (Files.exists(socket))
|
if (Files.exists(socket))
|
||||||
Files.delete(socket);
|
Files.delete(socket);
|
||||||
|
|
||||||
server.setHandler(new AbstractHandler.ErrorDispatchHandler()
|
server.setHandler(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
int l = 0;
|
int l = 0;
|
||||||
if (request.getContentLength() != 0)
|
if (request.getContentLength() != 0)
|
||||||
|
|
|
@ -21,8 +21,16 @@ package org.eclipse.jetty.util;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FilenameFilter;
|
import java.io.FilenameFilter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.FileVisitOption;
|
||||||
|
import java.nio.file.FileVisitResult;
|
||||||
|
import java.nio.file.FileVisitor;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.PathMatcher;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -32,6 +40,7 @@ import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
@ -45,6 +54,16 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
*/
|
*/
|
||||||
public class Scanner extends AbstractLifeCycle
|
public class Scanner extends AbstractLifeCycle
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* When walking a directory, a depth of 1 ensures that
|
||||||
|
* the directory's descendants are visited, not just the
|
||||||
|
* directory itself (as a file).
|
||||||
|
*
|
||||||
|
* @see Visitor#preVisitDirectory
|
||||||
|
*/
|
||||||
|
public static final int DEFAULT_SCAN_DEPTH = 1;
|
||||||
|
public static final int MAX_SCAN_DEPTH = Integer.MAX_VALUE;
|
||||||
|
|
||||||
private static final Logger LOG = Log.getLogger(Scanner.class);
|
private static final Logger LOG = Log.getLogger(Scanner.class);
|
||||||
private static int __scannerId = 0;
|
private static int __scannerId = 0;
|
||||||
private int _scanInterval;
|
private int _scanInterval;
|
||||||
|
@ -53,13 +72,13 @@ public class Scanner extends AbstractLifeCycle
|
||||||
private final Map<String, TimeNSize> _prevScan = new HashMap<>();
|
private final Map<String, TimeNSize> _prevScan = new HashMap<>();
|
||||||
private final Map<String, TimeNSize> _currentScan = new HashMap<>();
|
private final Map<String, TimeNSize> _currentScan = new HashMap<>();
|
||||||
private FilenameFilter _filter;
|
private FilenameFilter _filter;
|
||||||
private final List<File> _scanDirs = new ArrayList<>();
|
private final Map<Path, IncludeExcludeSet<PathMatcher, Path>> _scannables = new HashMap<>();
|
||||||
private volatile boolean _running = false;
|
private volatile boolean _running = false;
|
||||||
private boolean _reportExisting = true;
|
private boolean _reportExisting = true;
|
||||||
private boolean _reportDirs = true;
|
private boolean _reportDirs = true;
|
||||||
private Timer _timer;
|
private Timer _timer;
|
||||||
private TimerTask _task;
|
private TimerTask _task;
|
||||||
private int _scanDepth = 0;
|
private int _scanDepth = DEFAULT_SCAN_DEPTH;
|
||||||
|
|
||||||
public enum Notification
|
public enum Notification
|
||||||
{
|
{
|
||||||
|
@ -67,7 +86,32 @@ public class Scanner extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Map<String, Notification> _notifications = new HashMap<>();
|
private final Map<String, Notification> _notifications = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PathMatcherSet
|
||||||
|
*
|
||||||
|
* A set of PathMatchers for testing Paths against path matching patterns via
|
||||||
|
* @see IncludeExcludeSet
|
||||||
|
*/
|
||||||
|
static class PathMatcherSet extends HashSet<PathMatcher> implements Predicate<Path>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean test(Path p)
|
||||||
|
{
|
||||||
|
for (PathMatcher pm : this)
|
||||||
|
{
|
||||||
|
if (pm.matches(p))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TimeNSize
|
||||||
|
*
|
||||||
|
* Metadata about a file: Last modified time and file size.
|
||||||
|
*/
|
||||||
static class TimeNSize
|
static class TimeNSize
|
||||||
{
|
{
|
||||||
final long _lastModified;
|
final long _lastModified;
|
||||||
|
@ -103,6 +147,105 @@ public class Scanner extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visitor
|
||||||
|
*
|
||||||
|
* A FileVisitor for walking a subtree of paths. The Scanner uses
|
||||||
|
* this to examine the dirs and files it has been asked to scan.
|
||||||
|
*/
|
||||||
|
public class Visitor implements FileVisitor<Path>
|
||||||
|
{
|
||||||
|
Map<String, TimeNSize> scanInfoMap;
|
||||||
|
IncludeExcludeSet<PathMatcher,Path> rootIncludesExcludes;
|
||||||
|
Path root;
|
||||||
|
|
||||||
|
public Visitor(Path root, IncludeExcludeSet<PathMatcher,Path> rootIncludesExcludes, Map<String, TimeNSize> scanInfoMap)
|
||||||
|
{
|
||||||
|
this.root = root;
|
||||||
|
this.rootIncludesExcludes = rootIncludesExcludes;
|
||||||
|
this.scanInfoMap = scanInfoMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException
|
||||||
|
{
|
||||||
|
if (!Files.exists(dir))
|
||||||
|
return FileVisitResult.SKIP_SUBTREE;
|
||||||
|
|
||||||
|
File f = dir.toFile();
|
||||||
|
|
||||||
|
//if we want to report directories and we haven't already seen it
|
||||||
|
if (_reportDirs && !scanInfoMap.containsKey(f.getCanonicalPath()))
|
||||||
|
{
|
||||||
|
boolean accepted = false;
|
||||||
|
if (rootIncludesExcludes != null && !rootIncludesExcludes.isEmpty())
|
||||||
|
{
|
||||||
|
//accepted if not explicitly excluded and either is explicitly included or there are no explicit inclusions
|
||||||
|
Boolean result = rootIncludesExcludes.test(dir);
|
||||||
|
if (Boolean.TRUE == result)
|
||||||
|
accepted = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_filter == null || _filter.accept(f.getParentFile(), f.getName()))
|
||||||
|
accepted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accepted)
|
||||||
|
{
|
||||||
|
scanInfoMap.put(f.getCanonicalPath(), new TimeNSize(f.lastModified(), f.isDirectory() ? 0 : f.length()));
|
||||||
|
if (LOG.isDebugEnabled()) LOG.debug("scan accepted dir {} mod={}", f, f.lastModified());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException
|
||||||
|
{
|
||||||
|
if (!Files.exists(file))
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
|
||||||
|
File f = file.toFile();
|
||||||
|
boolean accepted = false;
|
||||||
|
|
||||||
|
if (f.isFile() || (f.isDirectory() && _reportDirs && !scanInfoMap.containsKey(f.getCanonicalPath())))
|
||||||
|
{
|
||||||
|
if (rootIncludesExcludes != null && !rootIncludesExcludes.isEmpty())
|
||||||
|
{
|
||||||
|
//accepted if not explicitly excluded and either is explicitly included or there are no explicit inclusions
|
||||||
|
Boolean result = rootIncludesExcludes.test(file);
|
||||||
|
if (Boolean.TRUE == result)
|
||||||
|
accepted = true;
|
||||||
|
}
|
||||||
|
else if (_filter == null || _filter.accept(f.getParentFile(), f.getName()))
|
||||||
|
accepted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accepted)
|
||||||
|
{
|
||||||
|
scanInfoMap.put(f.getCanonicalPath(), new TimeNSize(f.lastModified(), f.isDirectory() ? 0 : f.length()));
|
||||||
|
if (LOG.isDebugEnabled()) LOG.debug("scan accepted {} mod={}", f, f.lastModified());
|
||||||
|
}
|
||||||
|
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException
|
||||||
|
{
|
||||||
|
LOG.warn(exc);
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException
|
||||||
|
{
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener
|
* Listener
|
||||||
*
|
*
|
||||||
|
@ -171,36 +314,110 @@ public class Scanner extends AbstractLifeCycle
|
||||||
|
|
||||||
public void setScanDirs(List<File> dirs)
|
public void setScanDirs(List<File> dirs)
|
||||||
{
|
{
|
||||||
_scanDirs.clear();
|
_scannables.clear();
|
||||||
_scanDirs.addAll(dirs);
|
if (dirs == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (File f:dirs)
|
||||||
|
{
|
||||||
|
addScanDir(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public synchronized void addScanDir(File dir)
|
public synchronized void addScanDir(File dir)
|
||||||
{
|
{
|
||||||
_scanDirs.add(dir);
|
if (dir == null)
|
||||||
|
return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (dir.isDirectory())
|
||||||
|
addDirectory(dir.toPath());
|
||||||
|
else
|
||||||
|
addFile(dir.toPath());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOG.warn(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a file to be scanned. The file must not be null, and must exist.
|
||||||
|
*
|
||||||
|
* @param p the Path of the file to scan.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public synchronized void addFile(Path p) throws IOException
|
||||||
|
{
|
||||||
|
if (p == null)
|
||||||
|
throw new IllegalStateException("Null path");
|
||||||
|
|
||||||
|
File f = p.toFile();
|
||||||
|
if (!f.exists() || f.isDirectory())
|
||||||
|
throw new IllegalStateException("Not file or doesn't exist: " + f.getCanonicalPath());
|
||||||
|
_scannables.put(p, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a directory to be scanned. The directory must not be null and must exist.
|
||||||
|
*
|
||||||
|
* @param p the directory to scan.
|
||||||
|
* @return an IncludeExcludeSet to which the caller can add PathMatcher patterns to match
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public synchronized IncludeExcludeSet<PathMatcher, Path> addDirectory(Path p)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
if (p == null)
|
||||||
|
throw new IllegalStateException("Null path");
|
||||||
|
|
||||||
|
File f = p.toFile();
|
||||||
|
if (!f.exists() || !f.isDirectory())
|
||||||
|
throw new IllegalStateException("Not directory or doesn't exist: " + f.getCanonicalPath());
|
||||||
|
|
||||||
|
IncludeExcludeSet<PathMatcher, Path> includesExcludes = _scannables.get(p);
|
||||||
|
if (includesExcludes == null)
|
||||||
|
{
|
||||||
|
includesExcludes = new IncludeExcludeSet<>(PathMatcherSet.class);
|
||||||
|
_scannables.put(p.toRealPath(), includesExcludes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return includesExcludes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public List<File> getScanDirs()
|
public List<File> getScanDirs()
|
||||||
{
|
{
|
||||||
return Collections.unmodifiableList(_scanDirs);
|
ArrayList<File> files = new ArrayList<>();
|
||||||
|
for (Path p : _scannables.keySet())
|
||||||
|
files.add(p.toFile());
|
||||||
|
return Collections.unmodifiableList(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Path> getScannables()
|
||||||
|
{
|
||||||
|
return _scannables.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param recursive True if scanning is recursive
|
* @param recursive True if scanning is recursive
|
||||||
* @see #setScanDepth(int)
|
* @see #setScanDepth(int)
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setRecursive(boolean recursive)
|
public void setRecursive(boolean recursive)
|
||||||
{
|
{
|
||||||
_scanDepth = recursive ? -1 : 0;
|
_scanDepth = recursive ? Integer.MAX_VALUE : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return True if scanning is fully recursive (scandepth==-1)
|
* @return True if scanning is recursive
|
||||||
* @see #getScanDepth()
|
* @see #getScanDepth()
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public boolean getRecursive()
|
public boolean getRecursive()
|
||||||
{
|
{
|
||||||
return _scanDepth == -1;
|
return _scanDepth > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -229,6 +446,7 @@ public class Scanner extends AbstractLifeCycle
|
||||||
*
|
*
|
||||||
* @param filter the filename filter to use
|
* @param filter the filename filter to use
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setFilenameFilter(FilenameFilter filter)
|
public void setFilenameFilter(FilenameFilter filter)
|
||||||
{
|
{
|
||||||
_filter = filter;
|
_filter = filter;
|
||||||
|
@ -239,6 +457,7 @@ public class Scanner extends AbstractLifeCycle
|
||||||
*
|
*
|
||||||
* @return the filename filter
|
* @return the filename filter
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public FilenameFilter getFilenameFilter()
|
public FilenameFilter getFilenameFilter()
|
||||||
{
|
{
|
||||||
return _filter;
|
return _filter;
|
||||||
|
@ -310,6 +529,9 @@ public class Scanner extends AbstractLifeCycle
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_running = true;
|
_running = true;
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Scanner start: rprtExists={}, depth={}, rprtDirs={}, interval={}, filter={}, scannables={}",
|
||||||
|
_reportExisting, _scanDepth, _reportDirs, _scanInterval, _filter, _scannables);
|
||||||
|
|
||||||
if (_reportExisting)
|
if (_reportExisting)
|
||||||
{
|
{
|
||||||
|
@ -377,6 +599,23 @@ public class Scanner extends AbstractLifeCycle
|
||||||
_timer = null;
|
_timer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the list of scannables. The scanner must first
|
||||||
|
* be in the stopped state.
|
||||||
|
*/
|
||||||
|
public void reset()
|
||||||
|
{
|
||||||
|
if (!isStopped())
|
||||||
|
throw new IllegalStateException("Not stopped");
|
||||||
|
|
||||||
|
//clear the scannables
|
||||||
|
_scannables.clear();
|
||||||
|
|
||||||
|
//clear the previous scans
|
||||||
|
_currentScan.clear();
|
||||||
|
_prevScan.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param path tests if the path exists
|
* @param path tests if the path exists
|
||||||
|
@ -384,9 +623,9 @@ public class Scanner extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public boolean exists(String path)
|
public boolean exists(String path)
|
||||||
{
|
{
|
||||||
for (File dir : _scanDirs)
|
for (Path p : _scannables.keySet())
|
||||||
{
|
{
|
||||||
if (new File(dir, path).exists())
|
if (p.resolve(path).toFile().exists())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -419,23 +658,20 @@ public class Scanner extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively scan all files in the designated directories.
|
* Scan all of the given paths.
|
||||||
*/
|
*/
|
||||||
public synchronized void scanFiles()
|
public synchronized void scanFiles()
|
||||||
{
|
{
|
||||||
_currentScan.clear();
|
_currentScan.clear();
|
||||||
for (File dir : _scanDirs)
|
for (Path p : _scannables.keySet())
|
||||||
{
|
{
|
||||||
if ((dir != null) && (dir.exists()))
|
try
|
||||||
{
|
{
|
||||||
try
|
Files.walkFileTree(p, EnumSet.allOf(FileVisitOption.class),_scanDepth, new Visitor(p, _scannables.get(p), _currentScan));
|
||||||
{
|
}
|
||||||
scanFile(dir.getCanonicalFile(), _currentScan, 0);
|
catch (IOException e)
|
||||||
}
|
{
|
||||||
catch (IOException e)
|
LOG.warn("Error scanning files.", e);
|
||||||
{
|
|
||||||
LOG.warn("Error scanning files.", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -449,7 +685,6 @@ public class Scanner extends AbstractLifeCycle
|
||||||
private synchronized void reportDifferences(Map<String, TimeNSize> currentScan, Map<String, TimeNSize> oldScan)
|
private synchronized void reportDifferences(Map<String, TimeNSize> currentScan, Map<String, TimeNSize> oldScan)
|
||||||
{
|
{
|
||||||
// scan the differences and add what was found to the map of notifications:
|
// scan the differences and add what was found to the map of notifications:
|
||||||
|
|
||||||
Set<String> oldScanKeys = new HashSet<>(oldScan.keySet());
|
Set<String> oldScanKeys = new HashSet<>(oldScan.keySet());
|
||||||
|
|
||||||
// Look for new and changed files
|
// Look for new and changed files
|
||||||
|
@ -492,16 +727,16 @@ public class Scanner extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("scanned " + _scanDirs + ": " + _notifications);
|
LOG.debug("scanned " + _scannables.keySet() + ": " + _notifications);
|
||||||
|
|
||||||
// Process notifications
|
// Process notifications
|
||||||
// Only process notifications that are for stable files (ie same in old and current scan).
|
// Only process notifications that are for stable files (ie same in old and current scan).
|
||||||
List<String> bulkChanges = new ArrayList<>();
|
List<String> bulkChanges = new ArrayList<>();
|
||||||
for (Iterator<Entry<String, Notification>> iter = _notifications.entrySet().iterator(); iter.hasNext(); )
|
for (Iterator<Entry<String, Notification>> iter = _notifications.entrySet().iterator(); iter.hasNext(); )
|
||||||
{
|
{
|
||||||
|
|
||||||
Entry<String, Notification> entry = iter.next();
|
Entry<String, Notification> entry = iter.next();
|
||||||
String file = entry.getKey();
|
String file = entry.getKey();
|
||||||
|
|
||||||
// Is the file stable?
|
// Is the file stable?
|
||||||
if (oldScan.containsKey(file))
|
if (oldScan.containsKey(file))
|
||||||
{
|
{
|
||||||
|
@ -534,57 +769,6 @@ public class Scanner extends AbstractLifeCycle
|
||||||
reportBulkChanges(bulkChanges);
|
reportBulkChanges(bulkChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get last modified time on a single file or recurse if
|
|
||||||
* the file is a directory.
|
|
||||||
*
|
|
||||||
* @param f file or directory
|
|
||||||
* @param scanInfoMap map of filenames to last modified times
|
|
||||||
*/
|
|
||||||
private void scanFile(File f, Map<String, TimeNSize> scanInfoMap, int depth)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!f.exists())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (f.isFile() || depth > 0 && _reportDirs && f.isDirectory())
|
|
||||||
{
|
|
||||||
if (_filter == null || _filter.accept(f.getParentFile(), f.getName()))
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("scan accepted {}", f);
|
|
||||||
String name = f.getCanonicalPath();
|
|
||||||
scanInfoMap.put(name, new TimeNSize(f.lastModified(), f.isDirectory() ? 0 : f.length()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("scan rejected {}", f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it is a directory, scan if it is a known directory or the depth is OK.
|
|
||||||
if (f.isDirectory() && (depth < _scanDepth || _scanDepth == -1 || _scanDirs.contains(f)))
|
|
||||||
{
|
|
||||||
File[] files = f.listFiles();
|
|
||||||
if (files != null)
|
|
||||||
{
|
|
||||||
for (File file : files)
|
|
||||||
{
|
|
||||||
scanFile(file, scanInfoMap, depth + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LOG.warn("Error listing files in directory {}", f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
LOG.warn("Error scanning watched files", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void warn(Object listener, String filename, Throwable th)
|
private void warn(Object listener, String filename, Throwable th)
|
||||||
{
|
{
|
||||||
LOG.warn(listener + " failed on '" + filename, th);
|
LOG.warn(listener + " failed on '" + filename, th);
|
||||||
|
@ -653,6 +837,11 @@ public class Scanner extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report the list of filenames for which changes were detected.
|
||||||
|
*
|
||||||
|
* @param filenames names of all files added/changed/removed
|
||||||
|
*/
|
||||||
private void reportBulkChanges(List<String> filenames)
|
private void reportBulkChanges(List<String> filenames)
|
||||||
{
|
{
|
||||||
for (Listener l : _listeners)
|
for (Listener l : _listeners)
|
||||||
|
@ -670,7 +859,7 @@ public class Scanner extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* signal any scan cycle listeners that a scan has started
|
* Call ScanCycleListeners with start of scan
|
||||||
*/
|
*/
|
||||||
private void reportScanStart(int cycle)
|
private void reportScanStart(int cycle)
|
||||||
{
|
{
|
||||||
|
@ -691,7 +880,7 @@ public class Scanner extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sign
|
* Call ScanCycleListeners with end of scan.
|
||||||
*/
|
*/
|
||||||
private void reportScanEnd(int cycle)
|
private void reportScanEnd(int cycle)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,8 +24,12 @@ import java.security.PrivateKey;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import javax.net.ssl.SNIMatcher;
|
import javax.net.ssl.SNIMatcher;
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
|
import javax.net.ssl.SSLHandshakeException;
|
||||||
import javax.net.ssl.SSLSession;
|
import javax.net.ssl.SSLSession;
|
||||||
import javax.net.ssl.SSLSocket;
|
import javax.net.ssl.SSLSocket;
|
||||||
import javax.net.ssl.X509ExtendedKeyManager;
|
import javax.net.ssl.X509ExtendedKeyManager;
|
||||||
|
@ -41,14 +45,20 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
public class SniX509ExtendedKeyManager extends X509ExtendedKeyManager
|
public class SniX509ExtendedKeyManager extends X509ExtendedKeyManager
|
||||||
{
|
{
|
||||||
public static final String SNI_X509 = "org.eclipse.jetty.util.ssl.snix509";
|
public static final String SNI_X509 = "org.eclipse.jetty.util.ssl.snix509";
|
||||||
private static final String NO_MATCHERS = "no_matchers";
|
|
||||||
private static final Logger LOG = Log.getLogger(SniX509ExtendedKeyManager.class);
|
private static final Logger LOG = Log.getLogger(SniX509ExtendedKeyManager.class);
|
||||||
|
|
||||||
private final X509ExtendedKeyManager _delegate;
|
private final X509ExtendedKeyManager _delegate;
|
||||||
|
private final SslContextFactory.Server _sslContextFactory;
|
||||||
|
|
||||||
public SniX509ExtendedKeyManager(X509ExtendedKeyManager keyManager)
|
public SniX509ExtendedKeyManager(X509ExtendedKeyManager keyManager)
|
||||||
|
{
|
||||||
|
this(keyManager, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SniX509ExtendedKeyManager(X509ExtendedKeyManager keyManager, SslContextFactory.Server sslContextFactory)
|
||||||
{
|
{
|
||||||
_delegate = keyManager;
|
_delegate = keyManager;
|
||||||
|
_sslContextFactory = sslContextFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -65,53 +75,69 @@ public class SniX509ExtendedKeyManager extends X509ExtendedKeyManager
|
||||||
|
|
||||||
protected String chooseServerAlias(String keyType, Principal[] issuers, Collection<SNIMatcher> matchers, SSLSession session)
|
protected String chooseServerAlias(String keyType, Principal[] issuers, Collection<SNIMatcher> matchers, SSLSession session)
|
||||||
{
|
{
|
||||||
// Look for the aliases that are suitable for the keytype and issuers
|
// Look for the aliases that are suitable for the keyType and issuers.
|
||||||
String[] aliases = _delegate.getServerAliases(keyType, issuers);
|
String[] aliases = _delegate.getServerAliases(keyType, issuers);
|
||||||
if (aliases == null || aliases.length == 0)
|
if (aliases == null || aliases.length == 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Look for the SNI information.
|
// Find our SNIMatcher. There should only be one and it always matches (always returns true
|
||||||
String host = null;
|
// from AliasSNIMatcher.matches), but it will capture the SNI Host if one was presented.
|
||||||
X509 x509 = null;
|
String host = matchers == null ? null : matchers.stream()
|
||||||
if (matchers != null)
|
.filter(SslContextFactory.AliasSNIMatcher.class::isInstance)
|
||||||
|
.map(SslContextFactory.AliasSNIMatcher.class::cast)
|
||||||
|
.findFirst()
|
||||||
|
.map(SslContextFactory.AliasSNIMatcher::getHost)
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
for (SNIMatcher m : matchers)
|
// Filter the certificates by alias.
|
||||||
|
Collection<X509> certificates = Arrays.stream(aliases)
|
||||||
|
.map(_sslContextFactory::getX509)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// delegate the decision to accept to the sniSelector
|
||||||
|
SniSelector sniSelector = _sslContextFactory.getSNISelector();
|
||||||
|
if (sniSelector == null)
|
||||||
|
sniSelector = _sslContextFactory;
|
||||||
|
String alias = sniSelector.sniSelect(keyType, issuers, session, host, certificates);
|
||||||
|
|
||||||
|
// Check selected alias
|
||||||
|
if (alias != null && alias != SniSelector.DELEGATE)
|
||||||
{
|
{
|
||||||
if (m instanceof SslContextFactory.AliasSNIMatcher)
|
// Make sure we got back an alias from the acceptable aliases.
|
||||||
|
X509 x509 = _sslContextFactory.getX509(alias);
|
||||||
|
if (!Arrays.asList(aliases).contains(alias) || x509 == null)
|
||||||
{
|
{
|
||||||
SslContextFactory.AliasSNIMatcher matcher = (SslContextFactory.AliasSNIMatcher)m;
|
if (LOG.isDebugEnabled())
|
||||||
host = matcher.getHost();
|
LOG.debug("Invalid X509 match for SNI {}: {}", host, alias);
|
||||||
x509 = matcher.getX509();
|
return null;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("Matched {} with {} from {}", host, x509, Arrays.asList(aliases));
|
LOG.debug("Matched SNI {} with X509 {} from {}", host, x509, Arrays.asList(aliases));
|
||||||
|
if (session != null)
|
||||||
// Check if the SNI selected alias is allowable
|
|
||||||
if (x509 != null)
|
|
||||||
{
|
|
||||||
for (String a : aliases)
|
|
||||||
{
|
|
||||||
if (a.equals(x509.getAlias()))
|
|
||||||
{
|
|
||||||
session.putValue(SNI_X509, x509);
|
session.putValue(SNI_X509, x509);
|
||||||
return a;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return alias;
|
||||||
|
}
|
||||||
|
catch (Throwable x)
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Failure matching X509 for SNI " + host, x);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return NO_MATCHERS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket)
|
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket)
|
||||||
{
|
{
|
||||||
SSLSocket sslSocket = (SSLSocket)socket;
|
SSLSocket sslSocket = (SSLSocket)socket;
|
||||||
String alias = socket == null ? NO_MATCHERS : chooseServerAlias(keyType, issuers, sslSocket.getSSLParameters().getSNIMatchers(), sslSocket.getHandshakeSession());
|
String alias = (socket == null)
|
||||||
if (alias == NO_MATCHERS)
|
? chooseServerAlias(keyType, issuers, Collections.emptyList(), null)
|
||||||
|
: chooseServerAlias(keyType, issuers, sslSocket.getSSLParameters().getSNIMatchers(), sslSocket.getHandshakeSession());
|
||||||
|
if (alias == SniSelector.DELEGATE)
|
||||||
alias = _delegate.chooseServerAlias(keyType, issuers, socket);
|
alias = _delegate.chooseServerAlias(keyType, issuers, socket);
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("Chose alias {}/{} on {}", alias, keyType, socket);
|
LOG.debug("Chose alias {}/{} on {}", alias, keyType, socket);
|
||||||
|
@ -121,8 +147,10 @@ public class SniX509ExtendedKeyManager extends X509ExtendedKeyManager
|
||||||
@Override
|
@Override
|
||||||
public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine)
|
public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine)
|
||||||
{
|
{
|
||||||
String alias = engine == null ? NO_MATCHERS : chooseServerAlias(keyType, issuers, engine.getSSLParameters().getSNIMatchers(), engine.getHandshakeSession());
|
String alias = (engine == null)
|
||||||
if (alias == NO_MATCHERS)
|
? chooseServerAlias(keyType, issuers, Collections.emptyList(), null)
|
||||||
|
: chooseServerAlias(keyType, issuers, engine.getSSLParameters().getSNIMatchers(), engine.getHandshakeSession());
|
||||||
|
if (alias == SniSelector.DELEGATE)
|
||||||
alias = _delegate.chooseEngineServerAlias(keyType, issuers, engine);
|
alias = _delegate.chooseEngineServerAlias(keyType, issuers, engine);
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("Chose alias {}/{} on {}", alias, keyType, engine);
|
LOG.debug("Chose alias {}/{} on {}", alias, keyType, engine);
|
||||||
|
@ -152,4 +180,31 @@ public class SniX509ExtendedKeyManager extends X509ExtendedKeyManager
|
||||||
{
|
{
|
||||||
return _delegate.getServerAliases(keyType, issuers);
|
return _delegate.getServerAliases(keyType, issuers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Selects a certificate based on SNI information.</p>
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface SniSelector
|
||||||
|
{
|
||||||
|
String DELEGATE = "delegate_no_sni_match";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Selects a certificate based on SNI information.</p>
|
||||||
|
* <p>This method may be invoked multiple times during the TLS handshake, with different parameters.
|
||||||
|
* For example, the {@code keyType} could be different, and subsequently the collection of certificates
|
||||||
|
* (because they need to match the {@code keyType}.</p>
|
||||||
|
*
|
||||||
|
* @param keyType the key algorithm type name
|
||||||
|
* @param issuers the list of acceptable CA issuer subject names or null if it does not matter which issuers are used
|
||||||
|
* @param session the TLS handshake session or null if not known.
|
||||||
|
* @param sniHost the server name indication sent by the client, or null if the client did not send the server name indication
|
||||||
|
* @param certificates the list of certificates matching {@code keyType} and {@code issuers} known to this SslContextFactory
|
||||||
|
* @return the alias of the certificate to return to the client, from the {@code certificates} list,
|
||||||
|
* or {@link SniSelector#DELEGATE} if the certificate choice should be delegated to the
|
||||||
|
* nested key manager or null for no match.
|
||||||
|
* @throws SSLHandshakeException if the TLS handshake should be aborted
|
||||||
|
*/
|
||||||
|
public String sniSelect(String keyType, Principal[] issuers, SSLSession session, String sniHost, Collection<X509> certificates) throws SSLHandshakeException;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,7 @@ import javax.net.ssl.SNIMatcher;
|
||||||
import javax.net.ssl.SNIServerName;
|
import javax.net.ssl.SNIServerName;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
|
import javax.net.ssl.SSLHandshakeException;
|
||||||
import javax.net.ssl.SSLParameters;
|
import javax.net.ssl.SSLParameters;
|
||||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||||
import javax.net.ssl.SSLServerSocket;
|
import javax.net.ssl.SSLServerSocket;
|
||||||
|
@ -1146,7 +1147,7 @@ public abstract class SslContextFactory extends AbstractLifeCycle implements Dum
|
||||||
for (int idx = 0; idx < managers.length; idx++)
|
for (int idx = 0; idx < managers.length; idx++)
|
||||||
{
|
{
|
||||||
if (managers[idx] instanceof X509ExtendedKeyManager)
|
if (managers[idx] instanceof X509ExtendedKeyManager)
|
||||||
managers[idx] = new SniX509ExtendedKeyManager((X509ExtendedKeyManager)managers[idx]);
|
managers[idx] = newSniX509ExtendedKeyManager((X509ExtendedKeyManager)managers[idx]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1158,6 +1159,11 @@ public abstract class SslContextFactory extends AbstractLifeCycle implements Dum
|
||||||
return managers;
|
return managers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected X509ExtendedKeyManager newSniX509ExtendedKeyManager(X509ExtendedKeyManager keyManager)
|
||||||
|
{
|
||||||
|
return new SniX509ExtendedKeyManager(keyManager);
|
||||||
|
}
|
||||||
|
|
||||||
protected TrustManager[] getTrustManagers(KeyStore trustStore, Collection<? extends CRL> crls) throws Exception
|
protected TrustManager[] getTrustManagers(KeyStore trustStore, Collection<? extends CRL> crls) throws Exception
|
||||||
{
|
{
|
||||||
TrustManager[] managers = null;
|
TrustManager[] managers = null;
|
||||||
|
@ -2011,7 +2017,6 @@ public abstract class SslContextFactory extends AbstractLifeCycle implements Dum
|
||||||
class AliasSNIMatcher extends SNIMatcher
|
class AliasSNIMatcher extends SNIMatcher
|
||||||
{
|
{
|
||||||
private String _host;
|
private String _host;
|
||||||
private X509 _x509;
|
|
||||||
|
|
||||||
AliasSNIMatcher()
|
AliasSNIMatcher()
|
||||||
{
|
{
|
||||||
|
@ -2026,36 +2031,14 @@ public abstract class SslContextFactory extends AbstractLifeCycle implements Dum
|
||||||
|
|
||||||
if (serverName instanceof SNIHostName)
|
if (serverName instanceof SNIHostName)
|
||||||
{
|
{
|
||||||
String host = _host = ((SNIHostName)serverName).getAsciiName();
|
_host = StringUtil.asciiToLowerCase(((SNIHostName)serverName).getAsciiName());
|
||||||
host = StringUtil.asciiToLowerCase(host);
|
|
||||||
|
|
||||||
// Try an exact match
|
|
||||||
_x509 = _certHosts.get(host);
|
|
||||||
|
|
||||||
// Else try an exact wild match
|
|
||||||
if (_x509 == null)
|
|
||||||
{
|
|
||||||
_x509 = _certWilds.get(host);
|
|
||||||
|
|
||||||
// Else try an 1 deep wild match
|
|
||||||
if (_x509 == null)
|
|
||||||
{
|
|
||||||
int dot = host.indexOf('.');
|
|
||||||
if (dot >= 0)
|
|
||||||
{
|
|
||||||
String domain = host.substring(dot + 1);
|
|
||||||
_x509 = _certWilds.get(domain);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("SNI matched {}->{}", host, _x509);
|
LOG.debug("SNI host name {}", _host);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("SNI no match for {}", serverName);
|
LOG.debug("No SNI host name for {}", serverName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true and allow the KeyManager to accept or reject when choosing a certificate.
|
// Return true and allow the KeyManager to accept or reject when choosing a certificate.
|
||||||
|
@ -2068,11 +2051,6 @@ public abstract class SslContextFactory extends AbstractLifeCycle implements Dum
|
||||||
{
|
{
|
||||||
return _host;
|
return _host;
|
||||||
}
|
}
|
||||||
|
|
||||||
public X509 getX509()
|
|
||||||
{
|
|
||||||
return _x509;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Client extends SslContextFactory
|
public static class Client extends SslContextFactory
|
||||||
|
@ -2096,10 +2074,13 @@ public abstract class SslContextFactory extends AbstractLifeCycle implements Dum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Server extends SslContextFactory
|
@ManagedObject
|
||||||
|
public static class Server extends SslContextFactory implements SniX509ExtendedKeyManager.SniSelector
|
||||||
{
|
{
|
||||||
private boolean _needClientAuth;
|
private boolean _needClientAuth;
|
||||||
private boolean _wantClientAuth;
|
private boolean _wantClientAuth;
|
||||||
|
private boolean _sniRequired;
|
||||||
|
private SniX509ExtendedKeyManager.SniSelector _sniSelector;
|
||||||
|
|
||||||
public Server()
|
public Server()
|
||||||
{
|
{
|
||||||
|
@ -2143,6 +2124,88 @@ public abstract class SslContextFactory extends AbstractLifeCycle implements Dum
|
||||||
{
|
{
|
||||||
_wantClientAuth = wantClientAuth;
|
_wantClientAuth = wantClientAuth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the default {@link #sniSelect(String, Principal[], SSLSession, String, Collection)} implementation
|
||||||
|
* require an SNI match? Note that if a non SNI handshake is accepted, requests may still be rejected
|
||||||
|
* at the HTTP level for incorrect SNI (see SecureRequestCustomizer).
|
||||||
|
* @return true if no SNI match is handled as no certificate match, false if no SNI match is handled by
|
||||||
|
* delegation to the non SNI matching methods.
|
||||||
|
*/
|
||||||
|
@ManagedAttribute("Whether the TLS handshake is rejected if there is no SNI host match")
|
||||||
|
public boolean isSniRequired()
|
||||||
|
{
|
||||||
|
return _sniRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set if the default {@link #sniSelect(String, Principal[], SSLSession, String, Collection)} implementation
|
||||||
|
* require an SNI match? Note that if a non SNI handshake is accepted, requests may still be rejected
|
||||||
|
* at the HTTP level for incorrect SNI (see SecureRequestCustomizer).
|
||||||
|
* This setting may have no effect if {@link #sniSelect(String, Principal[], SSLSession, String, Collection)} is
|
||||||
|
* overridden or a non null function is passed to {@link #setSNISelector(SniX509ExtendedKeyManager.SniSelector)}.
|
||||||
|
* @param sniRequired true if no SNI match is handled as no certificate match, false if no SNI match is handled by
|
||||||
|
* delegation to the non SNI matching methods.
|
||||||
|
*/
|
||||||
|
public void setSniRequired(boolean sniRequired)
|
||||||
|
{
|
||||||
|
_sniRequired = sniRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected KeyManager[] getKeyManagers(KeyStore keyStore) throws Exception
|
||||||
|
{
|
||||||
|
KeyManager[] managers = super.getKeyManagers(keyStore);
|
||||||
|
if (isSniRequired())
|
||||||
|
{
|
||||||
|
if (managers == null || Arrays.stream(managers).noneMatch(SniX509ExtendedKeyManager.class::isInstance))
|
||||||
|
throw new IllegalStateException("No SNI Key managers when SNI is required");
|
||||||
|
}
|
||||||
|
return managers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the custom function to select certificates based on SNI information
|
||||||
|
*/
|
||||||
|
public SniX509ExtendedKeyManager.SniSelector getSNISelector()
|
||||||
|
{
|
||||||
|
return _sniSelector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets a custom function to select certificates based on SNI information.</p>
|
||||||
|
*
|
||||||
|
* @param sniSelector the selection function
|
||||||
|
*/
|
||||||
|
public void setSNISelector(SniX509ExtendedKeyManager.SniSelector sniSelector)
|
||||||
|
{
|
||||||
|
_sniSelector = sniSelector;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String sniSelect(String keyType, Principal[] issuers, SSLSession session, String sniHost, Collection<X509> certificates) throws SSLHandshakeException
|
||||||
|
{
|
||||||
|
if (sniHost == null)
|
||||||
|
{
|
||||||
|
// No SNI, so reject or delegate.
|
||||||
|
return _sniRequired ? null : SniX509ExtendedKeyManager.SniSelector.DELEGATE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Match the SNI host, or let the JDK decide unless unmatched SNIs are rejected.
|
||||||
|
return certificates.stream()
|
||||||
|
.filter(x509 -> x509.matches(sniHost))
|
||||||
|
.findFirst()
|
||||||
|
.map(X509::getAlias)
|
||||||
|
.orElse(_sniRequired ? null : SniX509ExtendedKeyManager.SniSelector.DELEGATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected X509ExtendedKeyManager newSniX509ExtendedKeyManager(X509ExtendedKeyManager keyManager)
|
||||||
|
{
|
||||||
|
return new SniX509ExtendedKeyManager(keyManager, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,6 +22,8 @@ import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.PathMatcher;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
@ -30,12 +32,14 @@ import java.util.concurrent.TimeUnit;
|
||||||
import org.eclipse.jetty.toolchain.test.FS;
|
import org.eclipse.jetty.toolchain.test.FS;
|
||||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
import org.eclipse.jetty.util.Scanner.Notification;
|
import org.eclipse.jetty.util.Scanner.Notification;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
|
import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
|
||||||
import org.junit.jupiter.api.condition.DisabledOnOs;
|
import org.junit.jupiter.api.condition.DisabledOnOs;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
@ -61,6 +65,8 @@ public class ScannerTest
|
||||||
_scanner = new Scanner();
|
_scanner = new Scanner();
|
||||||
_scanner.addScanDir(_directory);
|
_scanner.addScanDir(_directory);
|
||||||
_scanner.setScanInterval(0);
|
_scanner.setScanInterval(0);
|
||||||
|
_scanner.setReportDirs(false);
|
||||||
|
_scanner.setReportExistingFilesOnStartup(false);
|
||||||
_scanner.addListener(new Scanner.DiscreteListener()
|
_scanner.addListener(new Scanner.DiscreteListener()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
@ -89,8 +95,8 @@ public class ScannerTest
|
||||||
_bulk.add(filenames);
|
_bulk.add(filenames);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
_scanner.start();
|
_scanner.start();
|
||||||
|
|
||||||
_scanner.scan();
|
_scanner.scan();
|
||||||
|
|
||||||
assertTrue(_queue.isEmpty());
|
assertTrue(_queue.isEmpty());
|
||||||
|
@ -115,6 +121,155 @@ public class ScannerTest
|
||||||
_notification = notification;
|
_notification = notification;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDepth() throws Exception
|
||||||
|
{
|
||||||
|
File root = new File (_directory, "root");
|
||||||
|
FS.ensureDirExists(root);
|
||||||
|
FS.touch(new File(root, "foo.foo"));
|
||||||
|
FS.touch(new File(root, "foo2.foo"));
|
||||||
|
File dir = new File(root, "xxx");
|
||||||
|
FS.ensureDirExists(dir);
|
||||||
|
File x1 = new File(dir, "xxx.foo");
|
||||||
|
FS.touch(x1);
|
||||||
|
File x2 = new File(dir, "xxx2.foo");
|
||||||
|
FS.touch(x2);
|
||||||
|
File dir2 = new File(dir, "yyy");
|
||||||
|
FS.ensureDirExists(dir2);
|
||||||
|
File y1 = new File(dir2, "yyy.foo");
|
||||||
|
FS.touch(y1);
|
||||||
|
File y2 = new File(dir2, "yyy2.foo");
|
||||||
|
FS.touch(y2);
|
||||||
|
|
||||||
|
BlockingQueue<Event> queue = new LinkedBlockingQueue<Event>();
|
||||||
|
Scanner scanner = new Scanner();
|
||||||
|
scanner.setScanInterval(0);
|
||||||
|
scanner.setScanDepth(0);
|
||||||
|
scanner.setReportDirs(true);
|
||||||
|
scanner.setReportExistingFilesOnStartup(true);
|
||||||
|
scanner.addDirectory(root.toPath());
|
||||||
|
scanner.addListener(new Scanner.DiscreteListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void fileRemoved(String filename) throws Exception
|
||||||
|
{
|
||||||
|
queue.add(new Event(filename, Notification.REMOVED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fileChanged(String filename) throws Exception
|
||||||
|
{
|
||||||
|
queue.add(new Event(filename, Notification.CHANGED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fileAdded(String filename) throws Exception
|
||||||
|
{
|
||||||
|
queue.add(new Event(filename, Notification.ADDED));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
scanner.start();
|
||||||
|
Event e = queue.take();
|
||||||
|
assertNotNull(e);
|
||||||
|
assertEquals(Notification.ADDED, e._notification);
|
||||||
|
assertTrue(e._filename.endsWith(root.getName()));
|
||||||
|
queue.clear();
|
||||||
|
scanner.stop();
|
||||||
|
scanner.reset();
|
||||||
|
|
||||||
|
//Depth one should report the dir itself and its file and dir direct children
|
||||||
|
scanner.setScanDepth(1);
|
||||||
|
scanner.addDirectory(root.toPath());
|
||||||
|
scanner.start();
|
||||||
|
assertEquals(4, queue.size());
|
||||||
|
queue.clear();
|
||||||
|
scanner.stop();
|
||||||
|
scanner.reset();
|
||||||
|
|
||||||
|
//Depth 2 should report the dir itself, all file children, xxx and xxx's children
|
||||||
|
scanner.setScanDepth(2);
|
||||||
|
scanner.addDirectory(root.toPath());
|
||||||
|
scanner.start();
|
||||||
|
|
||||||
|
assertEquals(7, queue.size());
|
||||||
|
scanner.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPatterns() throws Exception
|
||||||
|
{
|
||||||
|
//test include and exclude patterns
|
||||||
|
File root = new File(_directory, "proot");
|
||||||
|
FS.ensureDirExists(root);
|
||||||
|
|
||||||
|
File ttt = new File(root, "ttt.txt");
|
||||||
|
FS.touch(ttt);
|
||||||
|
FS.touch(new File(root, "ttt.foo"));
|
||||||
|
File dir = new File(root, "xxx");
|
||||||
|
FS.ensureDirExists(dir);
|
||||||
|
|
||||||
|
File x1 = new File(dir, "ttt.xxx");
|
||||||
|
FS.touch(x1);
|
||||||
|
File x2 = new File(dir, "xxx.txt");
|
||||||
|
FS.touch(x2);
|
||||||
|
|
||||||
|
File dir2 = new File(dir, "yyy");
|
||||||
|
FS.ensureDirExists(dir2);
|
||||||
|
File y1 = new File(dir2, "ttt.yyy");
|
||||||
|
FS.touch(y1);
|
||||||
|
File y2 = new File(dir2, "yyy.txt");
|
||||||
|
FS.touch(y2);
|
||||||
|
|
||||||
|
BlockingQueue<Event> queue = new LinkedBlockingQueue<Event>();
|
||||||
|
//only scan the *.txt files for changes
|
||||||
|
Scanner scanner = new Scanner();
|
||||||
|
IncludeExcludeSet<PathMatcher, Path> pattern = scanner.addDirectory(root.toPath());
|
||||||
|
pattern.exclude(root.toPath().getFileSystem().getPathMatcher("glob:**/*.foo"));
|
||||||
|
pattern.exclude(root.toPath().getFileSystem().getPathMatcher("glob:**/ttt.xxx"));
|
||||||
|
scanner.setScanInterval(0);
|
||||||
|
scanner.setScanDepth(2); //should never see any files from subdir yyy
|
||||||
|
scanner.setReportDirs(false);
|
||||||
|
scanner.setReportExistingFilesOnStartup(false);
|
||||||
|
scanner.addListener(new Scanner.DiscreteListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void fileRemoved(String filename) throws Exception
|
||||||
|
{
|
||||||
|
queue.add(new Event(filename, Notification.REMOVED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fileChanged(String filename) throws Exception
|
||||||
|
{
|
||||||
|
queue.add(new Event(filename, Notification.CHANGED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fileAdded(String filename) throws Exception
|
||||||
|
{
|
||||||
|
queue.add(new Event(filename, Notification.ADDED));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
scanner.start();
|
||||||
|
assertTrue(queue.isEmpty());
|
||||||
|
|
||||||
|
Thread.sleep(1100); // make sure time in seconds changes
|
||||||
|
FS.touch(ttt);
|
||||||
|
FS.touch(x2);
|
||||||
|
FS.touch(x1);
|
||||||
|
FS.touch(y2);
|
||||||
|
scanner.scan();
|
||||||
|
scanner.scan(); //2 scans for file to be considered settled
|
||||||
|
|
||||||
|
assertThat(queue.size(), Matchers.equalTo(2));
|
||||||
|
for (Event e : queue)
|
||||||
|
{
|
||||||
|
assertTrue(e._filename.endsWith("ttt.txt") || e._filename.endsWith("xxx.txt"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@DisabledOnOs(WINDOWS) // TODO: needs review
|
@DisabledOnOs(WINDOWS) // TODO: needs review
|
||||||
|
@ -126,6 +281,7 @@ public class ScannerTest
|
||||||
// takes 2 scans to notice a0 and check that it is stable
|
// takes 2 scans to notice a0 and check that it is stable
|
||||||
_scanner.scan();
|
_scanner.scan();
|
||||||
_scanner.scan();
|
_scanner.scan();
|
||||||
|
|
||||||
Event event = _queue.poll();
|
Event event = _queue.poll();
|
||||||
assertNotNull(event, "Event should not be null");
|
assertNotNull(event, "Event should not be null");
|
||||||
assertEquals(_directory + "/a0", event._filename);
|
assertEquals(_directory + "/a0", event._filename);
|
||||||
|
|
|
@ -26,10 +26,10 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
|
|
||||||
public class EmptyServerHandler extends AbstractHandler.ErrorDispatchHandler
|
public class EmptyServerHandler extends AbstractHandler
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
jettyRequest.setHandled(true);
|
jettyRequest.setHandled(true);
|
||||||
service(target, jettyRequest, request, response);
|
service(target, jettyRequest, request, response);
|
||||||
|
|
|
@ -740,10 +740,10 @@ public class HttpClientContinueTest extends AbstractTest<TransportScenario>
|
||||||
public void test_NoExpect_Respond100Continue(Transport transport) throws Exception
|
public void test_NoExpect_Respond100Continue(Transport transport) throws Exception
|
||||||
{
|
{
|
||||||
init(transport);
|
init(transport);
|
||||||
scenario.start(new AbstractHandler.ErrorDispatchHandler()
|
scenario.start(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
jettyRequest.setHandled(true);
|
jettyRequest.setHandled(true);
|
||||||
// Force a 100 Continue response.
|
// Force a 100 Continue response.
|
||||||
|
|
|
@ -497,10 +497,10 @@ public class HttpClientStreamTest extends AbstractTest<TransportScenario>
|
||||||
public void testInputStreamContentProviderThrowingWhileReading(Transport transport) throws Exception
|
public void testInputStreamContentProviderThrowingWhileReading(Transport transport) throws Exception
|
||||||
{
|
{
|
||||||
init(transport);
|
init(transport);
|
||||||
scenario.start(new AbstractHandler.ErrorDispatchHandler()
|
scenario.start(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
IO.copy(request.getInputStream(), response.getOutputStream());
|
IO.copy(request.getInputStream(), response.getOutputStream());
|
||||||
|
|
|
@ -81,10 +81,10 @@ public class HttpTrailersTest extends AbstractTest<TransportScenario>
|
||||||
{
|
{
|
||||||
String trailerName = "Trailer";
|
String trailerName = "Trailer";
|
||||||
String trailerValue = "value";
|
String trailerValue = "value";
|
||||||
scenario.start(new AbstractHandler.ErrorDispatchHandler()
|
scenario.start(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
jettyRequest.setHandled(true);
|
jettyRequest.setHandled(true);
|
||||||
|
|
||||||
|
@ -120,10 +120,10 @@ public class HttpTrailersTest extends AbstractTest<TransportScenario>
|
||||||
public void testEmptyRequestTrailers(Transport transport) throws Exception
|
public void testEmptyRequestTrailers(Transport transport) throws Exception
|
||||||
{
|
{
|
||||||
init(transport);
|
init(transport);
|
||||||
scenario.start(new AbstractHandler.ErrorDispatchHandler()
|
scenario.start(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
jettyRequest.setHandled(true);
|
jettyRequest.setHandled(true);
|
||||||
|
|
||||||
|
@ -169,10 +169,10 @@ public class HttpTrailersTest extends AbstractTest<TransportScenario>
|
||||||
{
|
{
|
||||||
String trailerName = "Trailer";
|
String trailerName = "Trailer";
|
||||||
String trailerValue = "value";
|
String trailerValue = "value";
|
||||||
scenario.start(new AbstractHandler.ErrorDispatchHandler()
|
scenario.start(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
jettyRequest.setHandled(true);
|
jettyRequest.setHandled(true);
|
||||||
|
|
||||||
|
@ -216,10 +216,10 @@ public class HttpTrailersTest extends AbstractTest<TransportScenario>
|
||||||
public void testEmptyResponseTrailers(Transport transport) throws Exception
|
public void testEmptyResponseTrailers(Transport transport) throws Exception
|
||||||
{
|
{
|
||||||
init(transport);
|
init(transport);
|
||||||
scenario.start(new AbstractHandler.ErrorDispatchHandler()
|
scenario.start(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response)
|
public void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response)
|
||||||
{
|
{
|
||||||
jettyRequest.setHandled(true);
|
jettyRequest.setHandled(true);
|
||||||
|
|
||||||
|
@ -262,10 +262,10 @@ public class HttpTrailersTest extends AbstractTest<TransportScenario>
|
||||||
String trailerName = "Trailer";
|
String trailerName = "Trailer";
|
||||||
String trailerValue = "value";
|
String trailerValue = "value";
|
||||||
init(transport);
|
init(transport);
|
||||||
scenario.start(new AbstractHandler.ErrorDispatchHandler()
|
scenario.start(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
jettyRequest.setHandled(true);
|
jettyRequest.setHandled(true);
|
||||||
|
|
||||||
|
|
|
@ -204,10 +204,10 @@ public class ServerTimeoutsTest extends AbstractTest<TransportScenario>
|
||||||
{
|
{
|
||||||
init(transport);
|
init(transport);
|
||||||
CountDownLatch handlerLatch = new CountDownLatch(1);
|
CountDownLatch handlerLatch = new CountDownLatch(1);
|
||||||
scenario.start(new AbstractHandler.ErrorDispatchHandler()
|
scenario.start(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
AsyncContext asyncContext = request.startAsync();
|
AsyncContext asyncContext = request.startAsync();
|
||||||
|
@ -270,10 +270,10 @@ public class ServerTimeoutsTest extends AbstractTest<TransportScenario>
|
||||||
Assumptions.assumeFalse(scenario.transport == UNIX_SOCKET);
|
Assumptions.assumeFalse(scenario.transport == UNIX_SOCKET);
|
||||||
|
|
||||||
CountDownLatch handlerLatch = new CountDownLatch(1);
|
CountDownLatch handlerLatch = new CountDownLatch(1);
|
||||||
scenario.start(new AbstractHandler.ErrorDispatchHandler()
|
scenario.start(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
AsyncContext asyncContext = request.startAsync();
|
AsyncContext asyncContext = request.startAsync();
|
||||||
|
@ -338,10 +338,10 @@ public class ServerTimeoutsTest extends AbstractTest<TransportScenario>
|
||||||
scenario.requestLog.clear();
|
scenario.requestLog.clear();
|
||||||
scenario.httpConfig.setMinRequestDataRate(bytesPerSecond);
|
scenario.httpConfig.setMinRequestDataRate(bytesPerSecond);
|
||||||
CountDownLatch handlerLatch = new CountDownLatch(1);
|
CountDownLatch handlerLatch = new CountDownLatch(1);
|
||||||
scenario.start(new AbstractHandler.ErrorDispatchHandler()
|
scenario.start(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -402,10 +402,10 @@ public class ServerTimeoutsTest extends AbstractTest<TransportScenario>
|
||||||
int bytesPerSecond = 20;
|
int bytesPerSecond = 20;
|
||||||
scenario.httpConfig.setMinRequestDataRate(bytesPerSecond);
|
scenario.httpConfig.setMinRequestDataRate(bytesPerSecond);
|
||||||
CountDownLatch handlerLatch = new CountDownLatch(1);
|
CountDownLatch handlerLatch = new CountDownLatch(1);
|
||||||
scenario.start(new AbstractHandler.ErrorDispatchHandler()
|
scenario.start(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
ServletInputStream input = request.getInputStream();
|
ServletInputStream input = request.getInputStream();
|
||||||
|
@ -481,10 +481,10 @@ public class ServerTimeoutsTest extends AbstractTest<TransportScenario>
|
||||||
long idleTimeout = 3 * httpIdleTimeout;
|
long idleTimeout = 3 * httpIdleTimeout;
|
||||||
scenario.httpConfig.setIdleTimeout(httpIdleTimeout);
|
scenario.httpConfig.setIdleTimeout(httpIdleTimeout);
|
||||||
CountDownLatch handlerLatch = new CountDownLatch(1);
|
CountDownLatch handlerLatch = new CountDownLatch(1);
|
||||||
scenario.start(new AbstractHandler.ErrorDispatchHandler()
|
scenario.start(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
AsyncContext asyncContext = request.startAsync();
|
AsyncContext asyncContext = request.startAsync();
|
||||||
|
@ -665,7 +665,7 @@ public class ServerTimeoutsTest extends AbstractTest<TransportScenario>
|
||||||
assertTrue(clientLatch.await(15, TimeUnit.SECONDS));
|
assertTrue(clientLatch.await(15, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class BlockingReadHandler extends AbstractHandler.ErrorDispatchHandler
|
private static class BlockingReadHandler extends AbstractHandler
|
||||||
{
|
{
|
||||||
private final CountDownLatch handlerLatch;
|
private final CountDownLatch handlerLatch;
|
||||||
|
|
||||||
|
@ -675,7 +675,7 @@ public class ServerTimeoutsTest extends AbstractTest<TransportScenario>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
ServletInputStream input = request.getInputStream();
|
ServletInputStream input = request.getInputStream();
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory$Server">
|
<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory$Server">
|
||||||
<Set name="KeyStorePath"><Property name="jetty.home" default="." />/<Property name="jetty.sslContext.keyStorePath" default="keystore"/></Set>
|
<Set name="KeyStorePath"><Property name="jetty.home" default="." />/<Property name="jetty.sslContext.keyStorePath" default="keystore"/></Set>
|
||||||
<Set name="KeyStorePassword"><Property name="jetty.sslContext.keyStorePassword" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
|
<Set name="KeyStorePassword"><Property name="jetty.sslContext.keyStorePassword"/></Set>
|
||||||
<Set name="KeyManagerPassword"><Property name="jetty.sslContext.keyManagerPassword" default="OBF:1u2u1wml1z7s1z7a1wnl1u2g"/></Set>
|
<Set name="KeyManagerPassword"><Property name="jetty.sslContext.keyManagerPassword"/></Set>
|
||||||
<Set name="TrustStorePath"><Property name="jetty.home" default="." />/<Property name="jetty.sslContext.trustStorePath" default="keystore"/></Set>
|
<Set name="TrustStorePath"><Property name="jetty.home" default="." />/<Property name="jetty.sslContext.trustStorePath" default="keystore"/></Set>
|
||||||
<Set name="TrustStorePassword"><Property name="jetty.sslContext.trustStorePassword" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
|
<Set name="TrustStorePassword"><Property name="jetty.sslContext.trustStorePassword"/></Set>
|
||||||
<Set name="ExcludeCipherSuites">
|
<Set name="ExcludeCipherSuites">
|
||||||
<Array type="String">
|
<Array type="String">
|
||||||
<Item>SSL_RSA_WITH_DES_CBC_SHA</Item>
|
<Item>SSL_RSA_WITH_DES_CBC_SHA</Item>
|
||||||
|
|
Loading…
Reference in New Issue