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:
commit
d37dfd4357
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
source.. = src/main/java/
|
|
||||||
output.. = target/classes/
|
|
||||||
bin.includes = META-INF/,\
|
|
||||||
.
|
|
||||||
src.includes = META-INF/
|
|
|
@ -1,5 +0,0 @@
|
||||||
source.. = src/main/java/
|
|
||||||
output.. = target/classes/
|
|
||||||
bin.includes = META-INF/,\
|
|
||||||
.
|
|
||||||
src.includes = META-INF/
|
|
|
@ -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/
|
|
|
@ -1,4 +0,0 @@
|
||||||
source.. = src/main/java/
|
|
||||||
output.. = target/classes/
|
|
||||||
bin.includes = META-INF/,\
|
|
||||||
.
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
|
@ -0,0 +1 @@
|
||||||
|
invoker.goals = generate-resources
|
|
@ -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>
|
|
@ -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" )
|
|
@ -0,0 +1 @@
|
||||||
|
Comment: Jetty Runner
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 & reason)
|
* Representation of a WebSocket Close (status code & 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))
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue