I'm writing a WebSocket client in a java application, using the Jetty 9.4.18 libraries.
I'm pretty new to WebSockets, so I started testing using the two sample classes from the Jetty documentation, connecting to echo.websocket.org
The test runs fine when I connect without SSL, but if fails when the connection is done to wss://echo.websocket.org
I always get the same exception:
java.io.EOFException: HttpConnectionOverHTTP#50371e9d::DecryptedEndPoint#6dc65fc2{echo.websocket.org/174.129.224.73:443<->/192.168.1.34:60521,OPEN,fill=-,flush=C,to=226/0}
at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.earlyEOF(HttpReceiverOverHTTP.java:338)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:1551)
at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.shutdown(HttpReceiverOverHTTP.java:209)
at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.process(HttpReceiverOverHTTP.java:147)
at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:73)
at org.eclipse.jetty.client.http.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:133)
at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:155)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:411)
at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:305)
at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:159)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
at java.lang.Thread.run(Thread.java:748)
It looks like the server closes without answering to the handshake request.
I am aware of SslContextFactory, but my understanding is that it should be used only if you need your own TrustStore or KeyStore, or for other special cases.
Note also that after some failed attempt I downloaded another websocket implementation from https://github.com/TooTallNate/Java-WebSocket, and it works fine with both ws and wss, without setting anything specific for SSL.
However for this project I'm bind to use Jetty.
The code I'm using is exactly the sample from Jetty documentation at https://www.eclipse.org/jetty/documentation/9.4.x/jetty-websocket-client-api.html
the only change I did was to add an onError method to SimpleEchoSocket, that dumps the full exception stack.
Am I missing something?
Thanks in advance!
Unfortunately, websocket.org (and Kaazing host/proxy) has a bunch of TLS issues at this point in time, so using their public servers are not sane choice right now.
Here's a different demo, also using TLS and WebSocket, against a stackexchange server with a proper and sane TLS/SSL implementation.
This was written against Jetty 9.4.18.v20190429
package org.eclipse.jetty.demo;
import java.net.URI;
import java.util.concurrent.Future;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.client.WebSocketClient;
#WebSocket
public class SecureClientSocket
{
private static final Logger LOG = Log.getLogger(SecureClientSocket.class);
public static void main(String[] args)
{
String url = "wss://qa.sockets.stackexchange.com/";
SslContextFactory ssl = new SslContextFactory.Client();
ssl.setEndpointIdentificationAlgorithm("HTTPS");
HttpClient http = new HttpClient(ssl);
WebSocketClient client = new WebSocketClient(http);
try
{
http.start();
client.start();
SecureClientSocket socket = new SecureClientSocket();
Future<Session> fut = client.connect(socket, URI.create(url));
Session session = fut.get();
session.getRemote().sendString("Hello");
session.getRemote().sendString("155-questions-active");
}
catch (Throwable t)
{
LOG.warn(t);
}
finally
{
stop(http);
stop(client);
}
}
private static void stop(LifeCycle lifeCycle)
{
try
{
lifeCycle.stop();
}
catch (Exception e)
{
e.printStackTrace();
}
}
#OnWebSocketConnect
public void onConnect(Session sess)
{
LOG.info("onConnect({})", sess);
}
#OnWebSocketClose
public void onClose(int statusCode, String reason)
{
LOG.info("onClose({}, {})", statusCode, reason);
}
#OnWebSocketError
public void onError(Throwable cause)
{
LOG.warn(cause);
}
#OnWebSocketMessage
public void onMessage(String msg)
{
LOG.info("onMessage() - {}", msg);
}
}
Related
The WebSocket is working perfectly in localhost (tomcat) . but when i host (Openshift - tomcat) it immediately disconnects and not firing the onMessage method. I've checked the header and the status code is Status Code:101 Switching Protocols.
Here is my socket.
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
#ServerEndpoint("/TestSocket")
public class TestSocket {
#OnOpen
public void onOpen(Session session) {
try {
session.getBasicRemote().sendText("Connected");
} catch (IOException e) {
e.printStackTrace();
}
}
#OnMessage
public void onMessage(Session session, String message) {
System.out.println("New message : " + message);
try {
session.getBasicRemote().sendText("Message received -> :" + message);
} catch (IOException e) {
e.printStackTrace();
}
}
#OnClose
public void onClose() {
System.out.println("Closed");
}
}
Here is the live socket ws://shifar-shifz.rhcloud.com:8000/MyTestProject/testWebSocket. I can't figure out what the problem is. Please help me.
EDIT
I am using the Tomcat 7 (JBoss EWS 2.0) cartridge. The project was deployed through a WAR file.
I found it's working when i remove the web-socket-api.jar from the lib after the artifact building. I think the Openshift already contain another web-socket-api.jar in their server. and can't contain any duplicate of the existing jars/libs.
I'm new to messing around with APIs (both official and unofficial) and I'm using one called JavaSnap. I've been messing around with a very basic implementation of the example code, but have been running into errors. Here is the very basic code:
Snapchat snapchat = Snapchat.login("xxxx", "xxxxx");
Firstly I ran into loads of ClassNotFound errors and had to keep on downloading apache modules (commons, httpcomponents etc.) to allow the program to progress, but being class files this meant I couldn't see all at once what modules I needed to download. So if anyone wants to tell me how wrong I'm doing something feel free.
Anyway, now having cleared up all the ClassNotFound exceptions (I hope) I'm getting the following exception:
com.mashape.unirest.http.exceptions.UnirestException: javax.net.ssl.SSLPeerUnverifiedException: Host name 'feelinsonice-hrd.appspot.com' does not match the certificate subject provided by the peer (CN=*.appspot.com, O=Google Inc, L=Mountain View, ST=California, C=US)
at com.mashape.unirest.http.HttpClientHelper.request(HttpClientHelper.java:146)
at com.mashape.unirest.request.BaseRequest.asJson(BaseRequest.java:68)
at com.habosa.javasnap.Snapchat.requestJson(Snapchat.java:953)
at com.habosa.javasnap.Snapchat.login(Snapchat.java:160)
at Tester.go(Tester.java:21)
As I understand it, this is because I need to enable trusting all certificates, however to do this I believe I'd need to use HostNameVerifiers with SSLSocketFactorys, but I can't really begin to mess around with this as I only have the source for the JavaSnap API, and tracing the error up the stack the most recent method available for me to edit is this:
private static HttpResponse<JsonNode> requestJson(String path, Map<String, Object> params, File file) throws UnirestException {
MultipartBody req = prepareRequest(path, params, file);
// Execute and return response as JSON
HttpResponse<JsonNode> resp = req.asJson();
// Record
lastRequestPath = path;
lastResponse = resp;
lastResponseBodyClass = JsonNode.class;
return resp;
My question is, am I actually on the right lines with my thinking? If I am how can I achieve my goal of eliminating this error / trusting certificates? If I'm not then what in fact is the problem?
Thanks very much
i answer this old question to remember my search
the certificate error solution is a combination from a few places
https://github.com/Mashape/unirest-java/issues/70, where i started.
http://literatejava.com/networks/ignore-ssl-certificate-errors-apache-httpclient-4-4/ very good explanation.
http://www.baeldung.com/httpclient-ssl, solution for all versions.
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.SSLContext;
import javax.security.cert.CertificateException;
import javax.security.cert.X509Certificate;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
public class XXX {
private static HttpClient unsafeHttpClient;
static {
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy() {
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}).build();
unsafeHttpClient = HttpClients.custom().setSSLContext(sslContext)
.setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
e.printStackTrace();
}
}
public static HttpClient getClient() {
return unsafeHttpClient;
}
public static void main(String[] args) {
try {
HttpClient creepyClient = RestUnirestClient.getClient();
Unirest.setHttpClient(creepyClient);
HttpResponse<JsonNode> response = Unirest.get("https://httpbin.org/get?show_env=1").asJson();
System.out.println(response.getBody().toString());
} catch (UnirestException e) {
e.printStackTrace();
}
}
}
I am using CuratorFramework (I'm still a newbie) in order to connect to a Zookeeper instance. I would like to import a configuration but before that I would like to test that my program is able to connect to Zookeeper. So far I have something like that:
public Boolean zookeeperRunning() {
CuratorFramework curatorFramework =
CuratorFrameworkFactory.newClient(zookeeperConn, new RetryOneTime(1));
curatorFramework.start();
CuratorZookeeperClient zkClient = curatorFramework.getZookeeperClient();
return zkClient.isConnected();
}
I've already started ZooKeeper on my local machine and I checked the connection with zkCli and the client is able to connect to it. The zookeeperCon variable is set to "127.0.0.1:2181" (I tried with localhost:2181 as well). The problem is that the above method always returns false despite the fact that zkServer is up n running. Most probably, the syntax is not correct but I could not find a solution online. Could you please help me with why the above code cannot find the zkServer which is up and running?
You can use a builder to create a configured client and setup a listener to monitor your zk instance's state:
// start client
client = CuratorFrameworkFactory.builder()
.connectString("localhost:2181")
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.namespace("heavenize")
.build();
client.getConnectionStateListenable().addListener(new ConnectionStateListener() {
#Override
public void stateChanged(CuratorFramework client, ConnectionState newState)
{
log.info("State changed to: "+newState);
}
});
}
You should first connect to zookeeper after you get the zkClient, if success, then check the isConnected status. Demo code below(Refer: here):
private static CuratorFramework buildConnection(String url) {
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(url, new ExponentialBackoffRetry(100, 6));
// start connection
curatorFramework.start();
// wait 3 second to establish connect
try {
curatorFramework.blockUntilConnected(3, TimeUnit.SECONDS);
if (curatorFramework.getZookeeperClient().isConnected()) {
return curatorFramework.usingNamespace("");
}
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
// fail situation
curatorFramework.close();
throw new RuntimeException("failed to connect to zookeeper service : " + url);
}
you should connect to zookeeper server then check it. for example:
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.test.TestingServer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertTrue;
public class ZkClientTest {
TestingServer zkServer;
#Before
public void startZookeeper() throws Exception {
zkServer = new TestingServer(2181);
zkServer.start();
}
#After
public void stopZookeeper() throws IOException {
zkServer.stop();
}
#Test
public void should_connect_to_zookeeper_server_when_config_use_default_localhost_2181()
throws InterruptedException {
CuratorFramework client = ZkClient.getInstance().getClient();
try {
client.blockUntilConnected(3, TimeUnit.SECONDS);
assertTrue(ZkClient.getInstance().getClient().getZookeeperClient().isConnected());
} finally {
ZkClient.getInstance().close();
}
}
}
I try run this example:
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint(value = "/chat")
public class ChatServer {
private static final Logger LOGGER =
Logger.getLogger(ChatServer.class.getName());
#OnOpen
public void onOpen(Session session) {
LOGGER.log(Level.INFO, "New connection with client: {0}",
session.getId());
}
#OnMessage
public String onMessage(String message, Session session) {
LOGGER.log(Level.INFO, "New message from Client [{0}]: {1}",
new Object[] {session.getId(), message});
return "Server received [" + message + "]";
}
#OnClose
public void onClose(Session session) {
LOGGER.log(Level.INFO, "Close connection for client: {0}",
session.getId());
}
#OnError
public void onError(Throwable exception, Session session) {
LOGGER.log(Level.INFO, "Error for client: {0}", session.getId());
}
}
I use Tomcat 7.0.47, I check link: ws://localhost/Tests/chat.
Do I need register this websocket or add some things in web.xml?
Any idea why is not working for me?
I had the same problem trying to use WebSocket API on Tomcat 7.0.47. The error message being displayed client side wasn't any help at all and my server side endpoint was never being created.
After much wasted time I found it was due to way I had set the dependency for javax.websocket-api. I'm using Maven which has the default scope as compile which causes problems as Tomcat has the websocket-api.jar in its lib folder. Setting the dependency to provided solved it.
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
Hope this helps
It's also worth noting that if running behind Apache you will need mod_proxy_wstunnel and if using IIS you will need version 8.0 as anything prior does not support websockets.
I have made a simple ActiveMQ application.
It listens to a queue. If a message comes, print out the dataId
Here is the code:
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
import org.apache.activemq.ActiveMQConnectionFactory;
public class MQ implements MessageListener {
private Connection connection = null;
private Session session = null;
private Destination destination = null;
private void errorOnConnection(JMSException e) {
System.out.println("MQ is having problems. Exception::"+ e);
}
private void init() throws JMSException {
String BROKER_URL = "failover:(tcp://myQueue001:61616,tcp://myQueue002:61616)?randomize=false";
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
connection = connectionFactory.createConnection("user", "password");
connection.setExceptionListener(
new ExceptionListener() {
#Override public void onException(JMSException e) {
errorOnConnection(e);
}
});
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
destination = session.createQueue("myQueue");
MessageConsumer consumer = session.createConsumer(destination);
consumer.setMessageListener(this);
}
public boolean start() {
try {
if(connection==null )
init();
connection.start();
} catch (Exception e) {
System.out.println("MQListener cannot be started, exception: " + e);
}
return true;
}
#Override
public void onMessage(Message msg) {
try {
if(msg instanceof MapMessage){
MapMessage m = (MapMessage)msg;
int dataId = m.getIntProperty("dataId");
System.out.println(dataId);
}
} catch (JMSException e) {
System.out.println("Got an exception: " + e);
}
}
public static void main(String[] args) {
MQ mq = new MQ();
mq.start();
}
}
It works fine and does what it is meant to accomplish.
However, the problem is that it can run only for several days. After several days, it just quits silently without any exceptions or error.
The queue I am listening to is from 3rd party. From a guy there, the queue sometimes will be closed or restarted or interrupted.
But I think even if that happen, the default ActiveMQ settings will handle it by consistently reconnect to it, right? (according to http://activemq.apache.org/cms/configuring.html)
So any other possible causes which lead my code to quitting silently?
Depends on bit on your version. Since you are not doing anything yourself to keep the application running but instead depending on the ActiveMQ code to keep at least one non-deamon thread running. In some ActiveMQ versions the client wasn't always doing this so your application could quite while a failover was occurring. Best bet is to switch to v5.8.0 which I believe had some fixes for this.
You could add some polling code in main to read something from console or what not to ensure that the client stays up until you are sure you want it to go down.