diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java index d97093c3b70..34be934ccd2 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java @@ -48,25 +48,18 @@ import static org.junit.Assert.assertThat; */ public class HostnameVerificationTest { - private SslContextFactory sslContextFactory = new SslContextFactory(); - private Server server; + private SslContextFactory clientSslContextFactory = new SslContextFactory(); + private Server server = new Server(); private HttpClient client; private NetworkConnector connector; @Before public void setUp() throws Exception { - if (sslContextFactory != null) - { - // keystore contains a hostname which doesn't match localhost - sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); - sslContextFactory.setKeyStorePassword("storepwd"); - } - sslContextFactory.setEndpointIdentificationAlgorithm("HTTPS"); - - if (server == null) - server = new Server(); - connector = new ServerConnector(server, sslContextFactory); + SslContextFactory serverSslContextFactory = new SslContextFactory(); + serverSslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); + serverSslContextFactory.setKeyStorePassword("storepwd"); + connector = new ServerConnector(server, serverSslContextFactory); server.addConnector(connector); server.setHandler(new DefaultHandler() { @@ -79,9 +72,13 @@ public class HostnameVerificationTest }); server.start(); + // keystore contains a hostname which doesn't match localhost + clientSslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); + clientSslContextFactory.setKeyStorePassword("storepwd"); + QueuedThreadPool executor = new QueuedThreadPool(); executor.setName(executor.getName() + "-client"); - client = new HttpClient(sslContextFactory); + client = new HttpClient(clientSslContextFactory); client.setExecutor(executor); client.start(); } @@ -104,6 +101,7 @@ public class HostnameVerificationTest @Test public void simpleGetWithHostnameVerificationEnabledTest() throws Exception { + clientSslContextFactory.setEndpointIdentificationAlgorithm("HTTPS"); String uri = "https://localhost:" + connector.getLocalPort() + "/"; try { @@ -136,7 +134,7 @@ public class HostnameVerificationTest @Test public void simpleGetWithHostnameVerificationDisabledTest() throws Exception { - sslContextFactory.setEndpointIdentificationAlgorithm(null); + clientSslContextFactory.setEndpointIdentificationAlgorithm(null); String uri = "https://localhost:" + connector.getLocalPort() + "/"; try { @@ -157,7 +155,7 @@ public class HostnameVerificationTest @Test public void trustAllDisablesHostnameVerificationTest() throws Exception { - sslContextFactory.setTrustAll(true); + clientSslContextFactory.setTrustAll(true); String uri = "https://localhost:" + connector.getLocalPort() + "/"; try { diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java index 12e29cb2f63..8c1a66e92cf 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java @@ -37,7 +37,7 @@ import javax.servlet.ServletResponseWrapper; * when it detects that the application has been deployed in a non-jetty Servlet 3 * server. */ -public class Servlet3Continuation implements Continuation +public class Servlet3Continuation implements Continuation, AsyncListener { // Exception reused for all continuations // Turn on debug in ContinuationFilter to see real stack trace. @@ -46,7 +46,7 @@ public class Servlet3Continuation implements Continuation private final ServletRequest _request; private ServletResponse _response; private AsyncContext _context; - private final List _listeners=new ArrayList(); + private final List _listeners=new ArrayList(); private volatile boolean _initial=true; private volatile boolean _resumed=false; private volatile boolean _expired=false; @@ -58,70 +58,13 @@ public class Servlet3Continuation implements Continuation public Servlet3Continuation(ServletRequest request) { _request=request; - - _listeners.add(new AsyncListener() - { - @Override - public void onComplete(AsyncEvent event) throws IOException - { - } - - @Override - public void onError(AsyncEvent event) throws IOException - { - } - - @Override - public void onStartAsync(AsyncEvent event) throws IOException - { - event.getAsyncContext().addListener(this); - } - - @Override - public void onTimeout(AsyncEvent event) throws IOException - { - _initial=false; - event.getAsyncContext().dispatch(); - } - }); } /* ------------------------------------------------------------ */ @Override public void addContinuationListener(final ContinuationListener listener) { - AsyncListener wrapped = new AsyncListener() - { - @Override - public void onComplete(final AsyncEvent event) throws IOException - { - listener.onComplete(Servlet3Continuation.this); - } - - @Override - public void onError(AsyncEvent event) throws IOException - { - listener.onComplete(Servlet3Continuation.this); - } - - @Override - public void onStartAsync(AsyncEvent event) throws IOException - { - event.getAsyncContext().addListener(this); - } - - @Override - public void onTimeout(AsyncEvent event) throws IOException - { - _expired=true; - listener.onTimeout(Servlet3Continuation.this); - } - }; - - if (_context!=null) - _context.addListener(wrapped); - else - _listeners.add(wrapped); + _listeners.add(listener); } /* ------------------------------------------------------------ */ @@ -215,10 +158,7 @@ public class Servlet3Continuation implements Continuation _expired=false; _context=_request.startAsync(); _context.setTimeout(_timeoutMs); - - for (AsyncListener listener:_listeners) - _context.addListener(listener); - _listeners.clear(); + _context.addListener(this); } /* ------------------------------------------------------------ */ @@ -229,10 +169,7 @@ public class Servlet3Continuation implements Continuation _expired=false; _context=_request.startAsync(); _context.setTimeout(_timeoutMs); - - for (AsyncListener listener:_listeners) - _context.addListener(listener); - _listeners.clear(); + _context.addListener(this); } /* ------------------------------------------------------------ */ @@ -287,4 +224,38 @@ public class Servlet3Continuation implements Continuation } throw new IllegalStateException("!suspended"); } + + + /* ------------------------------------------------------------ */ + @Override + public void onComplete(AsyncEvent event) throws IOException + { + for (ContinuationListener listener:_listeners) + listener.onComplete(this); + } + + /* ------------------------------------------------------------ */ + @Override + public void onError(AsyncEvent event) throws IOException + { + } + + /* ------------------------------------------------------------ */ + @Override + public void onStartAsync(AsyncEvent event) throws IOException + { + _initial=false; + } + + /* ------------------------------------------------------------ */ + @Override + public void onTimeout(AsyncEvent event) throws IOException + { + _initial=false; + _expired=true; + for (ContinuationListener listener:_listeners) + listener.onTimeout(this); + if (event.getSuppliedRequest().isAsyncStarted()) + event.getAsyncContext().dispatch(); + } } diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/PushStrategy.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/PushStrategy.java index 43bb3cc3bbd..0e905c710c6 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/PushStrategy.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/PushStrategy.java @@ -34,8 +34,6 @@ public interface PushStrategy /** *

Applies the SPDY push logic for the primary resource.

* - * - * * @param stream the primary resource stream * @param requestHeaders the primary resource request headers * @param responseHeaders the primary resource response headers diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java index 21788699fd3..c76bc888c79 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java @@ -38,21 +38,21 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; /** - *

A SPDY push strategy that auto-populates push metadata based on referrer URLs.

A typical request for a main - * resource such as index.html is immediately followed by a number of requests for associated resources. - * Associated resource requests will have a Referer HTTP header that points to index.html, which is - * used to link the associated resource to the main resource.

However, also following a hyperlink generates a - * HTTP request with a Referer HTTP header that points to index.html; therefore a proper value for + *

A SPDY push strategy that auto-populates push metadata based on referrer URLs.

A typical request for a main + * resource such as {@code index.html} is immediately followed by a number of requests for associated resources. + * Associated resource requests will have a {@code Referer} HTTP header that points to {@code index.html}, which is + * used to link the associated resource to the main resource.

However, also following a hyperlink generates a + * HTTP request with a {@code Referer} HTTP header that points to {@code index.html}; therefore a proper value for * {@link #setReferrerPushPeriod(int)} has to be set. If the referrerPushPeriod for a main resource has elapsed, - * no more associated resources will be added for that main resource.

This class distinguishes associated main + * no more associated resources will be added for that main resource.

This class distinguishes associated main * resources by their URL path suffix and content type. CSS stylesheets, images and JavaScript files have * recognizable URL path suffixes that are classified as associated resources. The suffix regexs can be configured by * constructor argument

*

When CSS stylesheets refer to images, the CSS image request will have the CSS stylesheet as referrer. This - * implementation will push also the CSS image.

The push metadata built by this implementation is limited by the + * implementation will push also the CSS image.

The push metadata built by this implementation is limited by the * number of pages of the application itself, and by the {@link #setMaxAssociatedResources(int)} max associated resources} * parameter. This parameter limits the number of associated resources per each main resource, so that if a main - * resource has hundreds of associated resources, only up to the number specified by this parameter will be pushed.

+ * resource has hundreds of associated resources, only up to the number specified by this parameter will be pushed. */ public class ReferrerPushStrategy implements PushStrategy { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java index f0ff187bb0e..9869566234a 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java @@ -1303,6 +1303,15 @@ public class SslContextFactory extends AbstractLifeCycle return socket; } + /** + * Factory method for "scratch" {@link SSLEngine}s, usually only used for retrieving configuration + * information such as the application buffer size or the list of protocols/ciphers. + *

+ * This method should not be used for creating {@link SSLEngine}s that are used in actual socket + * communication. + * + * @return a new, "scratch" {@link SSLEngine} + */ public SSLEngine newSSLEngine() { if (!isRunning()) @@ -1312,6 +1321,14 @@ public class SslContextFactory extends AbstractLifeCycle return sslEngine; } + /** + * General purpose factory method for creating {@link SSLEngine}s, although creation of + * {@link SSLEngine}s on the server-side should prefer {@link #newSSLEngine(InetSocketAddress)}. + * + * @param host the remote host + * @param port the remote port + * @return a new {@link SSLEngine} + */ public SSLEngine newSSLEngine(String host, int port) { if (!isRunning()) @@ -1323,10 +1340,32 @@ public class SslContextFactory extends AbstractLifeCycle return sslEngine; } + /** + * Server-side only factory method for creating {@link SSLEngine}s. + *

+ * If the given {@code address} is null, it is equivalent to {@link #newSSLEngine()}, otherwise + * {@link #newSSLEngine(String, int)} is called. + *

+ * If {@link #getNeedClientAuth()} is {@code true}, then the host name is passed to + * {@link #newSSLEngine(String, int)}, possibly incurring in a reverse DNS lookup, which takes time + * and may hang the selector (since this method is usually called by the selector thread). + *

+ * Otherwise, the host address is passed to {@link #newSSLEngine(String, int)} without DNS lookup + * penalties. + *

+ * Clients that wish to create {@link SSLEngine} instances must use {@link #newSSLEngine(String, int)}. + * + * @param address the remote peer address + * @return a new {@link SSLEngine} + */ public SSLEngine newSSLEngine(InetSocketAddress address) { - // Must use the hostName, not the hostAddress, to allow correct host name verification - return address != null ? newSSLEngine(address.getAddress().getHostName(), address.getPort()) : newSSLEngine(); + if (address == null) + return newSSLEngine(); + + boolean useHostName = getNeedClientAuth(); + String hostName = useHostName ? address.getHostName() : address.getAddress().getHostAddress(); + return newSSLEngine(hostName, address.getPort()); } public void customize(SSLEngine sslEngine) diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/TomcatServerQuirksTest.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/TomcatServerQuirksTest.java index a2db61f4cfd..a424977db89 100644 --- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/TomcatServerQuirksTest.java +++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/TomcatServerQuirksTest.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.websocket.client; import java.io.IOException; import java.net.URI; import java.nio.ByteBuffer; +import java.util.Arrays; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -76,7 +77,7 @@ public class TomcatServerQuirksTest try { - int bufferSize = 512; + final int bufferSize = 512; server.start(); @@ -103,17 +104,15 @@ public class TomcatServerQuirksTest Assert.assertTrue("Timed out waiting for Client side WebSocket open event",websocket.openLatch.await(1,TimeUnit.SECONDS)); // Have server write frame. - int length = bufferSize / 2; - ByteBuffer serverFrame = ByteBuffer.allocate(bufferSize); - // BufferUtil.flipToFill(serverFrame); + byte payload[] = new byte[bufferSize / 2]; + Arrays.fill(payload,(byte)'x'); + ByteBuffer serverFrame = BufferUtil.allocate(bufferSize); + BufferUtil.flipToFill(serverFrame); serverFrame.put((byte)(0x80 | 0x01)); // FIN + TEXT serverFrame.put((byte)0x7E); // No MASK and 2 bytes length - serverFrame.put((byte)(length >> 8)); // first length byte - serverFrame.put((byte)(length & 0xFF)); // second length byte - for (int i = 0; i < length; ++i) - { - serverFrame.put((byte)'x'); - } + serverFrame.put((byte)(payload.length >> 8)); // first length byte + serverFrame.put((byte)(payload.length & 0xFF)); // second length byte + serverFrame.put(payload); BufferUtil.flipToFlush(serverFrame,0); byte buf[] = BufferUtil.toArray(serverFrame); socket.write(buf,0,buf.length); diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java index 14e457c41f3..189bb310192 100644 --- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java +++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java @@ -158,8 +158,12 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc { try { - ServletUpgradeRequest sockreq = new ServletUpgradeRequest(request); - ServletUpgradeResponse sockresp = new ServletUpgradeResponse(response); + // TODO: use ServletUpgradeRequest in Jetty 9.1 + @SuppressWarnings("deprecation") + ServletWebSocketRequest sockreq = new ServletWebSocketRequest(request); + // TODO: use ServletUpgradeResponse in Jetty 9.1 + @SuppressWarnings("deprecation") + ServletWebSocketResponse sockresp = new ServletWebSocketResponse(response); UpgradeContext context = getActiveUpgradeContext(); if (context == null) diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketOverSSLTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketOverSSLTest.java index 4297ca1bc82..f0676b1c8c6 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketOverSSLTest.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketOverSSLTest.java @@ -68,7 +68,7 @@ public class WebSocketOverSSLTest Future fut = client.connect(clientSocket,server.getServerUri()); // wait for connect - Session session = fut.get(1,TimeUnit.SECONDS); + Session session = fut.get(3,TimeUnit.SECONDS); // Generate text frame String msg = "this is an echo ... cho ... ho ... o"; @@ -98,13 +98,16 @@ public class WebSocketOverSSLTest WebSocketClient client = new WebSocketClient(server.getSslContextFactory()); try { + client.setConnectTimeout(3000); client.start(); CaptureSocket clientSocket = new CaptureSocket(); - Future fut = client.connect(clientSocket,server.getServerUri()); + URI requestUri = server.getServerUri(); + System.err.printf("Request URI: %s%n",requestUri.toASCIIString()); + Future fut = client.connect(clientSocket,requestUri); // wait for connect - Session session = fut.get(3,TimeUnit.SECONDS); + Session session = fut.get(5,TimeUnit.SECONDS); // Generate text frame session.getRemote().sendString("session.isSecure"); @@ -133,17 +136,19 @@ public class WebSocketOverSSLTest WebSocketClient client = new WebSocketClient(server.getSslContextFactory()); try { + client.setConnectTimeout(3000); client.start(); CaptureSocket clientSocket = new CaptureSocket(); URI requestUri = server.getServerUri().resolve("/deep?a=b"); - Future fut = client.connect(clientSocket,requestUri); + System.err.printf("Request URI: %s%n",requestUri.toASCIIString()); + client.connect(clientSocket,requestUri); // wait for connect - Session session = fut.get(3,TimeUnit.SECONDS); + clientSocket.awaitConnected(5000); // Generate text frame - session.getRemote().sendString("session.upgradeRequest.requestURI"); + clientSocket.getRemote().sendString("session.upgradeRequest.requestURI"); // Read frame (hopefully text frame) clientSocket.messages.awaitEventCount(1,500,TimeUnit.MILLISECONDS); diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java index d7d8b89de8a..2682efd98de 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java @@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit; import org.eclipse.jetty.toolchain.test.AdvancedRunner; import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception; import org.eclipse.jetty.util.Utf8StringBuilder; +import org.eclipse.jetty.util.log.StacklessLogging; import org.eclipse.jetty.util.log.StdErrLog; import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.extensions.Frame; @@ -206,14 +207,17 @@ public class WebSocketServletRFCTest client.sendStandardRequest(); client.expectUpgradeResponse(); - // Generate text frame - client.write(WebSocketFrame.text("CRASH")); + try (StacklessLogging context = new StacklessLogging(EventDriver.class)) + { + // Generate text frame + client.write(WebSocketFrame.text("CRASH")); - // Read frame (hopefully close frame) - IncomingFramesCapture capture = client.readFrames(1,TimeUnit.MILLISECONDS,500); - Frame cf = capture.getFrames().poll(); - CloseInfo close = new CloseInfo(cf); - Assert.assertThat("Close Frame.status code",close.getStatusCode(),is(StatusCode.SERVER_ERROR)); + // Read frame (hopefully close frame) + IncomingFramesCapture capture = client.readFrames(1,TimeUnit.MILLISECONDS,500); + Frame cf = capture.getFrames().poll(); + CloseInfo close = new CloseInfo(cf); + Assert.assertThat("Close Frame.status code",close.getStatusCode(),is(StatusCode.SERVER_ERROR)); + } } finally { diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/ABSocket.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/ABSocket.java index a510e74d953..ecd166295bb 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/ABSocket.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/ABSocket.java @@ -23,6 +23,7 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.api.Session; +import org.eclipse.jetty.websocket.api.WebSocketException; import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect; import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage; import org.eclipse.jetty.websocket.api.annotations.WebSocket; @@ -77,7 +78,14 @@ public class ABSocket } } - // echo the message back. - this.session.getRemote().sendStringByFuture(message); + try + { + // echo the message back. + this.session.getRemote().sendStringByFuture(message); + } + catch (WebSocketException e) + { + LOG.warn("Unable to echo TEXT message",e); + } } } diff --git a/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties b/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties index e7122e6fe09..6d5c86342bc 100644 --- a/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties +++ b/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties @@ -17,3 +17,6 @@ org.eclipse.jetty.websocket.server.browser.LEVEL=DEBUG ### Disabling intentional error out of RFCSocket org.eclipse.jetty.websocket.server.helper.RFCSocket.LEVEL=OFF + +### Hiding Stack Traces from ABSocket +org.eclipse.jetty.websocket.server.ab.ABSocket.STACKS=OFF diff --git a/pom.xml b/pom.xml index fa2c9f2fcd2..f40e7e76c0c 100644 --- a/pom.xml +++ b/pom.xml @@ -736,3 +736,4 @@ +