You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by "l.penet@senat.fr" <l....@senat.fr> on 2016/07/18 14:25:30 UTC
Websockets : differents behaviours on connection when using WS or WSS
Hi.
I am using Tomcat 8.0.36 with Atmosphere 2.4.5 (
https://github.com/Atmosphere/atmosphere ) to implement WebSockets with
fallbacks such as long polling.
I am writing tests using Tomcat JSR356 implementation.
I studied your WebSocket samples and I am using a fake trustore :
ClientEndpointConfig cec =
ClientEndpointConfig.Builder.create().build();
File keyStorePath = new File("path/to/test.keystore");
cec.getUserProperties().put(WsWebSocketContainer.SSL_TRUSTSTORE_PROPERTY,
keyStorePath.getAbsolutePath());
cec.getUserProperties().put(WsWebSocketContainer.SSL_TRUSTSTORE_PWD_PROPERTY,
"pouetpouet");
or similarly I am setting the WsWebSocketContainer.SSL_CONTEXT_PROPERTY
to a passthrough ssl context, accepting all certificates (it's just for
tests, it's ok).
My test looks like :
WebSocketContainer container =
ContainerProvider.getWebSocketContainer();
RecordingReceivedMessagesSocket socket = new
RecordingReceivedMessagesSocket();
URI echoUri = new URI(getWSTestURI("/ws/delaislimites"));
ClientEndpointConfig cec =
ClientEndpointConfig.Builder.create().build();
File keyStorePath = new File("path/to/test.keystore");
cec.getUserProperties().put(WsWebSocketContainer.SSL_TRUSTSTORE_PROPERTY,
keyStorePath.getAbsolutePath());
cec.getUserProperties().put(WsWebSocketContainer.SSL_TRUSTSTORE_PWD_PROPERTY,
"pouetpouet");
Session wsSession = container.connectToServer(socket, cec,
echoUri);
socket.close();
log.info("Attente de la fermeture de la socket");
Assert.assertTrue(socket.awaitClose(10,TimeUnit.SECONDS));
log.info("La socket doit avoir re�u OK");
Assert.assertTrue(socket.getReceivedMessages().contains("OK"));
Assert.assertTrue(true);
RecordingReceivedMessagesSocket class looks like :
@ClientEndpoint
@Log4j2
@Getter
public class RecordingReceivedMessagesSocket extends BaseTestSocket
{
List<String> receivedMessages = new ArrayList<>();
@OnMessage
public String onMessage(String msg, Session session)
{
log.info("Message re�u : {}", msg);
this.receivedMessages.add(msg);
return msg;
}
}
@ClientEndpoint
@Log4j2
@Getter
public class BaseTestSocket extends Endpoint
{
private Session session;
private final CountDownLatch closeLatch;
public BaseTestSocket()
{
this.closeLatch = new CountDownLatch(1);
}
@OnOpen
@Override
public void onOpen(Session session, EndpointConfig config)
{
log.info("Connexion �tablie.");
this.session = session;
}
public boolean awaitClose(int duration, TimeUnit unit) throws
InterruptedException
{
return this.closeLatch.await(duration,unit);
}
@OnClose
@Override
public void onClose(Session session, CloseReason reason)
{
log.info("Connexion ferm�e.");
this.closeLatch.countDown();
}
public void write(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
public void writeObject(Object object) throws IOException,
EncodeException {
this.session.getBasicRemote().sendObject(object);
}
public void close() throws IOException {
this.session.close();
}
}
When I implement getWSTestURI() so that it returns a url for a non
encrypted request, such as ws://localhost/8084/ws/delaislimites :
* RecordingReceivedMessagesSocket.onMessage gets called with the
immediate server reply ("OK").
The ServerEndPoint looks like :
@Log4j2
@ManagedService(path = "/ws/delaislimites")
public class WSDelaisLimites {
@Inject
private BroadcasterFactory factory;
@Inject
private AtmosphereResourceFactory resourceFactory;
@Inject
private MetaBroadcaster metaBroadcaster;
@Ready(encoders = {JacksonEncoder.class})
@DeliverTo(DeliverTo.DELIVER_TO.ALL)
public String onReady(final AtmosphereResource r) {
log.info("Browser {} connected.", r.uuid());
return "OK";
}
/**
* Invoked when the client disconnect or when an unexpected closing
of the underlying connection happens.
*
* @param event
*/
@Disconnect
public void onDisconnect(AtmosphereResourceEvent event) {
if (event.isCancelled()) {
log.info("Browser {} unexpectedly disconnected",
event.getResource().uuid());
} else if (event.isClosedByClient()) {
log.info("Browser {} closed the connection",
event.getResource().uuid());
}
}
/* ... */
@Message
public String onMessage(String message) throws IOException {
StringBuilder sb = new StringBuilder();
sb.append("Re�u le message texte ");
sb.append(message);
log.info(sb.toString());
return message;
}
}
So, I am getting "OK".
When I connect through SSL, with a url like
wss://localhost:8765/ws/delaislimites :
* RecordingReceivedMessagesSocket.onMessage never gets called with the
"OK" reply.
I tried to add the following block :
CountDownLatch latch = new CountDownLatch(1);
BasicText handler = new BasicText(latch);
wsSession.addMessageHandler(handler);
socket.write("Pouet");
Assert.assertTrue(handler.getLatch().await(10, TimeUnit.SECONDS));
between
Session wsSession = container.connectToServer(socket, cec,
echoUri);
and
socket.close();
to check that some other stuff works (like in your tests).
As expected, it does, and the BasicText handler gets a reply from the
server.
However, it does not get the initial reply too (and it seems quite
normal to me as it is added too late).
If I only add a
socket.write("Pouet");
RecordingReceivedMessagesSocket.onMessage is also called with server
messages.
So, is this difference in behaviour to be expected ? Is there some point
in spec that I missed that commands it ?
Thanks in advance for your explanations.
Ludovic
|
| AVANT D'IMPRIMER, PENSEZ A L'ENVIRONNEMENT.
|
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org
Re: Websockets : differents behaviours on connection when using WS or
WSS
Posted by Mark Thomas <ma...@apache.org>.
On 18/07/2016 16:25, l.penet@senat.fr wrote:
> Hi.
>
> I am using Tomcat 8.0.36 with Atmosphere 2.4.5 (
> https://github.com/Atmosphere/atmosphere ) to implement WebSockets with
> fallbacks such as long polling.
Can you reproduce this without Atmosphere? If not, that suggests an
Atmosphere bug. If yes, then it is likely there is a Tomcat bug.
It could also be a bug in you test case.
The simpler the test case the easier it will be to identify the root cause.
<snip/>
> So, is this difference in behaviour to be expected ?
No.
> Is there some point
> in spec that I missed that commands it ?
No.
Mark
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org
Re: Websockets : differents behaviours on connection when using WS or
WSS
Posted by "l.penet@senat.fr" <l....@senat.fr>.
On 18/07/2016 16:25, l.penet@senat.fr wrote:
> Hi.
>
> I am using Tomcat 8.0.36 with Atmosphere 2.4.5 (
> https://github.com/Atmosphere/atmosphere ) to implement WebSockets
> with fallbacks such as long polling.
>
> I am writing tests using Tomcat JSR356 implementation.
>
> I studied your WebSocket samples and I am using a fake trustore :
>
> ClientEndpointConfig cec =
> ClientEndpointConfig.Builder.create().build();
> File keyStorePath = new File("path/to/test.keystore");
> cec.getUserProperties().put(WsWebSocketContainer.SSL_TRUSTSTORE_PROPERTY,
> keyStorePath.getAbsolutePath());
> cec.getUserProperties().put(WsWebSocketContainer.SSL_TRUSTSTORE_PWD_PROPERTY,
> "pouetpouet");
>
> or similarly I am setting the
> WsWebSocketContainer.SSL_CONTEXT_PROPERTY to a passthrough ssl
> context, accepting all certificates (it's just for tests, it's ok).
>
>
> My test looks like :
>
> WebSocketContainer container =
> ContainerProvider.getWebSocketContainer();
> RecordingReceivedMessagesSocket socket = new
> RecordingReceivedMessagesSocket();
>
> URI echoUri = new URI(getWSTestURI("/ws/delaislimites"));
>
> ClientEndpointConfig cec =
> ClientEndpointConfig.Builder.create().build();
> File keyStorePath = new File("path/to/test.keystore");
> cec.getUserProperties().put(WsWebSocketContainer.SSL_TRUSTSTORE_PROPERTY,
> keyStorePath.getAbsolutePath());
> cec.getUserProperties().put(WsWebSocketContainer.SSL_TRUSTSTORE_PWD_PROPERTY,
> "pouetpouet");
>
> Session wsSession = container.connectToServer(socket, cec,
> echoUri);
I realised that my message was incomplete and, by the way, found the
answer myself.
When I do not go SSL, I do not call the same version of connectToServer.
I am doing
Session wsSession = container.connectToServer(socket, echoUri);
This version os connectToServer gets an Object rather than a endpoint as
first parameter and, among other things, looks for the ClientEndpoint
annotation.
If it finds it, it wraps it in a PojoEndpointClient (pojo is the first
parameter of connectToServer) :
Endpoint ep = new PojoEndpointClient(pojo,
Arrays.asList(annotation.decoders()));
So, if I do
container.connectToServer(new PojoEndpointClient(socket, new
ArrayList<>()), cec, echoUri);
everything is fine, because of the inits that PojoEndpointClient does.
Sorry for the noise.
Ludovic
>
> socket.close();
> log.info("Attente de la fermeture de la socket");
> Assert.assertTrue(socket.awaitClose(10,TimeUnit.SECONDS));
> log.info("La socket doit avoir re�u OK");
> Assert.assertTrue(socket.getReceivedMessages().contains("OK"));
> Assert.assertTrue(true);
>
> RecordingReceivedMessagesSocket class looks like :
>
>
> @ClientEndpoint
> @Log4j2
> @Getter
> public class RecordingReceivedMessagesSocket extends BaseTestSocket
> {
> List<String> receivedMessages = new ArrayList<>();
>
> @OnMessage
> public String onMessage(String msg, Session session)
> {
> log.info("Message re�u : {}", msg);
> this.receivedMessages.add(msg);
> return msg;
> }
> }
>
> @ClientEndpoint
> @Log4j2
> @Getter
> public class BaseTestSocket extends Endpoint
> {
> private Session session;
>
> private final CountDownLatch closeLatch;
>
> public BaseTestSocket()
> {
> this.closeLatch = new CountDownLatch(1);
> }
>
> @OnOpen
> @Override
> public void onOpen(Session session, EndpointConfig config)
> {
> log.info("Connexion �tablie.");
> this.session = session;
> }
>
> public boolean awaitClose(int duration, TimeUnit unit) throws
> InterruptedException
> {
> return this.closeLatch.await(duration,unit);
> }
>
> @OnClose
> @Override
> public void onClose(Session session, CloseReason reason)
> {
> log.info("Connexion ferm�e.");
> this.closeLatch.countDown();
> }
>
> public void write(String message) throws IOException {
> this.session.getBasicRemote().sendText(message);
> }
>
> public void writeObject(Object object) throws IOException,
> EncodeException {
> this.session.getBasicRemote().sendObject(object);
> }
>
> public void close() throws IOException {
> this.session.close();
> }
> }
>
>
> When I implement getWSTestURI() so that it returns a url for a non
> encrypted request, such as ws://localhost/8084/ws/delaislimites :
>
> * RecordingReceivedMessagesSocket.onMessage gets called with the
> immediate server reply ("OK").
>
>
> The ServerEndPoint looks like :
>
>
> @Log4j2
> @ManagedService(path = "/ws/delaislimites")
> public class WSDelaisLimites {
> @Inject
> private BroadcasterFactory factory;
>
> @Inject
> private AtmosphereResourceFactory resourceFactory;
>
> @Inject
> private MetaBroadcaster metaBroadcaster;
>
> @Ready(encoders = {JacksonEncoder.class})
> @DeliverTo(DeliverTo.DELIVER_TO.ALL)
> public String onReady(final AtmosphereResource r) {
> log.info("Browser {} connected.", r.uuid());
> return "OK";
> }
>
> /**
> * Invoked when the client disconnect or when an unexpected
> closing of the underlying connection happens.
> *
> * @param event
> */
> @Disconnect
> public void onDisconnect(AtmosphereResourceEvent event) {
> if (event.isCancelled()) {
> log.info("Browser {} unexpectedly disconnected",
> event.getResource().uuid());
> } else if (event.isClosedByClient()) {
> log.info("Browser {} closed the connection",
> event.getResource().uuid());
> }
> }
>
> /* ... */
> @Message
> public String onMessage(String message) throws IOException {
> StringBuilder sb = new StringBuilder();
> sb.append("Re�u le message texte ");
> sb.append(message);
> log.info(sb.toString());
> return message;
> }
> }
>
> So, I am getting "OK".
>
>
> When I connect through SSL, with a url like
> wss://localhost:8765/ws/delaislimites :
>
> * RecordingReceivedMessagesSocket.onMessage never gets called with the
> "OK" reply.
>
>
> I tried to add the following block :
>
> CountDownLatch latch = new CountDownLatch(1);
> BasicText handler = new BasicText(latch);
> wsSession.addMessageHandler(handler);
> socket.write("Pouet");
> Assert.assertTrue(handler.getLatch().await(10,
> TimeUnit.SECONDS));
>
> between
>
> Session wsSession = container.connectToServer(socket, cec,
> echoUri);
>
> and
>
> socket.close();
>
> to check that some other stuff works (like in your tests).
>
> As expected, it does, and the BasicText handler gets a reply from the
> server.
>
> However, it does not get the initial reply too (and it seems quite
> normal to me as it is added too late).
>
> If I only add a
>
> socket.write("Pouet");
>
> RecordingReceivedMessagesSocket.onMessage is also called with server
> messages.
>
> So, is this difference in behaviour to be expected ? Is there some
> point in spec that I missed that commands it ?
>
> Thanks in advance for your explanations.
>
> Ludovic
>
|
| AVANT D'IMPRIMER, PENSEZ A L'ENVIRONNEMENT.
|
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org