Merge remote-tracking branch 'origin/jetty-9.4.x' into jetty-10.0.x
This commit is contained in:
commit
5afe2e215f
|
@ -179,6 +179,11 @@ public class HttpClient extends ContainerLifeCycle
|
|||
public HttpClient(HttpClientTransport transport, SslContextFactory sslContextFactory)
|
||||
{
|
||||
this.transport = transport;
|
||||
if (sslContextFactory == null)
|
||||
{
|
||||
sslContextFactory = new SslContextFactory(false);
|
||||
sslContextFactory.setEndpointIdentificationAlgorithm("HTTPS");
|
||||
}
|
||||
this.sslContextFactory = sslContextFactory;
|
||||
}
|
||||
|
||||
|
|
|
@ -460,21 +460,6 @@ public class WebAppProvider extends ScanningAppProvider
|
|||
{
|
||||
File file = new File(filename);
|
||||
|
||||
//is the file that was removed a directory?
|
||||
if (file.isDirectory())
|
||||
{
|
||||
//is there a .xml file of the same name?
|
||||
if (exists(file.getName()+".xml")||exists(file.getName()+".XML"))
|
||||
return; //assume we will get removed events for the xml file
|
||||
|
||||
//is there .war file of the same name?
|
||||
if (exists(file.getName()+".war")||exists(file.getName()+".WAR"))
|
||||
return; //assume we will get removed events for the war file
|
||||
|
||||
super.fileRemoved(filename);
|
||||
return;
|
||||
}
|
||||
|
||||
//is the file that was removed a .war file?
|
||||
String lowname = file.getName().toLowerCase(Locale.ENGLISH);
|
||||
if (lowname.endsWith(".war"))
|
||||
|
@ -491,7 +476,20 @@ public class WebAppProvider extends ScanningAppProvider
|
|||
|
||||
//is the file that was removed an .xml file?
|
||||
if (lowname.endsWith(".xml"))
|
||||
{
|
||||
super.fileRemoved(filename);
|
||||
return;
|
||||
}
|
||||
|
||||
//is there a .xml file of the same name?
|
||||
if (exists(file.getName()+".xml")||exists(file.getName()+".XML"))
|
||||
return; //assume we will get removed events for the xml file
|
||||
|
||||
//is there .war file of the same name?
|
||||
if (exists(file.getName()+".war")||exists(file.getName()+".WAR"))
|
||||
return; //assume we will get removed events for the war file
|
||||
|
||||
super.fileRemoved(filename);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,6 +45,13 @@
|
|||
<onlyAnalyze>org.eclipse.jetty.http.spi.*</onlyAnalyze>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<reuseForks>false</reuseForks>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
|
@ -67,4 +74,32 @@
|
|||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>jdk9</id>
|
||||
<activation>
|
||||
<jdk>[1.9,)</jdk>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>javax.xml</groupId>
|
||||
<artifactId>jaxws-api</artifactId>
|
||||
<version>2.0EA3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.ws</groupId>
|
||||
<artifactId>jaxws-rt</artifactId>
|
||||
<version>2.3.0.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.activation</groupId>
|
||||
<artifactId>javax.activation-api</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
|
|
@ -57,9 +57,9 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer
|
|||
private InetSocketAddress _addr;
|
||||
|
||||
|
||||
private Map<String, JettyHttpContext> _contexts = new HashMap<String, JettyHttpContext>();
|
||||
private Map<String, JettyHttpContext> _contexts = new HashMap<>();
|
||||
|
||||
private Map<String, Connector> _connectors = new HashMap<String, Connector>();
|
||||
private Map<String, Connector> _connectors = new HashMap<>();
|
||||
|
||||
|
||||
public JettyHttpServer(Server server, boolean shared)
|
||||
|
@ -82,13 +82,14 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer
|
|||
@Override
|
||||
public void bind(InetSocketAddress addr, int backlog) throws IOException
|
||||
{
|
||||
this._addr = addr;
|
||||
// check if there is already a connector listening
|
||||
Collection<NetworkConnector> connectors = _server.getBeans(NetworkConnector.class);
|
||||
if (connectors != null)
|
||||
{
|
||||
for (NetworkConnector connector : connectors)
|
||||
{
|
||||
if (connector.getPort() == addr.getPort()) {
|
||||
if (connector.getPort() == addr.getPort()||connector.getLocalPort() == addr.getPort()) {
|
||||
if (LOG.isDebugEnabled()) LOG.debug("server already bound to port " + addr.getPort() + ", no need to rebind");
|
||||
return;
|
||||
}
|
||||
|
@ -98,7 +99,7 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer
|
|||
if (_serverShared)
|
||||
throw new IOException("jetty server is not bound to port " + addr.getPort());
|
||||
|
||||
this._addr = addr;
|
||||
|
||||
|
||||
if (LOG.isDebugEnabled()) LOG.debug("binding server to port " + addr.getPort());
|
||||
ServerConnector connector = new ServerConnector(_server);
|
||||
|
@ -153,9 +154,23 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer
|
|||
throw new IllegalArgumentException("missing required 'executor' argument");
|
||||
ThreadPool threadPool = _server.getThreadPool();
|
||||
if (threadPool instanceof DelegatingThreadPool)
|
||||
((DelegatingThreadPool)_server.getThreadPool()).setExecutor(executor);
|
||||
else
|
||||
throw new UnsupportedOperationException("!DelegatingThreadPool");
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_server.isRunning())
|
||||
{
|
||||
_server.stop();
|
||||
}
|
||||
((DelegatingThreadPool) _server.getThreadPool()).setExecutor(executor);
|
||||
_server.start();
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException( "!DelegatingThreadPool" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.http.spi;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.jws.WebMethod;
|
||||
import javax.jws.WebService;
|
||||
import javax.xml.ws.Endpoint;
|
||||
|
||||
public class TestEndpointMultiplePublishProblem
|
||||
{
|
||||
|
||||
private static String default_impl = System.getProperty("com.sun.net.httpserver.HttpServerProvider");
|
||||
|
||||
@BeforeClass
|
||||
public static void change_Impl()
|
||||
{
|
||||
System.setProperty("com.sun.net.httpserver.HttpServerProvider", JettyHttpServerProvider.class.getName());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void restore_Impl()
|
||||
{
|
||||
if(default_impl != null)
|
||||
{
|
||||
System.setProperty( "com.sun.net.httpserver.HttpServerProvider", default_impl );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mainJetty() throws Exception {
|
||||
|
||||
Server jettyWebServer = new Server(new DelegatingThreadPool(new QueuedThreadPool()));
|
||||
ServerConnector connector = new ServerConnector(jettyWebServer);
|
||||
connector.setHost("localhost");
|
||||
connector.setPort(0);
|
||||
connector.setReuseAddress(true);
|
||||
jettyWebServer.addConnector(connector);
|
||||
jettyWebServer.setHandler(new ContextHandlerCollection());
|
||||
|
||||
JettyHttpServerProvider.setServer(jettyWebServer);
|
||||
|
||||
jettyWebServer.start();
|
||||
|
||||
Endpoint.publish(String.format("http://%s:%d/hello", "localhost", 0), new Ws());
|
||||
// Comment out the below line for success in later java such as java8_u172, works before u151 or so
|
||||
Endpoint.publish(String.format("http://%s:%d/hello2", "localhost", 0), new Ws());
|
||||
|
||||
int port = connector.getLocalPort();
|
||||
|
||||
System.out.printf("Started, check: http://localhost:%d/hello?wsdl%n", port);
|
||||
}
|
||||
|
||||
|
||||
@WebService
|
||||
public static class Ws {
|
||||
@WebMethod
|
||||
public String hello() {
|
||||
return "Hello";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -71,12 +71,7 @@ public class TestSPIServer
|
|||
server = new JettyHttpServerProvider().createHttpServer(null, 10);
|
||||
|
||||
final HttpContext httpContext = server.createContext("/",
|
||||
new HttpHandler()
|
||||
{
|
||||
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) throws IOException
|
||||
{
|
||||
exchange -> {
|
||||
Headers responseHeaders = exchange.getResponseHeaders();
|
||||
responseHeaders.set("Content-Type","text/plain");
|
||||
exchange.sendResponseHeaders(200,0);
|
||||
|
@ -93,8 +88,6 @@ public class TestSPIServer
|
|||
responseBody.write(s.getBytes());
|
||||
}
|
||||
responseBody.close();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
httpContext.setAuthenticator(new BasicAuthenticator("Test")
|
||||
|
@ -161,12 +154,7 @@ public class TestSPIServer
|
|||
InetSocketAddress("localhost", 0), 10);
|
||||
|
||||
final HttpContext httpContext = server.createContext("/",
|
||||
new HttpHandler()
|
||||
{
|
||||
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) throws IOException
|
||||
{
|
||||
exchange -> {
|
||||
Headers responseHeaders = exchange.getResponseHeaders();
|
||||
responseHeaders.set("Content-Type","text/plain");
|
||||
exchange.sendResponseHeaders(200,0);
|
||||
|
@ -183,8 +171,6 @@ public class TestSPIServer
|
|||
responseBody.write(s.getBytes());
|
||||
}
|
||||
responseBody.close();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
httpContext.setAuthenticator(new BasicAuthenticator("Test")
|
||||
|
|
|
@ -237,14 +237,6 @@ public class HttpGenerator
|
|||
if (header==null)
|
||||
return Result.NEED_HEADER;
|
||||
|
||||
// If we have not been told our persistence, set the default
|
||||
if (_persistent==null)
|
||||
{
|
||||
_persistent=info.getHttpVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal();
|
||||
if (!_persistent && HttpMethod.CONNECT.is(info.getMethod()))
|
||||
_persistent=true;
|
||||
}
|
||||
|
||||
// prepare the header
|
||||
int pos=BufferUtil.flipToFill(header);
|
||||
try
|
||||
|
@ -413,25 +405,15 @@ public class HttpGenerator
|
|||
HttpVersion version=info.getHttpVersion();
|
||||
if (version==null)
|
||||
throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"No version");
|
||||
switch(version)
|
||||
|
||||
if (version==HttpVersion.HTTP_0_9)
|
||||
{
|
||||
case HTTP_1_0:
|
||||
if (_persistent==null)
|
||||
_persistent=Boolean.FALSE;
|
||||
break;
|
||||
|
||||
case HTTP_1_1:
|
||||
if (_persistent==null)
|
||||
_persistent=Boolean.TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
_persistent = false;
|
||||
_endOfContent=EndOfContent.EOF_CONTENT;
|
||||
if (BufferUtil.hasContent(content))
|
||||
_contentPrepared+=content.remaining();
|
||||
_state = last?State.COMPLETING:State.COMMITTED;
|
||||
return Result.FLUSH;
|
||||
_persistent = false;
|
||||
_endOfContent=EndOfContent.EOF_CONTENT;
|
||||
if (BufferUtil.hasContent(content))
|
||||
_contentPrepared+=content.remaining();
|
||||
_state = last?State.COMPLETING:State.COMMITTED;
|
||||
return Result.FLUSH;
|
||||
}
|
||||
|
||||
// Do we need a response header
|
||||
|
@ -702,7 +684,7 @@ public class HttpGenerator
|
|||
_persistent=false;
|
||||
}
|
||||
|
||||
if (!http11 && field.contains(HttpHeaderValue.KEEP_ALIVE.asString()))
|
||||
if (info.getHttpVersion() == HttpVersion.HTTP_1_0 && _persistent==null && field.contains(HttpHeaderValue.KEEP_ALIVE.asString()))
|
||||
{
|
||||
_persistent=true;
|
||||
}
|
||||
|
@ -734,6 +716,9 @@ public class HttpGenerator
|
|||
boolean assumed_content = assumed_content_request || content_type || chunked_hint;
|
||||
boolean nocontent_request = request!=null && content_length<=0 && !assumed_content;
|
||||
|
||||
if (_persistent==null)
|
||||
_persistent = http11 || (request!=null && HttpMethod.CONNECT.is(request.getMethod()));
|
||||
|
||||
// If the message is known not to have content
|
||||
if (_noContentResponse || nocontent_request)
|
||||
{
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.ArrayDeque;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
@ -698,7 +699,10 @@ public class StreamResetTest extends AbstractTest
|
|||
// Give time to the server to process the reset and drain the flusher queue.
|
||||
Thread.sleep(500);
|
||||
|
||||
HTTP2Session session = connector.getConnectionFactory(AbstractHTTP2ServerConnectionFactory.class).getBean(HTTP2Session.class);
|
||||
AbstractHTTP2ServerConnectionFactory http2 = connector.getConnectionFactory(AbstractHTTP2ServerConnectionFactory.class);
|
||||
Set<Session> sessions = http2.getBean(AbstractHTTP2ServerConnectionFactory.HTTP2SessionContainer.class).getSessions();
|
||||
Assert.assertEquals(1, sessions.size());
|
||||
HTTP2Session session = (HTTP2Session)sessions.iterator().next();
|
||||
HTTP2Flusher flusher = session.getBean(HTTP2Flusher.class);
|
||||
Assert.assertEquals(0, flusher.getFrameQueueSize());
|
||||
}
|
||||
|
|
|
@ -18,13 +18,18 @@
|
|||
|
||||
package org.eclipse.jetty.http2.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jetty.http2.BufferingFlowControlStrategy;
|
||||
import org.eclipse.jetty.http2.FlowControlStrategy;
|
||||
import org.eclipse.jetty.http2.HTTP2Connection;
|
||||
import org.eclipse.jetty.http2.api.Session;
|
||||
import org.eclipse.jetty.http2.api.server.ServerSessionListener;
|
||||
import org.eclipse.jetty.http2.frames.Frame;
|
||||
import org.eclipse.jetty.http2.frames.SettingsFrame;
|
||||
|
@ -38,12 +43,14 @@ import org.eclipse.jetty.server.HttpConfiguration;
|
|||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.annotation.Name;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
|
||||
@ManagedObject
|
||||
public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConnectionFactory
|
||||
{
|
||||
private final Connection.Listener connectionListener = new ConnectionListener();
|
||||
private final HTTP2SessionContainer sessionContainer = new HTTP2SessionContainer();
|
||||
private final HttpConfiguration httpConfiguration;
|
||||
private int maxDynamicTableSize = 4096;
|
||||
private int initialSessionRecvWindow = 1024 * 1024;
|
||||
|
@ -66,6 +73,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
|
|||
for (String p:protocols)
|
||||
if (!HTTP2ServerConnection.isSupportedProtocol(p))
|
||||
throw new IllegalArgumentException("Unsupported HTTP2 Protocol variant: "+p);
|
||||
addBean(sessionContainer);
|
||||
this.httpConfiguration = Objects.requireNonNull(httpConfiguration);
|
||||
addBean(httpConfiguration);
|
||||
setInputBufferSize(Frame.DEFAULT_MAX_LENGTH + Frame.HEADER_LENGTH);
|
||||
|
@ -234,7 +242,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
|
|||
|
||||
HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(),
|
||||
endPoint, httpConfiguration, parser, session, getInputBufferSize(), listener);
|
||||
connection.addListener(connectionListener);
|
||||
connection.addListener(sessionContainer);
|
||||
return configure(connection, connector, endPoint);
|
||||
}
|
||||
|
||||
|
@ -245,18 +253,55 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
|
|||
return new ServerParser(connector.getByteBufferPool(), listener, getMaxDynamicTableSize(), getHttpConfiguration().getRequestHeaderSize());
|
||||
}
|
||||
|
||||
private class ConnectionListener implements Connection.Listener
|
||||
@ManagedObject("The container of HTTP/2 sessions")
|
||||
public static class HTTP2SessionContainer implements Connection.Listener, Dumpable
|
||||
{
|
||||
private final Set<Session> sessions = ConcurrentHashMap.newKeySet();
|
||||
|
||||
@Override
|
||||
public void onOpened(Connection connection)
|
||||
{
|
||||
addManaged((LifeCycle)((HTTP2Connection)connection).getSession());
|
||||
Session session = ((HTTP2Connection)connection).getSession();
|
||||
sessions.add(session);
|
||||
LifeCycle.start(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(Connection connection)
|
||||
{
|
||||
removeBean(((HTTP2Connection)connection).getSession());
|
||||
Session session = ((HTTP2Connection)connection).getSession();
|
||||
if (sessions.remove(session))
|
||||
LifeCycle.stop(session);
|
||||
}
|
||||
|
||||
public Set<Session> getSessions()
|
||||
{
|
||||
return new HashSet<>(sessions);
|
||||
}
|
||||
|
||||
@ManagedAttribute(value = "The number of HTTP/2 sessions", readonly = true)
|
||||
public int getSize()
|
||||
{
|
||||
return sessions.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dump()
|
||||
{
|
||||
return ContainerLifeCycle.dump(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
ContainerLifeCycle.dumpObject(out, this);
|
||||
ContainerLifeCycle.dump(out, indent, sessions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x[size=%d]", getClass().getSimpleName(), hashCode(), getSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -199,7 +199,19 @@ public abstract class AbstractConnection implements Connection
|
|||
LOG.debug("onOpen {}", this);
|
||||
|
||||
for (Listener listener : _listeners)
|
||||
onOpened(listener);
|
||||
}
|
||||
|
||||
private void onOpened(Listener listener)
|
||||
{
|
||||
try
|
||||
{
|
||||
listener.onOpened(this);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
LOG.info("Failure while notifying listener " + listener, x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -209,7 +221,19 @@ public abstract class AbstractConnection implements Connection
|
|||
LOG.debug("onClose {}",this);
|
||||
|
||||
for (Listener listener : _listeners)
|
||||
onClosed(listener);
|
||||
}
|
||||
|
||||
private void onClosed(Listener listener)
|
||||
{
|
||||
try
|
||||
{
|
||||
listener.onClosed(this);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
LOG.info("Failure while notifying listener " + listener, x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -93,15 +93,19 @@ public abstract class FillInterest
|
|||
/**
|
||||
* Call to signal that a read is now possible.
|
||||
*/
|
||||
public void fillable()
|
||||
public boolean fillable()
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("fillable {}",this);
|
||||
Callback callback = _interested.get();
|
||||
if (callback != null && _interested.compareAndSet(callback, null))
|
||||
{
|
||||
callback.succeeded();
|
||||
else if (LOG.isDebugEnabled())
|
||||
return true;
|
||||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} lost race {}",this,callback);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -399,27 +399,27 @@ public class SslConnection extends AbstractConnection
|
|||
try
|
||||
{
|
||||
// If we are handshaking, then wake up any waiting write as well as it may have been blocked on the read
|
||||
boolean waiting_for_fill = false;
|
||||
boolean waiting_for_fill;
|
||||
synchronized(_decryptedEndPoint)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onFillable {}", SslConnection.this);
|
||||
|
||||
_fillState = FillState.IDLE;
|
||||
switch(_flushState)
|
||||
{
|
||||
case WAIT_FOR_FILL:
|
||||
waiting_for_fill = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
waiting_for_fill = _flushState==FlushState.WAIT_FOR_FILL;
|
||||
}
|
||||
|
||||
// Ensure a fill is always done if needed then wake up any fill interest
|
||||
if (waiting_for_fill)
|
||||
fill(BufferUtil.EMPTY_BUFFER);
|
||||
|
||||
getFillInterest().fillable();
|
||||
|
||||
if (waiting_for_fill)
|
||||
{
|
||||
synchronized(_decryptedEndPoint)
|
||||
{
|
||||
waiting_for_fill = _flushState==FlushState.WAIT_FOR_FILL;
|
||||
}
|
||||
if (waiting_for_fill)
|
||||
fill(BufferUtil.EMPTY_BUFFER);
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
|
@ -1246,11 +1246,11 @@ public class SslConnection extends AbstractConnection
|
|||
if (fillable)
|
||||
_fillState = FillState.IDLE;
|
||||
}
|
||||
|
||||
_decryptedEndPoint.getWriteFlusher().completeWrite();
|
||||
|
||||
if (fillable)
|
||||
_decryptedEndPoint.getFillInterest().fillable();
|
||||
|
||||
_decryptedEndPoint.getWriteFlusher().completeWrite();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -54,7 +54,7 @@ public class MavenServerConnector extends ContainerLifeCycle implements Connecto
|
|||
public static final int DEFAULT_MAX_IDLE_TIME = 30000;
|
||||
|
||||
private Server server;
|
||||
private ServerConnector delegate;
|
||||
private volatile ServerConnector delegate;
|
||||
private String host;
|
||||
private String name;
|
||||
private int port;
|
||||
|
@ -133,33 +133,28 @@ public class MavenServerConnector extends ContainerLifeCycle implements Connecto
|
|||
this.delegate = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.Graceful#shutdown()
|
||||
*/
|
||||
@Override
|
||||
public Future<Void> shutdown()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.shutdown();
|
||||
return checkDelegate().shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShutdown()
|
||||
{
|
||||
return checkDelegate().isShutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Connector#getServer()
|
||||
*/
|
||||
@Override
|
||||
public Server getServer()
|
||||
{
|
||||
return this.server;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Connector#getExecutor()
|
||||
*/
|
||||
@Override
|
||||
public Executor getExecutor()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getExecutor();
|
||||
return checkDelegate().getExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -168,8 +163,7 @@ public class MavenServerConnector extends ContainerLifeCycle implements Connecto
|
|||
@Override
|
||||
public Scheduler getScheduler()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getScheduler();
|
||||
return checkDelegate().getScheduler();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -178,8 +172,7 @@ public class MavenServerConnector extends ContainerLifeCycle implements Connecto
|
|||
@Override
|
||||
public ByteBufferPool getByteBufferPool()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getByteBufferPool();
|
||||
return checkDelegate().getByteBufferPool();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -188,8 +181,7 @@ public class MavenServerConnector extends ContainerLifeCycle implements Connecto
|
|||
@Override
|
||||
public ConnectionFactory getConnectionFactory(String nextProtocol)
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getConnectionFactory(nextProtocol);
|
||||
return checkDelegate().getConnectionFactory(nextProtocol);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -198,8 +190,7 @@ public class MavenServerConnector extends ContainerLifeCycle implements Connecto
|
|||
@Override
|
||||
public <T> T getConnectionFactory(Class<T> factoryType)
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getConnectionFactory(factoryType);
|
||||
return checkDelegate().getConnectionFactory(factoryType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -208,8 +199,7 @@ public class MavenServerConnector extends ContainerLifeCycle implements Connecto
|
|||
@Override
|
||||
public ConnectionFactory getDefaultConnectionFactory()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getDefaultConnectionFactory();
|
||||
return checkDelegate().getDefaultConnectionFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -218,8 +208,7 @@ public class MavenServerConnector extends ContainerLifeCycle implements Connecto
|
|||
@Override
|
||||
public Collection<ConnectionFactory> getConnectionFactories()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getConnectionFactories();
|
||||
return checkDelegate().getConnectionFactories();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -228,8 +217,7 @@ public class MavenServerConnector extends ContainerLifeCycle implements Connecto
|
|||
@Override
|
||||
public List<String> getProtocols()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getProtocols();
|
||||
return checkDelegate().getProtocols();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -239,8 +227,7 @@ public class MavenServerConnector extends ContainerLifeCycle implements Connecto
|
|||
@ManagedAttribute("maximum time a connection can be idle before being closed (in ms)")
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getIdleTimeout();
|
||||
return checkDelegate().getIdleTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -249,8 +236,7 @@ public class MavenServerConnector extends ContainerLifeCycle implements Connecto
|
|||
@Override
|
||||
public Object getTransport()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getTransport();
|
||||
return checkDelegate().getTransport();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -259,8 +245,7 @@ public class MavenServerConnector extends ContainerLifeCycle implements Connecto
|
|||
@Override
|
||||
public Collection<EndPoint> getConnectedEndPoints()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getConnectedEndPoints();
|
||||
return checkDelegate().getConnectedEndPoints();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -277,9 +262,11 @@ public class MavenServerConnector extends ContainerLifeCycle implements Connecto
|
|||
return this.delegate.getLocalPort();
|
||||
}
|
||||
|
||||
private void checkDelegate() throws IllegalStateException
|
||||
private ServerConnector checkDelegate() throws IllegalStateException
|
||||
{
|
||||
if (this.delegate == null)
|
||||
ServerConnector d = this.delegate;
|
||||
if (d == null)
|
||||
throw new IllegalStateException ("MavenServerConnector delegate not ready");
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,13 +41,13 @@ import org.eclipse.jetty.io.ArrayByteBufferPool;
|
|||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.ssl.SslConnection;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.ProcessorUtils;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.component.Graceful;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
@ -153,6 +153,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
|
|||
private final Thread[] _acceptors;
|
||||
private final Set<EndPoint> _endpoints = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
private final Set<EndPoint> _immutableEndPoints = Collections.unmodifiableSet(_endpoints);
|
||||
private final Graceful.Shutdown _shutdown = new Graceful.Shutdown();
|
||||
private CountDownLatch _stopping;
|
||||
private long _idleTimeout = 30000;
|
||||
private String _defaultProtocol;
|
||||
|
@ -261,6 +262,8 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
|
|||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
_shutdown.cancel();
|
||||
|
||||
if(_defaultProtocol==null)
|
||||
throw new IllegalStateException("No default protocol for "+this);
|
||||
_defaultConnectionFactory = getConnectionFactory(_defaultProtocol);
|
||||
|
@ -301,13 +304,19 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Future<Void> shutdown()
|
||||
{
|
||||
return new FutureCallback(true);
|
||||
return _shutdown.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShutdown()
|
||||
{
|
||||
return _shutdown.isShutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
|
|
|
@ -135,6 +135,16 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
|||
return _state;
|
||||
}
|
||||
|
||||
public boolean addListener(Listener listener)
|
||||
{
|
||||
return _listeners.add(listener);
|
||||
}
|
||||
|
||||
public boolean removeListener(Listener listener)
|
||||
{
|
||||
return _listeners.remove(listener);
|
||||
}
|
||||
|
||||
public long getBytesWritten()
|
||||
{
|
||||
return _written;
|
||||
|
|
|
@ -704,6 +704,10 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
_callback = callback;
|
||||
_header = null;
|
||||
_shutdownOut = false;
|
||||
|
||||
if (getConnector().isShutdown())
|
||||
_generator.setPersistent(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -817,7 +821,11 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
continue;
|
||||
}
|
||||
case DONE:
|
||||
{
|
||||
{
|
||||
// If shutdown after commit, we can still close here.
|
||||
if (getConnector().isShutdown())
|
||||
_shutdownOut=true;
|
||||
|
||||
return Action.SUCCEEDED;
|
||||
}
|
||||
case CONTINUE:
|
||||
|
|
|
@ -365,7 +365,7 @@ public class Request implements HttpServletRequest
|
|||
/* ------------------------------------------------------------ */
|
||||
private MultiMap<String> getParameters()
|
||||
{
|
||||
if (!_contentParamsExtracted)
|
||||
if (!_contentParamsExtracted)
|
||||
{
|
||||
// content parameters need boolean protection as they can only be read
|
||||
// once, but may be reset to null by a reset
|
||||
|
@ -406,7 +406,7 @@ public class Request implements HttpServletRequest
|
|||
_parameters=_contentParameters;
|
||||
else if (isNoParams(_contentParameters) || _contentParameters.size()==0)
|
||||
_parameters=_queryParameters;
|
||||
else
|
||||
else if(_parameters == null)
|
||||
{
|
||||
_parameters = new MultiMap<>();
|
||||
_parameters.addAllValues(_queryParameters);
|
||||
|
|
|
@ -18,6 +18,23 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.DateGenerator;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpGenerator;
|
||||
|
@ -32,7 +49,6 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
|||
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.util.AttributesMap;
|
||||
import org.eclipse.jetty.util.JavaVersion;
|
||||
import org.eclipse.jetty.util.Jetty;
|
||||
import org.eclipse.jetty.util.MultiException;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
@ -40,7 +56,6 @@ import org.eclipse.jetty.util.Uptime;
|
|||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.annotation.Name;
|
||||
import org.eclipse.jetty.util.component.Graceful;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -49,24 +64,6 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
|||
import org.eclipse.jetty.util.thread.ShutdownThread;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Jetty HTTP Servlet Server.
|
||||
* This class is the main class for the Jetty HTTP Servlet server.
|
||||
|
@ -463,48 +460,23 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("doStop {}",this);
|
||||
|
||||
MultiException mex=new MultiException();
|
||||
MultiException mex = new MultiException();
|
||||
|
||||
// list if graceful futures
|
||||
List<Future<Void>> futures = new ArrayList<>();
|
||||
|
||||
// First close the network connectors to stop accepting new connections
|
||||
for (Connector connector : _connectors)
|
||||
futures.add(connector.shutdown());
|
||||
|
||||
// Then tell the contexts that we are shutting down
|
||||
Handler[] gracefuls = getChildHandlersByClass(Graceful.class);
|
||||
for (Handler graceful : gracefuls)
|
||||
futures.add(((Graceful)graceful).shutdown());
|
||||
|
||||
// Shall we gracefully wait for zero connections?
|
||||
long stopTimeout = getStopTimeout();
|
||||
if (stopTimeout>0)
|
||||
try
|
||||
{
|
||||
long stop_by=System.currentTimeMillis()+stopTimeout;
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Graceful shutdown {} by ",this,new Date(stop_by));
|
||||
|
||||
// Wait for shutdowns
|
||||
for (Future<Void> future: futures)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!future.isDone())
|
||||
future.get(Math.max(1L,stop_by-System.currentTimeMillis()),TimeUnit.MILLISECONDS);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
mex.add(e);
|
||||
}
|
||||
}
|
||||
// list if graceful futures
|
||||
List<Future<Void>> futures = new ArrayList<>();
|
||||
// First shutdown the network connectors to stop accepting new connections
|
||||
for (Connector connector : _connectors)
|
||||
futures.add(connector.shutdown());
|
||||
// then shutdown all graceful handlers
|
||||
doShutdown(futures);
|
||||
}
|
||||
|
||||
// Cancel any shutdowns not done
|
||||
for (Future<Void> future: futures)
|
||||
if (!future.isDone())
|
||||
future.cancel(true);
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
mex.add(e);
|
||||
}
|
||||
|
||||
// Now stop the connectors (this will close existing connections)
|
||||
for (Connector connector : _connectors)
|
||||
{
|
||||
|
|
|
@ -18,14 +18,21 @@
|
|||
|
||||
package org.eclipse.jetty.server.handler;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.HandlerContainer;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.MultiException;
|
||||
import org.eclipse.jetty.util.component.Graceful;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -35,6 +42,8 @@ import org.eclipse.jetty.server.Server;
|
|||
*/
|
||||
public abstract class AbstractHandlerContainer extends AbstractHandler implements HandlerContainer
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractHandlerContainer.class);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public AbstractHandlerContainer()
|
||||
{
|
||||
|
@ -135,4 +144,60 @@ public abstract class AbstractHandlerContainer extends AbstractHandler implement
|
|||
for (Handler h : handlers)
|
||||
h.setServer(server);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Shutdown nested Gracefule handlers
|
||||
*
|
||||
* @param futures A list of Futures which must also be waited on for the shutdown (or null)
|
||||
* returns A MultiException to which any failures are added or null
|
||||
*/
|
||||
protected void doShutdown(List<Future<Void>> futures) throws MultiException
|
||||
{
|
||||
MultiException mex = null;
|
||||
|
||||
// tell the graceful handlers that we are shutting down
|
||||
Handler[] gracefuls = getChildHandlersByClass(Graceful.class);
|
||||
if (futures==null)
|
||||
futures = new ArrayList<>(gracefuls.length);
|
||||
for (Handler graceful : gracefuls)
|
||||
futures.add(((Graceful)graceful).shutdown());
|
||||
|
||||
// Wait for all futures with a reducing time budget
|
||||
long stopTimeout = getStopTimeout();
|
||||
if (stopTimeout>0)
|
||||
{
|
||||
long stop_by=System.currentTimeMillis()+stopTimeout;
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Graceful shutdown {} by ",this,new Date(stop_by));
|
||||
|
||||
// Wait for shutdowns
|
||||
for (Future<Void> future: futures)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!future.isDone())
|
||||
future.get(Math.max(1L,stop_by-System.currentTimeMillis()),TimeUnit.MILLISECONDS);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// If the future is also a callback, fail it here (rather than cancel) so we can capture the exception
|
||||
if (future instanceof Callback && !future.isDone())
|
||||
((Callback)future).failed(e);
|
||||
if (mex==null)
|
||||
mex = new MultiException();
|
||||
mex.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel any shutdowns not done
|
||||
for (Future<Void> future: futures)
|
||||
if (!future.isDone())
|
||||
future.cancel(true);
|
||||
|
||||
if (mex!=null)
|
||||
mex.ifExceptionThrowMulti();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,6 @@ import org.eclipse.jetty.server.Server;
|
|||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.util.AttributesMap;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.LazyList;
|
||||
import org.eclipse.jetty.util.Loader;
|
||||
import org.eclipse.jetty.util.MultiException;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
@ -969,6 +968,21 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
// Should we attempt a graceful shutdown?
|
||||
MultiException mex = null;
|
||||
|
||||
if (getStopTimeout()>0)
|
||||
{
|
||||
try
|
||||
{
|
||||
doShutdown(null);
|
||||
}
|
||||
catch (MultiException e)
|
||||
{
|
||||
mex = e;
|
||||
}
|
||||
}
|
||||
|
||||
_availability = Availability.UNAVAILABLE;
|
||||
|
||||
ClassLoader old_classloader = null;
|
||||
|
@ -1014,6 +1028,12 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
}
|
||||
_programmaticListeners.clear();
|
||||
}
|
||||
catch(Throwable x)
|
||||
{
|
||||
if (mex==null)
|
||||
mex = new MultiException();
|
||||
mex.add(x);
|
||||
}
|
||||
finally
|
||||
{
|
||||
__context.set(old_context);
|
||||
|
@ -1022,9 +1042,12 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
// reset the classloader
|
||||
if ((old_classloader == null || (old_classloader != old_webapploader)) && current_thread != null)
|
||||
current_thread.setContextClassLoader(old_classloader);
|
||||
}
|
||||
|
||||
_scontext.clearAttributes();
|
||||
_scontext.clearAttributes();
|
||||
}
|
||||
|
||||
if (mex!=null)
|
||||
mex.ifExceptionThrow();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -20,10 +20,8 @@ package org.eclipse.jetty.server.handler;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
import javax.servlet.AsyncEvent;
|
||||
|
@ -70,7 +68,14 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
|
|||
private final LongAdder _responses5xx = new LongAdder();
|
||||
private final LongAdder _responsesTotalBytes = new LongAdder();
|
||||
|
||||
private final AtomicReference<FutureCallback> _shutdown=new AtomicReference<>();
|
||||
private final Graceful.Shutdown _shutdown = new Graceful.Shutdown()
|
||||
{
|
||||
@Override
|
||||
protected FutureCallback newShutdownCallback()
|
||||
{
|
||||
return new FutureCallback(_requestStats.getCurrent()==0);
|
||||
}
|
||||
};
|
||||
|
||||
private final AtomicBoolean _wrapWarning = new AtomicBoolean();
|
||||
|
||||
|
@ -165,17 +170,16 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
|
|||
try
|
||||
{
|
||||
Handler handler = getHandler();
|
||||
if (handler!=null && _shutdown.get()==null && isStarted())
|
||||
if (handler!=null && !_shutdown.isShutdown() && isStarted())
|
||||
handler.handle(path, baseRequest, request, response);
|
||||
else if (baseRequest.isHandled())
|
||||
{
|
||||
if (_wrapWarning.compareAndSet(false,true))
|
||||
LOG.warn("Bad statistics configuration. Latencies will be incorrect in {}",this);
|
||||
}
|
||||
else
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.sendError(HttpStatus.SERVICE_UNAVAILABLE_503);
|
||||
if (!baseRequest.isHandled())
|
||||
baseRequest.setHandled(true);
|
||||
else if (_wrapWarning.compareAndSet(false,true))
|
||||
LOG.warn("Bad statistics configuration. Latencies will be incorrect in {}",this);
|
||||
if (!baseRequest.getResponse().isCommitted())
|
||||
response.sendError(HttpStatus.SERVICE_UNAVAILABLE_503);
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
@ -248,19 +252,16 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
|
|||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
_shutdown.set(null);
|
||||
_shutdown.cancel();
|
||||
super.doStart();
|
||||
statsReset();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
_shutdown.cancel();
|
||||
super.doStop();
|
||||
FutureCallback shutdown = _shutdown.get();
|
||||
if (shutdown!=null && !shutdown.isDone())
|
||||
shutdown.failed(new TimeoutException());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -551,7 +552,6 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
|
|||
sb.append("Max request time: ").append(getRequestTimeMax()).append("<br />\n");
|
||||
sb.append("Request time standard deviation: ").append(getRequestTimeStdDev()).append("<br />\n");
|
||||
|
||||
|
||||
sb.append("<h2>Dispatches:</h2>\n");
|
||||
sb.append("Total dispatched: ").append(getDispatched()).append("<br />\n");
|
||||
sb.append("Active dispatched: ").append(getDispatchedActive()).append("<br />\n");
|
||||
|
@ -561,7 +561,6 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
|
|||
sb.append("Max dispatched time: ").append(getDispatchedTimeMax()).append("<br />\n");
|
||||
sb.append("Dispatched time standard deviation: ").append(getDispatchedTimeStdDev()).append("<br />\n");
|
||||
|
||||
|
||||
sb.append("Total requests suspended: ").append(getAsyncRequests()).append("<br />\n");
|
||||
sb.append("Total requests expired: ").append(getExpires()).append("<br />\n");
|
||||
sb.append("Total requests resumed: ").append(getAsyncDispatches()).append("<br />\n");
|
||||
|
@ -575,17 +574,23 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
|
|||
sb.append("Bytes sent total: ").append(getResponsesBytesTotal()).append("<br />\n");
|
||||
|
||||
return sb.toString();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> shutdown()
|
||||
{
|
||||
FutureCallback shutdown=new FutureCallback(false);
|
||||
_shutdown.compareAndSet(null,shutdown);
|
||||
shutdown=_shutdown.get();
|
||||
if (_requestStats.getCurrent()==0)
|
||||
shutdown.succeeded();
|
||||
return shutdown;
|
||||
return _shutdown.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShutdown()
|
||||
{
|
||||
return _shutdown.isShutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x{%s,r=%d,d=%d}",getClass().getSimpleName(),hashCode(),getState(),_requestStats.getCurrent(),_dispatchedStats.getCurrent());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,10 +23,10 @@ import static org.hamcrest.Matchers.greaterThan;
|
|||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.lessThan;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
@ -35,6 +35,7 @@ import java.net.Socket;
|
|||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Exchanger;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
@ -46,14 +47,15 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.server.LocalConnector.LocalEndPoint;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
||||
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||
import org.eclipse.jetty.toolchain.test.OS;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hamcrest.Matchers;
|
||||
|
@ -105,15 +107,8 @@ public class GracefulStopTest
|
|||
assertThat(TimeUnit.NANOSECONDS.toMillis(stop-start),lessThan(900L));
|
||||
|
||||
assertThat(client.getInputStream().read(),Matchers.is(-1));
|
||||
|
||||
assertThat(handler.handling.get(),Matchers.is(false));
|
||||
assertThat(handler.thrown.get(),
|
||||
Matchers.anyOf(
|
||||
instanceOf(ClosedChannelException.class),
|
||||
instanceOf(EofException.class),
|
||||
instanceOf(EOFException.class))
|
||||
);
|
||||
|
||||
assertThat(handler.handling.get(),Matchers.is(false));
|
||||
assertThat(handler.thrown.get(),Matchers.notNullValue());
|
||||
client.close();
|
||||
}
|
||||
|
||||
|
@ -228,7 +223,7 @@ public class GracefulStopTest
|
|||
// Try creating a new connection
|
||||
try
|
||||
{
|
||||
new Socket("127.0.0.1", port);
|
||||
try(Socket s = new Socket("127.0.0.1", port)){}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
catch(ConnectException e)
|
||||
|
@ -286,10 +281,10 @@ public class GracefulStopTest
|
|||
{
|
||||
|
||||
@Override
|
||||
public Connection newConnection(Connector connector, EndPoint endPoint)
|
||||
public Connection newConnection(Connector con, EndPoint endPoint)
|
||||
{
|
||||
// Slow closing connection
|
||||
HttpConnection conn = new HttpConnection(getHttpConfiguration(), connector, endPoint, getHttpCompliance(), isRecordHttpComplianceViolations())
|
||||
HttpConnection conn = new HttpConnection(getHttpConfiguration(), con, endPoint, getHttpCompliance(), isRecordHttpComplianceViolations())
|
||||
{
|
||||
@Override
|
||||
public void close()
|
||||
|
@ -322,7 +317,7 @@ public class GracefulStopTest
|
|||
}
|
||||
}
|
||||
};
|
||||
return configure(conn, connector, endPoint);
|
||||
return configure(conn, con, endPoint);
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -420,19 +415,264 @@ public class GracefulStopTest
|
|||
{
|
||||
testSlowClose(5000,1000,Matchers.allOf(greaterThan(750L),lessThan(4999L)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponsesAreClosed() throws Exception
|
||||
{
|
||||
Server server= new Server();
|
||||
|
||||
LocalConnector connector = new LocalConnector(server);
|
||||
server.addConnector(connector);
|
||||
|
||||
StatisticsHandler stats = new StatisticsHandler();
|
||||
server.setHandler(stats);
|
||||
|
||||
ContextHandler context = new ContextHandler(stats,"/");
|
||||
|
||||
Exchanger<Void> exchanger0 = new Exchanger<>();
|
||||
Exchanger<Void> exchanger1 = new Exchanger<>();
|
||||
context.setHandler(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.setStatus(200);
|
||||
response.setContentLength(13);
|
||||
response.flushBuffer();
|
||||
|
||||
try
|
||||
{
|
||||
exchanger0.exchange(null);
|
||||
exchanger1.exchange(null);
|
||||
}
|
||||
catch(Throwable x)
|
||||
{
|
||||
throw new ServletException(x);
|
||||
}
|
||||
|
||||
response.getOutputStream().print("The Response\n");
|
||||
}
|
||||
});
|
||||
|
||||
server.setStopTimeout(1000);
|
||||
server.start();
|
||||
|
||||
LocalEndPoint endp = connector.executeRequest("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n");
|
||||
|
||||
exchanger0.exchange(null);
|
||||
exchanger1.exchange(null);
|
||||
|
||||
String response = endp.getResponse();
|
||||
assertThat(response,containsString("200 OK"));
|
||||
|
||||
endp.addInputAndExecute(BufferUtil.toBuffer("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"));
|
||||
|
||||
exchanger0.exchange(null);
|
||||
|
||||
server.getConnectors()[0].shutdown().get();
|
||||
|
||||
// Check completed 200 does not have close
|
||||
exchanger1.exchange(null);
|
||||
response = endp.getResponse();
|
||||
assertThat(response,containsString("200 OK"));
|
||||
assertThat(response,Matchers.not(containsString("Connection: close")));
|
||||
|
||||
// But endpoint is still closes soon after
|
||||
long end = System.nanoTime()+TimeUnit.SECONDS.toNanos(1);
|
||||
while (endp.isOpen() && System.nanoTime()<end)
|
||||
Thread.sleep(10);
|
||||
Assert.assertFalse(endp.isOpen());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testCommittedResponsesAreClosed() throws Exception
|
||||
{
|
||||
Server server= new Server();
|
||||
|
||||
LocalConnector connector = new LocalConnector(server);
|
||||
server.addConnector(connector);
|
||||
|
||||
StatisticsHandler stats = new StatisticsHandler();
|
||||
server.setHandler(stats);
|
||||
|
||||
ContextHandler context = new ContextHandler(stats,"/");
|
||||
|
||||
Exchanger<Void> exchanger0 = new Exchanger<>();
|
||||
Exchanger<Void> exchanger1 = new Exchanger<>();
|
||||
context.setHandler(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
try
|
||||
{
|
||||
exchanger0.exchange(null);
|
||||
exchanger1.exchange(null);
|
||||
}
|
||||
catch(Throwable x)
|
||||
{
|
||||
throw new ServletException(x);
|
||||
}
|
||||
|
||||
baseRequest.setHandled(true);
|
||||
response.setStatus(200);
|
||||
response.getWriter().println("The Response");
|
||||
response.getWriter().close();
|
||||
}
|
||||
});
|
||||
|
||||
server.setStopTimeout(1000);
|
||||
server.start();
|
||||
|
||||
LocalEndPoint endp = connector.executeRequest(
|
||||
"GET / HTTP/1.1\r\n"+
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n"
|
||||
);
|
||||
|
||||
exchanger0.exchange(null);
|
||||
exchanger1.exchange(null);
|
||||
|
||||
String response = endp.getResponse();
|
||||
assertThat(response,containsString("200 OK"));
|
||||
assertThat(response,Matchers.not(containsString("Connection: close")));
|
||||
|
||||
endp.addInputAndExecute(BufferUtil.toBuffer("GET / HTTP/1.1\r\nHost:localhost\r\n\r\n"));
|
||||
|
||||
exchanger0.exchange(null);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
new Thread(()->
|
||||
{
|
||||
try
|
||||
{
|
||||
server.stop();
|
||||
latch.countDown();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).start();
|
||||
while(server.isStarted())
|
||||
Thread.sleep(10);
|
||||
|
||||
|
||||
// Check new connections rejected!
|
||||
String unavailable = connector.getResponse("GET / HTTP/1.1\r\nHost:localhost\r\n\r\n");
|
||||
assertThat(unavailable,containsString(" 503 Service Unavailable"));
|
||||
assertThat(unavailable,Matchers.containsString("Connection: close"));
|
||||
|
||||
|
||||
// Check completed 200 has close
|
||||
exchanger1.exchange(null);
|
||||
response = endp.getResponse();
|
||||
assertThat(response,containsString("200 OK"));
|
||||
assertThat(response,Matchers.containsString("Connection: close"));
|
||||
assertTrue(latch.await(10,TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContextStop() throws Exception
|
||||
{
|
||||
Server server= new Server();
|
||||
|
||||
LocalConnector connector = new LocalConnector(server);
|
||||
server.addConnector(connector);
|
||||
|
||||
ContextHandler context = new ContextHandler(server,"/");
|
||||
|
||||
StatisticsHandler stats = new StatisticsHandler();
|
||||
context.setHandler(stats);
|
||||
|
||||
Exchanger<Void> exchanger0 = new Exchanger<>();
|
||||
Exchanger<Void> exchanger1 = new Exchanger<>();
|
||||
stats.setHandler(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
try
|
||||
{
|
||||
exchanger0.exchange(null);
|
||||
exchanger1.exchange(null);
|
||||
}
|
||||
catch(Throwable x)
|
||||
{
|
||||
throw new ServletException(x);
|
||||
}
|
||||
|
||||
baseRequest.setHandled(true);
|
||||
response.setStatus(200);
|
||||
response.getWriter().println("The Response");
|
||||
response.getWriter().close();
|
||||
}
|
||||
});
|
||||
|
||||
context.setStopTimeout(1000);
|
||||
server.start();
|
||||
|
||||
LocalEndPoint endp = connector.executeRequest(
|
||||
"GET / HTTP/1.1\r\n"+
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n"
|
||||
);
|
||||
|
||||
exchanger0.exchange(null);
|
||||
exchanger1.exchange(null);
|
||||
|
||||
String response = endp.getResponse();
|
||||
assertThat(response,containsString("200 OK"));
|
||||
assertThat(response,Matchers.not(containsString("Connection: close")));
|
||||
|
||||
endp.addInputAndExecute(BufferUtil.toBuffer("GET / HTTP/1.1\r\nHost:localhost\r\n\r\n"));
|
||||
exchanger0.exchange(null);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
new Thread(()->
|
||||
{
|
||||
try
|
||||
{
|
||||
context.stop();
|
||||
latch.countDown();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).start();
|
||||
while(context.isStarted())
|
||||
Thread.sleep(10);
|
||||
|
||||
// Check new connections accepted, but don't find context!
|
||||
String unavailable = connector.getResponse("GET / HTTP/1.1\r\nHost:localhost\r\n\r\n");
|
||||
assertThat(unavailable,containsString(" 404 Not Found"));
|
||||
|
||||
// Check completed 200 does not have close
|
||||
exchanger1.exchange(null);
|
||||
response = endp.getResponse();
|
||||
assertThat(response,containsString("200 OK"));
|
||||
assertThat(response,Matchers.not(Matchers.containsString("Connection: close")));
|
||||
assertTrue(latch.await(10,TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
static class NoopHandler extends AbstractHandler
|
||||
{
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
|
||||
NoopHandler()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
latch.countDown();
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.server;
|
|||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
@ -1060,7 +1061,7 @@ public class RequestTest
|
|||
String response = _connector.getResponse(request);
|
||||
assertThat(response, containsString(" 200 OK"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPartialRead() throws Exception
|
||||
{
|
||||
|
@ -1252,7 +1253,7 @@ public class RequestTest
|
|||
200, TimeUnit.MILLISECONDS
|
||||
);
|
||||
assertThat(response, containsString("200"));
|
||||
assertThat(response, Matchers.not(containsString("Connection: close")));
|
||||
assertThat(response, not(containsString("Connection: close")));
|
||||
assertThat(response, containsString("Hello World"));
|
||||
|
||||
response=_connector.getResponse(
|
||||
|
@ -1282,7 +1283,7 @@ public class RequestTest
|
|||
"\n"
|
||||
);
|
||||
assertThat(response, containsString("200"));
|
||||
assertThat(response, Matchers.not(containsString("Connection: close")));
|
||||
assertThat(response, not(containsString("Connection: close")));
|
||||
assertThat(response, containsString("Hello World"));
|
||||
|
||||
response=_connector.getResponse(
|
||||
|
|
|
@ -29,7 +29,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
|
||||
public class FutureCallback implements Future<Void>,Callback
|
||||
{
|
||||
private static Throwable COMPLETED=new ConstantThrowable();
|
||||
private final static Throwable COMPLETED=new ConstantThrowable();
|
||||
public final static FutureCallback SUCCEEDED=new FutureCallback(true);
|
||||
private final AtomicBoolean _done=new AtomicBoolean(false);
|
||||
private final CountDownLatch _latch=new CountDownLatch(1);
|
||||
private Throwable _cause;
|
||||
|
|
|
@ -234,4 +234,17 @@ public abstract class AbstractLifeCycle implements LifeCycle
|
|||
@Override public void lifeCycleStopped(LifeCycle event) {}
|
||||
@Override public void lifeCycleStopping(LifeCycle event) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
Class<?> clazz = getClass();
|
||||
String name = clazz.getSimpleName();
|
||||
if ((name==null || name.length()==0) && clazz.getSuperclass()!=null)
|
||||
{
|
||||
clazz = clazz.getSuperclass();
|
||||
name = clazz.getSimpleName();
|
||||
}
|
||||
return String.format("%s@%x{%s}",name,hashCode(),getState());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
package org.eclipse.jetty.util.component;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* A Lifecycle that can be gracefully shutdown.
|
||||
|
@ -26,4 +29,41 @@ import java.util.concurrent.Future;
|
|||
public interface Graceful
|
||||
{
|
||||
public Future<Void> shutdown();
|
||||
|
||||
public boolean isShutdown();
|
||||
|
||||
|
||||
public static class Shutdown implements Graceful
|
||||
{
|
||||
private final AtomicReference<FutureCallback> _shutdown=new AtomicReference<>();
|
||||
|
||||
protected FutureCallback newShutdownCallback()
|
||||
{
|
||||
return FutureCallback.SUCCEEDED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> shutdown()
|
||||
{
|
||||
return _shutdown.updateAndGet(fcb->{return fcb==null?newShutdownCallback():fcb;});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShutdown()
|
||||
{
|
||||
return _shutdown.get()!=null;
|
||||
}
|
||||
|
||||
public void cancel()
|
||||
{
|
||||
FutureCallback shutdown = _shutdown.getAndSet(null);
|
||||
if (shutdown!=null && !shutdown.isDone())
|
||||
shutdown.cancel(true);
|
||||
}
|
||||
|
||||
public FutureCallback get()
|
||||
{
|
||||
return _shutdown.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -353,28 +353,7 @@ public class SslContextFactory extends AbstractLifeCycle implements Dumpable
|
|||
|
||||
try
|
||||
{
|
||||
/* Use a pristine SSLEngine (not one from this SslContextFactory).
|
||||
* This will allow for proper detection and identification
|
||||
* of JRE/lib/security/java.security level disabled features
|
||||
*/
|
||||
SSLEngine sslEngine = SSLContext.getDefault().createSSLEngine();
|
||||
|
||||
List<Object> selections = new ArrayList<>();
|
||||
|
||||
// protocols
|
||||
selections.add(new SslSelectionDump("Protocol",
|
||||
sslEngine.getSupportedProtocols(),
|
||||
sslEngine.getEnabledProtocols(),
|
||||
getExcludeProtocols(),
|
||||
getIncludeProtocols()));
|
||||
|
||||
// ciphers
|
||||
selections.add(new SslSelectionDump("Cipher Suite",
|
||||
sslEngine.getSupportedCipherSuites(),
|
||||
sslEngine.getEnabledCipherSuites(),
|
||||
getExcludeCipherSuites(),
|
||||
getIncludeCipherSuites()));
|
||||
|
||||
List<SslSelectionDump> selections = selectionDump();
|
||||
ContainerLifeCycle.dump(out, indent, selections);
|
||||
}
|
||||
catch (NoSuchAlgorithmException ignore)
|
||||
|
@ -382,6 +361,33 @@ public class SslContextFactory extends AbstractLifeCycle implements Dumpable
|
|||
LOG.ignore(ignore);
|
||||
}
|
||||
}
|
||||
|
||||
List<SslSelectionDump> selectionDump() throws NoSuchAlgorithmException
|
||||
{
|
||||
/* Use a pristine SSLEngine (not one from this SslContextFactory).
|
||||
* This will allow for proper detection and identification
|
||||
* of JRE/lib/security/java.security level disabled features
|
||||
*/
|
||||
SSLEngine sslEngine = SSLContext.getDefault().createSSLEngine();
|
||||
|
||||
List<SslSelectionDump> selections = new ArrayList<>();
|
||||
|
||||
// protocols
|
||||
selections.add(new SslSelectionDump("Protocol",
|
||||
sslEngine.getSupportedProtocols(),
|
||||
sslEngine.getEnabledProtocols(),
|
||||
getExcludeProtocols(),
|
||||
getIncludeProtocols()));
|
||||
|
||||
// ciphers
|
||||
selections.add(new SslSelectionDump("Cipher Suite",
|
||||
sslEngine.getSupportedCipherSuites(),
|
||||
sslEngine.getEnabledCipherSuites(),
|
||||
getExcludeCipherSuites(),
|
||||
getIncludeCipherSuites()));
|
||||
|
||||
return selections;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
|
|
|
@ -30,9 +30,9 @@ import java.util.stream.Collectors;
|
|||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
|
||||
public class SslSelectionDump extends ContainerLifeCycle implements Dumpable
|
||||
class SslSelectionDump extends ContainerLifeCycle implements Dumpable
|
||||
{
|
||||
private static class CaptionedList extends ArrayList<String> implements Dumpable
|
||||
static class CaptionedList extends ArrayList<String> implements Dumpable
|
||||
{
|
||||
private final String caption;
|
||||
|
||||
|
@ -57,9 +57,9 @@ public class SslSelectionDump extends ContainerLifeCycle implements Dumpable
|
|||
}
|
||||
}
|
||||
|
||||
private final String type;
|
||||
private SslSelectionDump.CaptionedList enabled = new SslSelectionDump.CaptionedList("Enabled");
|
||||
private SslSelectionDump.CaptionedList disabled = new SslSelectionDump.CaptionedList("Disabled");
|
||||
final String type;
|
||||
final SslSelectionDump.CaptionedList enabled = new SslSelectionDump.CaptionedList("Enabled");
|
||||
final SslSelectionDump.CaptionedList disabled = new SslSelectionDump.CaptionedList("Disabled");
|
||||
|
||||
public SslSelectionDump(String type,
|
||||
String[] supportedByJVM,
|
||||
|
@ -87,16 +87,7 @@ public class SslSelectionDump extends ContainerLifeCycle implements Dumpable
|
|||
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append(entry);
|
||||
if (!jvmEnabled.contains(entry))
|
||||
{
|
||||
if (isPresent)
|
||||
{
|
||||
s.append(" -");
|
||||
isPresent = false;
|
||||
}
|
||||
s.append(" JreDisabled:java.security");
|
||||
}
|
||||
|
||||
|
||||
for (Pattern pattern : excludedPatterns)
|
||||
{
|
||||
Matcher m = pattern.matcher(entry);
|
||||
|
@ -114,10 +105,11 @@ public class SslSelectionDump extends ContainerLifeCycle implements Dumpable
|
|||
s.append(" ConfigExcluded:'").append(pattern.pattern()).append('\'');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
boolean isIncluded = false;
|
||||
|
||||
if (!includedPatterns.isEmpty())
|
||||
{
|
||||
boolean isIncluded = false;
|
||||
for (Pattern pattern : includedPatterns)
|
||||
{
|
||||
Matcher m = pattern.matcher(entry);
|
||||
|
@ -139,10 +131,22 @@ public class SslSelectionDump extends ContainerLifeCycle implements Dumpable
|
|||
{
|
||||
s.append(",");
|
||||
}
|
||||
s.append(" ConfigIncluded:NotSpecified");
|
||||
|
||||
s.append(" ConfigIncluded:NotSelected");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!isIncluded && !jvmEnabled.contains(entry))
|
||||
{
|
||||
if (isPresent)
|
||||
{
|
||||
s.append(" -");
|
||||
isPresent = false;
|
||||
}
|
||||
|
||||
s.append(" JVM:disabled");
|
||||
}
|
||||
|
||||
if (isPresent)
|
||||
{
|
||||
enabled.add(s.toString());
|
||||
|
|
|
@ -205,65 +205,65 @@ public class ContainerLifeCycleTest
|
|||
{
|
||||
ContainerLifeCycle a0 = new ContainerLifeCycle();
|
||||
String dump = trim(a0.dump());
|
||||
dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl");
|
||||
dump = check(dump, "ContainerLifeCycl");
|
||||
|
||||
ContainerLifeCycle aa0 = new ContainerLifeCycle();
|
||||
a0.addBean(aa0);
|
||||
dump = trim(a0.dump());
|
||||
dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl");
|
||||
dump = check(dump, " +? org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, "ContainerLifeCycl");
|
||||
dump = check(dump, " +? ContainerLife");
|
||||
|
||||
ContainerLifeCycle aa1 = new ContainerLifeCycle();
|
||||
a0.addBean(aa1);
|
||||
dump = trim(a0.dump());
|
||||
dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl");
|
||||
dump = check(dump, " +? org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " +? org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, "ContainerLifeCycl");
|
||||
dump = check(dump, " +? ContainerLife");
|
||||
dump = check(dump, " +? ContainerLife");
|
||||
dump = check(dump, "");
|
||||
|
||||
ContainerLifeCycle aa2 = new ContainerLifeCycle();
|
||||
a0.addBean(aa2, false);
|
||||
dump = trim(a0.dump());
|
||||
dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl");
|
||||
dump = check(dump, " +? org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " +? org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " +~ org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, "ContainerLifeCycl");
|
||||
dump = check(dump, " +? ContainerLife");
|
||||
dump = check(dump, " +? ContainerLife");
|
||||
dump = check(dump, " +~ ContainerLife");
|
||||
dump = check(dump, "");
|
||||
|
||||
aa1.start();
|
||||
a0.start();
|
||||
dump = trim(a0.dump());
|
||||
dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " +~ org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " +~ org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, "ContainerLifeCycl");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " +~ ContainerLife");
|
||||
dump = check(dump, " +~ ContainerLife");
|
||||
dump = check(dump, "");
|
||||
|
||||
a0.manage(aa1);
|
||||
a0.removeBean(aa2);
|
||||
dump = trim(a0.dump());
|
||||
dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, "ContainerLifeCycl");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, "");
|
||||
|
||||
ContainerLifeCycle aaa0 = new ContainerLifeCycle();
|
||||
aa0.addBean(aaa0);
|
||||
dump = trim(a0.dump());
|
||||
dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " | +~ org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, "ContainerLifeCycl");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " | +~ Container");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, "");
|
||||
|
||||
ContainerLifeCycle aa10 = new ContainerLifeCycle();
|
||||
aa1.addBean(aa10, true);
|
||||
dump = trim(a0.dump());
|
||||
dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " | +~ org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, "ContainerLifeCycl");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " | +~ Container");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " += Container");
|
||||
dump = check(dump, "");
|
||||
|
||||
final ContainerLifeCycle a1 = new ContainerLifeCycle();
|
||||
|
@ -282,57 +282,57 @@ public class ContainerLifeCycleTest
|
|||
};
|
||||
a0.addBean(aa, true);
|
||||
dump = trim(a0.dump());
|
||||
dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " | +~ org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " | += org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " +- org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " +- org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " +- org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " +- org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, "ContainerLifeCycl");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " | +~ Container");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " | += Container");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " +- Container");
|
||||
dump = check(dump, " +- Container");
|
||||
dump = check(dump, " +- Container");
|
||||
dump = check(dump, " +- Container");
|
||||
dump = check(dump, "");
|
||||
|
||||
a2.addBean(aa0, true);
|
||||
dump = trim(a0.dump());
|
||||
dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " | +~ org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " | += org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " +- org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " +- org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " | += org.eclipse.jetty.util.component.Conta");
|
||||
dump = check(dump, " | +~ org.eclipse.jetty.util.component.C");
|
||||
dump = check(dump, " +- org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " +- org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, "ContainerLifeCycl");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " | +~ Container");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " | += Container");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " +- Container");
|
||||
dump = check(dump, " +- Container");
|
||||
dump = check(dump, " | += Conta");
|
||||
dump = check(dump, " | +~ C");
|
||||
dump = check(dump, " +- Container");
|
||||
dump = check(dump, " +- Container");
|
||||
dump = check(dump, "");
|
||||
|
||||
a2.unmanage(aa0);
|
||||
dump = trim(a0.dump());
|
||||
dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " | +~ org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " | += org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " +- org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " +- org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " | +~ org.eclipse.jetty.util.component.Conta");
|
||||
dump = check(dump, " +- org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " +- org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, "ContainerLifeCycl");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " | +~ Container");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " | += Container");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " +- Container");
|
||||
dump = check(dump, " +- Container");
|
||||
dump = check(dump, " | +~ Conta");
|
||||
dump = check(dump, " +- Container");
|
||||
dump = check(dump, " +- Container");
|
||||
dump = check(dump, "");
|
||||
|
||||
a0.unmanage(aa);
|
||||
dump = trim(a0.dump());
|
||||
dump = check(dump, "org.eclipse.jetty.util.component.ContainerLifeCycl");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " | +~ org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " += org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, " | += org.eclipse.jetty.util.component.Container");
|
||||
dump = check(dump, " +~ org.eclipse.jetty.util.component.ContainerLife");
|
||||
dump = check(dump, "ContainerLifeCycl");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " | +~ Container");
|
||||
dump = check(dump, " += ContainerLife");
|
||||
dump = check(dump, " | += Container");
|
||||
dump = check(dump, " +~ ContainerLife");
|
||||
dump = check(dump, "");
|
||||
}
|
||||
|
||||
|
@ -580,7 +580,7 @@ public class ContainerLifeCycleTest
|
|||
s = s.substring(0, nl);
|
||||
}
|
||||
|
||||
Assert.assertEquals(x, s);
|
||||
Assert.assertThat(s,Matchers.startsWith(x));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -18,10 +18,14 @@
|
|||
|
||||
package org.eclipse.jetty.util.ssl;
|
||||
|
||||
import static org.eclipse.jetty.toolchain.test.matchers.RegexMatcher.matchesPattern;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
@ -30,7 +34,12 @@ import static org.junit.Assert.assertTrue;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
|
@ -70,7 +79,49 @@ public class SslContextFactoryTest
|
|||
|
||||
cf.start();
|
||||
|
||||
cf.dump(System.out, "");
|
||||
// cf.dump(System.out, "");
|
||||
List<SslSelectionDump> dumps = cf.selectionDump();
|
||||
|
||||
SslSelectionDump cipherDump = dumps.stream()
|
||||
.filter((dump)-> dump.type.contains("Cipher Suite"))
|
||||
.findFirst().get();
|
||||
|
||||
for(String enabledCipher : cipherDump.enabled)
|
||||
{
|
||||
assertThat("Enabled Cipher Suite", enabledCipher, not(matchesPattern(".*_RSA_.*(SHA1|MD5|SHA)")));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDump_IncludeTlsRsa() throws Exception
|
||||
{
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
cf.setIncludeCipherSuites("TLS_RSA_.*");
|
||||
cf.setExcludeCipherSuites("BOGUS"); // just to not exclude anything
|
||||
|
||||
cf.start();
|
||||
|
||||
// cf.dump(System.out, "");
|
||||
List<SslSelectionDump> dumps = cf.selectionDump();
|
||||
|
||||
SSLEngine ssl = SSLContext.getDefault().createSSLEngine();
|
||||
|
||||
List<String> tlsRsaSuites = Stream.of(ssl.getSupportedCipherSuites())
|
||||
.filter((suite)->suite.startsWith("TLS_RSA_"))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<String> selectedSuites = Arrays.asList(cf.getSelectedCipherSuites());
|
||||
SslSelectionDump cipherDump = dumps.stream()
|
||||
.filter((dump)-> dump.type.contains("Cipher Suite"))
|
||||
.findFirst().get();
|
||||
assertThat("Dump Enabled List size is equal to selected list size", cipherDump.enabled.size(), is(selectedSuites.size()));
|
||||
|
||||
for(String expectedCipherSuite: tlsRsaSuites)
|
||||
{
|
||||
assertThat("Selected Cipher Suites", selectedSuites, hasItem(expectedCipherSuite));
|
||||
assertThat("Dump Enabled Cipher Suites", cipherDump.enabled, hasItem(expectedCipherSuite));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -313,6 +313,13 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Try webapp=" + web_app + ", exists=" + web_app.exists() + ", directory=" + web_app.isDirectory()+" file="+(web_app.getFile()));
|
||||
|
||||
// Track the original web_app Resource, as this could be a PathResource.
|
||||
// Later steps force the Resource to be a JarFileResource, which introduces
|
||||
// URLConnection caches in such a way that it prevents Hot Redeployment
|
||||
// on MS Windows.
|
||||
Resource originalWarResource = web_app;
|
||||
|
||||
// Is the WAR usable directly?
|
||||
if (web_app.exists() && !web_app.isDirectory() && !web_app.toString().startsWith("jar:"))
|
||||
{
|
||||
|
@ -373,8 +380,9 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
}
|
||||
else
|
||||
{
|
||||
//only extract if the war file is newer, or a .extract_lock file is left behind meaning a possible partial extraction
|
||||
if (web_app.lastModified() > extractedWebAppDir.lastModified() || extractionLock.exists())
|
||||
// Only extract if the war file is newer, or a .extract_lock file is left behind meaning a possible partial extraction
|
||||
// Use the original War Resource to obtain lastModified to avoid filesystem locks on MS Windows.
|
||||
if (originalWarResource.lastModified() > extractedWebAppDir.lastModified() || extractionLock.exists())
|
||||
{
|
||||
extractionLock.createNewFile();
|
||||
IO.delete(extractedWebAppDir);
|
||||
|
|
|
@ -45,6 +45,8 @@ class DefaultHttpClientProvider
|
|||
if (sslContextFactory == null)
|
||||
{
|
||||
sslContextFactory = new SslContextFactory();
|
||||
sslContextFactory.setTrustAll(false);
|
||||
sslContextFactory.setEndpointIdentificationAlgorithm("HTTPS");
|
||||
}
|
||||
|
||||
HttpClient client = new HttpClient(sslContextFactory);
|
||||
|
|
36
pom.xml
36
pom.xml
|
@ -641,7 +641,7 @@
|
|||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.1</version>
|
||||
<version>0.8.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.agilejava.docbkx</groupId>
|
||||
|
@ -1050,40 +1050,6 @@
|
|||
</dependencyManagement>
|
||||
|
||||
<profiles>
|
||||
<!-- use last snapshot of jacoco for jdk11 -->
|
||||
<profile>
|
||||
<id>jdk11</id>
|
||||
<activation>
|
||||
<jdk>11</jdk>
|
||||
</activation>
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.2-SNAPSHOT</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>oss.snapshots</id>
|
||||
<name>OSS Snapshots</name>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>errorprone</id>
|
||||
<build>
|
||||
|
|
Loading…
Reference in New Issue