Merge remote-tracking branch 'eclipse/jetty-10.0.x' into jetty-10.0.x-websocketmapping-refactor

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2019-01-23 18:45:59 +11:00
commit d37dfd4357
32 changed files with 591 additions and 332 deletions

View File

@ -30,7 +30,7 @@ public class JAASPrincipal implements Principal, Serializable
{ {
private static final long serialVersionUID = -5538962177019315479L; private static final long serialVersionUID = -5538962177019315479L;
private String _name = null; private final String _name;
public JAASPrincipal(String userName) public JAASPrincipal(String userName)
{ {

View File

@ -1,5 +0,0 @@
source.. = src/main/java/
output.. = target/classes/
bin.includes = META-INF/,\
.
src.includes = META-INF/

View File

@ -1,5 +0,0 @@
source.. = src/main/java/
output.. = target/classes/
bin.includes = META-INF/,\
.
src.includes = META-INF/

View File

@ -1,8 +0,0 @@
source.. = src/main/java/
output.. = target/classes/
bin.includes = META-INF/,\
.,\
jettyhome/
bin.excludes = jettyhome/logs/*.log,\
jettyhome/lib/*
src.includes = jettyhome/

View File

@ -1,4 +0,0 @@
source.. = src/main/java/
output.. = target/classes/
bin.includes = META-INF/,\
.

View File

@ -11,8 +11,9 @@
<properties> <properties>
<assembly-directory>target/distribution</assembly-directory> <assembly-directory>target/distribution</assembly-directory>
<bundle-symbolic-name>${project.groupId}.runner</bundle-symbolic-name> <bundle-symbolic-name>${project.groupId}.runner</bundle-symbolic-name>
<it.debug>false</it.debug>
</properties> </properties>
<url>http://www.eclipse.org/jetty</url>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
@ -35,21 +36,38 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<!-- jetty-runner is not an OSGi component -->
<skip>true</skip>
</configuration>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-invoker-plugin</artifactId>
<executions>
<execution>
<id>integration-test</id>
<phase>integration-test</phase>
<goals>
<goal>install</goal>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration> <configuration>
<archive> <javaHome>${java.home}</javaHome>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> <environmentVariables>
</archive> <JAVA_HOME>${java.home}</JAVA_HOME>
</environmentVariables>
<debug>${it.debug}</debug>
<projectsDirectory>src/it</projectsDirectory>
<timeoutInSeconds>600</timeoutInSeconds>
<cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
<localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
<settingsFile>src/it/settings.xml</settingsFile>
<skipInvocation>${skipTests}</skipInvocation>
<scriptVariables>
<maven.dependency.plugin.version>${maven.dependency.plugin.version}</maven.dependency.plugin.version>
</scriptVariables>
<goals>
<goal>clean</goal>
</goals>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
@ -63,6 +81,28 @@
<skip>true</skip> <skip>true</skip>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<!-- jetty-runner is not an OSGi component -->
<skip>true</skip>
<!-- there is no way to skip MANIFEST creation by the plugin so just configure dummy location -->
<manifestLocation>${project.build.directory}/NON_USED_MANIFEST</manifestLocation>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>src/main/resources/MANIFEST.MF</manifestFile>
<manifest>
<mainClass>org.eclipse.jetty.runner.Runner</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>
</build> </build>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<settings>
<profiles>
<profile>
<id>it-repo</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<repositories>
<repository>
<id>local.central</id>
<url>@localRepositoryUrl@</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>local.central</id>
<url>@localRepositoryUrl@</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
</settings>

View File

@ -0,0 +1 @@
invoker.goals = generate-resources

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.its</groupId>
<artifactId>jetty-runner-it-test</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-runner</artifactId>
<version>@project.version@</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>@maven.dependency.plugin.version@</version>
<executions>
<execution>
<id>copy-jetty-runner</id>
<phase>generate-resources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-runner</artifactId>
<version>@project.version@</version>
<type>jar</type>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/</outputDirectory>
<destFileName>jetty-runner.jar</destFileName>
</artifactItem>
</artifactItems>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,10 @@
import java.util.jar.*
File artifact = new File( basedir, "target/jetty-runner.jar" )
assert artifact.exists()
JarFile jar = new JarFile( artifact );
Attributes manifest = jar.getManifest().getMainAttributes();
assert manifest.getValue( new Attributes.Name( "Main-Class" ) ).equals( "org.eclipse.jetty.runner.Runner" )

View File

@ -0,0 +1 @@
Comment: Jetty Runner

View File

@ -129,6 +129,17 @@ public interface Callback extends Invocable
}; };
} }
static Callback from(Runnable completed)
{
return new Completing()
{
public void completed()
{
completed.run();
}
};
}
class Completing implements Callback class Completing implements Callback
{ {
@Override @Override

View File

@ -18,24 +18,6 @@
package org.eclipse.jetty.websocket.javax.common; package org.eclipse.jetty.websocket.javax.common;
import org.eclipse.jetty.util.SharedBlockingCallback;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.core.FrameHandler;
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
import org.eclipse.jetty.websocket.javax.common.encoders.AvailableEncoders;
import org.eclipse.jetty.websocket.javax.common.util.ReflectUtils;
import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.Extension;
import javax.websocket.MessageHandler;
import javax.websocket.RemoteEndpoint.Async;
import javax.websocket.RemoteEndpoint.Basic;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.security.Principal; import java.security.Principal;
@ -48,6 +30,25 @@ import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.Extension;
import javax.websocket.MessageHandler;
import javax.websocket.RemoteEndpoint.Async;
import javax.websocket.RemoteEndpoint.Basic;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
import org.eclipse.jetty.util.SharedBlockingCallback;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.core.FrameHandler;
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
import org.eclipse.jetty.websocket.javax.common.encoders.AvailableEncoders;
import org.eclipse.jetty.websocket.javax.common.util.ReflectUtils;
/** /**
* Client Session for the JSR. * Client Session for the JSR.
*/ */
@ -535,7 +536,7 @@ public class JavaxWebSocketSession extends AbstractLifeCycle implements javax.we
@Override @Override
public boolean isOpen() public boolean isOpen()
{ {
return coreSession.isOpen(); return coreSession.isOutputOpen();
} }
/** /**

View File

@ -32,7 +32,14 @@ import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.pathmap.PathSpec; import org.eclipse.jetty.http.pathmap.PathSpec;
import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.server.*; import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.MavenTestingUtils;

View File

@ -18,6 +18,13 @@
package org.eclipse.jetty.websocket.javax.tests.client.misbehaving; package org.eclipse.jetty.websocket.javax.tests.client.misbehaving;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.websocket.ContainerProvider;
import javax.websocket.WebSocketContainer;
import org.eclipse.jetty.util.log.StacklessLogging; import org.eclipse.jetty.util.log.StacklessLogging;
import org.eclipse.jetty.websocket.core.internal.WebSocketChannel; import org.eclipse.jetty.websocket.core.internal.WebSocketChannel;
import org.eclipse.jetty.websocket.javax.tests.CoreServer; import org.eclipse.jetty.websocket.javax.tests.CoreServer;
@ -25,12 +32,6 @@ import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import javax.websocket.ContainerProvider;
import javax.websocket.WebSocketContainer;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;

View File

@ -38,7 +38,9 @@ import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
/** /**
* Tests a {@link javax.websocket.Decoder.TextStream} automatic decoding to a Socket onMessage parameter * Tests a {@link javax.websocket.Decoder.TextStream} automatic decoding to a Socket onMessage parameter

View File

@ -25,7 +25,12 @@ import java.net.URI;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.websocket.*; import javax.websocket.ContainerProvider;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
import javax.websocket.server.ServerContainer; import javax.websocket.server.ServerContainer;
import javax.websocket.server.ServerEndpointConfig; import javax.websocket.server.ServerEndpointConfig;

View File

@ -31,7 +31,13 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.websocket.*; import javax.websocket.ContainerProvider;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
import javax.websocket.server.ServerEndpoint; import javax.websocket.server.ServerEndpoint;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;

View File

@ -18,6 +18,11 @@
package org.eclipse.jetty.websocket.common; package org.eclipse.jetty.websocket.common;
import java.io.IOException;
import java.net.SocketAddress;
import java.time.Duration;
import java.util.Objects;
import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.websocket.api.CloseStatus; import org.eclipse.jetty.websocket.api.CloseStatus;
import org.eclipse.jetty.websocket.api.Session; import org.eclipse.jetty.websocket.api.Session;
@ -27,11 +32,6 @@ import org.eclipse.jetty.websocket.api.UpgradeResponse;
import org.eclipse.jetty.websocket.api.WebSocketBehavior; import org.eclipse.jetty.websocket.api.WebSocketBehavior;
import org.eclipse.jetty.websocket.core.FrameHandler; import org.eclipse.jetty.websocket.core.FrameHandler;
import java.io.IOException;
import java.net.SocketAddress;
import java.time.Duration;
import java.util.Objects;
public class WebSocketSessionImpl implements Session, Dumpable public class WebSocketSessionImpl implements Session, Dumpable
{ {
private final FrameHandler.CoreSession coreSession; private final FrameHandler.CoreSession coreSession;
@ -160,7 +160,7 @@ public class WebSocketSessionImpl implements Session, Dumpable
@Override @Override
public boolean isOpen() public boolean isOpen()
{ {
return remoteEndpoint.getCoreSession().isOpen(); return remoteEndpoint.getCoreSession().isOutputOpen();
} }
@Override @Override

View File

@ -18,14 +18,13 @@
package org.eclipse.jetty.websocket.core; package org.eclipse.jetty.websocket.core;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Utf8Appendable;
import org.eclipse.jetty.util.Utf8StringBuilder;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.function.Supplier;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Utf8Appendable;
import org.eclipse.jetty.util.Utf8StringBuilder;
/** /**
* Representation of a WebSocket Close (status code &amp; reason) * Representation of a WebSocket Close (status code &amp; reason)
@ -194,7 +193,7 @@ public class CloseStatus
int len = 2; // status code int len = 2; // status code
byte reasonBytes[] = null; byte[] reasonBytes = null;
if (reason != null) if (reason != null)
{ {
@ -208,7 +207,7 @@ public class CloseStatus
ByteBuffer buf = BufferUtil.allocate(len); ByteBuffer buf = BufferUtil.allocate(len);
BufferUtil.flipToFill(buf); BufferUtil.flipToFill(buf);
buf.put((byte)((statusCode >>> 8) & 0xFF)); buf.put((byte)((statusCode >>> 8) & 0xFF));
buf.put((byte)((statusCode >>> 0) & 0xFF)); buf.put((byte)(statusCode & 0xFF));
if ((reasonBytes != null) && (reasonBytes.length > 0)) if ((reasonBytes != null) && (reasonBytes.length > 0))
{ {

View File

@ -270,7 +270,7 @@ public interface FrameHandler extends IncomingFrames
/** /**
* @return True if the websocket is open outbound * @return True if the websocket is open outbound
*/ */
boolean isOpen(); boolean isOutputOpen();
/** /**
* If using BatchMode.ON or BatchMode.AUTO, trigger a flush of enqueued / batched frames. * If using BatchMode.ON or BatchMode.AUTO, trigger a flush of enqueued / batched frames.
@ -374,7 +374,7 @@ public interface FrameHandler extends IncomingFrames
} }
@Override @Override
public boolean isOpen() public boolean isOutputOpen()
{ {
return false; return false;
} }

View File

@ -19,18 +19,15 @@
package org.eclipse.jetty.websocket.core.internal; package org.eclipse.jetty.websocket.core.internal;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Queue;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.DecoratedObjectFactory; import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.IteratingCallback;
import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.component.Dumpable;
@ -201,7 +198,7 @@ public class ExtensionStack implements IncomingFrames, OutgoingFrames, Dumpable
outgoing.sendFrame(frame, callback, batch); outgoing.sendFrame(frame, callback, batch);
} }
public void connect(IncomingFrames incoming, OutgoingFrames outgoing, WebSocketChannel webSocketChannel) public void initialize(IncomingFrames incoming, OutgoingFrames outgoing, WebSocketChannel webSocketChannel)
{ {
if (extensions == null) if (extensions == null)
throw new IllegalStateException(); throw new IllegalStateException();

View File

@ -18,6 +18,7 @@
package org.eclipse.jetty.websocket.core.internal; package org.eclipse.jetty.websocket.core.internal;
import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
@ -74,6 +75,18 @@ public class FrameFlusher extends IteratingCallback
} }
} }
public void onClose()
{
Throwable cause = null;
synchronized (this)
{
if (!queue.isEmpty())
cause = new IOException("Closed");
}
if (cause!=null)
onCompleteFailure(cause);
}
@Override @Override
protected Action process() throws Throwable protected Action process() throws Throwable
{ {

View File

@ -20,16 +20,19 @@ package org.eclipse.jetty.websocket.core.internal;
import java.io.IOException; import java.io.IOException;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.URI; import java.net.URI;
import java.time.Duration; import java.time.Duration;
import java.util.ArrayDeque;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Queue;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.TimeoutException;
import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IteratingCallback;
import org.eclipse.jetty.util.Utf8Appendable; import org.eclipse.jetty.util.Utf8Appendable;
import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
@ -62,6 +65,7 @@ public class WebSocketChannel implements IncomingFrames, FrameHandler.CoreSessio
private final FrameHandler handler; private final FrameHandler handler;
private final Negotiated negotiated; private final Negotiated negotiated;
private final boolean demanding; private final boolean demanding;
private final Flusher flusher = new Flusher();
private WebSocketConnection connection; private WebSocketConnection connection;
private boolean autoFragment = WebSocketConstants.DEFAULT_AUTO_FRAGMENT; private boolean autoFragment = WebSocketConstants.DEFAULT_AUTO_FRAGMENT;
@ -79,7 +83,7 @@ public class WebSocketChannel implements IncomingFrames, FrameHandler.CoreSessio
this.behavior = behavior; this.behavior = behavior;
this.negotiated = negotiated; this.negotiated = negotiated;
this.demanding = handler.isDemanding(); this.demanding = handler.isDemanding();
negotiated.getExtensions().connect(new IncomingAdaptor(), new OutgoingAdaptor(), this); negotiated.getExtensions().initialize(new IncomingAdaptor(), new OutgoingAdaptor(), this);
} }
/** /**
@ -153,7 +157,7 @@ public class WebSocketChannel implements IncomingFrames, FrameHandler.CoreSessio
if (frame.getOpCode() == OpCode.CLOSE) if (frame.getOpCode() == OpCode.CLOSE)
{ {
if (!(frame instanceof ParsedFrame)) // already check in parser if (!(frame instanceof ParsedFrame)) // already check in parser
CloseStatus.getCloseStatus(frame); CloseStatus.getCloseStatus(frame); // return ignored as get used to validate there is a closeStatus
} }
} }
else else
@ -235,9 +239,14 @@ public class WebSocketChannel implements IncomingFrames, FrameHandler.CoreSessio
} }
@Override @Override
public boolean isOpen() public boolean isOutputOpen()
{ {
return channelState.isOutOpen(); return channelState.isOutputOpen();
}
public boolean isClosed()
{
return channelState.isClosed();
} }
public void setWebSocketConnection(WebSocketConnection connection) public void setWebSocketConnection(WebSocketConnection connection)
@ -282,99 +291,94 @@ public class WebSocketChannel implements IncomingFrames, FrameHandler.CoreSessio
public void onClosed(Throwable cause) public void onClosed(Throwable cause)
{ {
onClosed(cause, new CloseStatus(CloseStatus.NO_CLOSE, cause == null?null:cause.toString())); CloseStatus closeStatus = new CloseStatus(CloseStatus.NO_CLOSE, cause == null?null:cause.toString());
if (channelState.onClosed(closeStatus))
closeConnection(cause, closeStatus);
} }
public void onClosed(Throwable cause, CloseStatus closeStatus) public void closeConnection(Throwable cause, CloseStatus closeStatus)
{
if (channelState.onClosed(closeStatus))
{ {
connection.cancelDemand(); connection.cancelDemand();
// Forward Errors to Local WebSocket EndPoint // Forward Errors to Local WebSocket EndPoint
if (cause!=null)
{
try try
{ {
handler.onError(cause); handler.onError(cause);
} }
catch (Throwable e) catch (Throwable e)
{ {
if (e != cause)
cause.addSuppressed(e); cause.addSuppressed(e);
LOG.warn(cause); LOG.warn(cause);
} }
}
try try
{ {
handler.onClosed(closeStatus); handler.onClosed(closeStatus);
} }
catch (Exception e) catch (Throwable e)
{ {
LOG.warn(e); LOG.warn(e);
} }
if (connection.getEndPoint().isOpen())
connection.close();
} }
AbnormalCloseStatus abnormalCloseStatusFor(Throwable cause)
{
int code;
if (cause instanceof ProtocolException)
code = CloseStatus.PROTOCOL;
else if (cause instanceof CloseException)
code = ((CloseException)cause).getStatusCode();
else if (cause instanceof Utf8Appendable.NotUtf8Exception)
code = CloseStatus.BAD_PAYLOAD;
else if (cause instanceof WebSocketTimeoutException || cause instanceof TimeoutException || cause instanceof SocketTimeoutException)
code = CloseStatus.SHUTDOWN;
else if (behavior == Behavior.CLIENT)
code = CloseStatus.POLICY_VIOLATION;
else
code = CloseStatus.SERVER_ERROR;
return new AbnormalCloseStatus(code, cause.getMessage());
} }
/** /**
* Process an Error event seen by the Session and/or Connection * Process an Error that originated from the connection.
* For protocol causes, send and abnormal close frame
* otherwise just close the connection.
* *
* @param cause the cause * @param cause the cause
*/ */
public void processError(Throwable cause) public void processConnectionError(Throwable cause)
{ {
CloseStatus closeStatus; if (LOG.isDebugEnabled())
LOG.debug("processConnectionError {} {}", this, cause);
if (cause instanceof Utf8Appendable.NotUtf8Exception) CloseStatus closeStatus = abnormalCloseStatusFor(cause);
{
closeStatus = new CloseStatus(CloseStatus.BAD_PAYLOAD, cause.getMessage());
}
else if (cause instanceof SocketTimeoutException)
{
// A path often seen in Windows
closeStatus = new CloseStatus(CloseStatus.SHUTDOWN, cause.getMessage());
}
else if (cause instanceof IOException)
{
closeStatus = new CloseStatus(CloseStatus.PROTOCOL, cause.getMessage());
}
else if (cause instanceof SocketException)
{
// A path unique to Unix
closeStatus = new CloseStatus(CloseStatus.SHUTDOWN, cause.getMessage());
}
else if (cause instanceof CloseException)
{
CloseException ce = (CloseException)cause;
closeStatus = new CloseStatus(ce.getStatusCode(), ce.getMessage());
}
else if (cause instanceof WebSocketTimeoutException)
{
closeStatus = new CloseStatus(CloseStatus.SHUTDOWN, cause.getMessage());
}
else
{
LOG.warn("Unhandled Error (closing connection)", cause);
// Exception on end-user WS-Endpoint. if (closeStatus.getCode() == CloseStatus.PROTOCOL)
// Fast-fail & close connection with reason.
int statusCode = CloseStatus.SERVER_ERROR;
if (behavior == Behavior.CLIENT)
statusCode = CloseStatus.POLICY_VIOLATION;
closeStatus = new CloseStatus(statusCode, cause.getMessage());
}
try
{
// TODO can we avoid the illegal state exception in outClosed
close(closeStatus, Callback.NOOP, false); close(closeStatus, Callback.NOOP, false);
else if (channelState.onClosed(closeStatus))
closeConnection(cause, closeStatus);
} }
catch (IllegalStateException e)
/**
* Process an Error that originated from the handler.
* Send an abnormal close frame to ensure connection is closed.
*
* @param cause the cause
*/
public void processHandlerError(Throwable cause)
{ {
if (cause == null) if (LOG.isDebugEnabled())
cause = e; LOG.debug("processHandlerError {} {}", this, cause);
else
cause.addSuppressed(e); close(abnormalCloseStatusFor(cause), Callback.NOOP, false);
}
onClosed(cause, closeStatus);
} }
/** /**
@ -393,8 +397,6 @@ public class WebSocketChannel implements IncomingFrames, FrameHandler.CoreSessio
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("ConnectionState: Transition to CONNECTED"); LOG.debug("ConnectionState: Transition to CONNECTED");
try
{
// Open connection and handler // Open connection and handler
channelState.onOpen(); channelState.onOpen();
handler.onOpen(this); handler.onOpen(this);
@ -407,13 +409,15 @@ public class WebSocketChannel implements IncomingFrames, FrameHandler.CoreSessio
catch (Throwable t) catch (Throwable t)
{ {
LOG.warn("Error during OPEN", t); LOG.warn("Error during OPEN", t);
// TODO: this must trigger onError AND onClose try
processError(new CloseException(CloseStatus.SERVER_ERROR, t));
}
}
catch (Throwable t)
{ {
processError(t); // Handle error handler.onError(t);
}
catch (Exception e)
{
t.addSuppressed(e);
}
processHandlerError(new CloseException(CloseStatus.SERVER_ERROR, t));
} }
} }
@ -453,17 +457,13 @@ public class WebSocketChannel implements IncomingFrames, FrameHandler.CoreSessio
@Override @Override
public void sendFrame(Frame frame, Callback callback, boolean batch) public void sendFrame(Frame frame, Callback callback, boolean batch)
{
synchronized(this)
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("sendFrame({}, {}, {})", frame, callback, batch); LOG.debug("sendFrame({}, {}, {})", frame, callback, batch);
boolean closed;
try try
{ {
assertValidOutgoing(frame); assertValidOutgoing(frame);
closed = channelState.checkOutgoing(frame);
} }
catch (Throwable ex) catch (Throwable ex)
{ {
@ -471,56 +471,60 @@ public class WebSocketChannel implements IncomingFrames, FrameHandler.CoreSessio
return; return;
} }
try
{
synchronized(flusher)
{
boolean closeConnection = channelState.onOutgoingFrame(frame);
if (frame.getOpCode() == OpCode.CLOSE) if (frame.getOpCode() == OpCode.CLOSE)
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("close({}, {}, {})", CloseStatus.getCloseStatus(frame), callback, batch); LOG.debug("close({}, {}, {})", CloseStatus.getCloseStatus(frame), callback, batch);
if (closed) if (closeConnection)
{ {
callback = new Callback.Nested(callback) callback = new Callback.Nested(callback)
{ {
@Override @Override
public void completed() public void completed()
{ {
try closeConnection(null, channelState.getCloseStatus());
{
handler.onClosed(channelState.getCloseStatus());
}
catch (Throwable e)
{
try
{
handler.onError(e);
}
catch (Throwable e2)
{
e.addSuppressed(e2);
LOG.warn(e);
}
}
finally
{
connection.close();
}
} }
}; };
} }
} }
negotiated.getExtensions().sendFrame(frame, callback, batch); flusher.queue.offer(new FrameEntry(frame, callback, batch));
}
flusher.iterate();
}
catch (Throwable ex)
{
try
{
callback.failed(ex);
}
finally
{
if (frame.getOpCode() == OpCode.CLOSE)
{
CloseStatus closeStatus = CloseStatus.getCloseStatus(frame);
if (closeStatus instanceof AbnormalCloseStatus)
closeConnection(null, closeStatus);
}
}
} }
connection.sendFrameQueue();
} }
@Override @Override
public void flush(Callback callback) public void flush(Callback callback)
{ {
synchronized(this) synchronized(flusher)
{ {
negotiated.getExtensions().sendFrame(FrameFlusher.FLUSH_FRAME, callback, false); flusher.queue.offer(new FrameEntry(FrameFlusher.FLUSH_FRAME, callback, false));
} }
connection.sendFrameQueue(); flusher.iterate();
} }
@Override @Override
@ -613,14 +617,13 @@ public class WebSocketChannel implements IncomingFrames, FrameHandler.CoreSessio
LOG.debug("receiveFrame({}, {}) - connectionState={}, handler={}", LOG.debug("receiveFrame({}, {}) - connectionState={}, handler={}",
frame, callback, channelState, handler); frame, callback, channelState, handler);
boolean closeConnection = channelState.onIncomingFrame(frame);
boolean closed = channelState.checkIncoming(frame);
// Handle inbound close // Handle inbound close
if (frame.getOpCode() == OpCode.CLOSE) if (frame.getOpCode() == OpCode.CLOSE)
{ {
connection.cancelDemand(); connection.cancelDemand();
if (closed) if (closeConnection)
{ {
callback = new Callback.Nested(callback) callback = new Callback.Nested(callback)
{ {
@ -640,7 +643,7 @@ public class WebSocketChannel implements IncomingFrames, FrameHandler.CoreSessio
@Override @Override
public void completed() public void completed()
{ {
if (channelState.isOutOpen()) if (channelState.isOutputOpen())
{ {
CloseStatus closeStatus = CloseStatus.getCloseStatus(frame); CloseStatus closeStatus = CloseStatus.getCloseStatus(frame);
@ -648,8 +651,9 @@ public class WebSocketChannel implements IncomingFrames, FrameHandler.CoreSessio
LOG.debug("ConnectionState: sending close response {}", closeStatus); LOG.debug("ConnectionState: sending close response {}", closeStatus);
// this may race with a rare application close but errors are ignored // this may race with a rare application close but errors are ignored
if (closeStatus==null)
closeStatus = CloseStatus.NO_CODE_STATUS;
close(closeStatus.getCode(), closeStatus.getReason(), Callback.NOOP); close(closeStatus.getCode(), closeStatus.getReason(), Callback.NOOP);
return;
} }
} }
}; };
@ -735,8 +739,9 @@ public class WebSocketChannel implements IncomingFrames, FrameHandler.CoreSessio
@Override @Override
public String toString() public String toString()
{ {
return String.format("WSChannel@%x{%s,%s,af=%b,i/o=%d/%d,fs=%d}->%s", return String.format("WSChannel@%x{%s,%s,%s,af=%b,i/o=%d/%d,fs=%d}->%s",
hashCode(), hashCode(),
behavior,
channelState, channelState,
negotiated, negotiated,
autoFragment, autoFragment,
@ -745,4 +750,67 @@ public class WebSocketChannel implements IncomingFrames, FrameHandler.CoreSessio
maxFrameSize, maxFrameSize,
handler); handler);
} }
static class AbnormalCloseStatus extends CloseStatus
{
public AbnormalCloseStatus(int statusCode, String reasonPhrase)
{
super(statusCode, reasonPhrase);
}
}
private class Flusher extends IteratingCallback
{
private final Queue<FrameEntry> queue = new ArrayDeque<>();
FrameEntry entry;
@Override
protected Action process() throws Throwable
{
synchronized (this)
{
entry = queue.poll();
}
if (entry==null)
return Action.IDLE;
negotiated.getExtensions().sendFrame(entry.frame, this, entry.batch);
return Action.SCHEDULED;
}
@Override
public void succeeded()
{
entry.callback.succeeded();
super.succeeded();
}
@Override
protected void onCompleteFailure(Throwable cause)
{
entry.callback.failed(cause);
Queue<FrameEntry> entries;
synchronized (this)
{
entries = new ArrayDeque<>(queue);
queue.clear();
}
entries.forEach(e-> failEntry(cause, e));
}
private void failEntry(Throwable cause, FrameEntry e)
{
try
{
e.callback.failed(cause);
}
catch(Throwable x)
{
if (cause != x)
cause.addSuppressed(x);
LOG.warn(cause);
}
}
}
} }

View File

@ -33,8 +33,8 @@ public class WebSocketChannelState
CONNECTING, CONNECTING,
CONNECTED, CONNECTED,
OPEN, OPEN,
ICLOSED, ISHUT,
OCLOSED, OSHUT,
CLOSED CLOSED
} }
@ -68,7 +68,11 @@ public class WebSocketChannelState
@Override @Override
public String toString() public String toString()
{ {
return _channelState.toString(); return String.format("%s@%x{%s,i=%s,o=%s,c=%s}",getClass().getSimpleName(),hashCode(),
_channelState,
OpCode.name(_incomingContinuation),
OpCode.name(_outgoingContinuation),
_closeStatus);
} }
@ -85,16 +89,16 @@ public class WebSocketChannelState
return getState()==State.CLOSED; return getState()==State.CLOSED;
} }
public boolean isInOpen() public boolean isInputOpen()
{ {
State state = getState(); State state = getState();
return (state==State.OPEN || state==State.OCLOSED); return (state==State.OPEN || state==State.OSHUT);
} }
public boolean isOutOpen() public boolean isOutputOpen()
{ {
State state = getState(); State state = getState();
return (state==State.OPEN || state==State.ICLOSED); return (state==State.OPEN || state==State.ISHUT);
} }
public CloseStatus getCloseStatus() public CloseStatus getCloseStatus()
@ -118,28 +122,39 @@ public class WebSocketChannelState
} }
} }
public boolean checkOutgoing(Frame frame) throws ProtocolException public boolean onOutgoingFrame(Frame frame) throws ProtocolException
{ {
byte opcode = frame.getOpCode(); byte opcode = frame.getOpCode();
boolean fin = frame.isFin(); boolean fin = frame.isFin();
synchronized (this) synchronized (this)
{ {
if (!isOutOpen()) if (!isOutputOpen())
{
if (opcode == OpCode.CLOSE && CloseStatus.getCloseStatus(frame) instanceof WebSocketChannel.AbnormalCloseStatus)
_channelState = State.CLOSED;
throw new IllegalStateException(_channelState.toString()); throw new IllegalStateException(_channelState.toString());
}
if (opcode == OpCode.CLOSE) if (opcode == OpCode.CLOSE)
{ {
_closeStatus = CloseStatus.getCloseStatus(frame); _closeStatus = CloseStatus.getCloseStatus(frame);
if (_closeStatus instanceof WebSocketChannel.AbnormalCloseStatus)
{
_channelState = State.CLOSED;
return true;
}
switch (_channelState) switch (_channelState)
{ {
case OPEN: case OPEN:
_channelState = State.OCLOSED; _channelState = State.OSHUT;
return false; return false;
case ICLOSED:
case ISHUT:
_channelState = State.CLOSED; _channelState = State.CLOSED;
return true; return true;
default: default:
throw new IllegalStateException(_channelState.toString()); throw new IllegalStateException(_channelState.toString());
} }
@ -153,14 +168,14 @@ public class WebSocketChannelState
return false; return false;
} }
public boolean checkIncoming(Frame frame) throws ProtocolException public boolean onIncomingFrame(Frame frame) throws ProtocolException
{ {
byte opcode = frame.getOpCode(); byte opcode = frame.getOpCode();
boolean fin = frame.isFin(); boolean fin = frame.isFin();
synchronized (this) synchronized (this)
{ {
if (!isInOpen()) if (!isInputOpen())
throw new IllegalStateException(_channelState.toString()); throw new IllegalStateException(_channelState.toString());
if (opcode == OpCode.CLOSE) if (opcode == OpCode.CLOSE)
@ -170,9 +185,9 @@ public class WebSocketChannelState
switch (_channelState) switch (_channelState)
{ {
case OPEN: case OPEN:
_channelState = State.ICLOSED; _channelState = State.ISHUT;
return false; return false;
case OCLOSED: case OSHUT:
_channelState = State.CLOSED; _channelState = State.CLOSED;
return true; return true;
default: default:

View File

@ -18,6 +18,13 @@
package org.eclipse.jetty.websocket.core.internal; package org.eclipse.jetty.websocket.core.internal;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.Executor;
import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.Connection;
@ -34,13 +41,6 @@ import org.eclipse.jetty.websocket.core.MessageTooLargeException;
import org.eclipse.jetty.websocket.core.ProtocolException; import org.eclipse.jetty.websocket.core.ProtocolException;
import org.eclipse.jetty.websocket.core.WebSocketTimeoutException; import org.eclipse.jetty.websocket.core.WebSocketTimeoutException;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.Executor;
/** /**
* Provides the implementation of {@link org.eclipse.jetty.io.Connection} that is suitable for WebSocket * Provides the implementation of {@link org.eclipse.jetty.io.Connection} that is suitable for WebSocket
*/ */
@ -167,22 +167,44 @@ public class WebSocketConnection extends AbstractConnection implements Connectio
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("onClose() of physical connection"); LOG.debug("onClose() of physical connection");
// TODO review all close paths if (!channel.isClosed())
{
IOException e = new IOException("Closed"); IOException e = new IOException("Closed");
channel.onClosed(e); channel.onClosed(e);
}
flusher.onClose();
super.onClose(); super.onClose();
} }
@Override @Override
public boolean onIdleExpired() public boolean onIdleExpired()
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("onIdleExpired()"); LOG.debug("onIdleExpired()");
channel.processError(new WebSocketTimeoutException("Connection Idle Timeout")); // treat as a handler error because socket is still open
channel.processHandlerError(new WebSocketTimeoutException("Connection Idle Timeout"));
return true; return true;
} }
/**
* Event for no activity on connection (read or write)
*
* @return true to signal that the endpoint must be closed, false to keep the endpoint open
*/
@Override
protected boolean onReadTimeout(Throwable timeout)
{
if (LOG.isDebugEnabled())
LOG.debug("onReadTimeout()");
// treat as a handler error because socket is still open
channel.processHandlerError(new WebSocketTimeoutException("Timeout on Read", timeout));
return false;
}
protected void onFrame(Parser.ParsedFrame frame) protected void onFrame(Parser.ParsedFrame frame)
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
@ -219,7 +241,7 @@ public class WebSocketConnection extends AbstractConnection implements Connectio
referenced.release(); referenced.release();
// notify session & endpoint // notify session & endpoint
channel.processError(cause); channel.processHandlerError(cause);
} }
}); });
} }
@ -431,7 +453,7 @@ public class WebSocketConnection extends AbstractConnection implements Connectio
LOG.warn(t.toString()); LOG.warn(t.toString());
BufferUtil.clear(networkBuffer.getBuffer()); BufferUtil.clear(networkBuffer.getBuffer());
releaseNetworkBuffer(); releaseNetworkBuffer();
channel.processError(t); channel.processConnectionError(t);
} }
} }
@ -476,18 +498,6 @@ public class WebSocketConnection extends AbstractConnection implements Connectio
super.onOpen(); super.onOpen();
} }
/**
* Event for no activity on connection (read or write)
*
* @return true to signal that the endpoint must be closed, false to keep the endpoint open
*/
@Override
protected boolean onReadTimeout(Throwable timeout)
{
channel.processError(new WebSocketTimeoutException("Timeout on Read", timeout));
return false;
}
@Override @Override
public void setInputBufferSize(int inputBufferSize) public void setInputBufferSize(int inputBufferSize)
{ {
@ -577,7 +587,6 @@ public class WebSocketConnection extends AbstractConnection implements Connectio
/** /**
* Enqueue a Frame to be sent. * Enqueue a Frame to be sent.
* @see #sendFrameQueue()
* @param frame The frame to queue * @param frame The frame to queue
* @param callback The callback to call once the frame is sent * @param callback The callback to call once the frame is sent
* @param batch True if batch mode is to be used * @param batch True if batch mode is to be used
@ -592,10 +601,6 @@ public class WebSocketConnection extends AbstractConnection implements Connectio
wsf.setMask(mask); wsf.setMask(mask);
} }
flusher.enqueue(frame, callback, batch); flusher.enqueue(frame, callback, batch);
}
void sendFrameQueue()
{
flusher.iterate(); flusher.iterate();
} }
@ -610,7 +615,7 @@ public class WebSocketConnection extends AbstractConnection implements Connectio
public void onCompleteFailure(Throwable x) public void onCompleteFailure(Throwable x)
{ {
super.onCompleteFailure(x); super.onCompleteFailure(x);
channel.processError(x); channel.processConnectionError(x);
} }
} }
} }

View File

@ -18,6 +18,11 @@
package org.eclipse.jetty.websocket.core; package org.eclipse.jetty.websocket.core;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
@ -39,11 +44,6 @@ import org.eclipse.jetty.websocket.core.server.internal.RFC6455Handshaker;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.eclipse.jetty.util.Callback.NOOP; import static org.eclipse.jetty.util.Callback.NOOP;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
@ -65,7 +65,7 @@ public class WebSocketCloseTest extends WebSocketTester
enum State enum State
{ {
OPEN, ICLOSED, OCLOSED OPEN, ISHUT, OSHUT
} }
@AfterEach @AfterEach
@ -93,7 +93,7 @@ public class WebSocketCloseTest extends WebSocketTester
break; break;
} }
case ICLOSED: case ISHUT:
{ {
TestFrameHandler serverHandler = new TestFrameHandler(); TestFrameHandler serverHandler = new TestFrameHandler();
@ -109,12 +109,12 @@ public class WebSocketCloseTest extends WebSocketTester
assertNotNull(frame); assertNotNull(frame);
assertThat(new CloseStatus(frame.getPayload()).getCode(), is(CloseStatus.NORMAL)); assertThat(new CloseStatus(frame.getPayload()).getCode(), is(CloseStatus.NORMAL));
assertThat(server.handler.getCoreSession().toString(), containsString("ICLOSED")); assertThat(server.handler.getCoreSession().toString(), containsString("ISHUT"));
LOG.info("Server: ICLOSED"); LOG.info("Server: ISHUT");
break; break;
} }
case OCLOSED: case OSHUT:
{ {
TestFrameHandler serverHandler = new TestFrameHandler(); TestFrameHandler serverHandler = new TestFrameHandler();
@ -129,8 +129,8 @@ public class WebSocketCloseTest extends WebSocketTester
assertNotNull(frame); assertNotNull(frame);
assertThat(new CloseStatus(frame.getPayload()).getCode(), is(CloseStatus.NORMAL)); assertThat(new CloseStatus(frame.getPayload()).getCode(), is(CloseStatus.NORMAL));
assertThat(server.handler.getCoreSession().toString(), containsString("OCLOSED")); assertThat(server.handler.getCoreSession().toString(), containsString("OSHUT"));
LOG.info("Server: OCLOSED"); LOG.info("Server: OSHUT");
break; break;
} }
@ -140,7 +140,7 @@ public class WebSocketCloseTest extends WebSocketTester
@Test @Test
public void serverClose_ICLOSED() throws Exception public void serverClose_ICLOSED() throws Exception
{ {
setup(State.ICLOSED); setup(State.ISHUT);
server.handler.receivedCallback.poll().succeeded(); server.handler.receivedCallback.poll().succeeded();
Frame frame = receiveFrame(client.getInputStream()); Frame frame = receiveFrame(client.getInputStream());
@ -154,7 +154,7 @@ public class WebSocketCloseTest extends WebSocketTester
@Test @Test
public void serverDifferentClose_ICLOSED() throws Exception public void serverDifferentClose_ICLOSED() throws Exception
{ {
setup(State.ICLOSED); setup(State.ISHUT);
server.sendFrame(CloseStatus.toFrame(CloseStatus.SHUTDOWN)); server.sendFrame(CloseStatus.toFrame(CloseStatus.SHUTDOWN));
server.handler.receivedCallback.poll().succeeded(); server.handler.receivedCallback.poll().succeeded();
@ -171,7 +171,7 @@ public class WebSocketCloseTest extends WebSocketTester
{ {
try (StacklessLogging stackless = new StacklessLogging(WebSocketChannel.class)) try (StacklessLogging stackless = new StacklessLogging(WebSocketChannel.class))
{ {
setup(State.ICLOSED); setup(State.ISHUT);
server.handler.receivedCallback.poll().failed(new Exception("test failure")); server.handler.receivedCallback.poll().failed(new Exception("test failure"));
Frame frame = receiveFrame(client.getInputStream()); Frame frame = receiveFrame(client.getInputStream());
@ -186,7 +186,7 @@ public class WebSocketCloseTest extends WebSocketTester
@Test @Test
public void clientClose_OCLOSED() throws Exception public void clientClose_OCLOSED() throws Exception
{ {
setup(State.OCLOSED); setup(State.OSHUT);
server.handler.getCoreSession().demand(1); server.handler.getCoreSession().demand(1);
client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.NORMAL), true)); client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.NORMAL), true));
assertNotNull(server.handler.receivedFrames.poll(10, TimeUnit.SECONDS)); assertNotNull(server.handler.receivedFrames.poll(10, TimeUnit.SECONDS));
@ -201,7 +201,7 @@ public class WebSocketCloseTest extends WebSocketTester
@Test @Test
public void clientDifferentClose_OCLOSED() throws Exception public void clientDifferentClose_OCLOSED() throws Exception
{ {
setup(State.OCLOSED); setup(State.OSHUT);
server.handler.getCoreSession().demand(1); server.handler.getCoreSession().demand(1);
client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.BAD_PAYLOAD), true)); client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.BAD_PAYLOAD), true));
assertNotNull(server.handler.receivedFrames.poll(10, TimeUnit.SECONDS)); assertNotNull(server.handler.receivedFrames.poll(10, TimeUnit.SECONDS));
@ -218,7 +218,7 @@ public class WebSocketCloseTest extends WebSocketTester
{ {
try (StacklessLogging stackless = new StacklessLogging(WebSocketChannel.class)) try (StacklessLogging stackless = new StacklessLogging(WebSocketChannel.class))
{ {
setup(State.OCLOSED); setup(State.OSHUT);
server.handler.getCoreSession().demand(1); server.handler.getCoreSession().demand(1);
client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.NORMAL), true)); client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.NORMAL), true));
assertNotNull(server.handler.receivedFrames.poll(10, TimeUnit.SECONDS)); assertNotNull(server.handler.receivedFrames.poll(10, TimeUnit.SECONDS));
@ -246,7 +246,7 @@ public class WebSocketCloseTest extends WebSocketTester
@Test @Test
public void clientSendsBadFrame_OCLOSED() throws Exception public void clientSendsBadFrame_OCLOSED() throws Exception
{ {
setup(State.OCLOSED); setup(State.OSHUT);
client.getOutputStream().write(RawFrameBuilder.buildFrame(OpCode.PONG, "pong frame not masked", false)); client.getOutputStream().write(RawFrameBuilder.buildFrame(OpCode.PONG, "pong frame not masked", false));
server.handler.getCoreSession().demand(1); server.handler.getCoreSession().demand(1);
@ -258,7 +258,7 @@ public class WebSocketCloseTest extends WebSocketTester
@Test @Test
public void clientSendsBadFrame_ICLOSED() throws Exception public void clientSendsBadFrame_ICLOSED() throws Exception
{ {
setup(State.ICLOSED); setup(State.ISHUT);
client.getOutputStream().write(RawFrameBuilder.buildFrame(OpCode.PONG, "pong frame not masked", false)); client.getOutputStream().write(RawFrameBuilder.buildFrame(OpCode.PONG, "pong frame not masked", false));
assertFalse(server.handler.closed.await(250, TimeUnit.MILLISECONDS)); assertFalse(server.handler.closed.await(250, TimeUnit.MILLISECONDS));
@ -286,7 +286,7 @@ public class WebSocketCloseTest extends WebSocketTester
@Test @Test
public void clientAborts_OCLOSED() throws Exception public void clientAborts_OCLOSED() throws Exception
{ {
setup(State.OCLOSED); setup(State.OSHUT);
client.close(); client.close();
assertFalse(server.handler.closed.await(250, TimeUnit.MILLISECONDS)); assertFalse(server.handler.closed.await(250, TimeUnit.MILLISECONDS));
@ -299,7 +299,7 @@ public class WebSocketCloseTest extends WebSocketTester
@Test @Test
public void clientAborts_ICLOSED() throws Exception public void clientAborts_ICLOSED() throws Exception
{ {
setup(State.ICLOSED); setup(State.ISHUT);
client.close(); client.close();
assertFalse(server.handler.closed.await(250, TimeUnit.MILLISECONDS)); assertFalse(server.handler.closed.await(250, TimeUnit.MILLISECONDS));
@ -330,7 +330,7 @@ public class WebSocketCloseTest extends WebSocketTester
@Test @Test
public void onFrameThrows_OCLOSED() throws Exception public void onFrameThrows_OCLOSED() throws Exception
{ {
setup(State.OCLOSED); setup(State.OSHUT);
client.getOutputStream().write(RawFrameBuilder.buildFrame(OpCode.BINARY, "binary", true)); client.getOutputStream().write(RawFrameBuilder.buildFrame(OpCode.BINARY, "binary", true));
@ -478,7 +478,7 @@ public class WebSocketCloseTest extends WebSocketTester
public boolean isOpen() public boolean isOpen()
{ {
return handler.getCoreSession().isOpen(); return handler.getCoreSession().isOutputOpen();
} }
} }
} }

View File

@ -18,6 +18,11 @@
package org.eclipse.jetty.websocket.core.client; package org.eclipse.jetty.websocket.core.client;
import java.net.URI;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
@ -45,11 +50,6 @@ import org.hamcrest.Matchers;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.net.URI;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
@ -208,7 +208,7 @@ public class WebSocketClientServerTest
public boolean isOpen() public boolean isOpen()
{ {
return handler.getCoreSession().isOpen(); return handler.getCoreSession().isOutputOpen();
} }
} }
@ -272,7 +272,7 @@ public class WebSocketClientServerTest
public boolean isOpen() public boolean isOpen()
{ {
return handler.getCoreSession().isOpen(); return handler.getCoreSession().isOutputOpen();
} }
} }

View File

@ -18,6 +18,9 @@
package org.eclipse.jetty.websocket.core.extensions; package org.eclipse.jetty.websocket.core.extensions;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.util.DecoratedObjectFactory; import org.eclipse.jetty.util.DecoratedObjectFactory;
@ -35,9 +38,6 @@ import org.eclipse.jetty.websocket.core.internal.IdentityExtension;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -80,7 +80,7 @@ public class ExtensionStackTest
// Setup Listeners // Setup Listeners
IncomingFrames session = new IncomingFramesCapture(); IncomingFrames session = new IncomingFramesCapture();
OutgoingFrames connection = new OutgoingFramesCapture(); OutgoingFrames connection = new OutgoingFramesCapture();
stack.connect(session, connection, null); stack.initialize(session, connection, null);
// Dump // Dump
LOG.debug("{}", stack.dump()); LOG.debug("{}", stack.dump());
@ -104,7 +104,7 @@ public class ExtensionStackTest
// Setup Listeners // Setup Listeners
IncomingFrames session = new IncomingFramesCapture(); IncomingFrames session = new IncomingFramesCapture();
OutgoingFrames connection = new OutgoingFramesCapture(); OutgoingFrames connection = new OutgoingFramesCapture();
stack.connect(session, connection, null); stack.initialize(session, connection, null);
// Dump // Dump
LOG.debug("{}", stack.dump()); LOG.debug("{}", stack.dump());

View File

@ -18,6 +18,10 @@
package org.eclipse.jetty.websocket.core.extensions; package org.eclipse.jetty.websocket.core.extensions;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
@ -44,10 +48,6 @@ import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
import org.eclipse.jetty.websocket.core.server.internal.RFC6455Handshaker; import org.eclipse.jetty.websocket.core.server.internal.RFC6455Handshaker;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import static org.eclipse.jetty.util.Callback.NOOP; import static org.eclipse.jetty.util.Callback.NOOP;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -218,7 +218,7 @@ public class ValidationExtensionTest extends WebSocketTester
public boolean isOpen() public boolean isOpen()
{ {
return handler.getCoreSession().isOpen(); return handler.getCoreSession().isOutputOpen();
} }
} }
} }

View File

@ -18,6 +18,12 @@
package org.eclipse.jetty.websocket.core.server; package org.eclipse.jetty.websocket.core.server;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.NetworkConnector;
@ -46,12 +52,6 @@ import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
@ -547,7 +547,7 @@ public class WebSocketServerTest extends WebSocketTester
public boolean isOpen() public boolean isOpen()
{ {
return handler.getCoreSession().isOpen(); return handler.getCoreSession().isOutputOpen();
} }
} }
} }

View File

@ -436,7 +436,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version> <version>3.1.1</version>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.eclipse.jetty.toolchain</groupId> <groupId>org.eclipse.jetty.toolchain</groupId>