From a7849055e604fefe14ba976477b4c5ef6f2e6381 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Mon, 8 Feb 2016 21:26:36 +0300 Subject: [PATCH 01/72] proxy support --- .../client/HttpConnectionProvider.java | 12 ++++++++++ .../io/socket/engineio/client/Socket.java | 15 ++++++++++++ .../io/socket/engineio/client/Transport.java | 15 ++++++++++++ .../client/transports/PollingXHR.java | 14 +++++++++-- .../engineio/client/transports/WebSocket.java | 23 +++++++++++++++---- 5 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 src/main/java/io/socket/engineio/client/HttpConnectionProvider.java diff --git a/src/main/java/io/socket/engineio/client/HttpConnectionProvider.java b/src/main/java/io/socket/engineio/client/HttpConnectionProvider.java new file mode 100644 index 00000000..78c68577 --- /dev/null +++ b/src/main/java/io/socket/engineio/client/HttpConnectionProvider.java @@ -0,0 +1,12 @@ +package io.socket.engineio.client; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; + +/** + * @author Eugene.Kudelevsky + */ +public interface HttpConnectionProvider { + HttpURLConnection openConnection(URL url) throws IOException; +} diff --git a/src/main/java/io/socket/engineio/client/Socket.java b/src/main/java/io/socket/engineio/client/Socket.java index 91fb75c8..16e56dda 100644 --- a/src/main/java/io/socket/engineio/client/Socket.java +++ b/src/main/java/io/socket/engineio/client/Socket.java @@ -128,6 +128,11 @@ public void run() {} private Future pingIntervalTimer; private SSLContext sslContext; private HostnameVerifier hostnameVerifier; + public String proxyHost; + public int proxyPort = -1; + public String proxyLogin; + public String proxyPassword; + private HttpConnectionProvider httpConnectionProvider; private ReadyState readyState; private ScheduledExecutorService heartbeatScheduler; @@ -205,6 +210,11 @@ public Socket(Options opts) { this.policyPort = opts.policyPort != 0 ? opts.policyPort : 843; this.rememberUpgrade = opts.rememberUpgrade; this.hostnameVerifier = opts.hostnameVerifier != null ? opts.hostnameVerifier : defaultHostnameVerifier; + this.proxyHost = opts.proxyHost; + this.proxyPort = opts.proxyPort; + this.proxyLogin = opts.proxyLogin; + this.proxyPassword = opts.proxyPassword; + this.httpConnectionProvider = opts.httpConnectionProvider; } public static void setDefaultSSLContext(SSLContext sslContext) { @@ -271,6 +281,11 @@ private Transport createTransport(String name) { opts.policyPort = this.policyPort; opts.socket = this; opts.hostnameVerifier = this.hostnameVerifier; + opts.proxyHost = this.proxyHost; + opts.proxyPort = this.proxyPort; + opts.proxyLogin = this.proxyLogin; + opts.proxyPassword = this.proxyPassword; + opts.httpConnectionProvider = this.httpConnectionProvider; Transport transport; if (WebSocket.NAME.equals(name)) { diff --git a/src/main/java/io/socket/engineio/client/Transport.java b/src/main/java/io/socket/engineio/client/Transport.java index ca79ea9e..b588f9b0 100644 --- a/src/main/java/io/socket/engineio/client/Transport.java +++ b/src/main/java/io/socket/engineio/client/Transport.java @@ -43,6 +43,11 @@ public String toString() { protected SSLContext sslContext; protected Socket socket; protected HostnameVerifier hostnameVerifier; + protected String proxyHost; + protected int proxyPort; + protected String proxyLogin; + protected String proxyPassword; + protected HttpConnectionProvider httpConnectionProvider; protected ReadyState readyState; @@ -57,6 +62,11 @@ public Transport(Options opts) { this.sslContext = opts.sslContext; this.socket = opts.socket; this.hostnameVerifier = opts.hostnameVerifier; + this.proxyHost = opts.proxyHost; + this.proxyPort = opts.proxyPort; + this.proxyLogin = opts.proxyLogin; + this.proxyPassword = opts.proxyPassword; + this.httpConnectionProvider = opts.httpConnectionProvider; } protected Transport onError(String msg, Exception desc) { @@ -152,5 +162,10 @@ public static class Options { public SSLContext sslContext; public HostnameVerifier hostnameVerifier; protected Socket socket; + public String proxyHost; + public int proxyPort = -1; + public String proxyLogin; + public String proxyPassword; + public HttpConnectionProvider httpConnectionProvider; } } diff --git a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java index 864b114f..acbed3f6 100644 --- a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java +++ b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java @@ -2,8 +2,9 @@ import io.socket.emitter.Emitter; -import io.socket.thread.EventThread; +import io.socket.engineio.client.HttpConnectionProvider; import io.socket.engineio.client.Transport; +import io.socket.thread.EventThread; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; @@ -37,6 +38,7 @@ protected Request request(Request.Options opts) { opts.uri = this.uri(); opts.sslContext = this.sslContext; opts.hostnameVerifier = this.hostnameVerifier; + opts.httpConnectionProvider = this.httpConnectionProvider; Request req = new Request(opts); @@ -149,6 +151,7 @@ public static class Request extends Emitter { private SSLContext sslContext; private HttpURLConnection xhr; private HostnameVerifier hostnameVerifier; + private HttpConnectionProvider httpConnectionProvider; public Request(Options opts) { this.method = opts.method != null ? opts.method : "GET"; @@ -156,6 +159,7 @@ public Request(Options opts) { this.data = opts.data; this.sslContext = opts.sslContext; this.hostnameVerifier = opts.hostnameVerifier; + this.httpConnectionProvider = opts.httpConnectionProvider; } public void create() { @@ -163,7 +167,12 @@ public void create() { try { logger.fine(String.format("xhr open %s: %s", this.method, this.uri)); URL url = new URL(this.uri); - xhr = (HttpURLConnection)url.openConnection(); + if (httpConnectionProvider != null) { + xhr = httpConnectionProvider.openConnection(url); + } + if (xhr == null) { + xhr = (HttpURLConnection) url.openConnection(); + } xhr.setRequestMethod(this.method); } catch (IOException e) { this.onError(e); @@ -322,6 +331,7 @@ public static class Options { public byte[] data; public SSLContext sslContext; public HostnameVerifier hostnameVerifier; + public HttpConnectionProvider httpConnectionProvider; } } } diff --git a/src/main/java/io/socket/engineio/client/transports/WebSocket.java b/src/main/java/io/socket/engineio/client/transports/WebSocket.java index 79c7979d..e7746793 100644 --- a/src/main/java/io/socket/engineio/client/transports/WebSocket.java +++ b/src/main/java/io/socket/engineio/client/transports/WebSocket.java @@ -8,17 +8,15 @@ import io.socket.thread.EventThread; import io.socket.utf8.UTF8Exception; import io.socket.yeast.Yeast; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; +import okhttp3.*; import okhttp3.ws.WebSocketCall; import okhttp3.ws.WebSocketListener; import okio.Buffer; import javax.net.ssl.SSLSocketFactory; import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Proxy; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -61,6 +59,21 @@ protected void doOpen() { if (this.hostnameVerifier != null) { clientBuilder.hostnameVerifier(this.hostnameVerifier); } + if (proxyHost != null && !proxyHost.isEmpty() && proxyPort >= 0) { + clientBuilder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort))); + } + if (proxyLogin != null && !proxyLogin.isEmpty()) { + final String credentials = Credentials.basic(proxyLogin, proxyPassword); + + clientBuilder.proxyAuthenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + return response.request().newBuilder() + .header("Proxy-Authorization", credentials) + .build(); + } + }); + } Request.Builder builder = new Request.Builder().url(uri()); for (Map.Entry> entry : headers.entrySet()) { for (String v : entry.getValue()) { From e6daeaeb28ecc3fad6d13c8470587010bc8ea418 Mon Sep 17 00:00:00 2001 From: Dominik Auf der Maur Date: Tue, 26 Apr 2016 15:17:59 +0200 Subject: [PATCH 02/72] log exceptions thrown in async tasks --- src/main/java/io/socket/thread/EventThread.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/io/socket/thread/EventThread.java b/src/main/java/io/socket/thread/EventThread.java index 64c6ab9e..43986200 100644 --- a/src/main/java/io/socket/thread/EventThread.java +++ b/src/main/java/io/socket/thread/EventThread.java @@ -4,6 +4,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; +import java.util.logging.Level; +import java.util.logging.Logger; /** @@ -11,6 +13,8 @@ */ public class EventThread extends Thread { + private static final Logger logger = Logger.getLogger(EventThread.class.getName()); + private static final ThreadFactory THREAD_FACTORY = new ThreadFactory() { @Override public Thread newThread(Runnable runnable) { @@ -73,6 +77,9 @@ public static void nextTick(final Runnable task) { public void run() { try { task.run(); + } catch (Throwable t) { + logger.log(Level.SEVERE, "Task threw exception", t); + throw t; } finally { synchronized (EventThread.class) { counter--; From 8bbddbe00ac27b71526444377c42cc292807566a Mon Sep 17 00:00:00 2001 From: George Kankava Date: Fri, 4 Mar 2016 13:15:42 +0400 Subject: [PATCH 03/72] multiple code improvements: squid:S2293, squid:S1213, squid:S2185, squid:S1905, squid:S1226 --- src/main/java/io/socket/yeast/Yeast.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/java/io/socket/yeast/Yeast.java b/src/main/java/io/socket/yeast/Yeast.java index 32fd4eb7..f7c1e757 100644 --- a/src/main/java/io/socket/yeast/Yeast.java +++ b/src/main/java/io/socket/yeast/Yeast.java @@ -11,7 +11,8 @@ public final class Yeast { private static char[] alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".toCharArray(); private static int length = alphabet.length; - + private static int seed = 0; + private static String prev; private static Map map = new HashMap(length); static { for (int i = 0; i < length; i++) { @@ -21,17 +22,13 @@ public final class Yeast { private Yeast () {} - private static int seed = 0; - - private static String prev; - public static String encode(long num) { final StringBuilder encoded = new StringBuilder(); - + long dividedNum; do { encoded.insert(0, alphabet[(int)(num % length)]); - num = (long)Math.floor(num / length); - } while (num > 0); + dividedNum = num / length; + } while (dividedNum > 0); return encoded.toString(); } From d4cc84d08e10f2211d169be6dab3c1fd121fe27e Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Tue, 17 May 2016 16:41:41 +0300 Subject: [PATCH 04/72] Simplify API: remove HttpConnectionProvider --- .../client/HttpConnectionProvider.java | 12 ------------ .../java/io/socket/engineio/client/Socket.java | 13 ++++--------- .../io/socket/engineio/client/Transport.java | 13 ++++--------- .../engineio/client/transports/PollingXHR.java | 18 +++++++----------- .../engineio/client/transports/WebSocket.java | 6 ++---- 5 files changed, 17 insertions(+), 45 deletions(-) delete mode 100644 src/main/java/io/socket/engineio/client/HttpConnectionProvider.java diff --git a/src/main/java/io/socket/engineio/client/HttpConnectionProvider.java b/src/main/java/io/socket/engineio/client/HttpConnectionProvider.java deleted file mode 100644 index 78c68577..00000000 --- a/src/main/java/io/socket/engineio/client/HttpConnectionProvider.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.socket.engineio.client; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URL; - -/** - * @author Eugene.Kudelevsky - */ -public interface HttpConnectionProvider { - HttpURLConnection openConnection(URL url) throws IOException; -} diff --git a/src/main/java/io/socket/engineio/client/Socket.java b/src/main/java/io/socket/engineio/client/Socket.java index 16e56dda..207ddfe3 100644 --- a/src/main/java/io/socket/engineio/client/Socket.java +++ b/src/main/java/io/socket/engineio/client/Socket.java @@ -12,6 +12,7 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; +import java.net.Proxy; import java.net.URI; import java.net.URISyntaxException; import java.util.*; @@ -128,11 +129,9 @@ public void run() {} private Future pingIntervalTimer; private SSLContext sslContext; private HostnameVerifier hostnameVerifier; - public String proxyHost; - public int proxyPort = -1; + public Proxy proxy; public String proxyLogin; public String proxyPassword; - private HttpConnectionProvider httpConnectionProvider; private ReadyState readyState; private ScheduledExecutorService heartbeatScheduler; @@ -210,11 +209,9 @@ public Socket(Options opts) { this.policyPort = opts.policyPort != 0 ? opts.policyPort : 843; this.rememberUpgrade = opts.rememberUpgrade; this.hostnameVerifier = opts.hostnameVerifier != null ? opts.hostnameVerifier : defaultHostnameVerifier; - this.proxyHost = opts.proxyHost; - this.proxyPort = opts.proxyPort; + this.proxy = opts.proxy; this.proxyLogin = opts.proxyLogin; this.proxyPassword = opts.proxyPassword; - this.httpConnectionProvider = opts.httpConnectionProvider; } public static void setDefaultSSLContext(SSLContext sslContext) { @@ -281,11 +278,9 @@ private Transport createTransport(String name) { opts.policyPort = this.policyPort; opts.socket = this; opts.hostnameVerifier = this.hostnameVerifier; - opts.proxyHost = this.proxyHost; - opts.proxyPort = this.proxyPort; + opts.proxy = this.proxy; opts.proxyLogin = this.proxyLogin; opts.proxyPassword = this.proxyPassword; - opts.httpConnectionProvider = this.httpConnectionProvider; Transport transport; if (WebSocket.NAME.equals(name)) { diff --git a/src/main/java/io/socket/engineio/client/Transport.java b/src/main/java/io/socket/engineio/client/Transport.java index b588f9b0..d11cd050 100644 --- a/src/main/java/io/socket/engineio/client/Transport.java +++ b/src/main/java/io/socket/engineio/client/Transport.java @@ -9,6 +9,7 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; +import java.net.Proxy; import java.util.Map; public abstract class Transport extends Emitter { @@ -43,11 +44,9 @@ public String toString() { protected SSLContext sslContext; protected Socket socket; protected HostnameVerifier hostnameVerifier; - protected String proxyHost; - protected int proxyPort; + protected Proxy proxy; protected String proxyLogin; protected String proxyPassword; - protected HttpConnectionProvider httpConnectionProvider; protected ReadyState readyState; @@ -62,11 +61,9 @@ public Transport(Options opts) { this.sslContext = opts.sslContext; this.socket = opts.socket; this.hostnameVerifier = opts.hostnameVerifier; - this.proxyHost = opts.proxyHost; - this.proxyPort = opts.proxyPort; + this.proxy = opts.proxy; this.proxyLogin = opts.proxyLogin; this.proxyPassword = opts.proxyPassword; - this.httpConnectionProvider = opts.httpConnectionProvider; } protected Transport onError(String msg, Exception desc) { @@ -162,10 +159,8 @@ public static class Options { public SSLContext sslContext; public HostnameVerifier hostnameVerifier; protected Socket socket; - public String proxyHost; - public int proxyPort = -1; + public Proxy proxy; public String proxyLogin; public String proxyPassword; - public HttpConnectionProvider httpConnectionProvider; } } diff --git a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java index acbed3f6..54f6dcc6 100644 --- a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java +++ b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java @@ -2,7 +2,6 @@ import io.socket.emitter.Emitter; -import io.socket.engineio.client.HttpConnectionProvider; import io.socket.engineio.client.Transport; import io.socket.thread.EventThread; @@ -11,6 +10,7 @@ import javax.net.ssl.SSLContext; import java.io.*; import java.net.HttpURLConnection; +import java.net.Proxy; import java.net.URL; import java.nio.ByteBuffer; import java.util.*; @@ -38,7 +38,7 @@ protected Request request(Request.Options opts) { opts.uri = this.uri(); opts.sslContext = this.sslContext; opts.hostnameVerifier = this.hostnameVerifier; - opts.httpConnectionProvider = this.httpConnectionProvider; + opts.proxy = this.proxy; Request req = new Request(opts); @@ -151,7 +151,7 @@ public static class Request extends Emitter { private SSLContext sslContext; private HttpURLConnection xhr; private HostnameVerifier hostnameVerifier; - private HttpConnectionProvider httpConnectionProvider; + private Proxy proxy; public Request(Options opts) { this.method = opts.method != null ? opts.method : "GET"; @@ -159,7 +159,7 @@ public Request(Options opts) { this.data = opts.data; this.sslContext = opts.sslContext; this.hostnameVerifier = opts.hostnameVerifier; - this.httpConnectionProvider = opts.httpConnectionProvider; + this.proxy = opts.proxy; } public void create() { @@ -167,12 +167,8 @@ public void create() { try { logger.fine(String.format("xhr open %s: %s", this.method, this.uri)); URL url = new URL(this.uri); - if (httpConnectionProvider != null) { - xhr = httpConnectionProvider.openConnection(url); - } - if (xhr == null) { - xhr = (HttpURLConnection) url.openConnection(); - } + xhr = proxy != null ? (HttpURLConnection) url.openConnection(proxy) + : (HttpURLConnection) url.openConnection(); xhr.setRequestMethod(this.method); } catch (IOException e) { this.onError(e); @@ -331,7 +327,7 @@ public static class Options { public byte[] data; public SSLContext sslContext; public HostnameVerifier hostnameVerifier; - public HttpConnectionProvider httpConnectionProvider; + public Proxy proxy; } } } diff --git a/src/main/java/io/socket/engineio/client/transports/WebSocket.java b/src/main/java/io/socket/engineio/client/transports/WebSocket.java index e7746793..31875fcc 100644 --- a/src/main/java/io/socket/engineio/client/transports/WebSocket.java +++ b/src/main/java/io/socket/engineio/client/transports/WebSocket.java @@ -15,8 +15,6 @@ import javax.net.ssl.SSLSocketFactory; import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Proxy; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -59,8 +57,8 @@ protected void doOpen() { if (this.hostnameVerifier != null) { clientBuilder.hostnameVerifier(this.hostnameVerifier); } - if (proxyHost != null && !proxyHost.isEmpty() && proxyPort >= 0) { - clientBuilder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort))); + if (proxy != null) { + clientBuilder.proxy(proxy); } if (proxyLogin != null && !proxyLogin.isEmpty()) { final String credentials = Credentials.basic(proxyLogin, proxyPassword); From fc9a1c45dc058ff1ae6d125d2385e386e5c2c66c Mon Sep 17 00:00:00 2001 From: Erik Ogenvik Date: Thu, 19 May 2016 09:48:54 +0200 Subject: [PATCH 05/72] Act on the same number. Else we'll enter an infinite loop. --- src/main/java/io/socket/yeast/Yeast.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/socket/yeast/Yeast.java b/src/main/java/io/socket/yeast/Yeast.java index f7c1e757..0f60808a 100644 --- a/src/main/java/io/socket/yeast/Yeast.java +++ b/src/main/java/io/socket/yeast/Yeast.java @@ -24,10 +24,10 @@ private Yeast () {} public static String encode(long num) { final StringBuilder encoded = new StringBuilder(); - long dividedNum; + long dividedNum = num; do { - encoded.insert(0, alphabet[(int)(num % length)]); - dividedNum = num / length; + encoded.insert(0, alphabet[(int)(dividedNum % length)]); + dividedNum = dividedNum / length; } while (dividedNum > 0); return encoded.toString(); From 330bf99dc3352b25c6b380c2ca19a044fdfebf81 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Mon, 13 Jun 2016 21:40:04 +0900 Subject: [PATCH 06/72] test: use TLSv1 for node 0.12 or higher --- src/test/java/io/socket/engineio/client/SSLConnectionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/io/socket/engineio/client/SSLConnectionTest.java b/src/test/java/io/socket/engineio/client/SSLConnectionTest.java index a68a5bd2..76037eff 100644 --- a/src/test/java/io/socket/engineio/client/SSLConnectionTest.java +++ b/src/test/java/io/socket/engineio/client/SSLConnectionTest.java @@ -60,7 +60,7 @@ SSLContext createSSLContext() throws GeneralSecurityException, IOException { TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ks); - SSLContext sslContext = SSLContext.getInstance("TLS"); + SSLContext sslContext = SSLContext.getInstance("TLSv1"); sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); return sslContext; } From f119063af76e279e04a26c1917625ae2a7bdd9fd Mon Sep 17 00:00:00 2001 From: Vachagan Balayan Date: Fri, 1 Jul 2016 14:55:22 +0800 Subject: [PATCH 07/72] changed EventThread to extend daemon property from parent thread --- src/main/java/io/socket/thread/EventThread.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/io/socket/thread/EventThread.java b/src/main/java/io/socket/thread/EventThread.java index 43986200..90f7aec7 100644 --- a/src/main/java/io/socket/thread/EventThread.java +++ b/src/main/java/io/socket/thread/EventThread.java @@ -20,6 +20,7 @@ public class EventThread extends Thread { public Thread newThread(Runnable runnable) { thread = new EventThread(runnable); thread.setName("EventThread"); + thread.setDaemon(Thread.currentThread().isDaemon()); return thread; } }; From 912dfa211bc2cfecea61449b2c16a26b1c23bc70 Mon Sep 17 00:00:00 2001 From: Dave Roberge Date: Sun, 17 Jul 2016 12:41:52 -0400 Subject: [PATCH 08/72] Close the web socket after sending a close frame. Previously, the underlying socket was being closed with the cancel call. Because the socket was closed, the close frame could never be sent. --- .../io/socket/engineio/client/transports/WebSocket.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/socket/engineio/client/transports/WebSocket.java b/src/main/java/io/socket/engineio/client/transports/WebSocket.java index bb176843..c4101a97 100644 --- a/src/main/java/io/socket/engineio/client/transports/WebSocket.java +++ b/src/main/java/io/socket/engineio/client/transports/WebSocket.java @@ -190,9 +190,6 @@ protected void onClose() { } protected void doClose() { - if (wsCall != null) { - wsCall.cancel(); - } if (ws != null) { try { ws.close(1000, ""); @@ -202,6 +199,9 @@ protected void doClose() { // websocket already closed } } + if (wsCall != null) { + wsCall.cancel(); + } } protected String uri() { From 1c166b25d9a7eb97f149695b20da53a25f8a490f Mon Sep 17 00:00:00 2001 From: Stefan Haacker Date: Tue, 26 Jul 2016 11:12:55 -0400 Subject: [PATCH 09/72] [Fix] "must call close()" crash --- .../io/socket/engineio/client/transports/WebSocket.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/socket/engineio/client/transports/WebSocket.java b/src/main/java/io/socket/engineio/client/transports/WebSocket.java index bb176843..9cd24713 100644 --- a/src/main/java/io/socket/engineio/client/transports/WebSocket.java +++ b/src/main/java/io/socket/engineio/client/transports/WebSocket.java @@ -163,8 +163,13 @@ public void run() { } }; - final int[] total = new int[] { packets.length }; + final int[] total = new int[]{packets.length}; for (Packet packet : packets) { + if (this.readyState != ReadyState.OPENING && this.readyState != ReadyState.OPEN) { + // Ensure we don't try to send anymore packets if the socket ends up being closed due to an exception + break; + } + Parser.encodePacket(packet, new Parser.EncodeCallback() { @Override public void call(Object packet) { @@ -176,6 +181,7 @@ public void call(Object packet) { } } catch (IOException e) { logger.fine("websocket closed before onclose event"); + close(); } if (0 == --total[0]) done.run(); From 000dfef237b3eac6348a9d28bf332e4df1b4d6b6 Mon Sep 17 00:00:00 2001 From: vicv Date: Tue, 16 Aug 2016 16:15:53 -0400 Subject: [PATCH 10/72] Update Okhttp-ws --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d09b4597..a4206af6 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ com.squareup.okhttp3 okhttp-ws - 3.0.1 + 3.4.1 org.json From 59586f76094a99b565a750a666985db45cc85a01 Mon Sep 17 00:00:00 2001 From: wzurita Date: Mon, 29 Aug 2016 23:50:01 +0200 Subject: [PATCH 11/72] Refactoring the cleanup method so it is called after the stream/reader is closed. Fixes #65 --- .../io/socket/engineio/client/transports/PollingXHR.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java index 2bec7cc5..3a5df8e9 100644 --- a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java +++ b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java @@ -229,7 +229,6 @@ public void run() { private void onSuccess() { this.emit(EVENT_SUCCESS); - this.cleanup(); } private void onData(String data) { @@ -244,7 +243,6 @@ private void onData(byte[] data) { private void onError(Exception err) { this.emit(EVENT_ERROR, err); - this.cleanup(); } private void onRequestHeaders(Map> headers) { @@ -304,11 +302,9 @@ private void onLoad() { try { if (reader != null) reader.close(); } catch (IOException e) {} + this.cleanup(); } } - public void abort() { - this.cleanup(); - } public static class Options { From 94d37278e6453002afa4135433527c7ef4c6686a Mon Sep 17 00:00:00 2001 From: nkzawa Date: Fri, 16 Sep 2016 13:28:51 +0200 Subject: [PATCH 12/72] UTF8Exception: remove the data property --- src/main/java/io/socket/utf8/UTF8Exception.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/io/socket/utf8/UTF8Exception.java b/src/main/java/io/socket/utf8/UTF8Exception.java index b46badf5..077da0be 100644 --- a/src/main/java/io/socket/utf8/UTF8Exception.java +++ b/src/main/java/io/socket/utf8/UTF8Exception.java @@ -4,8 +4,6 @@ public class UTF8Exception extends IOException { - public String data; - public UTF8Exception() { super(); } From a9f7c65e1a911b1f82ebf3cf531f1ac98c379e43 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Fri, 16 Sep 2016 14:19:43 +0200 Subject: [PATCH 13/72] update plugins --- pom.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index a4206af6..0278b938 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.3 + 3.5.1 1.7 1.7 @@ -100,7 +100,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.14.1 + 2.19.1 -Dfile.encoding=UTF-8 @@ -128,7 +128,7 @@ org.apache.maven.plugins maven-source-plugin - 2.4 + 3.0.1 attach-sources @@ -141,7 +141,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.3 + 2.10.4 attach-javadocs @@ -154,7 +154,7 @@ org.apache.maven.plugins maven-release-plugin - 2.5 + 2.5.3 true false @@ -165,7 +165,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.6 + 1.6.7 true ossrh @@ -176,7 +176,7 @@ org.codehaus.mojo exec-maven-plugin - 1.4.0 + 1.5.0 npm-install @@ -197,7 +197,7 @@ org.codehaus.mojo versions-maven-plugin - 2.2 + 2.3 com.github.github From 4b2df0d0454b5096fc005bfbc6b49d6a04747823 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Mon, 19 Sep 2016 15:10:52 +0200 Subject: [PATCH 14/72] test: bump engine.io --- src/test/resources/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/package.json b/src/test/resources/package.json index cdef2377..794d3686 100644 --- a/src/test/resources/package.json +++ b/src/test/resources/package.json @@ -1,6 +1,6 @@ { "private": true, "dependencies": { - "engine.io": "1.6.8" + "engine.io": "1.6.11" } } From 08642a7873bd53f49dbca735f562cd407e355f63 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Mon, 19 Sep 2016 16:22:39 +0200 Subject: [PATCH 15/72] prepare 0.8.0 --- History.md | 16 ++++++++++++++++ README.md | 4 ++-- pom.xml | 2 +- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/History.md b/History.md index 10d57d8f..73176e3d 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,19 @@ + +0.8.0 / 2016-09-19 +================== + +* update okhttp-ws [VicV] +* proxy support [Eugene-Kudelevsky] +* several code improvements [georgekankava] +* EventThread: log exceptions [Dominik Auf der Maur] +* EventThread: extend deamon property from parent thread [vach] +* Yeast: fix infinite loop bug [erikogenvik] +* WebSocket: close the web socket after sending a close frame [dave-r12] +* WebSocket: fix "must call close()" crash [chendrak] +* Polling: disconnect after closing stream/reader [wzurita] +* UTF8Exception: remove the data property +* test: use TLSv1 + 0.7.0 / 2016-02-01 ================== diff --git a/README.md b/README.md index 09afd3e8..e23f880c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Add the following dependency to your `pom.xml`. io.socket engine.io-client - 0.7.0 + 0.8.0 ``` @@ -25,7 +25,7 @@ Add the following dependency to your `pom.xml`. Add it as a gradle dependency for Android Studio, in `build.gradle`: ```groovy -compile ('io.socket:engine.io-client:0.7.0') { +compile ('io.socket:engine.io-client:0.8.0') { // excluding org.json which is provided by Android exclude group: 'org.json', module: 'json' } diff --git a/pom.xml b/pom.xml index 0278b938..8f682f51 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 0.7.1-SNAPSHOT + 0.8.0-SNAPSHOT jar engine.io-client Engine.IO Client Library for Java From 1fa93ca155b3af7db399633317c259aabf37dfcb Mon Sep 17 00:00:00 2001 From: nkzawa Date: Mon, 19 Sep 2016 16:23:30 +0200 Subject: [PATCH 16/72] [maven-release-plugin] prepare release engine.io-client-0.8.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8f682f51..f8097289 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 0.8.0-SNAPSHOT + 0.8.0 jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:git://github.com/socketio/engine.io-client-java.git scm:git:git@github.com:socketio/engine.io-client-java.git - HEAD + engine.io-client-0.8.0 From b46c144bfb0dad0a535da26ada581700a11b756a Mon Sep 17 00:00:00 2001 From: nkzawa Date: Fri, 23 Sep 2016 19:20:41 +0900 Subject: [PATCH 17/72] pom.xml: fix git url --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f8097289..33b59f3f 100644 --- a/pom.xml +++ b/pom.xml @@ -28,8 +28,8 @@ https://github.com/socketio/engine.io-client-java - scm:git:git://github.com/socketio/engine.io-client-java.git - scm:git:git@github.com:socketio/engine.io-client-java.git + scm:git:https://github.com/socketio/engine.io-client-java.git + scm:git:https://github.com/socketio/engine.io-client-java.git engine.io-client-0.8.0 From 1e72b45077460df0669b8ca63b4a1e68a378e1a6 Mon Sep 17 00:00:00 2001 From: Akshat Goel Date: Mon, 26 Sep 2016 20:53:59 +0530 Subject: [PATCH 18/72] fixed added onClose --- .../java/io/socket/engineio/client/transports/WebSocket.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/socket/engineio/client/transports/WebSocket.java b/src/main/java/io/socket/engineio/client/transports/WebSocket.java index 6d9be0ac..3447494c 100644 --- a/src/main/java/io/socket/engineio/client/transports/WebSocket.java +++ b/src/main/java/io/socket/engineio/client/transports/WebSocket.java @@ -192,7 +192,7 @@ public void call(Object packet) { } } catch (IOException e) { logger.fine("websocket closed before onclose event"); - close(); + doClose(); } if (0 == --total[0]) done.run(); From cfe87bf42725f062725bd8806befe0b0257a9515 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Tue, 27 Sep 2016 23:42:26 +0900 Subject: [PATCH 19/72] 0.8.1-SNAPSHOT --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 33b59f3f..fabdbc6d 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 0.8.0 + 0.8.1-SNAPSHOT jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:https://github.com/socketio/engine.io-client-java.git scm:git:https://github.com/socketio/engine.io-client-java.git - engine.io-client-0.8.0 + HEAD From ba612b481760103cfbd0929b2bd46c436882fcc8 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Tue, 27 Sep 2016 23:44:16 +0900 Subject: [PATCH 20/72] prepare v0.8.1 --- History.md | 5 +++++ README.md | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index 73176e3d..9e444e07 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,9 @@ +0.8.1 / 2016-09-27 +================== + +* fix NullPointerException [eckovation] + 0.8.0 / 2016-09-19 ================== diff --git a/README.md b/README.md index e23f880c..8e8f672f 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Add the following dependency to your `pom.xml`. io.socket engine.io-client - 0.8.0 + 0.8.1 ``` @@ -25,7 +25,7 @@ Add the following dependency to your `pom.xml`. Add it as a gradle dependency for Android Studio, in `build.gradle`: ```groovy -compile ('io.socket:engine.io-client:0.8.0') { +compile ('io.socket:engine.io-client:0.8.1') { // excluding org.json which is provided by Android exclude group: 'org.json', module: 'json' } From 5beb22327aefc3b51dc826c8c1101f963777178c Mon Sep 17 00:00:00 2001 From: nkzawa Date: Tue, 27 Sep 2016 23:56:00 +0900 Subject: [PATCH 21/72] [maven-release-plugin] prepare release engine.io-client-0.8.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index fabdbc6d..8303807d 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 0.8.1-SNAPSHOT + 0.8.1 jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:https://github.com/socketio/engine.io-client-java.git scm:git:https://github.com/socketio/engine.io-client-java.git - HEAD + engine.io-client-0.8.1 From 0be006a93b2c4d44913c2d4b860f967f49d9c13c Mon Sep 17 00:00:00 2001 From: nkzawa Date: Tue, 27 Sep 2016 23:56:09 +0900 Subject: [PATCH 22/72] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8303807d..297ad7b7 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 0.8.1 + 0.8.2-SNAPSHOT jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:https://github.com/socketio/engine.io-client-java.git scm:git:https://github.com/socketio/engine.io-client-java.git - engine.io-client-0.8.1 + HEAD From 35b2fa93fa568060df2031de0a4d6d5252a93ec1 Mon Sep 17 00:00:00 2001 From: Akshat Goel Date: Wed, 12 Oct 2016 04:34:56 +0530 Subject: [PATCH 23/72] fix added to fix following crash Fatal Exception: java.lang.IllegalStateException: closed at okhttp3.internal.ws.RealWebSocket.sendMessage(RealWebSocket.java:107) at io.socket.engineio.client.transports.WebSocket$4.call(WebSocket.java:189) at io.socket.engineio.parser.Parser.encodePacket(Parser.java:63) at io.socket.engineio.parser.Parser.encodePacket(Parser.java:42) at io.socket.engineio.client.transports.WebSocket.write(WebSocket.java:184) at io.socket.engineio.client.Transport$3.run(Transport.java:108) at io.socket.thread.EventThread.exec(EventThread.java:55) at io.socket.engineio.client.Transport.send(Transport.java:103) at io.socket.engineio.client.Socket.flush(Socket.java:615) at io.socket.engineio.client.Socket.onDrain(Socket.java:606) at io.socket.engineio.client.Socket.access$1100(Socket.java:31) at io.socket.engineio.client.Socket$6.call(Socket.java:308) at io.socket.emitter.Emitter.emit(Emitter.java:117) at io.socket.engineio.client.transports.WebSocket$3$1.run(WebSocket.java:171) at io.socket.thread.EventThread$2.run(EventThread.java:80) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) at java.lang.Thread.run(Thread.java:818) --- .../java/io/socket/engineio/client/transports/WebSocket.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/io/socket/engineio/client/transports/WebSocket.java b/src/main/java/io/socket/engineio/client/transports/WebSocket.java index 3447494c..22bfee05 100644 --- a/src/main/java/io/socket/engineio/client/transports/WebSocket.java +++ b/src/main/java/io/socket/engineio/client/transports/WebSocket.java @@ -190,6 +190,9 @@ public void call(Object packet) { } else if (packet instanceof byte[]) { self.ws.sendMessage(RequestBody.create(BINARY, (byte[]) packet)); } + } catch (IllegalStateException e) { + logger.fine("websocket closed before we could write"); + doClose(); } catch (IOException e) { logger.fine("websocket closed before onclose event"); doClose(); From eb127d97e4dd83bbfc9281c81d3930963f298a34 Mon Sep 17 00:00:00 2001 From: Akshat Goel Date: Wed, 12 Oct 2016 11:50:23 +0530 Subject: [PATCH 24/72] removed the doClose() inside catcher of IllegalStateException --- .../java/io/socket/engineio/client/transports/WebSocket.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/io/socket/engineio/client/transports/WebSocket.java b/src/main/java/io/socket/engineio/client/transports/WebSocket.java index 22bfee05..13261d53 100644 --- a/src/main/java/io/socket/engineio/client/transports/WebSocket.java +++ b/src/main/java/io/socket/engineio/client/transports/WebSocket.java @@ -192,7 +192,6 @@ public void call(Object packet) { } } catch (IllegalStateException e) { logger.fine("websocket closed before we could write"); - doClose(); } catch (IOException e) { logger.fine("websocket closed before onclose event"); doClose(); From e373455eb9af77186c9cded3e64b561c25ac9039 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Sat, 22 Oct 2016 11:30:19 +0900 Subject: [PATCH 25/72] prepare 0.8.2 --- History.md | 5 +++++ README.md | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index 9e444e07..33056467 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,9 @@ +0.8.2 / 2016-10-22 +================== + +* fix IllegalStateException error of websocket [eckovation] + 0.8.1 / 2016-09-27 ================== diff --git a/README.md b/README.md index 8e8f672f..2eeacf77 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Add the following dependency to your `pom.xml`. io.socket engine.io-client - 0.8.1 + 0.8.2 ``` @@ -25,7 +25,7 @@ Add the following dependency to your `pom.xml`. Add it as a gradle dependency for Android Studio, in `build.gradle`: ```groovy -compile ('io.socket:engine.io-client:0.8.1') { +compile ('io.socket:engine.io-client:0.8.2') { // excluding org.json which is provided by Android exclude group: 'org.json', module: 'json' } From 2371550c9c5677da97bbe6b0dc0c63f4cd85f755 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Sat, 22 Oct 2016 11:44:41 +0900 Subject: [PATCH 26/72] [maven-release-plugin] prepare release engine.io-client-0.8.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 297ad7b7..939269d4 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 0.8.2-SNAPSHOT + 0.8.2 jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:https://github.com/socketio/engine.io-client-java.git scm:git:https://github.com/socketio/engine.io-client-java.git - HEAD + engine.io-client-0.8.2 From 822bef1407fd3e3b4a862994889dab5da63a24f1 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Sat, 22 Oct 2016 11:44:50 +0900 Subject: [PATCH 27/72] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 939269d4..644936ae 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 0.8.2 + 0.8.3-SNAPSHOT jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:https://github.com/socketio/engine.io-client-java.git scm:git:https://github.com/socketio/engine.io-client-java.git - engine.io-client-0.8.2 + HEAD From 201e915a2ca402522c06dda011398e1f1ec4977e Mon Sep 17 00:00:00 2001 From: vicv Date: Fri, 4 Nov 2016 12:31:53 -0400 Subject: [PATCH 28/72] 3.4.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 644936ae..3d73b8ac 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ com.squareup.okhttp3 okhttp-ws - 3.4.1 + 3.4.2 org.json From 657d8e89b54e9ed0fc2abace7d1ccc23063c75dc Mon Sep 17 00:00:00 2001 From: Yu-Hsuan Lin Date: Fri, 2 Dec 2016 16:26:28 +0800 Subject: [PATCH 29/72] okhttp-ws into okhttp --- pom.xml | 4 +- .../engineio/client/transports/WebSocket.java | 81 +++++++------------ 2 files changed, 30 insertions(+), 55 deletions(-) diff --git a/pom.xml b/pom.xml index 3d73b8ac..9ce6df21 100644 --- a/pom.xml +++ b/pom.xml @@ -48,8 +48,8 @@ com.squareup.okhttp3 - okhttp-ws - 3.4.2 + okhttp + 3.5.0 org.json diff --git a/src/main/java/io/socket/engineio/client/transports/WebSocket.java b/src/main/java/io/socket/engineio/client/transports/WebSocket.java index 13261d53..313f5570 100644 --- a/src/main/java/io/socket/engineio/client/transports/WebSocket.java +++ b/src/main/java/io/socket/engineio/client/transports/WebSocket.java @@ -9,9 +9,7 @@ import io.socket.utf8.UTF8Exception; import io.socket.yeast.Yeast; import okhttp3.*; -import okhttp3.ws.WebSocketCall; -import okhttp3.ws.WebSocketListener; -import okio.Buffer; +import okio.ByteString; import javax.net.ssl.SSLSocketFactory; import java.io.IOException; @@ -22,8 +20,6 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Logger; -import static okhttp3.ws.WebSocket.BINARY; -import static okhttp3.ws.WebSocket.TEXT; public class WebSocket extends Transport { @@ -31,8 +27,7 @@ public class WebSocket extends Transport { private static final Logger logger = Logger.getLogger(PollingXHR.class.getName()); - private okhttp3.ws.WebSocket ws; - private WebSocketCall wsCall; + private okhttp3.WebSocket ws; public WebSocket(Options opts) { super(opts); @@ -80,11 +75,9 @@ public Request authenticate(Route route, Response response) throws IOException { } final Request request = builder.build(); final OkHttpClient client = clientBuilder.build(); - wsCall = WebSocketCall.create(client, request); - wsCall.enqueue(new WebSocketListener() { + ws = client.newWebSocket(request, new WebSocketListener() { @Override - public void onOpen(okhttp3.ws.WebSocket webSocket, Response response) { - ws = webSocket; + public void onOpen(okhttp3.WebSocket webSocket, Response response) { final Map> headers = response.headers().toMultimap(); EventThread.exec(new Runnable() { @Override @@ -96,44 +89,33 @@ public void run() { } @Override - public void onMessage(final ResponseBody responseBody) throws IOException { - Object data = null; - if (responseBody.contentType() == TEXT) { - data = responseBody.string(); - } else if (responseBody.contentType() == BINARY) { - data = responseBody.source().readByteArray(); - } else { - EventThread.exec(new Runnable() { - @Override - public void run() { - self.onError("Unknown payload type: " + responseBody.contentType(), new IllegalStateException()); - } - }); + public void onMessage(okhttp3.WebSocket webSocket, final String text) { + if (text == null) { + return; } - responseBody.source().close(); - final Object finalData = data; EventThread.exec(new Runnable() { @Override public void run() { - if (finalData == null) { - return; - } - if (finalData instanceof String) { - self.onData((String) finalData); - } else { - self.onData((byte[]) finalData); - } + self.onData(text); } }); - } @Override - public void onPong(Buffer payload) { + public void onMessage(okhttp3.WebSocket webSocket, final ByteString bytes) { + if (bytes == null) { + return; + } + EventThread.exec(new Runnable() { + @Override + public void run() { + self.onData(bytes.toByteArray()); + } + }); } @Override - public void onClose(int code, String reason) { + public void onClosed(okhttp3.WebSocket webSocket, int code, String reason) { EventThread.exec(new Runnable() { @Override public void run() { @@ -143,11 +125,14 @@ public void run() { } @Override - public void onFailure(final IOException e, final Response response) { + public void onFailure(okhttp3.WebSocket webSocket, final Throwable t, Response response) { + if (!(t instanceof Exception)) { + return; + } EventThread.exec(new Runnable() { @Override public void run() { - self.onError("websocket error", e); + self.onError("websocket error", (Exception) t); } }); } @@ -186,15 +171,12 @@ public void run() { public void call(Object packet) { try { if (packet instanceof String) { - self.ws.sendMessage(RequestBody.create(TEXT, (String) packet)); + self.ws.send((String) packet); } else if (packet instanceof byte[]) { - self.ws.sendMessage(RequestBody.create(BINARY, (byte[]) packet)); + self.ws.send(ByteString.of((byte[]) packet)); } } catch (IllegalStateException e) { logger.fine("websocket closed before we could write"); - } catch (IOException e) { - logger.fine("websocket closed before onclose event"); - doClose(); } if (0 == --total[0]) done.run(); @@ -203,23 +185,16 @@ public void call(Object packet) { } } - @Override - protected void onClose() { - super.onClose(); - } - protected void doClose() { if (ws != null) { try { ws.close(1000, ""); - } catch (IOException e) { - // websocket already closed } catch (IllegalStateException e) { // websocket already closed } } - if (wsCall != null) { - wsCall.cancel(); + if (ws != null) { + ws.cancel(); } } From fd929e6664662e1611d06f1a6306a82477c685ef Mon Sep 17 00:00:00 2001 From: nkzawa Date: Mon, 12 Dec 2016 17:43:24 +0900 Subject: [PATCH 30/72] prepare next release --- History.md | 5 +++++ README.md | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index 33056467..120ba524 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,9 @@ +0.8.3 / 2016-12-12 +================== + +* replace okhttp-ws with okhttp (#78) [@b95505017] + 0.8.2 / 2016-10-22 ================== diff --git a/README.md b/README.md index 2eeacf77..a96485eb 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Add the following dependency to your `pom.xml`. io.socket engine.io-client - 0.8.2 + 0.8.3 ``` @@ -25,7 +25,7 @@ Add the following dependency to your `pom.xml`. Add it as a gradle dependency for Android Studio, in `build.gradle`: ```groovy -compile ('io.socket:engine.io-client:0.8.2') { +compile ('io.socket:engine.io-client:0.8.3') { // excluding org.json which is provided by Android exclude group: 'org.json', module: 'json' } From 59ab4c7445e011badd8115e7809db63c22552d98 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Mon, 12 Dec 2016 17:53:22 +0900 Subject: [PATCH 31/72] [maven-release-plugin] prepare release engine.io-client-0.8.3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9ce6df21..408278c2 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 0.8.3-SNAPSHOT + 0.8.3 jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:https://github.com/socketio/engine.io-client-java.git scm:git:https://github.com/socketio/engine.io-client-java.git - HEAD + engine.io-client-0.8.3 From 80535c6304d1fb39b1fe969968b6d842e84c5e90 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Mon, 12 Dec 2016 17:53:30 +0900 Subject: [PATCH 32/72] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 408278c2..08fd06cb 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 0.8.3 + 0.8.4-SNAPSHOT jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:https://github.com/socketio/engine.io-client-java.git scm:git:https://github.com/socketio/engine.io-client-java.git - engine.io-client-0.8.3 + HEAD From c817af5b224ebf9c0248e62283b25b673851cd80 Mon Sep 17 00:00:00 2001 From: Yu-Hsuan Lin Date: Tue, 2 May 2017 01:15:47 +0800 Subject: [PATCH 33/72] Options for inject okhttp Call/WebSocket factory --- README.md | 13 +- pom.xml | 2 +- .../io/socket/engineio/client/Socket.java | 74 +++---- .../io/socket/engineio/client/Transport.java | 31 +-- .../client/transports/PollingXHR.java | 180 ++++++------------ .../engineio/client/transports/WebSocket.java | 63 ++---- .../socket/engineio/client/ExecutionTest.java | 2 +- .../engineio/client/SSLConnectionTest.java | 85 +++++---- .../engineio/client/ServerConnectionTest.java | 2 +- 9 files changed, 184 insertions(+), 268 deletions(-) diff --git a/README.md b/README.md index a96485eb..041a8734 100644 --- a/README.md +++ b/README.md @@ -94,14 +94,19 @@ socket.on(Socket.EVENT_OPEN, new Emitter.Listener() { Use custom SSL settings: ```java +OkHttpClient okHttpClient = new OkHttpClient.Builder() + .hostnameVerifier(myHostnameVerifier) + .sslSocketFactory(mySSLContext.getSocketFactory(), myX509TrustManager) + .build(); + // default SSLContext for all sockets -Socket.setDefaultSSLContext(mySSLContext); -Socket.setDefaultHostnameVerifier(myHostnameVerifier); +Socket.setDefaultOkHttpWebSocketFactory(okHttpClient); +Socket.setDefaultOkHttpCallFactory(okHttpClient); // set as an option opts = new Socket.Options(); -opts.sslContext = mySSLContext; -opts.hostnameVerifier = myHostnameVerifier; +opts.callFactory = okHttpClient; +opts.webSocketFactory = okHttpClient; socket = new Socket(opts); ``` diff --git a/pom.xml b/pom.xml index 08fd06cb..2c3a9f31 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ com.squareup.okhttp3 okhttp - 3.5.0 + 3.7.0 org.json diff --git a/src/main/java/io/socket/engineio/client/Socket.java b/src/main/java/io/socket/engineio/client/Socket.java index 1a919942..c7730004 100644 --- a/src/main/java/io/socket/engineio/client/Socket.java +++ b/src/main/java/io/socket/engineio/client/Socket.java @@ -1,27 +1,31 @@ package io.socket.engineio.client; -import io.socket.emitter.Emitter; -import io.socket.engineio.client.transports.Polling; -import io.socket.engineio.client.transports.PollingXHR; -import io.socket.engineio.client.transports.WebSocket; -import io.socket.engineio.parser.Packet; -import io.socket.engineio.parser.Parser; -import io.socket.parseqs.ParseQS; -import io.socket.thread.EventThread; import org.json.JSONException; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; -import java.net.Proxy; import java.net.URI; import java.net.URISyntaxException; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import io.socket.emitter.Emitter; +import io.socket.engineio.client.transports.Polling; +import io.socket.engineio.client.transports.PollingXHR; +import io.socket.engineio.client.transports.WebSocket; +import io.socket.engineio.parser.Packet; +import io.socket.engineio.parser.Parser; +import io.socket.parseqs.ParseQS; +import io.socket.thread.EventThread; +import okhttp3.OkHttpClient; + /** * The socket class for Event.IO Client. @@ -98,8 +102,9 @@ public String toString() { private static boolean priorWebsocketSuccess = false; - private static SSLContext defaultSSLContext; - private static HostnameVerifier defaultHostnameVerifier; + private static okhttp3.WebSocket.Factory defaultWebSocketFactory; + private static okhttp3.Call.Factory defaultCallFactory; + private static OkHttpClient defaultOkHttpClient; private boolean secure; private boolean upgrade; @@ -122,11 +127,8 @@ public String toString() { /*package*/ Transport transport; private Future pingTimeoutTimer; private Future pingIntervalTimer; - private SSLContext sslContext; - private HostnameVerifier hostnameVerifier; - public Proxy proxy; - public String proxyLogin; - public String proxyPassword; + private okhttp3.WebSocket.Factory webSocketFactory; + private okhttp3.Call.Factory callFactory; private ReadyState readyState; private ScheduledExecutorService heartbeatScheduler; @@ -190,7 +192,6 @@ public Socket(Options opts) { opts.port = this.secure ? 443 : 80; } - this.sslContext = opts.sslContext != null ? opts.sslContext : defaultSSLContext; this.hostname = opts.hostname != null ? opts.hostname : "localhost"; this.port = opts.port; this.query = opts.query != null ? @@ -203,18 +204,28 @@ public Socket(Options opts) { opts.transports : new String[]{Polling.NAME, WebSocket.NAME})); this.policyPort = opts.policyPort != 0 ? opts.policyPort : 843; this.rememberUpgrade = opts.rememberUpgrade; - this.hostnameVerifier = opts.hostnameVerifier != null ? opts.hostnameVerifier : defaultHostnameVerifier; - this.proxy = opts.proxy; - this.proxyLogin = opts.proxyLogin; - this.proxyPassword = opts.proxyPassword; + this.callFactory = opts.callFactory != null ? opts.callFactory : defaultCallFactory; + this.webSocketFactory = opts.webSocketFactory != null ? opts.webSocketFactory : defaultWebSocketFactory; + if (callFactory == null) { + if (defaultOkHttpClient == null) { + defaultOkHttpClient = new OkHttpClient(); + } + callFactory = defaultOkHttpClient; + } + if (webSocketFactory == null) { + if (defaultOkHttpClient == null) { + defaultOkHttpClient = new OkHttpClient(); + } + webSocketFactory = defaultOkHttpClient; + } } - public static void setDefaultSSLContext(SSLContext sslContext) { - defaultSSLContext = sslContext; + public static void setDefaultOkHttpWebSocketFactory(okhttp3.WebSocket.Factory factory) { + defaultWebSocketFactory = factory; } - public static void setDefaultHostnameVerifier(HostnameVerifier hostnameVerifier) { - defaultHostnameVerifier = hostnameVerifier; + public static void setDefaultOkHttpCallFactory(okhttp3.Call.Factory factory) { + defaultCallFactory = factory; } /** @@ -262,7 +273,6 @@ private Transport createTransport(String name) { } Transport.Options opts = new Transport.Options(); - opts.sslContext = this.sslContext; opts.hostname = this.hostname; opts.port = this.port; opts.secure = this.secure; @@ -272,10 +282,8 @@ private Transport createTransport(String name) { opts.timestampParam = this.timestampParam; opts.policyPort = this.policyPort; opts.socket = this; - opts.hostnameVerifier = this.hostnameVerifier; - opts.proxy = this.proxy; - opts.proxyLogin = this.proxyLogin; - opts.proxyPassword = this.proxyPassword; + opts.callFactory = this.callFactory; + opts.webSocketFactory = this.webSocketFactory; Transport transport; if (WebSocket.NAME.equals(name)) { diff --git a/src/main/java/io/socket/engineio/client/Transport.java b/src/main/java/io/socket/engineio/client/Transport.java index d11cd050..442c7762 100644 --- a/src/main/java/io/socket/engineio/client/Transport.java +++ b/src/main/java/io/socket/engineio/client/Transport.java @@ -1,16 +1,15 @@ package io.socket.engineio.client; +import java.util.Map; + import io.socket.emitter.Emitter; import io.socket.engineio.parser.Packet; import io.socket.engineio.parser.Parser; import io.socket.thread.EventThread; import io.socket.utf8.UTF8Exception; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; -import java.net.Proxy; -import java.util.Map; +import okhttp3.Call; +import okhttp3.WebSocket; public abstract class Transport extends Emitter { @@ -41,14 +40,10 @@ public String toString() { protected String path; protected String hostname; protected String timestampParam; - protected SSLContext sslContext; protected Socket socket; - protected HostnameVerifier hostnameVerifier; - protected Proxy proxy; - protected String proxyLogin; - protected String proxyPassword; - protected ReadyState readyState; + protected WebSocket.Factory webSocketFactory; + protected Call.Factory callFactory; public Transport(Options opts) { this.path = opts.path; @@ -58,12 +53,9 @@ public Transport(Options opts) { this.query = opts.query; this.timestampParam = opts.timestampParam; this.timestampRequests = opts.timestampRequests; - this.sslContext = opts.sslContext; this.socket = opts.socket; - this.hostnameVerifier = opts.hostnameVerifier; - this.proxy = opts.proxy; - this.proxyLogin = opts.proxyLogin; - this.proxyPassword = opts.proxyPassword; + this.webSocketFactory = opts.webSocketFactory; + this.callFactory = opts.callFactory; } protected Transport onError(String msg, Exception desc) { @@ -156,11 +148,8 @@ public static class Options { public int port = -1; public int policyPort = -1; public Map query; - public SSLContext sslContext; - public HostnameVerifier hostnameVerifier; protected Socket socket; - public Proxy proxy; - public String proxyLogin; - public String proxyPassword; + public WebSocket.Factory webSocketFactory; + public Call.Factory callFactory; } } diff --git a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java index 45eb6d90..5262c6c8 100644 --- a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java +++ b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java @@ -1,20 +1,25 @@ package io.socket.engineio.client.transports; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.logging.Logger; + import io.socket.emitter.Emitter; import io.socket.engineio.client.Transport; import io.socket.thread.EventThread; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import java.io.*; -import java.net.HttpURLConnection; -import java.net.Proxy; -import java.net.URL; -import java.nio.ByteBuffer; -import java.util.*; -import java.util.logging.Logger; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.RequestBody; +import okhttp3.Response; public class PollingXHR extends Polling { @@ -33,9 +38,7 @@ protected Request request(Request.Options opts) { opts = new Request.Options(); } opts.uri = this.uri(); - opts.sslContext = this.sslContext; - opts.hostnameVerifier = this.hostnameVerifier; - opts.proxy = this.proxy; + opts.callFactory = this.callFactory; Request req = new Request(opts); @@ -136,6 +139,7 @@ public static class Request extends Emitter { public static final String EVENT_ERROR = "error"; public static final String EVENT_REQUEST_HEADERS = "requestHeaders"; public static final String EVENT_RESPONSE_HEADERS = "responseHeaders"; + private static final String BINARY_CONTENT_TYPE = "application/octet-stream"; private String method; private String uri; @@ -143,93 +147,60 @@ public static class Request extends Emitter { // data is always a binary private byte[] data; - private SSLContext sslContext; - private HttpURLConnection xhr; - private HostnameVerifier hostnameVerifier; - private Proxy proxy; + private Call.Factory callFactory; + private Response response; + private Call requestCall; public Request(Options opts) { this.method = opts.method != null ? opts.method : "GET"; this.uri = opts.uri; this.data = opts.data; - this.sslContext = opts.sslContext; - this.hostnameVerifier = opts.hostnameVerifier; - this.proxy = opts.proxy; + this.callFactory = opts.callFactory != null ? opts.callFactory : new OkHttpClient(); } public void create() { final Request self = this; - try { - logger.fine(String.format("xhr open %s: %s", this.method, this.uri)); - URL url = new URL(this.uri); - xhr = proxy != null ? (HttpURLConnection) url.openConnection(proxy) - : (HttpURLConnection) url.openConnection(); - xhr.setRequestMethod(this.method); - } catch (IOException e) { - this.onError(e); - return; - } - - xhr.setConnectTimeout(10000); - - if (xhr instanceof HttpsURLConnection) { - if (this.sslContext != null) { - ((HttpsURLConnection)xhr).setSSLSocketFactory(this.sslContext.getSocketFactory()); - } - if (this.hostnameVerifier != null) { - ((HttpsURLConnection)xhr).setHostnameVerifier(this.hostnameVerifier); - } - } - + logger.fine(String.format("xhr open %s: %s", this.method, this.uri)); Map> headers = new TreeMap>(String.CASE_INSENSITIVE_ORDER); if ("POST".equals(this.method)) { - xhr.setDoOutput(true); - headers.put("Content-type", new LinkedList(Arrays.asList("application/octet-stream"))); + headers.put("Content-type", new LinkedList(Collections.singletonList(BINARY_CONTENT_TYPE))); } self.onRequestHeaders(headers); + + logger.fine(String.format("sending xhr with url %s | data %s", this.uri, Arrays.toString(this.data))); + okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder(); for (Map.Entry> header : headers.entrySet()) { for (String v : header.getValue()){ - xhr.addRequestProperty(header.getKey(), v); + requestBuilder.addHeader(header.getKey(), v); } } - - logger.fine(String.format("sending xhr with url %s | data %s", this.uri, this.data)); - new Thread(new Runnable() { + okhttp3.Request request = requestBuilder + .url(HttpUrl.parse(self.uri)) + .method(self.method, (self.data != null) ? + RequestBody.create(MediaType.parse(BINARY_CONTENT_TYPE), self.data) : null) + .build(); + + requestCall = callFactory.newCall(request); + requestCall.enqueue(new Callback() { @Override - public void run() { - OutputStream output = null; - try { - if (self.data != null) { - xhr.setFixedLengthStreamingMode(self.data.length); - output = new BufferedOutputStream(xhr.getOutputStream()); - output.write(self.data); - output.flush(); - } - - Map> headers = xhr.getHeaderFields(); - self.onResponseHeaders(headers); + public void onFailure(Call call, IOException e) { + self.onError(e); + } - final int statusCode = xhr.getResponseCode(); - if (HttpURLConnection.HTTP_OK == statusCode) { - self.onLoad(); - } else { - self.onError(new IOException(Integer.toString(statusCode))); - } - } catch (IOException e) { - self.onError(e); - } catch (NullPointerException e) { - // It would occur to disconnect - // https://code.google.com/p/android/issues/detail?id=76592 - self.onError(e); - } finally { - try { - if (output != null) output.close(); - } catch (IOException e) {} + @Override + public void onResponse(Call call, Response response) throws IOException { + self.response = response; + self.onResponseHeaders(response.headers().toMultimap()); + + if (response.isSuccessful()) { + self.onLoad(); + } else { + self.onError(new IOException(Integer.toString(response.code()))); } } - }).start(); + }); } private void onSuccess() { @@ -258,56 +229,17 @@ private void onResponseHeaders(Map> headers) { this.emit(EVENT_RESPONSE_HEADERS, headers); } - private void cleanup() { - if (xhr == null) { - return; - } - - xhr.disconnect(); - xhr = null; - } - private void onLoad() { - InputStream input = null; - BufferedReader reader = null; - String contentType = xhr.getContentType(); + String contentType = response.body().contentType().toString(); + try { - if ("application/octet-stream".equalsIgnoreCase(contentType)) { - input = new BufferedInputStream(this.xhr.getInputStream()); - List buffers = new ArrayList(); - int capacity = 0; - int len = 0; - byte[] buffer = new byte[1024]; - while ((len = input.read(buffer)) > 0) { - byte[] tempBuffer = new byte[len]; - System.arraycopy(buffer, 0, tempBuffer, 0, len); - buffers.add(tempBuffer); - capacity += len; - } - ByteBuffer data = ByteBuffer.allocate(capacity); - for (byte[] b : buffers) { - data.put(b); - } - this.onData(data.array()); + if (BINARY_CONTENT_TYPE.equalsIgnoreCase(contentType)) { + this.onData(response.body().bytes()); } else { - String line; - StringBuilder data = new StringBuilder(); - reader = new BufferedReader(new InputStreamReader(xhr.getInputStream())); - while ((line = reader.readLine()) != null) { - data.append(line); - } - this.onData(data.toString()); + this.onData(response.body().string()); } } catch (IOException e) { this.onError(e); - } finally { - try { - if (input != null) input.close(); - } catch (IOException e) {} - try { - if (reader != null) reader.close(); - } catch (IOException e) {} - this.cleanup(); } } @@ -316,9 +248,7 @@ public static class Options { public String uri; public String method; public byte[] data; - public SSLContext sslContext; - public HostnameVerifier hostnameVerifier; - public Proxy proxy; + public Call.Factory callFactory; } } } diff --git a/src/main/java/io/socket/engineio/client/transports/WebSocket.java b/src/main/java/io/socket/engineio/client/transports/WebSocket.java index 313f5570..d6e2f1a3 100644 --- a/src/main/java/io/socket/engineio/client/transports/WebSocket.java +++ b/src/main/java/io/socket/engineio/client/transports/WebSocket.java @@ -1,6 +1,12 @@ package io.socket.engineio.client.transports; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.logging.Logger; + import io.socket.engineio.client.Transport; import io.socket.engineio.parser.Packet; import io.socket.engineio.parser.Parser; @@ -8,18 +14,12 @@ import io.socket.thread.EventThread; import io.socket.utf8.UTF8Exception; import io.socket.yeast.Yeast; -import okhttp3.*; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.WebSocketListener; import okio.ByteString; -import javax.net.ssl.SSLSocketFactory; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; - public class WebSocket extends Transport { @@ -39,34 +39,7 @@ protected void doOpen() { this.emit(EVENT_REQUEST_HEADERS, headers); final WebSocket self = this; - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder() - // turn off timeouts (github.com/socketio/engine.io-client-java/issues/32) - .connectTimeout(0, TimeUnit.MILLISECONDS) - .readTimeout(0, TimeUnit.MILLISECONDS) - .writeTimeout(0, TimeUnit.MILLISECONDS); - - if (this.sslContext != null) { - SSLSocketFactory factory = sslContext.getSocketFactory();// (SSLSocketFactory) SSLSocketFactory.getDefault(); - clientBuilder.sslSocketFactory(factory); - } - if (this.hostnameVerifier != null) { - clientBuilder.hostnameVerifier(this.hostnameVerifier); - } - if (proxy != null) { - clientBuilder.proxy(proxy); - } - if (proxyLogin != null && !proxyLogin.isEmpty()) { - final String credentials = Credentials.basic(proxyLogin, proxyPassword); - - clientBuilder.proxyAuthenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - return response.request().newBuilder() - .header("Proxy-Authorization", credentials) - .build(); - } - }); - } + okhttp3.WebSocket.Factory factory = webSocketFactory != null ? webSocketFactory : new OkHttpClient(); Request.Builder builder = new Request.Builder().url(uri()); for (Map.Entry> entry : headers.entrySet()) { for (String v : entry.getValue()) { @@ -74,8 +47,7 @@ public Request authenticate(Route route, Response response) throws IOException { } } final Request request = builder.build(); - final OkHttpClient client = clientBuilder.build(); - ws = client.newWebSocket(request, new WebSocketListener() { + ws = factory.newWebSocket(request, new WebSocketListener() { @Override public void onOpen(okhttp3.WebSocket webSocket, Response response) { final Map> headers = response.headers().toMultimap(); @@ -137,7 +109,6 @@ public void run() { }); } }); - client.dispatcher().executorService().shutdown(); } protected void write(Packet[] packets) throws UTF8Exception { @@ -187,14 +158,8 @@ public void call(Object packet) { protected void doClose() { if (ws != null) { - try { - ws.close(1000, ""); - } catch (IllegalStateException e) { - // websocket already closed - } - } - if (ws != null) { - ws.cancel(); + ws.close(1000, ""); + ws = null; } } diff --git a/src/test/java/io/socket/engineio/client/ExecutionTest.java b/src/test/java/io/socket/engineio/client/ExecutionTest.java index a24a6f87..4f6a32ed 100644 --- a/src/test/java/io/socket/engineio/client/ExecutionTest.java +++ b/src/test/java/io/socket/engineio/client/ExecutionTest.java @@ -17,7 +17,7 @@ public class ExecutionTest extends Connection { private static final Logger logger = Logger.getLogger(Socket.class.getName()); - final static int TIMEOUT = 30 * 1000; + final static int TIMEOUT = 100 * 1000; @Test(timeout = TIMEOUT) public void execConnection() throws InterruptedException, IOException { diff --git a/src/test/java/io/socket/engineio/client/SSLConnectionTest.java b/src/test/java/io/socket/engineio/client/SSLConnectionTest.java index 76037eff..2e6a128f 100644 --- a/src/test/java/io/socket/engineio/client/SSLConnectionTest.java +++ b/src/test/java/io/socket/engineio/client/SSLConnectionTest.java @@ -1,15 +1,10 @@ package io.socket.engineio.client; -import io.socket.emitter.Emitter; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -18,38 +13,35 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +import io.socket.emitter.Emitter; +import okhttp3.OkHttpClient; + import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; @RunWith(JUnit4.class) public class SSLConnectionTest extends Connection { - static HostnameVerifier hostnameVerifier = new javax.net.ssl.HostnameVerifier(){ - public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) { - return hostname.equals("localhost"); - } - }; + private static OkHttpClient sOkHttpClient; private Socket socket; - @After - public void tearDown() { - Socket.setDefaultSSLContext(null); - } - - @Override - Socket.Options createOptions() { - Socket.Options opts = super.createOptions(); - opts.secure = true; - return opts; - } - - @Override - String[] createEnv() { - return new String[] {"DEBUG=engine*", "PORT=" + PORT, "SSL=1"}; + static { + try { + prepareOkHttpClient(); + } catch (GeneralSecurityException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } } - SSLContext createSSLContext() throws GeneralSecurityException, IOException { + private static void prepareOkHttpClient() throws GeneralSecurityException, IOException { KeyStore ks = KeyStore.getInstance("JKS"); File file = new File("src/test/resources/keystore.jks"); ks.load(new FileInputStream(file), "password".toCharArray()); @@ -62,7 +54,34 @@ SSLContext createSSLContext() throws GeneralSecurityException, IOException { SSLContext sslContext = SSLContext.getInstance("TLSv1"); sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - return sslContext; + + sOkHttpClient = new OkHttpClient.Builder() + .hostnameVerifier(new javax.net.ssl.HostnameVerifier(){ + public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) { + return hostname.equals("localhost"); + } + }) + .sslSocketFactory(sslContext.getSocketFactory(), + (X509TrustManager) tmf.getTrustManagers()[0]) + .build(); + } + + @After + public void tearDown() { + Socket.setDefaultOkHttpCallFactory(null); + Socket.setDefaultOkHttpWebSocketFactory(null); + } + + @Override + Socket.Options createOptions() { + Socket.Options opts = super.createOptions(); + opts.secure = true; + return opts; + } + + @Override + String[] createEnv() { + return new String[] {"DEBUG=engine*", "PORT=" + PORT, "SSL=1"}; } @Test(timeout = TIMEOUT) @@ -70,8 +89,8 @@ public void connect() throws Exception { final BlockingQueue values = new LinkedBlockingQueue(); Socket.Options opts = createOptions(); - opts.sslContext = createSSLContext(); - opts.hostnameVerifier = SSLConnectionTest.hostnameVerifier; + opts.callFactory = sOkHttpClient; + opts.webSocketFactory = sOkHttpClient; socket = new Socket(opts); socket.on(Socket.EVENT_OPEN, new Emitter.Listener() { @Override @@ -95,8 +114,8 @@ public void upgrade() throws Exception { final BlockingQueue values = new LinkedBlockingQueue(); Socket.Options opts = createOptions(); - opts.sslContext = createSSLContext(); - opts.hostnameVerifier = SSLConnectionTest.hostnameVerifier; + opts.callFactory = sOkHttpClient; + opts.webSocketFactory = sOkHttpClient; socket = new Socket(opts); socket.on(Socket.EVENT_OPEN, new Emitter.Listener() { @Override @@ -125,8 +144,8 @@ public void call(Object... args) { public void defaultSSLContext() throws Exception { final BlockingQueue values = new LinkedBlockingQueue(); - Socket.setDefaultSSLContext(createSSLContext()); - Socket.setDefaultHostnameVerifier(SSLConnectionTest.hostnameVerifier); + Socket.setDefaultOkHttpWebSocketFactory(sOkHttpClient); + Socket.setDefaultOkHttpCallFactory(sOkHttpClient); socket = new Socket(createOptions()); socket.on(Socket.EVENT_OPEN, new Emitter.Listener() { @Override diff --git a/src/test/java/io/socket/engineio/client/ServerConnectionTest.java b/src/test/java/io/socket/engineio/client/ServerConnectionTest.java index c2bdaad5..2beb744a 100644 --- a/src/test/java/io/socket/engineio/client/ServerConnectionTest.java +++ b/src/test/java/io/socket/engineio/client/ServerConnectionTest.java @@ -163,8 +163,8 @@ public void call(Object... args) { }); socket.open(); - assertThat(messages.take(), is("foo")); assertThat(messages.take(), is("hi")); + assertThat(messages.take(), is("foo")); socket.close(); } From 115f32171d58b2789beb1876a746faab6fa4c91c Mon Sep 17 00:00:00 2001 From: nkzawa Date: Tue, 11 Jul 2017 18:16:49 +0900 Subject: [PATCH 34/72] parser: check empty arg --- src/main/java/io/socket/engineio/parser/Parser.java | 4 ++++ src/test/java/io/socket/engineio/parser/ParserTest.java | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/src/main/java/io/socket/engineio/parser/Parser.java b/src/main/java/io/socket/engineio/parser/Parser.java index 010ba9c8..c34dce59 100644 --- a/src/main/java/io/socket/engineio/parser/Parser.java +++ b/src/main/java/io/socket/engineio/parser/Parser.java @@ -76,6 +76,10 @@ public static Packet decodePacket(String data) { } public static Packet decodePacket(String data, boolean utf8decode) { + if (data == null) { + return err; + } + int type; try { type = Character.getNumericValue(data.charAt(0)); diff --git a/src/test/java/io/socket/engineio/parser/ParserTest.java b/src/test/java/io/socket/engineio/parser/ParserTest.java index a9043123..86b7c7f7 100644 --- a/src/test/java/io/socket/engineio/parser/ParserTest.java +++ b/src/test/java/io/socket/engineio/parser/ParserTest.java @@ -156,6 +156,13 @@ public void call(String data) { }); } + @Test + public void decodeEmptyPayload() { + Packet p = decodePacket((String)null); + assertThat(p.type, is(Packet.ERROR)); + assertThat(p.data, is(ERROR_DATA)); + } + @Test public void decodeBadFormat() { Packet p = decodePacket(":::"); From bb323f00ae002f3819e0c0ed3d0782b52989cf15 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Tue, 11 Jul 2017 19:10:40 +0900 Subject: [PATCH 35/72] onPacket now emits data on 'closing' state as well --- src/main/java/io/socket/engineio/client/Socket.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/socket/engineio/client/Socket.java b/src/main/java/io/socket/engineio/client/Socket.java index c7730004..796b88fb 100644 --- a/src/main/java/io/socket/engineio/client/Socket.java +++ b/src/main/java/io/socket/engineio/client/Socket.java @@ -496,7 +496,9 @@ private void onOpen() { } private void onPacket(Packet packet) { - if (this.readyState == ReadyState.OPENING || this.readyState == ReadyState.OPEN) { + if (this.readyState == ReadyState.OPENING || + this.readyState == ReadyState.OPEN || + this.readyState == ReadyState.CLOSING) { logger.fine(String.format("socket received: type '%s', data '%s'", packet.type, packet.data)); this.emit(EVENT_PACKET, packet); From 633120459f235f4741729d17de727e2a622f2372 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Tue, 11 Jul 2017 19:11:28 +0900 Subject: [PATCH 36/72] test against engine.io 1.8.4 --- src/test/resources/package-lock.json | 136 +++++++++++++++++++++++++++ src/test/resources/package.json | 2 +- 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/package-lock.json diff --git a/src/test/resources/package-lock.json b/src/test/resources/package-lock.json new file mode 100644 index 00000000..92892601 --- /dev/null +++ b/src/test/resources/package-lock.json @@ -0,0 +1,136 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "arraybuffer.slice": { + "version": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", + "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=" + }, + "blob": { + "version": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "engine.io": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.4.tgz", + "integrity": "sha1-d7zhK4Dl1gQpM3/sOw2vaR68kAM=", + "requires": { + "accepts": "1.3.3", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "2.3.3", + "engine.io-parser": "1.3.2", + "ws": "1.1.4" + }, + "dependencies": { + "accepts": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", + "requires": { + "mime-types": "2.1.15", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "requires": { + "ms": "0.7.2" + } + }, + "engine.io-parser": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz", + "integrity": "sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo=", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", + "base64-arraybuffer": "0.1.5", + "blob": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "has-binary": "0.1.7", + "wtf-8": "1.0.0" + } + }, + "has-binary": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", + "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=", + "requires": { + "isarray": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" + } + }, + "mime-db": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", + "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=" + }, + "mime-types": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", + "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", + "requires": { + "mime-db": "1.27.0" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "ws": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.4.tgz", + "integrity": "sha1-V/QNA2gy5fUFVmKjl8Tedu1mv2E=", + "requires": { + "options": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "ultron": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz" + } + } + } + }, + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "options": { + "version": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" + }, + "ultron": { + "version": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" + }, + "wtf-8": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz", + "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=" + } + } +} diff --git a/src/test/resources/package.json b/src/test/resources/package.json index 794d3686..68be2fbb 100644 --- a/src/test/resources/package.json +++ b/src/test/resources/package.json @@ -1,6 +1,6 @@ { "private": true, "dependencies": { - "engine.io": "1.6.11" + "engine.io": "1.8.4" } } From 850a5110b94163307a7aaf66a4d09e2e5331914a Mon Sep 17 00:00:00 2001 From: nkzawa Date: Tue, 11 Jul 2017 19:44:30 +0900 Subject: [PATCH 37/72] set accept header --- .../java/io/socket/engineio/client/transports/PollingXHR.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java index 5262c6c8..e72b5fbd 100644 --- a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java +++ b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java @@ -167,6 +167,8 @@ public void create() { headers.put("Content-type", new LinkedList(Collections.singletonList(BINARY_CONTENT_TYPE))); } + headers.put("Accept", new LinkedList(Collections.singletonList("*/*"))); + self.onRequestHeaders(headers); logger.fine(String.format("sending xhr with url %s | data %s", this.uri, Arrays.toString(this.data))); From 75da2ea0b7a5e292ecd9cdbcc84620c03d17d6cc Mon Sep 17 00:00:00 2001 From: nkzawa Date: Tue, 11 Jul 2017 20:23:35 +0900 Subject: [PATCH 38/72] bump okhttp --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2c3a9f31..8933d7e6 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ com.squareup.okhttp3 okhttp - 3.7.0 + 3.8.1 org.json From f3d92f9aac62a0c74dfbf4d1a685a62a5b011be8 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Tue, 11 Jul 2017 21:26:22 +0900 Subject: [PATCH 39/72] polling-xhr: always close body --- .../engineio/client/transports/PollingXHR.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java index e72b5fbd..52d01121 100644 --- a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java +++ b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java @@ -20,6 +20,7 @@ import okhttp3.OkHttpClient; import okhttp3.RequestBody; import okhttp3.Response; +import okhttp3.ResponseBody; public class PollingXHR extends Polling { @@ -196,10 +197,14 @@ public void onResponse(Call call, Response response) throws IOException { self.response = response; self.onResponseHeaders(response.headers().toMultimap()); - if (response.isSuccessful()) { - self.onLoad(); - } else { - self.onError(new IOException(Integer.toString(response.code()))); + try { + if (response.isSuccessful()) { + self.onLoad(); + } else { + self.onError(new IOException(Integer.toString(response.code()))); + } + } finally { + response.close(); } } }); From 3ce2c9b72e5defe3061f39fa563df8a467cc35cf Mon Sep 17 00:00:00 2001 From: nkzawa Date: Tue, 11 Jul 2017 21:27:11 +0900 Subject: [PATCH 40/72] cache response.body call just in case --- .../io/socket/engineio/client/transports/PollingXHR.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java index 52d01121..d0e26755 100644 --- a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java +++ b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java @@ -237,13 +237,14 @@ private void onResponseHeaders(Map> headers) { } private void onLoad() { - String contentType = response.body().contentType().toString(); + ResponseBody body = response.body(); + String contentType = body.contentType().toString(); try { if (BINARY_CONTENT_TYPE.equalsIgnoreCase(contentType)) { - this.onData(response.body().bytes()); + this.onData(body.bytes()); } else { - this.onData(response.body().string()); + this.onData(body.string()); } } catch (IOException e) { this.onError(e); From 8a35f112fa5c991e15fd8676e489644c1955b72f Mon Sep 17 00:00:00 2001 From: nkzawa Date: Wed, 12 Jul 2017 01:53:26 +0900 Subject: [PATCH 41/72] update version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8933d7e6..64651273 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 0.8.4-SNAPSHOT + 0.9.0-SNAPSHOT jar engine.io-client Engine.IO Client Library for Java From 80cf5a1d4197f77287e440b757c741e41e40c0fc Mon Sep 17 00:00:00 2001 From: nkzawa Date: Wed, 12 Jul 2017 02:13:28 +0900 Subject: [PATCH 42/72] [maven-release-plugin] prepare release engine.io-client-0.9.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 64651273..62894cc1 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 0.9.0-SNAPSHOT + 0.9.0 jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:https://github.com/socketio/engine.io-client-java.git scm:git:https://github.com/socketio/engine.io-client-java.git - HEAD + engine.io-client-0.9.0 From 60a0f96905fe02b49608765373dc3b3a9a454098 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Wed, 12 Jul 2017 02:13:43 +0900 Subject: [PATCH 43/72] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 62894cc1..106422f0 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 0.9.0 + 0.9.1-SNAPSHOT jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:https://github.com/socketio/engine.io-client-java.git scm:git:https://github.com/socketio/engine.io-client-java.git - engine.io-client-0.9.0 + HEAD From 4f5f774a4688dd512fe6936fff076f4a5e65124f Mon Sep 17 00:00:00 2001 From: nkzawa Date: Wed, 12 Jul 2017 02:33:21 +0900 Subject: [PATCH 44/72] update History.md --- History.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/History.md b/History.md index 120ba524..641a2e2e 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,13 @@ +0.9.0 / 2017-07-11 +================== + +* compatible with engine.io 1.8.4 +* add options for injecting OKHttpClient [@b95505017] +* emit data on `closing` state on onPacket as well +* set default accept header +* update okhttp + 0.8.3 / 2016-12-12 ================== From e4f1a56cfc39b0d82363ccad36ca0c9a92f70818 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Wed, 12 Jul 2017 12:30:12 +0900 Subject: [PATCH 45/72] test: shutdown okhttpclient --- .../io/socket/engineio/client/ExecutionTest.java | 2 +- .../engineio/client/executions/Connection.java | 14 +++++++++++++- .../client/executions/ConnectionFailure.java | 9 ++++++++- .../engineio/client/executions/ImmediateClose.java | 9 ++++++++- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/test/java/io/socket/engineio/client/ExecutionTest.java b/src/test/java/io/socket/engineio/client/ExecutionTest.java index 4f6a32ed..a24a6f87 100644 --- a/src/test/java/io/socket/engineio/client/ExecutionTest.java +++ b/src/test/java/io/socket/engineio/client/ExecutionTest.java @@ -17,7 +17,7 @@ public class ExecutionTest extends Connection { private static final Logger logger = Logger.getLogger(Socket.class.getName()); - final static int TIMEOUT = 100 * 1000; + final static int TIMEOUT = 30 * 1000; @Test(timeout = TIMEOUT) public void execConnection() throws InterruptedException, IOException { diff --git a/src/test/java/io/socket/engineio/client/executions/Connection.java b/src/test/java/io/socket/engineio/client/executions/Connection.java index ac91686e..0bc7e0bd 100644 --- a/src/test/java/io/socket/engineio/client/executions/Connection.java +++ b/src/test/java/io/socket/engineio/client/executions/Connection.java @@ -2,13 +2,19 @@ import io.socket.emitter.Emitter; import io.socket.engineio.client.Socket; +import okhttp3.OkHttpClient; import java.net.URISyntaxException; public class Connection { public static void main(String[] args) throws URISyntaxException { - final Socket socket = new Socket("http://localhost:" + System.getenv("PORT")); + final OkHttpClient client = new OkHttpClient(); + Socket.Options opts = new Socket.Options(); + opts.webSocketFactory = client; + opts.callFactory = client; + + final Socket socket = new Socket("http://localhost:" + System.getenv("PORT"), opts); socket.on(Socket.EVENT_OPEN, new Emitter.Listener() { @Override public void call(Object... args) { @@ -16,6 +22,12 @@ public void call(Object... args) { socket.close(); } }); + socket.on(Socket.EVENT_CLOSE, new Emitter.Listener() { + @Override + public void call(Object... args) { + client.dispatcher().executorService().shutdown(); + } + }); socket.open(); } } diff --git a/src/test/java/io/socket/engineio/client/executions/ConnectionFailure.java b/src/test/java/io/socket/engineio/client/executions/ConnectionFailure.java index 54501138..890fe1d1 100644 --- a/src/test/java/io/socket/engineio/client/executions/ConnectionFailure.java +++ b/src/test/java/io/socket/engineio/client/executions/ConnectionFailure.java @@ -2,15 +2,21 @@ import io.socket.emitter.Emitter; import io.socket.engineio.client.Socket; +import okhttp3.OkHttpClient; import java.net.URISyntaxException; public class ConnectionFailure { public static void main(String[] args) throws URISyntaxException { + final OkHttpClient client = new OkHttpClient(); + Socket.Options opts = new Socket.Options(); + opts.webSocketFactory = client; + opts.callFactory = client; + int port = Integer.parseInt(System.getenv("PORT")); port++; - final Socket socket = new Socket("http://localhost:" + port); + final Socket socket = new Socket("http://localhost:" + port, opts); socket.on(Socket.EVENT_CLOSE, new Emitter.Listener() { @Override public void call(Object... args) { @@ -20,6 +26,7 @@ public void call(Object... args) { @Override public void call(Object... args) { System.out.println("error"); + client.dispatcher().executorService().shutdown(); } }); socket.open(); diff --git a/src/test/java/io/socket/engineio/client/executions/ImmediateClose.java b/src/test/java/io/socket/engineio/client/executions/ImmediateClose.java index c90b11fb..0c087159 100644 --- a/src/test/java/io/socket/engineio/client/executions/ImmediateClose.java +++ b/src/test/java/io/socket/engineio/client/executions/ImmediateClose.java @@ -2,13 +2,19 @@ import io.socket.emitter.Emitter; import io.socket.engineio.client.Socket; +import okhttp3.OkHttpClient; import java.net.URISyntaxException; public class ImmediateClose { public static void main(String[] args) throws URISyntaxException { - final Socket socket = new Socket("http://localhost:" + System.getenv("PORT")); + final OkHttpClient client = new OkHttpClient(); + Socket.Options opts = new Socket.Options(); + opts.webSocketFactory = client; + opts.callFactory = client; + + final Socket socket = new Socket("http://localhost:" + System.getenv("PORT"), opts); socket.on(Socket.EVENT_OPEN, new Emitter.Listener() { @Override public void call(Object... args) { @@ -18,6 +24,7 @@ public void call(Object... args) { @Override public void call(Object... args) { System.out.println("close"); + client.dispatcher().executorService().shutdown(); } }); socket.open(); From 8b07bbd9f07ddcc9a385441d9f79f62473cefcfc Mon Sep 17 00:00:00 2001 From: nkzawa Date: Wed, 12 Jul 2017 12:31:41 +0900 Subject: [PATCH 46/72] utf8: add strict option --- src/main/java/io/socket/utf8/UTF8.java | 45 +++++++++++++++++++------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/src/main/java/io/socket/utf8/UTF8.java b/src/main/java/io/socket/utf8/UTF8.java index 511d478f..e7145792 100644 --- a/src/main/java/io/socket/utf8/UTF8.java +++ b/src/main/java/io/socket/utf8/UTF8.java @@ -18,6 +18,12 @@ public final class UTF8 { private UTF8 () {} public static String encode(String string) throws UTF8Exception { + return encode(string, new Options()); + } + + public static String encode(String string, Options opts) throws UTF8Exception { + boolean strict = opts.strict; + int[] codePoints = ucs2decode(string); int length = codePoints.length; int index = -1; @@ -25,18 +31,24 @@ public static String encode(String string) throws UTF8Exception { StringBuilder byteString = new StringBuilder(); while (++index < length) { codePoint = codePoints[index]; - byteString.append(encodeCodePoint(codePoint)); + byteString.append(encodeCodePoint(codePoint, strict)); } return byteString.toString(); } public static String decode(String byteString) throws UTF8Exception { + return decode(byteString, new Options()); + } + + public static String decode(String byteString, Options opts) throws UTF8Exception { + boolean strict = opts.strict; + byteArray = ucs2decode(byteString); byteCount = byteArray.length; byteIndex = 0; List codePoints = new ArrayList(); int tmp; - while ((tmp = decodeSymbol()) != -1) { + while ((tmp = decodeSymbol(strict)) != -1) { codePoints.add(tmp); } return ucs2encode(listToArray(codePoints)); @@ -54,7 +66,7 @@ private static int[] ucs2decode(String string) { return output; } - private static String encodeCodePoint(int codePoint) throws UTF8Exception { + private static String encodeCodePoint(int codePoint, boolean strict) throws UTF8Exception { StringBuilder symbol = new StringBuilder(); if ((codePoint & 0xFFFFFF80) == 0) { return symbol.append(Character.toChars(codePoint)).toString(); @@ -62,7 +74,9 @@ private static String encodeCodePoint(int codePoint) throws UTF8Exception { if ((codePoint & 0xFFFFF800) == 0) { symbol.append(Character.toChars(((codePoint >> 6) & 0x1F) | 0xC0)); } else if ((codePoint & 0xFFFF0000) == 0) { - checkScalarValue(codePoint); + if (!checkScalarValue(codePoint, strict)) { + codePoint = 0xFFFD; + } symbol.append(Character.toChars(((codePoint >> 12) & 0x0F) | 0xE0)); symbol.append(createByte(codePoint, 6)); } else if ((codePoint & 0xFFE00000) == 0) { @@ -78,7 +92,7 @@ private static char[] createByte(int codePoint, int shift) { return Character.toChars(((codePoint >> shift) & 0x3F) | 0x80); } - private static int decodeSymbol() throws UTF8Exception { + private static int decodeSymbol(boolean strict) throws UTF8Exception { int byte1; int byte2; int byte3; @@ -115,8 +129,7 @@ private static int decodeSymbol() throws UTF8Exception { byte3 = readContinuationByte(); codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3; if (codePoint >= 0x0800) { - checkScalarValue(codePoint); - return codePoint; + return checkScalarValue(codePoint, strict) ? codePoint : 0xFFFD; } else { throw new UTF8Exception(INVALID_CONTINUATION_BYTE); } @@ -158,13 +171,17 @@ private static String ucs2encode(int[] array) { return output.toString(); } - private static void checkScalarValue(int codePoint) throws UTF8Exception { + private static boolean checkScalarValue(int codePoint, boolean strict) throws UTF8Exception { if (codePoint >= 0xD800 && codePoint <= 0xDFFF) { - throw new UTF8Exception( - "Lone surrogate U+" + Integer.toHexString(codePoint).toUpperCase() + - " is not a scalar value" - ); + if (strict) { + throw new UTF8Exception( + "Lone surrogate U+" + Integer.toHexString(codePoint).toUpperCase() + + " is not a scalar value" + ); + } + return false; } + return true; } private static int[] listToArray(List list) { @@ -175,4 +192,8 @@ private static int[] listToArray(List list) { } return array; } + + public static class Options { + public boolean strict = true; + } } From 1b3c79521038cba39344fe576b81f9935ddf883a Mon Sep 17 00:00:00 2001 From: nkzawa Date: Thu, 13 Jul 2017 12:47:00 +0900 Subject: [PATCH 47/72] update parser to not utf8 encode for string payloads --- .../engineio/client/transports/Polling.java | 14 +- .../client/transports/PollingXHR.java | 48 +++++- .../io/socket/engineio/parser/Parser.java | 156 +++++++++++------- .../io/socket/engineio/parser/ParserTest.java | 64 ++++--- 4 files changed, 188 insertions(+), 94 deletions(-) diff --git a/src/main/java/io/socket/engineio/client/transports/Polling.java b/src/main/java/io/socket/engineio/client/transports/Polling.java index b6d577ba..a055357b 100644 --- a/src/main/java/io/socket/engineio/client/transports/Polling.java +++ b/src/main/java/io/socket/engineio/client/transports/Polling.java @@ -183,10 +183,16 @@ public void run() { } }; - Parser.encodePayload(packets, new Parser.EncodeCallback() { + Parser.encodePayload(packets, new Parser.EncodeCallback() { @Override - public void call(byte[] data) { - self.doWrite(data, callbackfn); + public void call(Object data) { + if (data instanceof byte[]) { + self.doWrite((byte[])data, callbackfn); + } else if (data instanceof String) { + self.doWrite((String)data, callbackfn); + } else { + logger.warning("Unexpected data: " + data); + } } }); } @@ -220,5 +226,7 @@ protected String uri() { abstract protected void doWrite(byte[] data, Runnable fn); + abstract protected void doWrite(String data, Runnable fn); + abstract protected void doPoll(); } diff --git a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java index d0e26755..ed118eb3 100644 --- a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java +++ b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; +import java.util.logging.Level; import java.util.logging.Logger; import io.socket.emitter.Emitter; @@ -26,6 +27,8 @@ public class PollingXHR extends Polling { private static final Logger logger = Logger.getLogger(PollingXHR.class.getName()); + private static boolean LOGGABLE_FINE = logger.isLoggable(Level.FINE); + public PollingXHR(Transport.Options opts) { super(opts); } @@ -66,6 +69,15 @@ public void run() { @Override protected void doWrite(byte[] data, final Runnable fn) { + this.doWrite((Object) data, fn); + } + + @Override + protected void doWrite(String data, final Runnable fn) { + this.doWrite((Object) data, fn); + } + + private void doWrite(Object data, final Runnable fn) { Request.Options opts = new Request.Options(); opts.method = "POST"; opts.data = data; @@ -140,13 +152,17 @@ public static class Request extends Emitter { public static final String EVENT_ERROR = "error"; public static final String EVENT_REQUEST_HEADERS = "requestHeaders"; public static final String EVENT_RESPONSE_HEADERS = "responseHeaders"; + private static final String BINARY_CONTENT_TYPE = "application/octet-stream"; + private static final String TEXT_CONTENT_TYPE = "text/plain;charset=UTF-8"; + + private static final MediaType BINARY_MEDIA_TYPE = MediaType.parse(BINARY_CONTENT_TYPE); + private static final MediaType TEXT_MEDIA_TYPE = MediaType.parse(TEXT_CONTENT_TYPE); private String method; private String uri; - // data is always a binary - private byte[] data; + private Object data; private Call.Factory callFactory; private Response response; @@ -161,28 +177,42 @@ public Request(Options opts) { public void create() { final Request self = this; - logger.fine(String.format("xhr open %s: %s", this.method, this.uri)); + if (LOGGABLE_FINE) logger.fine(String.format("xhr open %s: %s", this.method, this.uri)); Map> headers = new TreeMap>(String.CASE_INSENSITIVE_ORDER); if ("POST".equals(this.method)) { - headers.put("Content-type", new LinkedList(Collections.singletonList(BINARY_CONTENT_TYPE))); + if (this.data instanceof byte[]) { + headers.put("Content-type", new LinkedList(Collections.singletonList(BINARY_CONTENT_TYPE))); + } else { + headers.put("Content-type", new LinkedList(Collections.singletonList(TEXT_CONTENT_TYPE))); + } } headers.put("Accept", new LinkedList(Collections.singletonList("*/*"))); - self.onRequestHeaders(headers); + this.onRequestHeaders(headers); + + if (LOGGABLE_FINE) { + logger.fine(String.format("sending xhr with url %s | data %s", this.uri, + this.data instanceof byte[] ? Arrays.toString((byte[]) this.data) : this.data)); + } - logger.fine(String.format("sending xhr with url %s | data %s", this.uri, Arrays.toString(this.data))); okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder(); for (Map.Entry> header : headers.entrySet()) { for (String v : header.getValue()){ requestBuilder.addHeader(header.getKey(), v); } } + RequestBody body = null; + if (this.data instanceof byte[]) { + body = RequestBody.create(BINARY_MEDIA_TYPE, (byte[])this.data); + } else if (this.data instanceof String) { + body = RequestBody.create(TEXT_MEDIA_TYPE, (String)this.data); + } + okhttp3.Request request = requestBuilder .url(HttpUrl.parse(self.uri)) - .method(self.method, (self.data != null) ? - RequestBody.create(MediaType.parse(BINARY_CONTENT_TYPE), self.data) : null) + .method(self.method, body) .build(); requestCall = callFactory.newCall(request); @@ -255,7 +285,7 @@ public static class Options { public String uri; public String method; - public byte[] data; + public Object data; public Call.Factory callFactory; } } diff --git a/src/main/java/io/socket/engineio/parser/Parser.java b/src/main/java/io/socket/engineio/parser/Parser.java index c34dce59..fe6c3622 100644 --- a/src/main/java/io/socket/engineio/parser/Parser.java +++ b/src/main/java/io/socket/engineio/parser/Parser.java @@ -35,6 +35,11 @@ public class Parser { private static Packet err = new Packet(Packet.ERROR, "parser error"); + private static UTF8.Options utf8Options = new UTF8.Options(); + static { + utf8Options.strict = false; + } + private Parser() {} @@ -55,7 +60,7 @@ public static void encodePacket(Packet packet, boolean utf8encode, EncodeCallbac String encoded = String.valueOf(packets.get(packet.type)); if (null != packet.data) { - encoded += utf8encode ? UTF8.encode(String.valueOf(packet.data)) : String.valueOf(packet.data); + encoded += utf8encode ? UTF8.encode(String.valueOf(packet.data), utf8Options) : String.valueOf(packet.data); } @SuppressWarnings("unchecked") @@ -89,7 +94,7 @@ public static Packet decodePacket(String data, boolean utf8decode) { if (utf8decode) { try { - data = UTF8.decode(data); + data = UTF8.decode(data, utf8Options); } catch (UTF8Exception e) { return err; } @@ -113,7 +118,40 @@ public static Packet decodePacket(byte[] data) { return new Packet(packetslist.get(type), intArray); } - public static void encodePayload(Packet[] packets, EncodeCallback callback) throws UTF8Exception { + public static void encodePayload(Packet[] packets, EncodeCallback callback) throws UTF8Exception { + for (Packet packet : packets) { + if (packet.data instanceof byte[]) { + @SuppressWarnings("unchecked") + EncodeCallback _callback = (EncodeCallback) callback; + encodePayloadAsBinary(packets, _callback); + return; + } + } + + if (packets.length == 0) { + callback.call("0:"); + return; + } + + final StringBuilder result = new StringBuilder(); + + for (Packet packet : packets) { + encodePacket(packet, false, new EncodeCallback() { + @Override + public void call(Object message) { + result.append(setLengthHeader((String)message)); + } + }); + } + + callback.call(result.toString()); + } + + private static String setLengthHeader(String message) { + return message.length() + ":" + message; + } + + private static void encodePayloadAsBinary(Packet[] packets, EncodeCallback callback) throws UTF8Exception { if (packets.length == 0) { callback.call(new byte[0]); return; @@ -122,35 +160,44 @@ public static void encodePayload(Packet[] packets, EncodeCallback callba final ArrayList results = new ArrayList(packets.length); for (Packet packet : packets) { - encodePacket(packet, true, new EncodeCallback() { + encodeOneBinaryPacket(packet, new EncodeCallback() { @Override - public void call(Object packet) { - if (packet instanceof String) { - String encodingLength = String.valueOf(((String) packet).length()); - byte[] sizeBuffer = new byte[encodingLength.length() + 2]; - - sizeBuffer[0] = (byte)0; // is a string - for (int i = 0; i < encodingLength.length(); i ++) { - sizeBuffer[i + 1] = (byte)Character.getNumericValue(encodingLength.charAt(i)); - } - sizeBuffer[sizeBuffer.length - 1] = (byte)255; - results.add(Buffer.concat(new byte[][] {sizeBuffer, stringToByteArray((String)packet)})); - return; - } + public void call(byte[] data) { + results.add(data); + } + }); + } - String encodingLength = String.valueOf(((byte[])packet).length); + callback.call(Buffer.concat(results.toArray(new byte[results.size()][]))); + } + + private static void encodeOneBinaryPacket(Packet p, final EncodeCallback doneCallback) throws UTF8Exception { + encodePacket(p, true, new EncodeCallback() { + @Override + public void call(Object packet) { + if (packet instanceof String) { + String encodingLength = String.valueOf(((String) packet).length()); byte[] sizeBuffer = new byte[encodingLength.length() + 2]; - sizeBuffer[0] = (byte)1; // is binary + + sizeBuffer[0] = (byte)0; // is a string for (int i = 0; i < encodingLength.length(); i ++) { sizeBuffer[i + 1] = (byte)Character.getNumericValue(encodingLength.charAt(i)); } sizeBuffer[sizeBuffer.length - 1] = (byte)255; - results.add(Buffer.concat(new byte[][] {sizeBuffer, (byte[])packet})); + doneCallback.call(Buffer.concat(new byte[][] {sizeBuffer, stringToByteArray((String)packet)})); + return; } - }); - } - callback.call(Buffer.concat(results.toArray(new byte[results.size()][]))); + String encodingLength = String.valueOf(((byte[])packet).length); + byte[] sizeBuffer = new byte[encodingLength.length() + 2]; + sizeBuffer[0] = (byte)1; // is binary + for (int i = 0; i < encodingLength.length(); i ++) { + sizeBuffer[i + 1] = (byte)Character.getNumericValue(encodingLength.charAt(i)); + } + sizeBuffer[sizeBuffer.length - 1] = (byte)255; + doneCallback.call(Buffer.concat(new byte[][] {sizeBuffer, (byte[])packet})); + } + }); } public static void decodePayload(String data, DecodePayloadCallback callback) { @@ -165,37 +212,40 @@ public static void decodePayload(String data, DecodePayloadCallback call if (':' != chr) { length.append(chr); - } else { - int n; - try { - n = Integer.parseInt(length.toString()); - } catch (NumberFormatException e) { - callback.call(err, 0, 1); - return; - } + continue; + } + + int n; + try { + n = Integer.parseInt(length.toString()); + } catch (NumberFormatException e) { + callback.call(err, 0, 1); + return; + } - String msg; - try { - msg = data.substring(i + 1, i + 1 + n); - } catch (IndexOutOfBoundsException e) { + String msg; + try { + msg = data.substring(i + 1, i + 1 + n); + } catch (IndexOutOfBoundsException e) { + callback.call(err, 0, 1); + return; + } + + if (msg.length() != 0) { + Packet packet = decodePacket(msg, false); + if (err.type.equals(packet.type) && err.data.equals(packet.data)) { callback.call(err, 0, 1); return; } - if (msg.length() != 0) { - Packet packet = decodePacket(msg, true); - if (err.type.equals(packet.type) && err.data.equals(packet.data)) { - callback.call(err, 0, 1); - return; - } - - boolean ret = callback.call(packet, i + n, l); - if (!ret) return; + boolean ret = callback.call(packet, i + n, l); + if (!ret) { + return; } - - i += n; - length = new StringBuilder(); } + + i += n; + length = new StringBuilder(); } if (length.length() > 0) { @@ -210,23 +260,17 @@ public static void decodePayload(byte[] data, DecodePayloadCallback callback) { while (bufferTail.capacity() > 0) { StringBuilder strLen = new StringBuilder(); boolean isString = (bufferTail.get(0) & 0xFF) == 0; - boolean numberTooLong = false; for (int i = 1; ; i++) { int b = bufferTail.get(i) & 0xFF; if (b == 255) break; // supports only integer if (strLen.length() > MAX_INT_CHAR_LENGTH) { - numberTooLong = true; - break; + callback.call(err, 0, 1); + return; } strLen.append(b); } - if (numberTooLong) { - @SuppressWarnings("unchecked") - DecodePayloadCallback tempCallback = callback; - tempCallback.call(err, 0, 1); - return; - } + bufferTail.position(strLen.length() + 1); bufferTail = bufferTail.slice(); diff --git a/src/test/java/io/socket/engineio/parser/ParserTest.java b/src/test/java/io/socket/engineio/parser/ParserTest.java index 86b7c7f7..d8e7692b 100644 --- a/src/test/java/io/socket/engineio/parser/ParserTest.java +++ b/src/test/java/io/socket/engineio/parser/ParserTest.java @@ -156,6 +156,19 @@ public void call(String data) { }); } + @Test + public void encodingStringMessageWithLoneSurrogatesReplacedByUFFFD() throws UTF8Exception { + String data = "\uDC00\uD834\uDF06\uDC00 \uD800\uD835\uDF07\uD800"; + encodePacket(new Packet(Packet.MESSAGE, data), true, new EncodeCallback() { + @Override + public void call(String encoded) { + Packet p = decodePacket(encoded, true); + assertThat(p.type, is(Packet.MESSAGE)); + assertThat(p.data, is("\uFFFD\uD834\uDF06\uFFFD \uFFFD\uD835\uDF07\uFFFD")); + } + }); + } + @Test public void decodeEmptyPayload() { Packet p = decodePacket((String)null); @@ -186,20 +199,20 @@ public void decodeInvalidUTF8() { @Test public void encodePayloads() throws UTF8Exception { - encodePayload(new Packet[]{new Packet(Packet.PING), new Packet(Packet.PONG)}, new EncodeCallback() { + encodePayload(new Packet[]{new Packet(Packet.PING), new Packet(Packet.PONG)}, new EncodeCallback() { @Override - public void call(byte[] data) { - assertThat(data, isA(byte[].class)); + public void call(String data) { + assertThat(data, isA(String.class)); } }); } @Test public void encodeAndDecodePayloads() throws UTF8Exception { - encodePayload(new Packet[] {new Packet(Packet.MESSAGE, "a")}, new EncodeCallback() { + encodePayload(new Packet[] {new Packet(Packet.MESSAGE, "a")}, new EncodeCallback() { @Override - public void call(byte[] data) { - decodePayload(data, new DecodePayloadCallback() { + public void call(String data) { + decodePayload(data, new DecodePayloadCallback() { @Override public boolean call(Packet packet, int index, int total) { boolean isLast = index + 1 == total; @@ -209,10 +222,10 @@ public boolean call(Packet packet, int index, int total) { }); } }); - encodePayload(new Packet[]{new Packet(Packet.MESSAGE, "a"), new Packet(Packet.PING)}, new EncodeCallback() { + encodePayload(new Packet[]{new Packet(Packet.MESSAGE, "a"), new Packet(Packet.PING)}, new EncodeCallback() { @Override - public void call(byte[] data) { - decodePayload(data, new DecodePayloadCallback() { + public void call(String data) { + decodePayload(data, new DecodePayloadCallback() { @Override public boolean call(Packet packet, int index, int total) { boolean isLast = index + 1 == total; @@ -230,10 +243,10 @@ public boolean call(Packet packet, int index, int total) { @Test public void encodeAndDecodeEmptyPayloads() throws UTF8Exception { - encodePayload(new Packet[] {}, new EncodeCallback() { + encodePayload(new Packet[] {}, new EncodeCallback() { @Override - public void call(byte[] data) { - decodePayload(data, new DecodePayloadCallback() { + public void call(String data) { + decodePayload(data, new DecodePayloadCallback() { @Override public boolean call(Packet packet, int index, int total) { assertThat(packet.type, is(Packet.OPEN)); @@ -246,6 +259,19 @@ public boolean call(Packet packet, int index, int total) { }); } + @Test + public void notUTF8EncodeWhenDealingWithStringsOnly() throws UTF8Exception { + encodePayload(new Packet[] { + new Packet(Packet.MESSAGE, "€€€"), + new Packet(Packet.MESSAGE, "α") + }, new EncodeCallback() { + @Override + public void call(String data) { + assertThat(data, is("4:4€€€2:4α")); + } + }); + } + @Test public void decodePayloadBadFormat() { decodePayload("1!", new DecodePayloadCallback() { @@ -328,20 +354,6 @@ public boolean call(Packet packet, int index, int total) { }); } - @Test - public void decodePayloadInvalidUTF8() { - decodePayload("2:4\uffff", new DecodePayloadCallback() { - @Override - public boolean call(Packet packet, int index, int total) { - boolean isLast = index + 1 == total; - assertThat(packet.type, is(Packet.ERROR)); - assertThat(packet.data, is(ERROR_DATA)); - assertThat(isLast, is(true)); - return true; - } - }); - } - @Test public void encodeBinaryMessage() throws UTF8Exception { final byte[] data = new byte[5]; From 46de5813ca9858d90af1525b409d332211551f13 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Thu, 13 Jul 2017 12:47:48 +0900 Subject: [PATCH 48/72] run tests against engine.io 3.1.0 --- src/test/resources/package-lock.json | 212 ++++++++++++++------------- src/test/resources/package.json | 2 +- src/test/resources/server.js | 5 +- 3 files changed, 114 insertions(+), 105 deletions(-) diff --git a/src/test/resources/package-lock.json b/src/test/resources/package-lock.json index 92892601..1cea6912 100644 --- a/src/test/resources/package-lock.json +++ b/src/test/resources/package-lock.json @@ -2,10 +2,34 @@ "requires": true, "lockfileVersion": 1, "dependencies": { + "accepts": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", + "requires": { + "mime-types": "2.1.15", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, "arraybuffer.slice": { "version": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=" }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, "blob": { "version": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" @@ -15,122 +39,104 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "requires": { + "ms": "2.0.0" + } + }, "engine.io": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.4.tgz", - "integrity": "sha1-d7zhK4Dl1gQpM3/sOw2vaR68kAM=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.0.tgz", + "integrity": "sha1-XKQ4486f28kVxKIcjdnhJmcG5X4=", "requires": { "accepts": "1.3.3", "base64id": "1.0.0", "cookie": "0.3.1", - "debug": "2.3.3", - "engine.io-parser": "1.3.2", - "ws": "1.1.4" + "debug": "2.6.8", + "engine.io-parser": "2.1.1", + "uws": "0.14.5", + "ws": "2.3.1" + } + }, + "engine.io-parser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.1.tgz", + "integrity": "sha1-4Ps/DgRi9/WLt3waUun1p+JuRmg=", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", + "base64-arraybuffer": "0.1.5", + "blob": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "has-binary2": "1.0.2" + } + }, + "has-binary2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.2.tgz", + "integrity": "sha1-6D26SfC5vk0CbSc2U1DZ8D9Uvpg=", + "requires": { + "isarray": "2.0.1" }, "dependencies": { - "accepts": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", - "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", - "requires": { - "mime-types": "2.1.15", - "negotiator": "0.6.1" - } - }, - "after": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" - }, - "base64-arraybuffer": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", - "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" - }, - "base64id": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", - "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" - }, - "debug": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", - "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", - "requires": { - "ms": "0.7.2" - } - }, - "engine.io-parser": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz", - "integrity": "sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo=", - "requires": { - "after": "0.8.2", - "arraybuffer.slice": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", - "base64-arraybuffer": "0.1.5", - "blob": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", - "has-binary": "0.1.7", - "wtf-8": "1.0.0" - } - }, - "has-binary": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", - "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=", - "requires": { - "isarray": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - } - }, - "mime-db": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", - "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=" - }, - "mime-types": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", - "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", - "requires": { - "mime-db": "1.27.0" - } - }, - "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" - }, - "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" - }, - "ws": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.4.tgz", - "integrity": "sha1-V/QNA2gy5fUFVmKjl8Tedu1mv2E=", - "requires": { - "options": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", - "ultron": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz" - } + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" } } }, - "isarray": { - "version": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "mime-db": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", + "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=" }, - "options": { - "version": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", - "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" + "mime-types": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", + "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", + "requires": { + "mime-db": "1.27.0" + } }, - "ultron": { - "version": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", - "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "wtf-8": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz", - "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=" + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "safe-buffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz", + "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=" + }, + "uws": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/uws/-/uws-0.14.5.tgz", + "integrity": "sha1-Z6rzPEaypYel9mZtAPdpEyjxSdw=", + "optional": true + }, + "ws": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-2.3.1.tgz", + "integrity": "sha1-a5Sz5EfLajY/eF6vlK9jWejoHIA=", + "requires": { + "safe-buffer": "5.0.1", + "ultron": "1.1.0" + }, + "dependencies": { + "ultron": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.0.tgz", + "integrity": "sha1-sHoualQagV/Go0zNRTO67DB8qGQ=" + } + } } } } diff --git a/src/test/resources/package.json b/src/test/resources/package.json index 68be2fbb..f7c59176 100644 --- a/src/test/resources/package.json +++ b/src/test/resources/package.json @@ -1,6 +1,6 @@ { "private": true, "dependencies": { - "engine.io": "1.8.4" + "engine.io": "3.1.0" } } diff --git a/src/test/resources/server.js b/src/test/resources/server.js index ef43dee9..31a5a70f 100644 --- a/src/test/resources/server.js +++ b/src/test/resources/server.js @@ -11,7 +11,10 @@ if (process.env.SSL) { http = require('http').createServer(); } -var server = engine.attach(http, {pingInterval: 500}); +var server = engine.attach(http, { + pingInterval: 500, + wsEngine: 'ws' +}); var port = process.env.PORT || 3000 http.listen(port, function() { From c8867048dd6f85ec04e2e6d08de4593a6b10dcbc Mon Sep 17 00:00:00 2001 From: nkzawa Date: Thu, 13 Jul 2017 12:51:29 +0900 Subject: [PATCH 49/72] add the transportOptions option --- .../io/socket/engineio/client/Socket.java | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/main/java/io/socket/engineio/client/Socket.java b/src/main/java/io/socket/engineio/client/Socket.java index 796b88fb..60b914e1 100644 --- a/src/main/java/io/socket/engineio/client/Socket.java +++ b/src/main/java/io/socket/engineio/client/Socket.java @@ -121,6 +121,7 @@ public String toString() { private String path; private String timestampParam; private List transports; + private Map transportOptions; private List upgrades; private Map query; /*package*/ LinkedList writeBuffer = new LinkedList(); @@ -202,6 +203,8 @@ public Socket(Options opts) { this.timestampRequests = opts.timestampRequests; this.transports = new ArrayList(Arrays.asList(opts.transports != null ? opts.transports : new String[]{Polling.NAME, WebSocket.NAME})); + this.transportOptions = opts.transportOptions != null ? + opts.transportOptions : new HashMap(); this.policyPort = opts.policyPort != 0 ? opts.policyPort : 843; this.rememberUpgrade = opts.rememberUpgrade; this.callFactory = opts.callFactory != null ? opts.callFactory : defaultCallFactory; @@ -272,18 +275,22 @@ private Transport createTransport(String name) { query.put("sid", this.id); } + // per-transport options + Transport.Options options = this.transportOptions.get(name); + Transport.Options opts = new Transport.Options(); - opts.hostname = this.hostname; - opts.port = this.port; - opts.secure = this.secure; - opts.path = this.path; opts.query = query; - opts.timestampRequests = this.timestampRequests; - opts.timestampParam = this.timestampParam; - opts.policyPort = this.policyPort; opts.socket = this; - opts.callFactory = this.callFactory; - opts.webSocketFactory = this.webSocketFactory; + + opts.hostname = options != null ? options.hostname : this.hostname; + opts.port = options != null ? options.port : this.port; + opts.secure = options != null ? options.secure : this.secure; + opts.path = options != null ? options.path : this.path; + opts.timestampRequests = options != null ? options.timestampRequests : this.timestampRequests; + opts.timestampParam = options != null ? options.timestampParam : this.timestampParam; + opts.policyPort = options != null ? options.policyPort : this.policyPort; + opts.callFactory = options != null ? options.callFactory : this.callFactory; + opts.webSocketFactory = options != null ? options.webSocketFactory : this.webSocketFactory; Transport transport; if (WebSocket.NAME.equals(name)) { @@ -866,7 +873,7 @@ public static class Options extends Transport.Options { public boolean rememberUpgrade; public String host; public String query; - + public Map transportOptions; private static Options fromURI(URI uri, Options opts) { if (opts == null) { From cad9a3f85c0e6ce325ae891990f9328de59fffbe Mon Sep 17 00:00:00 2001 From: nkzawa Date: Thu, 13 Jul 2017 13:00:58 +0900 Subject: [PATCH 50/72] update README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 041a8734..7079a77e 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,9 @@ socket = new Socket(opts); This library supports all of the features the JS client does, including events, options and upgrading transport. Android is fully supported. ### Extra features only for Java client -Some features are added for simulating browser behavior like handling cookies. + +#### Accessing HTTP Headers +You can access HTTP headers like the following. ```java socket.on(Socket.EVENT_TRANSPORT, new Emitter.listener() { From ce1c29daeb2c6dcf48dd205f6334a6df26a0d2cc Mon Sep 17 00:00:00 2001 From: nkzawa Date: Thu, 13 Jul 2017 15:41:49 +0900 Subject: [PATCH 51/72] update travis setting --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index ab29bccf..84c2bc29 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: java +sudo: false install: mvn install -DskipTests=true -Dgpg.skip=true jdk: - openjdk7 - oraclejdk8 +dist: trusty From 8b1fbdcc992e89963acd730baa72f5c3e5f0f3e7 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Fri, 14 Jul 2017 09:38:03 +0900 Subject: [PATCH 52/72] update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7079a77e..46920be1 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Add the following dependency to your `pom.xml`. io.socket engine.io-client - 0.8.3 + 0.9.0 ``` @@ -25,7 +25,7 @@ Add the following dependency to your `pom.xml`. Add it as a gradle dependency for Android Studio, in `build.gradle`: ```groovy -compile ('io.socket:engine.io-client:0.8.3') { +compile ('io.socket:engine.io-client:0.9.0') { // excluding org.json which is provided by Android exclude group: 'org.json', module: 'json' } From bfad012739db853e20d419cce2d4aff023832226 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Fri, 14 Jul 2017 14:04:50 +0900 Subject: [PATCH 53/72] prepare release --- History.md | 8 ++++++++ README.md | 9 +++++++-- pom.xml | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/History.md b/History.md index 641a2e2e..1d187084 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,12 @@ +1.0.0 / 2017-07-14 +================== + +* compatible with engine.io 3.1.0 +* update parser: no strict UTF8 check +* no UTF encodng for payloads which contains string only +* add `transportOptions` option + 0.9.0 / 2017-07-11 ================== diff --git a/README.md b/README.md index 46920be1..8abe70ae 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Add the following dependency to your `pom.xml`. io.socket engine.io-client - 0.9.0 + 1.0.0 ``` @@ -25,12 +25,17 @@ Add the following dependency to your `pom.xml`. Add it as a gradle dependency for Android Studio, in `build.gradle`: ```groovy -compile ('io.socket:engine.io-client:0.9.0') { +compile ('io.socket:engine.io-client:1.0.0') { // excluding org.json which is provided by Android exclude group: 'org.json', module: 'json' } ``` +#### Engine.IO Server 1.x suppport + +The current version of engine.io-client-java doesn't support engine.io server 1.x. +Please use engine.io-client-java 0.9.x for that instead. + ## Usage Engine.IO-client Java has the similar api with the JS client. You can use `Socket` to connect: diff --git a/pom.xml b/pom.xml index 106422f0..c56cc19d 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 0.9.1-SNAPSHOT + 1.0.0-SNAPSHOT jar engine.io-client Engine.IO Client Library for Java From 17dc5b4a608dfce3e9f37d2355d1a14b568cb26e Mon Sep 17 00:00:00 2001 From: nkzawa Date: Fri, 14 Jul 2017 14:43:44 +0900 Subject: [PATCH 54/72] add loggable checks --- .../io/socket/engineio/client/Socket.java | 65 ++++++++++++++----- .../engineio/client/transports/Polling.java | 9 ++- 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/main/java/io/socket/engineio/client/Socket.java b/src/main/java/io/socket/engineio/client/Socket.java index 60b914e1..3f61f9ad 100644 --- a/src/main/java/io/socket/engineio/client/Socket.java +++ b/src/main/java/io/socket/engineio/client/Socket.java @@ -14,6 +14,7 @@ import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.logging.Level; import java.util.logging.Logger; import io.socket.emitter.Emitter; @@ -266,7 +267,9 @@ public void run() { } private Transport createTransport(String name) { - logger.fine(String.format("creating transport '%s'", name)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("creating transport '%s'", name)); + } Map query = new HashMap(this.query); query.put("EIO", String.valueOf(Parser.PROTOCOL)); @@ -307,11 +310,15 @@ private Transport createTransport(String name) { } private void setTransport(Transport transport) { - logger.fine(String.format("setting transport %s", transport.name)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("setting transport %s", transport.name)); + } final Socket self = this; if (this.transport != null) { - logger.fine(String.format("clearing existing transport %s", this.transport.name)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("clearing existing transport %s", this.transport.name)); + } this.transport.off(); } @@ -341,7 +348,9 @@ public void call(Object... args) { } private void probe(final String name) { - logger.fine(String.format("probing transport '%s'", name)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("probing transport '%s'", name)); + } final Transport[] transport = new Transport[] {this.createTransport(name)}; final boolean[] failed = new boolean[] {false}; final Socket self = this; @@ -355,7 +364,9 @@ private void probe(final String name) { public void call(Object... args) { if (failed[0]) return; - logger.fine(String.format("probe transport '%s' opened", name)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("probe transport '%s' opened", name)); + } Packet packet = new Packet(Packet.PING, "probe"); transport[0].send(new Packet[] {packet}); transport[0].once(Transport.EVENT_PACKET, new Listener() { @@ -365,13 +376,17 @@ public void call(Object... args) { Packet msg = (Packet)args[0]; if (Packet.PONG.equals(msg.type) && "probe".equals(msg.data)) { - logger.fine(String.format("probe transport '%s' pong", name)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("probe transport '%s' pong", name)); + } self.upgrading = true; self.emit(EVENT_UPGRADING, transport[0]); if (null == transport[0]) return; Socket.priorWebsocketSuccess = WebSocket.NAME.equals(transport[0].name); - logger.fine(String.format("pausing current transport '%s'", self.transport.name)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("pausing current transport '%s'", self.transport.name)); + } ((Polling)self.transport).pause(new Runnable() { @Override public void run() { @@ -392,7 +407,9 @@ public void run() { } }); } else { - logger.fine(String.format("probe transport '%s' failed", name)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("probe transport '%s' failed", name)); + } EngineIOException err = new EngineIOException(PROBE_ERROR); err.transport = transport[0].name; self.emit(EVENT_UPGRADE_ERROR, err); @@ -433,7 +450,9 @@ public void call(Object... args) { freezeTransport.call(); - logger.fine(String.format("probe transport \"%s\" failed because of error: %s", name, err)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("probe transport \"%s\" failed because of error: %s", name, err)); + } self.emit(EVENT_UPGRADE_ERROR, error); } @@ -460,7 +479,9 @@ public void call(Object... args) { public void call(Object... args) { Transport to = (Transport)args[0]; if (transport[0] != null && !to.name.equals(transport[0].name)) { - logger.fine(String.format("'%s' works - aborting '%s'", to.name, transport[0].name)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("'%s' works - aborting '%s'", to.name, transport[0].name)); + } freezeTransport.call(); } } @@ -506,7 +527,9 @@ private void onPacket(Packet packet) { if (this.readyState == ReadyState.OPENING || this.readyState == ReadyState.OPEN || this.readyState == ReadyState.CLOSING) { - logger.fine(String.format("socket received: type '%s', data '%s'", packet.type, packet.data)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("socket received: type '%s', data '%s'", packet.type, packet.data)); + } this.emit(EVENT_PACKET, packet); this.emit(EVENT_HEARTBEAT); @@ -529,7 +552,9 @@ private void onPacket(Packet packet) { this.emit(EVENT_MESSAGE, packet.data); } } else { - logger.fine(String.format("packet received with socket readyState '%s'", this.readyState)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("packet received with socket readyState '%s'", this.readyState)); + } } } @@ -585,7 +610,9 @@ public void run() { EventThread.exec(new Runnable() { @Override public void run() { - logger.fine(String.format("writing ping packet - expecting pong within %sms", self.pingTimeout)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("writing ping packet - expecting pong within %sms", self.pingTimeout)); + } self.ping(); self.onHeartbeat(self.pingTimeout); } @@ -627,7 +654,9 @@ private void onDrain() { private void flush() { if (this.readyState != ReadyState.CLOSED && this.transport.writable && !this.upgrading && this.writeBuffer.size() != 0) { - logger.fine(String.format("flushing %d packets in socket", this.writeBuffer.size())); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("flushing %d packets in socket", this.writeBuffer.size())); + } this.prevBufferLen = this.writeBuffer.size(); this.transport.send(this.writeBuffer.toArray(new Packet[this.writeBuffer.size()])); this.emit(EVENT_FLUSH); @@ -784,7 +813,9 @@ public void call(Object... args) { } private void onError(Exception err) { - logger.fine(String.format("socket error %s", err)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("socket error %s", err)); + } Socket.priorWebsocketSuccess = false; this.emit(EVENT_ERROR, err); this.onClose("transport error", err); @@ -796,7 +827,9 @@ private void onClose(String reason) { private void onClose(String reason, Exception desc) { if (ReadyState.OPENING == this.readyState || ReadyState.OPEN == this.readyState || ReadyState.CLOSING == this.readyState) { - logger.fine(String.format("socket close with reason: %s", reason)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("socket close with reason: %s", reason)); + } final Socket self = this; // clear timers diff --git a/src/main/java/io/socket/engineio/client/transports/Polling.java b/src/main/java/io/socket/engineio/client/transports/Polling.java index a055357b..9341d9ac 100644 --- a/src/main/java/io/socket/engineio/client/transports/Polling.java +++ b/src/main/java/io/socket/engineio/client/transports/Polling.java @@ -12,6 +12,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.logging.Level; import java.util.logging.Logger; abstract public class Polling extends Transport { @@ -108,7 +109,9 @@ protected void onData(byte[] data) { private void _onData(Object data) { final Polling self = this; - logger.fine(String.format("polling got data %s", data)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("polling got data %s", data)); + } Parser.DecodePayloadCallback callback = new Parser.DecodePayloadCallback() { @Override public boolean call(Packet packet, int index, int total) { @@ -141,7 +144,9 @@ public boolean call(Packet packet, int index, int total) { if (this.readyState == ReadyState.OPEN) { this.poll(); } else { - logger.fine(String.format("ignoring poll - transport state '%s'", this.readyState)); + if (logger.isLoggable(Level.FINE)) { + logger.fine(String.format("ignoring poll - transport state '%s'", this.readyState)); + } } } } From fb1e448856fe00fddf833693e1ecda8e105af375 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Fri, 14 Jul 2017 14:50:33 +0900 Subject: [PATCH 55/72] [maven-release-plugin] prepare release engine.io-client-1.0.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c56cc19d..e04ce098 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 1.0.0-SNAPSHOT + 1.0.0 jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:https://github.com/socketio/engine.io-client-java.git scm:git:https://github.com/socketio/engine.io-client-java.git - HEAD + engine.io-client-1.0.0 From 559eb38de17a4a4045a56f1da6c642dfb7e53abe Mon Sep 17 00:00:00 2001 From: nkzawa Date: Fri, 14 Jul 2017 14:50:44 +0900 Subject: [PATCH 56/72] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e04ce098..e722fc2f 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 1.0.0 + 1.0.1-SNAPSHOT jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:https://github.com/socketio/engine.io-client-java.git scm:git:https://github.com/socketio/engine.io-client-java.git - engine.io-client-1.0.0 + HEAD From 9a7176bae6b9c7e1300545c94bf6b421d8a27a2a Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Tue, 8 Dec 2020 09:52:30 +0100 Subject: [PATCH 57/72] ci: migrate to GitHub Actions Due to the recent changes to the Travis CI platform (see [1]), we will now use GitHub Actions to run the tests. Note: the certificate was updated because it failed with newer Node.js versions ``` _tls_common.js:129 c.context.setCert(cert); ^ Error: error:140AB18F:SSL routines:SSL_CTX_use_certificate:ee key too small at Object.createSecureContext (_tls_common.js:129:17) at Server.setSecureContext (_tls_wrap.js:1328:27) ``` Reference: https://docs.github.com/en/free-pro-team@latest/actions/guides/building-and-testing-java-with-maven [1]: https://blog.travis-ci.com/2020-11-02-travis-ci-new-billing --- .github/workflows/ci.yml | 34 ++++++++++++++++ .travis.yml | 7 ---- README.md | 3 +- .../engineio/client/SSLConnectionTest.java | 2 +- src/test/resources/cert.pem | 27 +++++++++---- src/test/resources/key.pem | 37 +++++++++++++----- src/test/resources/keystore.jks | Bin 859 -> 941 bytes 7 files changed, 84 insertions(+), 26 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..2d3e1343 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: CI + +on: + push: + pull_request: + schedule: + - cron: '0 0 * * 0' + +jobs: + verify: + runs-on: ubuntu-latest + + strategy: + matrix: + java: [8, 11] + + steps: + - uses: actions/checkout@v2 + - name: Setup java + uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - name: Cache Maven packages + uses: actions/cache@v2 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2 + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: 14.x + - name: Run the Maven verify phase + run: mvn verify -Dgpg.skip=true diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 84c2bc29..00000000 --- a/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: java -sudo: false -install: mvn install -DskipTests=true -Dgpg.skip=true -jdk: - - openjdk7 - - oraclejdk8 -dist: trusty diff --git a/README.md b/README.md index 8abe70ae..587c387f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # Engine.IO-client Java -[![Build Status](https://travis-ci.org/socketio/engine.io-client-java.png?branch=master)](https://travis-ci.org/socketio/engine.io-client-java) + +[![Build Status](https://github.com/socketio/engine.io-client-java/workflows/CI/badge.svg)](https://github.com/socketio/engine.io-client-java/actions) This is the Engine.IO Client Library for Java, which is simply ported from the [JavaScript client](https://github.com/socketio/engine.io-client). diff --git a/src/test/java/io/socket/engineio/client/SSLConnectionTest.java b/src/test/java/io/socket/engineio/client/SSLConnectionTest.java index 2e6a128f..1405e4df 100644 --- a/src/test/java/io/socket/engineio/client/SSLConnectionTest.java +++ b/src/test/java/io/socket/engineio/client/SSLConnectionTest.java @@ -52,7 +52,7 @@ private static void prepareOkHttpClient() throws GeneralSecurityException, IOExc TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ks); - SSLContext sslContext = SSLContext.getInstance("TLSv1"); + SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); sOkHttpClient = new OkHttpClient.Builder() diff --git a/src/test/resources/cert.pem b/src/test/resources/cert.pem index bea755ce..00d8bffe 100644 --- a/src/test/resources/cert.pem +++ b/src/test/resources/cert.pem @@ -1,10 +1,21 @@ -----BEGIN CERTIFICATE----- -MIIBfDCCASYCCQDTnGd/oOyF1DANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB -VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0 -cyBQdHkgTHRkMB4XDTE0MDcwNzEzMTUzN1oXDTQxMTEyMTEzMTUzN1owRTELMAkG -A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0 -IFdpZGdpdHMgUHR5IEx0ZDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC6sdeFPlqk -5Pap9woFx1RO05gLidw4MNcL+ZRSxy/sNeE4PhT/RLFcEvnXiHc92wT8YB5Z+WCM -k/jRQ0q19PNPAgMBAAEwDQYJKoZIhvcNAQEFBQADQQCnmm1N/yZiMBZw2JDfbsx3 -ecc0BGQ2BwWQuGHzP07TMi1AuOyNZSczl907OphYb9iRC8shZ4O+oXjQAuGTQ1Hp +MIIDazCCAlOgAwIBAgIUL0sTZnQmQ4K4o4NqeA1VAsKrn20wDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDEyMDgwOTE3NDlaFw0zMDEy +MDYwOTE3NDlaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDKCTIWvz8s+SjqjxOSmQSF3hvQVjfuIxAwCqKYKdiO +4ix72gkM2WRtzb6icOpDF9zVmcN2QIUXC+hvmVLVMGISZBA4qnGpRwGfVsJlxkO/ +yIOQ4OVn8tJHT+qv9sE656CV+yMbhcoR4E6n03hXcyRz44f14rz1yHz1cjrsDCqa +HfjQkMjXEi/oiOYvGOr7EqAlf0fHyne/FdRg3sfqjy9GXxD4djEzBt6ug11cIjvw +21lP3jC2Te9gng+9cxGlmBYZ6l2OxDZQYjVfOlhTEGOc/J1fP1cVXt/P1fJ5byR8 +ltN6KCcorPwxa6rtCEVy3PXdnKTj1eX5UocIRYVj3e57AgMBAAGjUzBRMB0GA1Ud +DgQWBBRJPJeTbeYMbtebcMKinxhVgr8x/TAfBgNVHSMEGDAWgBRJPJeTbeYMbteb +cMKinxhVgr8x/TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQC1 +VLs5pldkzYoXI+3ry6TTTDxG/AJ1g/GKC4AXp9V+v44FA/dzD8dWVAGKLE/C1IYj +tm3VDeKBGTIgk5EFm0SI0bfgvJwOkSg0WJiX5rrvaXDB2J1tZX50XKZq68BYCiq9 +Qm41bSVV7xccRr7XG2bpKzHqbfjCDIDRdG8WnuTtysVGXMmjObPnrR8SoFVmrGcR +nrkGgp//QWNlGVRYL6cHbkt6eLjDTWJxeKUIN0SlSKOP52Olh1GWBxTeQtnP9VUY +yoj8Fj4lHaCAOlS5W9/kAJSTiLNnmi7v3eKYi+5wuHMFKxr/yRyaUloq78uaBJxa +Y2xdMyPo+uzo0rAXGoUT -----END CERTIFICATE----- diff --git a/src/test/resources/key.pem b/src/test/resources/key.pem index 4a78a226..0c2ddfc3 100644 --- a/src/test/resources/key.pem +++ b/src/test/resources/key.pem @@ -1,9 +1,28 @@ ------BEGIN RSA PRIVATE KEY----- -MIIBOwIBAAJBALqx14U+WqTk9qn3CgXHVE7TmAuJ3Dgw1wv5lFLHL+w14Tg+FP9E -sVwS+deIdz3bBPxgHln5YIyT+NFDSrX0808CAwEAAQJAIdwLSIEsk2drTRwe1zl1 -ku5RTxZruE0zU1qqifDSQjab1StAK1tapxBVRlRlyLCfD704UClsU8sjGtq0Nh6n -kQIhAO2YJM1g0w9bWYet3zC2UdEASPzaQ7llpZmc51NRBx2NAiEAyShICAaclEuy -wwuD4hibV+b6I8CLYoyPBo32EaceN0sCIQCUed6NxfM/houlgV+Xtmfcnzv9X3yx -EDdzjpz08Q7sRQIgZFv1fBOYYSBXQppnJRFzx2pUmCvDHtrTrMh84RfIqnsCIQCf -JjNXXxOaHn1PNZpi6EHReiFQmy1Swt+AxpTsKixsfA== ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDKCTIWvz8s+Sjq +jxOSmQSF3hvQVjfuIxAwCqKYKdiO4ix72gkM2WRtzb6icOpDF9zVmcN2QIUXC+hv +mVLVMGISZBA4qnGpRwGfVsJlxkO/yIOQ4OVn8tJHT+qv9sE656CV+yMbhcoR4E6n +03hXcyRz44f14rz1yHz1cjrsDCqaHfjQkMjXEi/oiOYvGOr7EqAlf0fHyne/FdRg +3sfqjy9GXxD4djEzBt6ug11cIjvw21lP3jC2Te9gng+9cxGlmBYZ6l2OxDZQYjVf +OlhTEGOc/J1fP1cVXt/P1fJ5byR8ltN6KCcorPwxa6rtCEVy3PXdnKTj1eX5UocI +RYVj3e57AgMBAAECggEAMuJiBSyhwrf2QC1M5q03YGfyZWRxrb6TAyaKkPxpGIOK +ZJ8jjGLsUmNxUgRSXBeUfQ+/FPdnDcjn/8OEA0GuUad2Fm+HNPU3SWRWjb+DrLfZ +uxGJdcbIg0FzgGILhMR1w5B+5R2rKRlvdgFi29OaKL3zrlAu+1BFeKQOhwkBadMT +9Z7lFi4dUPCpgtm7F0lM5jMQvHslGtPu/VQTyrAvdyJjDtXfqDYFXMFgxyUuy0wh +dtMCxfnzePXDbS1D9wgzw1Dmmx/4gWoE80IHOUs7nzM1hPHQs8Qyr5ZFQ0iHq6DC +qcixIwRxZwunNyZ7M+JEPsSM20d0TF5FLFkw44Y9AQKBgQDvKCFbJTqD8yxTlD3H +sPKQCd4s08hR4E+sXnr3fF4ExyX1VwEPzev9fK4ez8pbQVFeuv0o89QhDQBJEGIu +HG0f2fYYcfil3+b3NYBTTEt+IIvhEE2LLCV1zkFe0uoG+qbZjksaHeXZ77TnKnGd +nTWHhoKZ7xMbKJzROUoMJ7GwuwKBgQDYQ8varcqW6UO4LS87OHA2lEs66OfJxnBk +Oox+Z34HXOsXlEqArx8S5/cX4/EM8UECobaqIQKzkvgRA5krL2Vroh588kJXf3yK +O5wESuE7zimg+m2RYnazXpdyxvgWhp1WSZzrm6ybJVCtUiY0x4SAaIWnU102JNMX +oge093K9QQKBgQCaJTKCrdcubxEV+clsKWfeYQ3btNE7vKl9vxPg6j8rMzULEf30 +MtS1eKQ95c5WzR3mQf2kZKxIdTnG3hF6CQZo7jKJhQQv3cXfdpN0nQtXiyC9eqWQ +W271pHBL7wO6ZdofBXDwr26T7sWZ7ah3X3m+FXuePhMBgUa6MAPDG96SuwKBgQDE +H096hArqKqaQGuHvWbJhvMAwr1Csqnn4WyRX6bDgKoLEgmXCJ44NjjGGB9/tdcgY +A+Fsjb0ubsTqYRIBmNzn7ECr3OMPCH0/uuk091ck7kTQSOseYmX1Kn47x3bqrq92 +thFJlYbFt+RfGdWuHZXrAV7brH0mgeSxVO6aTaFPQQKBgQDfkqfxQRmLEwIJygfk +Y1XwEvZqIf0gCZEHWPsGiYExClHc21RZSTbhc+XZ8DTgxYe375uMV6z5aolwjjrI +9bTMejqAC4l58rxdkE1NbxvQVbPwTdM/H4HyYJk9IPKSF0A11YLbalvGo0liWHKo +jfrYDnesTOn3+RLPe6G0K7jFgQ== +-----END PRIVATE KEY----- diff --git a/src/test/resources/keystore.jks b/src/test/resources/keystore.jks index 24c507bacc738aa6c51ef2948f26ec1d8d8fe416..3884f8a689b4c42ebc35f4e8f0631f8d69e9df6b 100644 GIT binary patch literal 941 zcmezO_TO6u1_mY|W(3o$xs}zsAwP$66E5M@XRYoEy_zRQ3%gWNzW`PRtPAmRPZTD zF_07IH8LE~X|%MutNzb$)8R>KC3glcn{Z^o20eqLR7x+Me(B(Vee%=PY@A_36)` zb`ICpxnV1!yosnT{$ZpGJ;VEak#FgK^KE33!kB!?O zrqbq*UEB@g%dgh$?_*{DUd(?yEQGO3$N$ikHsx)(S9u>bN*XClp2#}erQ_oE2Ycr5 zP1G=nm@)m?uJ@S*2XD;HO|2`5S(f$sKm?c8UZ*_MT-DI`;xcagu1lxA)HZyT`{NK# z!^M((v3XD4o;vClb8@le=I3kWg%*UStw|T0x09`D{(r~hRLPJC{pIX=-c=Pl4*Mn* zRxIT(cUkJOxc_>~G^Zl3=dDsiggkC>gR?1BcXke$)@pD;|B+_5=*mfrij zk7jhgE7(!Ysx9^Zq|B_KD6RLWXR*wQO3sNjR(|p8&5KJL#HCt=1&>X8ajJ(mf&1i= N@*1CXL-nJsvjJnCYz6=T literal 859 zcmezO_TO6u1_mY|W&~qKLmm2`#U#kc$jZRd#MsER zPD-`O=1F|QBTwE*IeWyGDm-B0JohKljs5zEP30#xyfir2@#5EIe)cNQDo54_4vmk} zGM6oKP*EcK!UrX3z9@ zZ>t}PU7YsyoU)c;eaF><#m?V$1^BKq{g{_iccLjdP!zUQserSMz@P_Qzsu zu^r~!te^XTg#7Yd^kD%j=Vnf8rM{XA%sW|sM!2i3b#4$AWxZ8>>eju(^Iy4cIDMYC zeZlfc>*kdC3oZVbYO8ghbzNq|)|2!9Ee~0^t^IqNO{IpG;7YM=JI}1UR6Zm9jF{R) z!|(s<*slNS{lDK;c1?oX&GXk?{%!D{-MCIU<@e#;eOCj&pO##1297J%2t88+OJF=T z0OP3!h}D=l87|LBuV3({^@;&68>d#AN85K^V5G4!7`Pg88*s8QhqABsr2J#?5E@27Jypq(Sywnnf@XVC-%#vb-fRaiDpOO> Date: Tue, 8 Dec 2020 11:13:18 +0100 Subject: [PATCH 58/72] chore: bump engine.io server version --- src/test/resources/package-lock.json | 143 +++++++++++---------------- src/test/resources/package.json | 2 +- 2 files changed, 61 insertions(+), 84 deletions(-) diff --git a/src/test/resources/package-lock.json b/src/test/resources/package-lock.json index 1cea6912..72697128 100644 --- a/src/test/resources/package-lock.json +++ b/src/test/resources/package-lock.json @@ -3,12 +3,12 @@ "lockfileVersion": 1, "dependencies": { "accepts": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", - "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", "requires": { - "mime-types": "2.1.15", - "negotiator": "0.6.1" + "mime-types": "~2.1.24", + "negotiator": "0.6.2" } }, "after": { @@ -17,22 +17,24 @@ "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" }, "arraybuffer.slice": { - "version": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", - "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=" + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" }, "base64-arraybuffer": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", - "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", + "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=" }, "base64id": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", - "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" }, "blob": { - "version": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", - "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" }, "cookie": { "version": "0.3.1", @@ -40,103 +42,78 @@ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" }, "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "engine.io": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.0.tgz", - "integrity": "sha1-XKQ4486f28kVxKIcjdnhJmcG5X4=", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.2.tgz", + "integrity": "sha512-b4Q85dFkGw+TqgytGPrGgACRUhsdKc9S9ErRAXpPGy/CXKs4tYoHDkvIRdsseAF7NjfVwjRFIn6KTnbw7LwJZg==", "requires": { - "accepts": "1.3.3", - "base64id": "1.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", "cookie": "0.3.1", - "debug": "2.6.8", - "engine.io-parser": "2.1.1", - "uws": "0.14.5", - "ws": "2.3.1" + "debug": "~4.1.0", + "engine.io-parser": "~2.2.0", + "ws": "^7.1.2" } }, "engine.io-parser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.1.tgz", - "integrity": "sha1-4Ps/DgRi9/WLt3waUun1p+JuRmg=", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz", + "integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==", "requires": { "after": "0.8.2", - "arraybuffer.slice": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", - "base64-arraybuffer": "0.1.5", - "blob": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", - "has-binary2": "1.0.2" + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.4", + "blob": "0.0.5", + "has-binary2": "~1.0.2" } }, "has-binary2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.2.tgz", - "integrity": "sha1-6D26SfC5vk0CbSc2U1DZ8D9Uvpg=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", "requires": { "isarray": "2.0.1" - }, - "dependencies": { - "isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" - } } }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, "mime-db": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", - "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=" + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" }, "mime-types": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", - "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", "requires": { - "mime-db": "1.27.0" + "mime-db": "1.44.0" } }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" - }, - "safe-buffer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz", - "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=" - }, - "uws": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/uws/-/uws-0.14.5.tgz", - "integrity": "sha1-Z6rzPEaypYel9mZtAPdpEyjxSdw=", - "optional": true + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, "ws": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-2.3.1.tgz", - "integrity": "sha1-a5Sz5EfLajY/eF6vlK9jWejoHIA=", - "requires": { - "safe-buffer": "5.0.1", - "ultron": "1.1.0" - }, - "dependencies": { - "ultron": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.0.tgz", - "integrity": "sha1-sHoualQagV/Go0zNRTO67DB8qGQ=" - } - } + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", + "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==" } } } diff --git a/src/test/resources/package.json b/src/test/resources/package.json index f7c59176..d60498e5 100644 --- a/src/test/resources/package.json +++ b/src/test/resources/package.json @@ -1,6 +1,6 @@ { "private": true, "dependencies": { - "engine.io": "3.1.0" + "engine.io": "^3.4.2" } } From 6f065b7a62603730979d43cec71af0046ca4ab7c Mon Sep 17 00:00:00 2001 From: Jacek Mleczek Date: Fri, 15 Mar 2019 11:21:43 +0100 Subject: [PATCH 59/72] fix: handle responses without content type (#101) This fixes NullPointerException when response doesn't have content type. Exception stack trace: ``` java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String okhttp3.MediaType.toString()' on a null object reference at io.socket.engineio.client.transports.PollingXHR$Request.onLoad(PollingXHR.java:271) at io.socket.engineio.client.transports.PollingXHR$Request.access$700(PollingXHR.java:148) at io.socket.engineio.client.transports.PollingXHR$Request$1.onResponse(PollingXHR.java:232) at okhttp3.RealCall$AsyncCall.execute(RealCall.java:141) at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764) ``` --- .../java/io/socket/engineio/client/transports/PollingXHR.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java index ed118eb3..827c24f6 100644 --- a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java +++ b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java @@ -268,10 +268,10 @@ private void onResponseHeaders(Map> headers) { private void onLoad() { ResponseBody body = response.body(); - String contentType = body.contentType().toString(); + MediaType mediaType = body.contentType(); try { - if (BINARY_CONTENT_TYPE.equalsIgnoreCase(contentType)) { + if (mediaType != null && BINARY_CONTENT_TYPE.equalsIgnoreCase(mediaType.toString())) { this.onData(body.bytes()); } else { this.onData(body.string()); From 180db9516f830dd172f783070b54eea7d2781a94 Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Tue, 8 Dec 2020 23:36:49 +0100 Subject: [PATCH 60/72] ci: add java 7 in the test matrix It was already present in the Travis test matrix. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d3e1343..439755f9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: - java: [8, 11] + java: [7, 8, 11] steps: - uses: actions/checkout@v2 From 8016a5d7462f9379b4ad0f5660188c8626319ca6 Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Thu, 10 Dec 2020 12:32:39 +0100 Subject: [PATCH 61/72] chore: bump OkHttp client version Versions above 3.12.x have dropped support for Java 7. Related: https://square.github.io/okhttp/changelog_3x/#version-3130 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e722fc2f..eb3d1491 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ com.squareup.okhttp3 okhttp - 3.8.1 + 3.12.12 org.json From 7b3cc94af99d90d439fd1e984c786ab112e75678 Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Thu, 10 Dec 2020 14:07:39 +0100 Subject: [PATCH 62/72] chore(release): prepare release engine.io-client-1.0.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index eb3d1491..7560fefb 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 1.0.1-SNAPSHOT + 1.0.1 jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:https://github.com/socketio/engine.io-client-java.git scm:git:https://github.com/socketio/engine.io-client-java.git - HEAD + engine.io-client-1.0.1 From 475f89a8e07f6e2cdb828b5f71f9b8de62d59910 Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Thu, 10 Dec 2020 14:07:39 +0100 Subject: [PATCH 63/72] chore(release): prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7560fefb..240af40e 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 1.0.1 + 1.0.2-SNAPSHOT jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:https://github.com/socketio/engine.io-client-java.git scm:git:https://github.com/socketio/engine.io-client-java.git - engine.io-client-1.0.1 + HEAD From b1b7002691caf9bdeb3f1de461de26998479802c Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Thu, 10 Dec 2020 14:26:00 +0100 Subject: [PATCH 64/72] docs: add changelog for version 1.0.1 --- History.md | 7 +++++++ README.md | 29 +++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/History.md b/History.md index 1d187084..f2088196 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,11 @@ +1.0.1 / 2020-12-10 +================== + +### Bug Fixes + +* handle responses without content type ([#101](https://github.com/socketio/engine.io-client-java/issues/101)) ([6f065b7](https://github.com/socketio/engine.io-client-java/commit/6f065b7a62603730979d43cec71af0046ca4ab7c)) + 1.0.0 / 2017-07-14 ================== diff --git a/README.md b/README.md index 587c387f..39dd81e8 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,26 @@ This is the Engine.IO Client Library for Java, which is simply ported from the [ See also: [Socket.IO-client Java](https://github.com/socketio/socket.io-client-java) +## Table of content + +- [Compatibility](#compatibility) +- [Installation](#installation) + - [Maven](#maven) + - [Gradle](#gradle) +- [Usage](#usage) +- [Features](#features) +- [License](#license) + +## Compatibility + +| Client version | Engine.IO server | Socket.IO server | +| -------------- | ---------------- | ---------------- | +| 0.9.x | 1.x | 1.x | +| 1.x | 3.x | 2.x | +| - | 4.x | 3.x | + ## Installation -The latest artifact is available on Maven Central. To install manually, please refer [dependencies](https://socketio.github.io/engine.io-client-java/dependencies.html). +The latest artifact is available on Maven Central. ### Maven Add the following dependency to your `pom.xml`. @@ -17,7 +35,7 @@ Add the following dependency to your `pom.xml`. io.socket engine.io-client - 1.0.0 + 1.0.1 ``` @@ -26,17 +44,12 @@ Add the following dependency to your `pom.xml`. Add it as a gradle dependency for Android Studio, in `build.gradle`: ```groovy -compile ('io.socket:engine.io-client:1.0.0') { +compile ('io.socket:engine.io-client:1.0.1') { // excluding org.json which is provided by Android exclude group: 'org.json', module: 'json' } ``` -#### Engine.IO Server 1.x suppport - -The current version of engine.io-client-java doesn't support engine.io server 1.x. -Please use engine.io-client-java 0.9.x for that instead. - ## Usage Engine.IO-client Java has the similar api with the JS client. You can use `Socket` to connect: From 41f89a38b7594f54ee9906bc91051874a60b690d Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Wed, 9 Dec 2020 01:57:52 +0100 Subject: [PATCH 65/72] feat: add support for Engine.IO v4 Reference: https://github.com/socketio/engine.io-protocol#difference-between-v3-and-v4 --- .../io/socket/engineio/client/Socket.java | 65 +- .../io/socket/engineio/client/Transport.java | 9 +- .../engineio/client/transports/Polling.java | 31 +- .../client/transports/PollingXHR.java | 48 +- .../engineio/client/transports/WebSocket.java | 15 +- .../io/socket/engineio/parser/Base64.java | 665 ++++++++++++++++++ .../io/socket/engineio/parser/Parser.java | 314 ++------- src/main/java/io/socket/utf8/UTF8.java | 199 ------ .../java/io/socket/utf8/UTF8Exception.java | 22 - .../engineio/client/ConnectionTest.java | 16 + .../io/socket/engineio/parser/ParserTest.java | 107 +-- src/test/java/io/socket/utf8/UTF8Test.java | 114 --- src/test/resources/package-lock.json | 82 +-- src/test/resources/package.json | 2 +- 14 files changed, 827 insertions(+), 862 deletions(-) create mode 100644 src/main/java/io/socket/engineio/parser/Base64.java delete mode 100644 src/main/java/io/socket/utf8/UTF8.java delete mode 100644 src/main/java/io/socket/utf8/UTF8Exception.java delete mode 100644 src/test/java/io/socket/utf8/UTF8Test.java diff --git a/src/main/java/io/socket/engineio/client/Socket.java b/src/main/java/io/socket/engineio/client/Socket.java index 3f61f9ad..9b0423ed 100644 --- a/src/main/java/io/socket/engineio/client/Socket.java +++ b/src/main/java/io/socket/engineio/client/Socket.java @@ -128,7 +128,6 @@ public String toString() { /*package*/ LinkedList writeBuffer = new LinkedList(); /*package*/ Transport transport; private Future pingTimeoutTimer; - private Future pingIntervalTimer; private okhttp3.WebSocket.Factory webSocketFactory; private okhttp3.Call.Factory callFactory; @@ -137,7 +136,7 @@ public String toString() { private final Listener onHeartbeatAsListener = new Listener() { @Override public void call(Object... args) { - Socket.this.onHeartbeat(args.length > 0 ? (Long)args[0]: 0); + Socket.this.onHeartbeat(); } }; @@ -540,9 +539,14 @@ private void onPacket(Packet packet) { } catch (JSONException e) { this.emit(EVENT_ERROR, new EngineIOException(e)); } - } else if (Packet.PONG.equals(packet.type)) { - this.setPing(); - this.emit(EVENT_PONG); + } else if (Packet.PING.equals(packet.type)) { + this.emit(EVENT_PING); + EventThread.exec(new Runnable() { + @Override + public void run() { + Socket.this.sendPacket(Packet.PONG, null); + } + }); } else if (Packet.ERROR.equals(packet.type)) { EngineIOException err = new EngineIOException("server error"); err.code = packet.data; @@ -568,20 +572,18 @@ private void onHandshake(HandshakeData data) { this.onOpen(); // In case open handler closes socket if (ReadyState.CLOSED == this.readyState) return; - this.setPing(); + this.onHeartbeat(); this.off(EVENT_HEARTBEAT, this.onHeartbeatAsListener); this.on(EVENT_HEARTBEAT, this.onHeartbeatAsListener); } - private void onHeartbeat(long timeout) { + private void onHeartbeat() { if (this.pingTimeoutTimer != null) { pingTimeoutTimer.cancel(false); } - if (timeout <= 0) { - timeout = this.pingInterval + this.pingTimeout; - } + long timeout = this.pingInterval + this.pingTimeout; final Socket self = this; this.pingTimeoutTimer = this.getHeartbeatScheduler().schedule(new Runnable() { @@ -598,46 +600,6 @@ public void run() { }, timeout, TimeUnit.MILLISECONDS); } - private void setPing() { - if (this.pingIntervalTimer != null) { - pingIntervalTimer.cancel(false); - } - - final Socket self = this; - this.pingIntervalTimer = this.getHeartbeatScheduler().schedule(new Runnable() { - @Override - public void run() { - EventThread.exec(new Runnable() { - @Override - public void run() { - if (logger.isLoggable(Level.FINE)) { - logger.fine(String.format("writing ping packet - expecting pong within %sms", self.pingTimeout)); - } - self.ping(); - self.onHeartbeat(self.pingTimeout); - } - }); - } - }, this.pingInterval, TimeUnit.MILLISECONDS); - } - - /** - * Sends a ping packet. - */ - private void ping() { - EventThread.exec(new Runnable() { - @Override - public void run() { - Socket.this.sendPacket(Packet.PING, new Runnable() { - @Override - public void run() { - Socket.this.emit(EVENT_PING); - } - }); - } - }); - } - private void onDrain() { for (int i = 0; i < this.prevBufferLen; i++) { this.writeBuffer.poll(); @@ -833,9 +795,6 @@ private void onClose(String reason, Exception desc) { final Socket self = this; // clear timers - if (this.pingIntervalTimer != null) { - this.pingIntervalTimer.cancel(false); - } if (this.pingTimeoutTimer != null) { this.pingTimeoutTimer.cancel(false); } diff --git a/src/main/java/io/socket/engineio/client/Transport.java b/src/main/java/io/socket/engineio/client/Transport.java index 442c7762..56b921cc 100644 --- a/src/main/java/io/socket/engineio/client/Transport.java +++ b/src/main/java/io/socket/engineio/client/Transport.java @@ -7,7 +7,6 @@ import io.socket.engineio.parser.Packet; import io.socket.engineio.parser.Parser; import io.socket.thread.EventThread; -import io.socket.utf8.UTF8Exception; import okhttp3.Call; import okhttp3.WebSocket; @@ -96,11 +95,7 @@ public void send(final Packet[] packets) { @Override public void run() { if (Transport.this.readyState == ReadyState.OPEN) { - try { - Transport.this.write(packets); - } catch (UTF8Exception err) { - throw new RuntimeException(err); - } + Transport.this.write(packets); } else { throw new RuntimeException("Transport not open"); } @@ -131,7 +126,7 @@ protected void onClose() { this.emit(EVENT_CLOSE); } - abstract protected void write(Packet[] packets) throws UTF8Exception; + abstract protected void write(Packet[] packets); abstract protected void doOpen(); diff --git a/src/main/java/io/socket/engineio/client/transports/Polling.java b/src/main/java/io/socket/engineio/client/transports/Polling.java index 9341d9ac..9aa73cc3 100644 --- a/src/main/java/io/socket/engineio/client/transports/Polling.java +++ b/src/main/java/io/socket/engineio/client/transports/Polling.java @@ -7,7 +7,6 @@ import io.socket.engineio.parser.Parser; import io.socket.parseqs.ParseQS; import io.socket.thread.EventThread; -import io.socket.utf8.UTF8Exception; import io.socket.yeast.Yeast; import java.util.HashMap; @@ -129,13 +128,7 @@ public boolean call(Packet packet, int index, int total) { } }; - if (data instanceof String) { - @SuppressWarnings("unchecked") - Parser.DecodePayloadCallback tempCallback = callback; - Parser.decodePayload((String)data, tempCallback); - } else if (data instanceof byte[]) { - Parser.decodePayload((byte[])data, callback); - } + Parser.decodePayload((String) data, callback); if (this.readyState != ReadyState.CLOSED) { this.polling = false; @@ -158,11 +151,7 @@ protected void doClose() { @Override public void call(Object... args) { logger.fine("writing close packet"); - try { - self.write(new Packet[]{new Packet(Packet.CLOSE)}); - } catch (UTF8Exception err) { - throw new RuntimeException(err); - } + self.write(new Packet[]{new Packet(Packet.CLOSE)}); } }; @@ -177,7 +166,7 @@ public void call(Object... args) { } } - protected void write(Packet[] packets) throws UTF8Exception { + protected void write(Packet[] packets) { final Polling self = this; this.writable = false; final Runnable callbackfn = new Runnable() { @@ -188,16 +177,10 @@ public void run() { } }; - Parser.encodePayload(packets, new Parser.EncodeCallback() { + Parser.encodePayload(packets, new Parser.EncodeCallback() { @Override - public void call(Object data) { - if (data instanceof byte[]) { - self.doWrite((byte[])data, callbackfn); - } else if (data instanceof String) { - self.doWrite((String)data, callbackfn); - } else { - logger.warning("Unexpected data: " + data); - } + public void call(String data) { + self.doWrite(data, callbackfn); } }); } @@ -229,8 +212,6 @@ protected String uri() { return schema + "://" + (ipv6 ? "[" + this.hostname + "]" : this.hostname) + port + this.path + derivedQuery; } - abstract protected void doWrite(byte[] data, Runnable fn); - abstract protected void doWrite(String data, Runnable fn); abstract protected void doPoll(); diff --git a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java index 827c24f6..64b3cda7 100644 --- a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java +++ b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java @@ -67,17 +67,8 @@ public void run() { return req; } - @Override - protected void doWrite(byte[] data, final Runnable fn) { - this.doWrite((Object) data, fn); - } - @Override protected void doWrite(String data, final Runnable fn) { - this.doWrite((Object) data, fn); - } - - private void doWrite(Object data, final Runnable fn) { Request.Options opts = new Request.Options(); opts.method = "POST"; opts.data = data; @@ -121,11 +112,7 @@ public void call(final Object... args) { @Override public void run() { Object arg = args.length > 0 ? args[0] : null; - if (arg instanceof String) { - self.onData((String)arg); - } else if (arg instanceof byte[]) { - self.onData((byte[])arg); - } + self.onData((String)arg); } }); } @@ -153,16 +140,14 @@ public static class Request extends Emitter { public static final String EVENT_REQUEST_HEADERS = "requestHeaders"; public static final String EVENT_RESPONSE_HEADERS = "responseHeaders"; - private static final String BINARY_CONTENT_TYPE = "application/octet-stream"; private static final String TEXT_CONTENT_TYPE = "text/plain;charset=UTF-8"; - private static final MediaType BINARY_MEDIA_TYPE = MediaType.parse(BINARY_CONTENT_TYPE); private static final MediaType TEXT_MEDIA_TYPE = MediaType.parse(TEXT_CONTENT_TYPE); private String method; private String uri; - private Object data; + private String data; private Call.Factory callFactory; private Response response; @@ -181,11 +166,7 @@ public void create() { Map> headers = new TreeMap>(String.CASE_INSENSITIVE_ORDER); if ("POST".equals(this.method)) { - if (this.data instanceof byte[]) { - headers.put("Content-type", new LinkedList(Collections.singletonList(BINARY_CONTENT_TYPE))); - } else { - headers.put("Content-type", new LinkedList(Collections.singletonList(TEXT_CONTENT_TYPE))); - } + headers.put("Content-type", new LinkedList(Collections.singletonList(TEXT_CONTENT_TYPE))); } headers.put("Accept", new LinkedList(Collections.singletonList("*/*"))); @@ -193,8 +174,7 @@ public void create() { this.onRequestHeaders(headers); if (LOGGABLE_FINE) { - logger.fine(String.format("sending xhr with url %s | data %s", this.uri, - this.data instanceof byte[] ? Arrays.toString((byte[]) this.data) : this.data)); + logger.fine(String.format("sending xhr with url %s | data %s", this.uri, this.data)); } okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder(); @@ -204,10 +184,8 @@ public void create() { } } RequestBody body = null; - if (this.data instanceof byte[]) { - body = RequestBody.create(BINARY_MEDIA_TYPE, (byte[])this.data); - } else if (this.data instanceof String) { - body = RequestBody.create(TEXT_MEDIA_TYPE, (String)this.data); + if (this.data != null) { + body = RequestBody.create(TEXT_MEDIA_TYPE, this.data); } okhttp3.Request request = requestBuilder @@ -249,11 +227,6 @@ private void onData(String data) { this.onSuccess(); } - private void onData(byte[] data) { - this.emit(EVENT_DATA, data); - this.onSuccess(); - } - private void onError(Exception err) { this.emit(EVENT_ERROR, err); } @@ -268,14 +241,9 @@ private void onResponseHeaders(Map> headers) { private void onLoad() { ResponseBody body = response.body(); - MediaType mediaType = body.contentType(); try { - if (mediaType != null && BINARY_CONTENT_TYPE.equalsIgnoreCase(mediaType.toString())) { - this.onData(body.bytes()); - } else { - this.onData(body.string()); - } + this.onData(body.string()); } catch (IOException e) { this.onError(e); } @@ -285,7 +253,7 @@ public static class Options { public String uri; public String method; - public Object data; + public String data; public Call.Factory callFactory; } } diff --git a/src/main/java/io/socket/engineio/client/transports/WebSocket.java b/src/main/java/io/socket/engineio/client/transports/WebSocket.java index d6e2f1a3..74cf65ff 100644 --- a/src/main/java/io/socket/engineio/client/transports/WebSocket.java +++ b/src/main/java/io/socket/engineio/client/transports/WebSocket.java @@ -1,18 +1,11 @@ package io.socket.engineio.client.transports; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.logging.Logger; - import io.socket.engineio.client.Transport; import io.socket.engineio.parser.Packet; import io.socket.engineio.parser.Parser; import io.socket.parseqs.ParseQS; import io.socket.thread.EventThread; -import io.socket.utf8.UTF8Exception; import io.socket.yeast.Yeast; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -20,6 +13,12 @@ import okhttp3.WebSocketListener; import okio.ByteString; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.logging.Logger; + public class WebSocket extends Transport { @@ -111,7 +110,7 @@ public void run() { }); } - protected void write(Packet[] packets) throws UTF8Exception { + protected void write(Packet[] packets) { final WebSocket self = this; this.writable = false; diff --git a/src/main/java/io/socket/engineio/parser/Base64.java b/src/main/java/io/socket/engineio/parser/Base64.java new file mode 100644 index 00000000..d56a7cea --- /dev/null +++ b/src/main/java/io/socket/engineio/parser/Base64.java @@ -0,0 +1,665 @@ +// from https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/util/Base64.java +package io.socket.engineio.parser; + +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.io.UnsupportedEncodingException; + +/** + * Utilities for encoding and decoding the Base64 representation of + * binary data. See RFCs 2045 and 3548. + */ +public class Base64 { + /** + * Default values for encoder/decoder flags. + */ + public static final int DEFAULT = 0; + /** + * Encoder flag bit to omit the padding '=' characters at the end + * of the output (if any). + */ + public static final int NO_PADDING = 1; + /** + * Encoder flag bit to omit all line terminators (i.e., the output + * will be on one long line). + */ + public static final int NO_WRAP = 2; + /** + * Encoder flag bit to indicate lines should be terminated with a + * CRLF pair instead of just an LF. Has no effect if {@code + * NO_WRAP} is specified as well. + */ + public static final int CRLF = 4; + /** + * Encoder/decoder flag bit to indicate using the "URL and + * filename safe" variant of Base64 (see RFC 3548 section 4) where + * {@code -} and {@code _} are used in place of {@code +} and + * {@code /}. + */ + public static final int URL_SAFE = 8; + /** + * Flag to pass to Base64OutputStream to indicate that it + * should not close the output stream it is wrapping when it + * itself is closed. + */ + public static final int NO_CLOSE = 16; + // -------------------------------------------------------- + // shared code + // -------------------------------------------------------- + /* package */ static abstract class Coder { + public byte[] output; + public int op; + /** + * Encode/decode another block of input data. this.output is + * provided by the caller, and must be big enough to hold all + * the coded data. On exit, this.opwill be set to the length + * of the coded data. + * + * @param finish true if this is the final call to process for + * this object. Will finalize the coder state and + * include any final bytes in the output. + * + * @return true if the input so far is good; false if some + * error has been detected in the input stream.. + */ + public abstract boolean process(byte[] input, int offset, int len, boolean finish); + /** + * @return the maximum number of bytes a call to process() + * could produce for the given number of input bytes. This may + * be an overestimate. + */ + public abstract int maxOutputSize(int len); + } + // -------------------------------------------------------- + // decoding + // -------------------------------------------------------- + /** + * Decode the Base64-encoded data in input and return the data in + * a new byte array. + * + *

The padding '=' characters at the end are considered optional, but + * if any are present, there must be the correct number of them. + * + * @param str the input String to decode, which is converted to + * bytes using the default charset + * @param flags controls certain features of the decoded output. + * Pass {@code DEFAULT} to decode standard Base64. + * + * @throws IllegalArgumentException if the input contains + * incorrect padding + */ + public static byte[] decode(String str, int flags) { + return decode(str.getBytes(), flags); + } + /** + * Decode the Base64-encoded data in input and return the data in + * a new byte array. + * + *

The padding '=' characters at the end are considered optional, but + * if any are present, there must be the correct number of them. + * + * @param input the input array to decode + * @param flags controls certain features of the decoded output. + * Pass {@code DEFAULT} to decode standard Base64. + * + * @throws IllegalArgumentException if the input contains + * incorrect padding + */ + public static byte[] decode(byte[] input, int flags) { + return decode(input, 0, input.length, flags); + } + /** + * Decode the Base64-encoded data in input and return the data in + * a new byte array. + * + *

The padding '=' characters at the end are considered optional, but + * if any are present, there must be the correct number of them. + * + * @param input the data to decode + * @param offset the position within the input array at which to start + * @param len the number of bytes of input to decode + * @param flags controls certain features of the decoded output. + * Pass {@code DEFAULT} to decode standard Base64. + * + * @throws IllegalArgumentException if the input contains + * incorrect padding + */ + public static byte[] decode(byte[] input, int offset, int len, int flags) { + // Allocate space for the most data the input could represent. + // (It could contain less if it contains whitespace, etc.) + Decoder decoder = new Decoder(flags, new byte[len*3/4]); + if (!decoder.process(input, offset, len, true)) { + throw new IllegalArgumentException("bad base-64"); + } + // Maybe we got lucky and allocated exactly enough output space. + if (decoder.op == decoder.output.length) { + return decoder.output; + } + // Need to shorten the array, so allocate a new one of the + // right size and copy. + byte[] temp = new byte[decoder.op]; + System.arraycopy(decoder.output, 0, temp, 0, decoder.op); + return temp; + } + /* package */ static class Decoder extends Coder { + /** + * Lookup table for turning bytes into their position in the + * Base64 alphabet. + */ + private static final int DECODE[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }; + /** + * Decode lookup table for the "web safe" variant (RFC 3548 + * sec. 4) where - and _ replace + and /. + */ + private static final int DECODE_WEBSAFE[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }; + /** Non-data values in the DECODE arrays. */ + private static final int SKIP = -1; + private static final int EQUALS = -2; + /** + * States 0-3 are reading through the next input tuple. + * State 4 is having read one '=' and expecting exactly + * one more. + * State 5 is expecting no more data or padding characters + * in the input. + * State 6 is the error state; an error has been detected + * in the input and no future input can "fix" it. + */ + private int state; // state number (0 to 6) + private int value; + final private int[] alphabet; + public Decoder(int flags, byte[] output) { + this.output = output; + alphabet = ((flags & URL_SAFE) == 0) ? DECODE : DECODE_WEBSAFE; + state = 0; + value = 0; + } + /** + * @return an overestimate for the number of bytes {@code + * len} bytes could decode to. + */ + public int maxOutputSize(int len) { + return len * 3/4 + 10; + } + /** + * Decode another block of input data. + * + * @return true if the state machine is still healthy. false if + * bad base-64 data has been detected in the input stream. + */ + public boolean process(byte[] input, int offset, int len, boolean finish) { + if (this.state == 6) return false; + int p = offset; + len += offset; + // Using local variables makes the decoder about 12% + // faster than if we manipulate the member variables in + // the loop. (Even alphabet makes a measurable + // difference, which is somewhat surprising to me since + // the member variable is final.) + int state = this.state; + int value = this.value; + int op = 0; + final byte[] output = this.output; + final int[] alphabet = this.alphabet; + while (p < len) { + // Try the fast path: we're starting a new tuple and the + // next four bytes of the input stream are all data + // bytes. This corresponds to going through states + // 0-1-2-3-0. We expect to use this method for most of + // the data. + // + // If any of the next four bytes of input are non-data + // (whitespace, etc.), value will end up negative. (All + // the non-data values in decode are small negative + // numbers, so shifting any of them up and or'ing them + // together will result in a value with its top bit set.) + // + // You can remove this whole block and the output should + // be the same, just slower. + if (state == 0) { + while (p+4 <= len && + (value = ((alphabet[input[p] & 0xff] << 18) | + (alphabet[input[p+1] & 0xff] << 12) | + (alphabet[input[p+2] & 0xff] << 6) | + (alphabet[input[p+3] & 0xff]))) >= 0) { + output[op+2] = (byte) value; + output[op+1] = (byte) (value >> 8); + output[op] = (byte) (value >> 16); + op += 3; + p += 4; + } + if (p >= len) break; + } + // The fast path isn't available -- either we've read a + // partial tuple, or the next four input bytes aren't all + // data, or whatever. Fall back to the slower state + // machine implementation. + int d = alphabet[input[p++] & 0xff]; + switch (state) { + case 0: + if (d >= 0) { + value = d; + ++state; + } else if (d != SKIP) { + this.state = 6; + return false; + } + break; + case 1: + if (d >= 0) { + value = (value << 6) | d; + ++state; + } else if (d != SKIP) { + this.state = 6; + return false; + } + break; + case 2: + if (d >= 0) { + value = (value << 6) | d; + ++state; + } else if (d == EQUALS) { + // Emit the last (partial) output tuple; + // expect exactly one more padding character. + output[op++] = (byte) (value >> 4); + state = 4; + } else if (d != SKIP) { + this.state = 6; + return false; + } + break; + case 3: + if (d >= 0) { + // Emit the output triple and return to state 0. + value = (value << 6) | d; + output[op+2] = (byte) value; + output[op+1] = (byte) (value >> 8); + output[op] = (byte) (value >> 16); + op += 3; + state = 0; + } else if (d == EQUALS) { + // Emit the last (partial) output tuple; + // expect no further data or padding characters. + output[op+1] = (byte) (value >> 2); + output[op] = (byte) (value >> 10); + op += 2; + state = 5; + } else if (d != SKIP) { + this.state = 6; + return false; + } + break; + case 4: + if (d == EQUALS) { + ++state; + } else if (d != SKIP) { + this.state = 6; + return false; + } + break; + case 5: + if (d != SKIP) { + this.state = 6; + return false; + } + break; + } + } + if (!finish) { + // We're out of input, but a future call could provide + // more. + this.state = state; + this.value = value; + this.op = op; + return true; + } + // Done reading input. Now figure out where we are left in + // the state machine and finish up. + switch (state) { + case 0: + // Output length is a multiple of three. Fine. + break; + case 1: + // Read one extra input byte, which isn't enough to + // make another output byte. Illegal. + this.state = 6; + return false; + case 2: + // Read two extra input bytes, enough to emit 1 more + // output byte. Fine. + output[op++] = (byte) (value >> 4); + break; + case 3: + // Read three extra input bytes, enough to emit 2 more + // output bytes. Fine. + output[op++] = (byte) (value >> 10); + output[op++] = (byte) (value >> 2); + break; + case 4: + // Read one padding '=' when we expected 2. Illegal. + this.state = 6; + return false; + case 5: + // Read all the padding '='s we expected and no more. + // Fine. + break; + } + this.state = state; + this.op = op; + return true; + } + } + // -------------------------------------------------------- + // encoding + // -------------------------------------------------------- + /** + * Base64-encode the given data and return a newly allocated + * String with the result. + * + * @param input the data to encode + * @param flags controls certain features of the encoded output. + * Passing {@code DEFAULT} results in output that + * adheres to RFC 2045. + */ + public static String encodeToString(byte[] input, int flags) { + try { + return new String(encode(input, flags), "US-ASCII"); + } catch (UnsupportedEncodingException e) { + // US-ASCII is guaranteed to be available. + throw new AssertionError(e); + } + } + /** + * Base64-encode the given data and return a newly allocated + * String with the result. + * + * @param input the data to encode + * @param offset the position within the input array at which to + * start + * @param len the number of bytes of input to encode + * @param flags controls certain features of the encoded output. + * Passing {@code DEFAULT} results in output that + * adheres to RFC 2045. + */ + public static String encodeToString(byte[] input, int offset, int len, int flags) { + try { + return new String(encode(input, offset, len, flags), "US-ASCII"); + } catch (UnsupportedEncodingException e) { + // US-ASCII is guaranteed to be available. + throw new AssertionError(e); + } + } + /** + * Base64-encode the given data and return a newly allocated + * byte[] with the result. + * + * @param input the data to encode + * @param flags controls certain features of the encoded output. + * Passing {@code DEFAULT} results in output that + * adheres to RFC 2045. + */ + public static byte[] encode(byte[] input, int flags) { + return encode(input, 0, input.length, flags); + } + /** + * Base64-encode the given data and return a newly allocated + * byte[] with the result. + * + * @param input the data to encode + * @param offset the position within the input array at which to + * start + * @param len the number of bytes of input to encode + * @param flags controls certain features of the encoded output. + * Passing {@code DEFAULT} results in output that + * adheres to RFC 2045. + */ + public static byte[] encode(byte[] input, int offset, int len, int flags) { + Encoder encoder = new Encoder(flags, null); + // Compute the exact length of the array we will produce. + int output_len = len / 3 * 4; + // Account for the tail of the data and the padding bytes, if any. + if (encoder.do_padding) { + if (len % 3 > 0) { + output_len += 4; + } + } else { + switch (len % 3) { + case 0: break; + case 1: output_len += 2; break; + case 2: output_len += 3; break; + } + } + // Account for the newlines, if any. + if (encoder.do_newline && len > 0) { + output_len += (((len-1) / (3 * Encoder.LINE_GROUPS)) + 1) * + (encoder.do_cr ? 2 : 1); + } + encoder.output = new byte[output_len]; + encoder.process(input, offset, len, true); + assert encoder.op == output_len; + return encoder.output; + } + /* package */ static class Encoder extends Coder { + /** + * Emit a new line every this many output tuples. Corresponds to + * a 76-character line length (the maximum allowable according to + * RFC 2045). + */ + public static final int LINE_GROUPS = 19; + /** + * Lookup table for turning Base64 alphabet positions (6 bits) + * into output bytes. + */ + private static final byte ENCODE[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', + }; + /** + * Lookup table for turning Base64 alphabet positions (6 bits) + * into output bytes. + */ + private static final byte ENCODE_WEBSAFE[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_', + }; + final private byte[] tail; + /* package */ int tailLen; + private int count; + final public boolean do_padding; + final public boolean do_newline; + final public boolean do_cr; + final private byte[] alphabet; + public Encoder(int flags, byte[] output) { + this.output = output; + do_padding = (flags & NO_PADDING) == 0; + do_newline = (flags & NO_WRAP) == 0; + do_cr = (flags & CRLF) != 0; + alphabet = ((flags & URL_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE; + tail = new byte[2]; + tailLen = 0; + count = do_newline ? LINE_GROUPS : -1; + } + /** + * @return an overestimate for the number of bytes {@code + * len} bytes could encode to. + */ + public int maxOutputSize(int len) { + return len * 8/5 + 10; + } + public boolean process(byte[] input, int offset, int len, boolean finish) { + // Using local variables makes the encoder about 9% faster. + final byte[] alphabet = this.alphabet; + final byte[] output = this.output; + int op = 0; + int count = this.count; + int p = offset; + len += offset; + int v = -1; + // First we need to concatenate the tail of the previous call + // with any input bytes available now and see if we can empty + // the tail. + switch (tailLen) { + case 0: + // There was no tail. + break; + case 1: + if (p+2 <= len) { + // A 1-byte tail with at least 2 bytes of + // input available now. + v = ((tail[0] & 0xff) << 16) | + ((input[p++] & 0xff) << 8) | + (input[p++] & 0xff); + tailLen = 0; + }; + break; + case 2: + if (p+1 <= len) { + // A 2-byte tail with at least 1 byte of input. + v = ((tail[0] & 0xff) << 16) | + ((tail[1] & 0xff) << 8) | + (input[p++] & 0xff); + tailLen = 0; + } + break; + } + if (v != -1) { + output[op++] = alphabet[(v >> 18) & 0x3f]; + output[op++] = alphabet[(v >> 12) & 0x3f]; + output[op++] = alphabet[(v >> 6) & 0x3f]; + output[op++] = alphabet[v & 0x3f]; + if (--count == 0) { + if (do_cr) output[op++] = '\r'; + output[op++] = '\n'; + count = LINE_GROUPS; + } + } + // At this point either there is no tail, or there are fewer + // than 3 bytes of input available. + // The main loop, turning 3 input bytes into 4 output bytes on + // each iteration. + while (p+3 <= len) { + v = ((input[p] & 0xff) << 16) | + ((input[p+1] & 0xff) << 8) | + (input[p+2] & 0xff); + output[op] = alphabet[(v >> 18) & 0x3f]; + output[op+1] = alphabet[(v >> 12) & 0x3f]; + output[op+2] = alphabet[(v >> 6) & 0x3f]; + output[op+3] = alphabet[v & 0x3f]; + p += 3; + op += 4; + if (--count == 0) { + if (do_cr) output[op++] = '\r'; + output[op++] = '\n'; + count = LINE_GROUPS; + } + } + if (finish) { + // Finish up the tail of the input. Note that we need to + // consume any bytes in tail before any bytes + // remaining in input; there should be at most two bytes + // total. + if (p-tailLen == len-1) { + int t = 0; + v = ((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 4; + tailLen -= t; + output[op++] = alphabet[(v >> 6) & 0x3f]; + output[op++] = alphabet[v & 0x3f]; + if (do_padding) { + output[op++] = '='; + output[op++] = '='; + } + if (do_newline) { + if (do_cr) output[op++] = '\r'; + output[op++] = '\n'; + } + } else if (p-tailLen == len-2) { + int t = 0; + v = (((tailLen > 1 ? tail[t++] : input[p++]) & 0xff) << 10) | + (((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 2); + tailLen -= t; + output[op++] = alphabet[(v >> 12) & 0x3f]; + output[op++] = alphabet[(v >> 6) & 0x3f]; + output[op++] = alphabet[v & 0x3f]; + if (do_padding) { + output[op++] = '='; + } + if (do_newline) { + if (do_cr) output[op++] = '\r'; + output[op++] = '\n'; + } + } else if (do_newline && op > 0 && count != LINE_GROUPS) { + if (do_cr) output[op++] = '\r'; + output[op++] = '\n'; + } + assert tailLen == 0; + assert p == len; + } else { + // Save the leftovers in tail to be consumed on the next + // call to encodeInternal. + if (p == len-1) { + tail[tailLen++] = input[p]; + } else if (p == len-2) { + tail[tailLen++] = input[p]; + tail[tailLen++] = input[p+1]; + } + } + this.op = op; + this.count = count; + return true; + } + } + + private Base64() { } // don't instantiate +} diff --git a/src/main/java/io/socket/engineio/parser/Parser.java b/src/main/java/io/socket/engineio/parser/Parser.java index fe6c3622..f92e1e08 100644 --- a/src/main/java/io/socket/engineio/parser/Parser.java +++ b/src/main/java/io/socket/engineio/parser/Parser.java @@ -1,20 +1,13 @@ package io.socket.engineio.parser; - -import io.socket.utf8.UTF8; -import io.socket.utf8.UTF8Exception; - -import java.nio.ByteBuffer; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; public class Parser { - private static final int MAX_INT_CHAR_LENGTH = String.valueOf(Integer.MAX_VALUE).length(); + public static final int PROTOCOL = 4; - public static final int PROTOCOL = 3; + private static final char SEPARATOR = '\u001e'; private static final Map packets = new HashMap() {{ put(Packet.OPEN, 0); @@ -26,61 +19,38 @@ public class Parser { put(Packet.NOOP, 6); }}; - private static final Map packetslist = new HashMap(); + private static final Map packetslist = new HashMap<>(); static { for (Map.Entry entry : packets.entrySet()) { packetslist.put(entry.getValue(), entry.getKey()); } } - private static Packet err = new Packet(Packet.ERROR, "parser error"); - - private static UTF8.Options utf8Options = new UTF8.Options(); - static { - utf8Options.strict = false; - } - + private static final Packet err = new Packet(Packet.ERROR, "parser error"); private Parser() {} - public static void encodePacket(Packet packet, EncodeCallback callback) throws UTF8Exception { - encodePacket(packet, false, callback); - } - - public static void encodePacket(Packet packet, boolean utf8encode, EncodeCallback callback) throws UTF8Exception { + public static void encodePacket(Packet packet, EncodeCallback callback) { if (packet.data instanceof byte[]) { - @SuppressWarnings("unchecked") - Packet packetToEncode = packet; - @SuppressWarnings("unchecked") - EncodeCallback callbackToEncode = callback; - encodeByteArray(packetToEncode, callbackToEncode); - return; - } - - String encoded = String.valueOf(packets.get(packet.type)); - - if (null != packet.data) { - encoded += utf8encode ? UTF8.encode(String.valueOf(packet.data), utf8Options) : String.valueOf(packet.data); + ((EncodeCallback) callback).call(((Packet) packet).data); + } else { + String type = String.valueOf(packets.get(packet.type)); + String content = packet.data != null ? String.valueOf(packet.data) : ""; + ((EncodeCallback) callback).call(type + content); } - - @SuppressWarnings("unchecked") - EncodeCallback tempCallback = callback; - tempCallback.call(encoded); } - private static void encodeByteArray(Packet packet, EncodeCallback callback) { - byte[] data = packet.data; - byte[] resultArray = new byte[1 + data.length]; - resultArray[0] = packets.get(packet.type).byteValue(); - System.arraycopy(data, 0, resultArray, 1, data.length); - callback.call(resultArray); + private static void encodePacketAsBase64(Packet packet, EncodeCallback callback) { + if (packet.data instanceof byte[]) { + byte[] data = ((Packet) packet).data; + String value = "b" + Base64.encodeToString(data, Base64.DEFAULT); + callback.call(value); + } else { + encodePacket(packet, callback); + } } public static Packet decodePacket(String data) { - return decodePacket(data, false); - } - - public static Packet decodePacket(String data, boolean utf8decode) { if (data == null) { return err; } @@ -92,14 +62,6 @@ public static Packet decodePacket(String data, boolean utf8decode) { type = -1; } - if (utf8decode) { - try { - data = UTF8.decode(data, utf8Options); - } catch (UTF8Exception e) { - return err; - } - } - if (type < 0 || type >= packetslist.size()) { return err; } @@ -111,93 +73,44 @@ public static Packet decodePacket(String data, boolean utf8decode) { } } - public static Packet decodePacket(byte[] data) { - int type = data[0]; - byte[] intArray = new byte[data.length - 1]; - System.arraycopy(data, 1, intArray, 0, intArray.length); - return new Packet(packetslist.get(type), intArray); - } - - public static void encodePayload(Packet[] packets, EncodeCallback callback) throws UTF8Exception { - for (Packet packet : packets) { - if (packet.data instanceof byte[]) { - @SuppressWarnings("unchecked") - EncodeCallback _callback = (EncodeCallback) callback; - encodePayloadAsBinary(packets, _callback); - return; - } - } - - if (packets.length == 0) { - callback.call("0:"); - return; + public static Packet decodeBase64Packet(String data) { + if (data == null) { + return err; } - final StringBuilder result = new StringBuilder(); - - for (Packet packet : packets) { - encodePacket(packet, false, new EncodeCallback() { - @Override - public void call(Object message) { - result.append(setLengthHeader((String)message)); - } - }); + if (data.charAt(0) == 'b') { + return new Packet(Packet.MESSAGE, Base64.decode(data.substring(1), Base64.DEFAULT)); + } else { + return decodePacket(data); } - - callback.call(result.toString()); } - private static String setLengthHeader(String message) { - return message.length() + ":" + message; + public static Packet decodePacket(byte[] data) { + return new Packet<>(Packet.MESSAGE, data); } - private static void encodePayloadAsBinary(Packet[] packets, EncodeCallback callback) throws UTF8Exception { + public static void encodePayload(Packet[] packets, EncodeCallback callback) { if (packets.length == 0) { - callback.call(new byte[0]); + callback.call("0:"); return; } - final ArrayList results = new ArrayList(packets.length); + final StringBuilder result = new StringBuilder(); - for (Packet packet : packets) { - encodeOneBinaryPacket(packet, new EncodeCallback() { + for (int i = 0, l = packets.length; i < l; i++) { + final boolean isLast = i == l - 1; + encodePacketAsBase64(packets[i], new EncodeCallback() { @Override - public void call(byte[] data) { - results.add(data); + public void call(String message) { + result.append(message); + if (!isLast) { + result.append(SEPARATOR); + } } }); } - callback.call(Buffer.concat(results.toArray(new byte[results.size()][]))); - } - - private static void encodeOneBinaryPacket(Packet p, final EncodeCallback doneCallback) throws UTF8Exception { - encodePacket(p, true, new EncodeCallback() { - @Override - public void call(Object packet) { - if (packet instanceof String) { - String encodingLength = String.valueOf(((String) packet).length()); - byte[] sizeBuffer = new byte[encodingLength.length() + 2]; - - sizeBuffer[0] = (byte)0; // is a string - for (int i = 0; i < encodingLength.length(); i ++) { - sizeBuffer[i + 1] = (byte)Character.getNumericValue(encodingLength.charAt(i)); - } - sizeBuffer[sizeBuffer.length - 1] = (byte)255; - doneCallback.call(Buffer.concat(new byte[][] {sizeBuffer, stringToByteArray((String)packet)})); - return; - } - - String encodingLength = String.valueOf(((byte[])packet).length); - byte[] sizeBuffer = new byte[encodingLength.length() + 2]; - sizeBuffer[0] = (byte)1; // is binary - for (int i = 0; i < encodingLength.length(); i ++) { - sizeBuffer[i + 1] = (byte)Character.getNumericValue(encodingLength.charAt(i)); - } - sizeBuffer[sizeBuffer.length - 1] = (byte)255; - doneCallback.call(Buffer.concat(new byte[][] {sizeBuffer, (byte[])packet})); - } - }); + callback.call(result.toString()); } public static void decodePayload(String data, DecodePayloadCallback callback) { @@ -206,159 +119,30 @@ public static void decodePayload(String data, DecodePayloadCallback call return; } - StringBuilder length = new StringBuilder(); - for (int i = 0, l = data.length(); i < l; i++) { - char chr = data.charAt(i); - - if (':' != chr) { - length.append(chr); - continue; - } + String[] messages = data.split(String.valueOf(SEPARATOR)); - int n; - try { - n = Integer.parseInt(length.toString()); - } catch (NumberFormatException e) { + for (int i = 0, l = messages.length; i < l; i++) { + Packet packet = decodeBase64Packet(messages[i]); + if (err.type.equals(packet.type) && err.data.equals(packet.data)) { callback.call(err, 0, 1); return; } - String msg; - try { - msg = data.substring(i + 1, i + 1 + n); - } catch (IndexOutOfBoundsException e) { - callback.call(err, 0, 1); + boolean ret = callback.call(packet, i, l); + if (!ret) { return; } - - if (msg.length() != 0) { - Packet packet = decodePacket(msg, false); - if (err.type.equals(packet.type) && err.data.equals(packet.data)) { - callback.call(err, 0, 1); - return; - } - - boolean ret = callback.call(packet, i + n, l); - if (!ret) { - return; - } - } - - i += n; - length = new StringBuilder(); - } - - if (length.length() > 0) { - callback.call(err, 0, 1); } } - public static void decodePayload(byte[] data, DecodePayloadCallback callback) { - ByteBuffer bufferTail = ByteBuffer.wrap(data); - List buffers = new ArrayList(); - - while (bufferTail.capacity() > 0) { - StringBuilder strLen = new StringBuilder(); - boolean isString = (bufferTail.get(0) & 0xFF) == 0; - for (int i = 1; ; i++) { - int b = bufferTail.get(i) & 0xFF; - if (b == 255) break; - // supports only integer - if (strLen.length() > MAX_INT_CHAR_LENGTH) { - callback.call(err, 0, 1); - return; - } - strLen.append(b); - } - - bufferTail.position(strLen.length() + 1); - bufferTail = bufferTail.slice(); - - int msgLength = Integer.parseInt(strLen.toString()); - - bufferTail.position(1); - bufferTail.limit(msgLength + 1); - byte[] msg = new byte[bufferTail.remaining()]; - bufferTail.get(msg); - if (isString) { - buffers.add(byteArrayToString(msg)); - } else { - buffers.add(msg); - } - bufferTail.clear(); - bufferTail.position(msgLength + 1); - bufferTail = bufferTail.slice(); - } + public interface EncodeCallback { - int total = buffers.size(); - for (int i = 0; i < total; i++) { - Object buffer = buffers.get(i); - if (buffer instanceof String) { - @SuppressWarnings("unchecked") - DecodePayloadCallback tempCallback = callback; - tempCallback.call(decodePacket((String)buffer, true), i, total); - } else if (buffer instanceof byte[]) { - @SuppressWarnings("unchecked") - DecodePayloadCallback tempCallback = callback; - tempCallback.call(decodePacket((byte[])buffer), i, total); - } - } - } - - private static String byteArrayToString(byte[] bytes) { - StringBuilder builder = new StringBuilder(); - for (byte b : bytes) { - builder.appendCodePoint(b & 0xFF); - } - return builder.toString(); - } - - private static byte[] stringToByteArray(String string) { - int len = string.length(); - byte[] bytes = new byte[len]; - for (int i = 0; i < len; i++) { - bytes[i] = (byte)Character.codePointAt(string, i); - } - return bytes; - } - - public static interface EncodeCallback { - - public void call(T data); - } - - - public static interface DecodePayloadCallback { - - public boolean call(Packet packet, int index, int total); - } -} - - -class Buffer { - - private Buffer() {} - - public static byte[] concat(byte[][] list) { - int length = 0; - for (byte[] buf : list) { - length += buf.length; - } - return concat(list, length); + void call(T data); } - public static byte[] concat(byte[][] list, int length) { - if (list.length == 0) { - return new byte[0]; - } else if (list.length == 1) { - return list[0]; - } - ByteBuffer buffer = ByteBuffer.allocate(length); - for (byte[] buf : list) { - buffer.put(buf); - } + public interface DecodePayloadCallback { - return buffer.array(); + boolean call(Packet packet, int index, int total); } } diff --git a/src/main/java/io/socket/utf8/UTF8.java b/src/main/java/io/socket/utf8/UTF8.java deleted file mode 100644 index e7145792..00000000 --- a/src/main/java/io/socket/utf8/UTF8.java +++ /dev/null @@ -1,199 +0,0 @@ -package io.socket.utf8; - -import java.util.ArrayList; -import java.util.List; - -/** - * UTF-8 encoder/decoder ported from utf8.js. - * - * @see https://github.com/mathiasbynens/utf8.js - */ -public final class UTF8 { - - private static final String INVALID_CONTINUATION_BYTE = "Invalid continuation byte"; - private static int[] byteArray; - private static int byteCount; - private static int byteIndex; - - private UTF8 () {} - - public static String encode(String string) throws UTF8Exception { - return encode(string, new Options()); - } - - public static String encode(String string, Options opts) throws UTF8Exception { - boolean strict = opts.strict; - - int[] codePoints = ucs2decode(string); - int length = codePoints.length; - int index = -1; - int codePoint; - StringBuilder byteString = new StringBuilder(); - while (++index < length) { - codePoint = codePoints[index]; - byteString.append(encodeCodePoint(codePoint, strict)); - } - return byteString.toString(); - } - - public static String decode(String byteString) throws UTF8Exception { - return decode(byteString, new Options()); - } - - public static String decode(String byteString, Options opts) throws UTF8Exception { - boolean strict = opts.strict; - - byteArray = ucs2decode(byteString); - byteCount = byteArray.length; - byteIndex = 0; - List codePoints = new ArrayList(); - int tmp; - while ((tmp = decodeSymbol(strict)) != -1) { - codePoints.add(tmp); - } - return ucs2encode(listToArray(codePoints)); - } - - private static int[] ucs2decode(String string) { - int length = string.length(); - int[] output = new int[string.codePointCount(0, length)]; - int counter = 0; - int value; - for (int i = 0; i < length; i += Character.charCount(value)) { - value = string.codePointAt(i); - output[counter++] = value; - } - return output; - } - - private static String encodeCodePoint(int codePoint, boolean strict) throws UTF8Exception { - StringBuilder symbol = new StringBuilder(); - if ((codePoint & 0xFFFFFF80) == 0) { - return symbol.append(Character.toChars(codePoint)).toString(); - } - if ((codePoint & 0xFFFFF800) == 0) { - symbol.append(Character.toChars(((codePoint >> 6) & 0x1F) | 0xC0)); - } else if ((codePoint & 0xFFFF0000) == 0) { - if (!checkScalarValue(codePoint, strict)) { - codePoint = 0xFFFD; - } - symbol.append(Character.toChars(((codePoint >> 12) & 0x0F) | 0xE0)); - symbol.append(createByte(codePoint, 6)); - } else if ((codePoint & 0xFFE00000) == 0) { - symbol.append(Character.toChars(((codePoint >> 18) & 0x07) | 0xF0)); - symbol.append(createByte(codePoint, 12)); - symbol.append(createByte(codePoint, 6)); - } - symbol.append(Character.toChars((codePoint & 0x3F) | 0x80)); - return symbol.toString(); - } - - private static char[] createByte(int codePoint, int shift) { - return Character.toChars(((codePoint >> shift) & 0x3F) | 0x80); - } - - private static int decodeSymbol(boolean strict) throws UTF8Exception { - int byte1; - int byte2; - int byte3; - int byte4; - int codePoint; - - if (byteIndex > byteCount) { - throw new UTF8Exception("Invalid byte index"); - } - - if (byteIndex == byteCount) { - return -1; - } - - byte1 = byteArray[byteIndex] & 0xFF; - byteIndex++; - - if ((byte1 & 0x80) == 0) { - return byte1; - } - - if ((byte1 & 0xE0) == 0xC0) { - byte2 = readContinuationByte(); - codePoint = ((byte1 & 0x1F) << 6) | byte2; - if (codePoint >= 0x80) { - return codePoint; - } else { - throw new UTF8Exception(INVALID_CONTINUATION_BYTE); - } - } - - if ((byte1 & 0xF0) == 0xE0) { - byte2 = readContinuationByte(); - byte3 = readContinuationByte(); - codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3; - if (codePoint >= 0x0800) { - return checkScalarValue(codePoint, strict) ? codePoint : 0xFFFD; - } else { - throw new UTF8Exception(INVALID_CONTINUATION_BYTE); - } - } - - if ((byte1 & 0xF8) == 0xF0) { - byte2 = readContinuationByte(); - byte3 = readContinuationByte(); - byte4 = readContinuationByte(); - codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) | (byte3 << 0x06) | byte4; - if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) { - return codePoint; - } - } - - throw new UTF8Exception(INVALID_CONTINUATION_BYTE); - } - - private static int readContinuationByte() throws UTF8Exception { - if (byteIndex >= byteCount) { - throw new UTF8Exception("Invalid byte index"); - } - - int continuationByte = byteArray[byteIndex] & 0xFF; - byteIndex++; - - if ((continuationByte & 0xC0) == 0x80) { - return continuationByte & 0x3F; - } - - throw new UTF8Exception(INVALID_CONTINUATION_BYTE); - } - - private static String ucs2encode(int[] array) { - StringBuilder output = new StringBuilder(); - for (int value : array) { - output.appendCodePoint(value); - } - return output.toString(); - } - - private static boolean checkScalarValue(int codePoint, boolean strict) throws UTF8Exception { - if (codePoint >= 0xD800 && codePoint <= 0xDFFF) { - if (strict) { - throw new UTF8Exception( - "Lone surrogate U+" + Integer.toHexString(codePoint).toUpperCase() + - " is not a scalar value" - ); - } - return false; - } - return true; - } - - private static int[] listToArray(List list) { - int size = list.size(); - int[] array = new int[size]; - for (int i = 0; i < size; i++) { - array[i] = list.get(i); - } - return array; - } - - public static class Options { - public boolean strict = true; - } -} diff --git a/src/main/java/io/socket/utf8/UTF8Exception.java b/src/main/java/io/socket/utf8/UTF8Exception.java deleted file mode 100644 index 077da0be..00000000 --- a/src/main/java/io/socket/utf8/UTF8Exception.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.socket.utf8; - -import java.io.IOException; - -public class UTF8Exception extends IOException { - - public UTF8Exception() { - super(); - } - - public UTF8Exception(String message) { - super(message); - } - - public UTF8Exception(String message, Throwable cause) { - super(message, cause); - } - - public UTF8Exception(Throwable cause) { - super(cause); - } -} diff --git a/src/test/java/io/socket/engineio/client/ConnectionTest.java b/src/test/java/io/socket/engineio/client/ConnectionTest.java index ac0997e4..a9192791 100644 --- a/src/test/java/io/socket/engineio/client/ConnectionTest.java +++ b/src/test/java/io/socket/engineio/client/ConnectionTest.java @@ -242,4 +242,20 @@ public void call(Object... args) { socket.open(); assertThat((Integer) values.take(), is(0)); } + + @Test(timeout = TIMEOUT) + public void receivePing() throws InterruptedException { + final BlockingQueue values = new LinkedBlockingQueue<>(); + + socket = new Socket(createOptions()); + socket.on(Socket.EVENT_PING, new Emitter.Listener() { + @Override + public void call(Object... args) { + values.offer("end"); + socket.close(); + } + }); + socket.open(); + assertThat(values.take(), is("end")); + } } diff --git a/src/test/java/io/socket/engineio/parser/ParserTest.java b/src/test/java/io/socket/engineio/parser/ParserTest.java index d8e7692b..d5498b91 100644 --- a/src/test/java/io/socket/engineio/parser/ParserTest.java +++ b/src/test/java/io/socket/engineio/parser/ParserTest.java @@ -1,6 +1,5 @@ package io.socket.engineio.parser; -import io.socket.utf8.UTF8Exception; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -15,7 +14,7 @@ public class ParserTest { static final String ERROR_DATA = "parser error"; @Test - public void encodeAsString() throws UTF8Exception { + public void encodeAsString() { encodePacket(new Packet(Packet.MESSAGE, "test"), new EncodeCallback() { @Override public void call(String data) { @@ -25,7 +24,7 @@ public void call(String data) { } @Test - public void decodeAsPacket() throws UTF8Exception { + public void decodeAsPacket() { encodePacket(new Packet(Packet.MESSAGE, "test"), new EncodeCallback() { @Override public void call(String data) { @@ -35,7 +34,7 @@ public void call(String data) { } @Test - public void noData() throws UTF8Exception { + public void noData() { encodePacket(new Packet(Packet.MESSAGE), new EncodeCallback() { @Override public void call(String data) { @@ -47,7 +46,7 @@ public void call(String data) { } @Test - public void encodeOpenPacket() throws UTF8Exception { + public void encodeOpenPacket() { encodePacket(new Packet(Packet.OPEN, "{\"some\":\"json\"}"), new EncodeCallback() { @Override public void call(String data) { @@ -59,7 +58,7 @@ public void call(String data) { } @Test - public void encodeClosePacket() throws UTF8Exception { + public void encodeClosePacket() { encodePacket(new Packet(Packet.CLOSE), new EncodeCallback() { @Override public void call(String data) { @@ -70,7 +69,7 @@ public void call(String data) { } @Test - public void encodePingPacket() throws UTF8Exception { + public void encodePingPacket() { encodePacket(new Packet(Packet.PING, "1"), new EncodeCallback() { @Override public void call(String data) { @@ -82,7 +81,7 @@ public void call(String data) { } @Test - public void encodePongPacket() throws UTF8Exception { + public void encodePongPacket() { encodePacket(new Packet(Packet.PONG, "1"), new EncodeCallback() { @Override public void call(String data) { @@ -94,7 +93,7 @@ public void call(String data) { } @Test - public void encodeMessagePacket() throws UTF8Exception { + public void encodeMessagePacket() { encodePacket(new Packet(Packet.MESSAGE, "aaa"), new EncodeCallback() { @Override public void call(String data) { @@ -106,7 +105,7 @@ public void call(String data) { } @Test - public void encodeUTF8SpecialCharsMessagePacket() throws UTF8Exception { + public void encodeUTF8SpecialCharsMessagePacket() { encodePacket(new Packet(Packet.MESSAGE, "utf8 — string"), new EncodeCallback() { @Override public void call(String data) { @@ -118,7 +117,7 @@ public void call(String data) { } @Test - public void encodeMessagePacketCoercingToString() throws UTF8Exception { + public void encodeMessagePacketCoercingToString() { encodePacket(new Packet(Packet.MESSAGE, 1), new EncodeCallback() { @Override public void call(String data) { @@ -130,7 +129,7 @@ public void call(String data) { } @Test - public void encodeUpgradePacket() throws UTF8Exception { + public void encodeUpgradePacket() { encodePacket(new Packet(Packet.UPGRADE), new EncodeCallback() { @Override public void call(String data) { @@ -141,7 +140,7 @@ public void call(String data) { } @Test - public void encodingFormat() throws UTF8Exception { + public void encodingFormat() { encodePacket(new Packet(Packet.MESSAGE, "test"), new EncodeCallback() { @Override public void call(String data) { @@ -156,19 +155,6 @@ public void call(String data) { }); } - @Test - public void encodingStringMessageWithLoneSurrogatesReplacedByUFFFD() throws UTF8Exception { - String data = "\uDC00\uD834\uDF06\uDC00 \uD800\uD835\uDF07\uD800"; - encodePacket(new Packet(Packet.MESSAGE, data), true, new EncodeCallback() { - @Override - public void call(String encoded) { - Packet p = decodePacket(encoded, true); - assertThat(p.type, is(Packet.MESSAGE)); - assertThat(p.data, is("\uFFFD\uD834\uDF06\uFFFD \uFFFD\uD835\uDF07\uFFFD")); - } - }); - } - @Test public void decodeEmptyPayload() { Packet p = decodePacket((String)null); @@ -191,14 +177,7 @@ public void decodeInexistentTypes() { } @Test - public void decodeInvalidUTF8() { - Packet p = decodePacket("4\uffff", true); - assertThat(p.type, is(Packet.ERROR)); - assertThat(p.data, is(ERROR_DATA)); - } - - @Test - public void encodePayloads() throws UTF8Exception { + public void encodePayloads() { encodePayload(new Packet[]{new Packet(Packet.PING), new Packet(Packet.PONG)}, new EncodeCallback() { @Override public void call(String data) { @@ -208,7 +187,7 @@ public void call(String data) { } @Test - public void encodeAndDecodePayloads() throws UTF8Exception { + public void encodeAndDecodePayloads() { encodePayload(new Packet[] {new Packet(Packet.MESSAGE, "a")}, new EncodeCallback() { @Override public void call(String data) { @@ -242,7 +221,7 @@ public boolean call(Packet packet, int index, int total) { } @Test - public void encodeAndDecodeEmptyPayloads() throws UTF8Exception { + public void encodeAndDecodeEmptyPayloads() { encodePayload(new Packet[] {}, new EncodeCallback() { @Override public void call(String data) { @@ -260,30 +239,20 @@ public boolean call(Packet packet, int index, int total) { } @Test - public void notUTF8EncodeWhenDealingWithStringsOnly() throws UTF8Exception { + public void notUTF8EncodeWhenDealingWithStringsOnly() { encodePayload(new Packet[] { new Packet(Packet.MESSAGE, "€€€"), new Packet(Packet.MESSAGE, "α") }, new EncodeCallback() { @Override public void call(String data) { - assertThat(data, is("4:4€€€2:4α")); + assertThat(data, is("4€€€\u001e4α")); } }); } @Test public void decodePayloadBadFormat() { - decodePayload("1!", new DecodePayloadCallback() { - @Override - public boolean call(Packet packet, int index, int total) { - boolean isLast = index + 1 == total; - assertThat(packet.type, is(Packet.ERROR)); - assertThat(packet.data, is(ERROR_DATA)); - assertThat(isLast, is(true)); - return true; - } - }); decodePayload("", new DecodePayloadCallback() { @Override public boolean call(Packet packet, int index, int total) { @@ -306,33 +275,9 @@ public boolean call(Packet packet, int index, int total) { }); } - @Test - public void decodePayloadBadLength() { - decodePayload("1:", new DecodePayloadCallback() { - @Override - public boolean call(Packet packet, int index, int total) { - boolean isLast = index + 1 == total; - assertThat(packet.type, is(Packet.ERROR)); - assertThat(packet.data, is(ERROR_DATA)); - assertThat(isLast, is(true)); - return true; - } - }); - } - @Test public void decodePayloadBadPacketFormat() { - decodePayload("3:99:", new DecodePayloadCallback() { - @Override - public boolean call(Packet packet, int index, int total) { - boolean isLast = index + 1 == total; - assertThat(packet.type, is(Packet.ERROR)); - assertThat(packet.data, is(ERROR_DATA)); - assertThat(isLast, is(true)); - return true; - } - }); - decodePayload("1:aa", new DecodePayloadCallback() { + decodePayload("99:", new DecodePayloadCallback() { @Override public boolean call(Packet packet, int index, int total) { boolean isLast = index + 1 == total; @@ -342,7 +287,7 @@ public boolean call(Packet packet, int index, int total) { return true; } }); - decodePayload("1:a2:b", new DecodePayloadCallback() { + decodePayload("aa", new DecodePayloadCallback() { @Override public boolean call(Packet packet, int index, int total) { boolean isLast = index + 1 == total; @@ -355,7 +300,7 @@ public boolean call(Packet packet, int index, int total) { } @Test - public void encodeBinaryMessage() throws UTF8Exception { + public void encodeBinaryMessage() { final byte[] data = new byte[5]; for (int i = 0; i < data.length; i++) { data[0] = (byte)i; @@ -371,7 +316,7 @@ public void call(byte[] encoded) { } @Test - public void encodeBinaryContents() throws UTF8Exception { + public void encodeBinaryContents() { final byte[] firstBuffer = new byte[5]; for (int i = 0 ; i < firstBuffer.length; i++) { firstBuffer[0] = (byte)i; @@ -384,9 +329,9 @@ public void encodeBinaryContents() throws UTF8Exception { encodePayload(new Packet[]{ new Packet(Packet.MESSAGE, firstBuffer), new Packet(Packet.MESSAGE, secondBuffer), - }, new EncodeCallback() { + }, new EncodeCallback() { @Override - public void call(byte[] data) { + public void call(String data) { decodePayload(data, new DecodePayloadCallback() { @Override public boolean call(Packet packet, int index, int total) { @@ -405,7 +350,7 @@ public boolean call(Packet packet, int index, int total) { } @Test - public void encodeMixedBinaryAndStringContents() throws UTF8Exception { + public void encodeMixedBinaryAndStringContents() { final byte[] firstBuffer = new byte[123]; for (int i = 0 ; i < firstBuffer.length; i++) { firstBuffer[0] = (byte)i; @@ -414,9 +359,9 @@ public void encodeMixedBinaryAndStringContents() throws UTF8Exception { new Packet(Packet.MESSAGE, firstBuffer), new Packet(Packet.MESSAGE, "hello"), new Packet(Packet.CLOSE), - }, new EncodeCallback() { + }, new EncodeCallback() { @Override - public void call(byte[] encoded) { + public void call(String encoded) { decodePayload(encoded, new DecodePayloadCallback() { @Override public boolean call(Packet packet, int index, int total) { diff --git a/src/test/java/io/socket/utf8/UTF8Test.java b/src/test/java/io/socket/utf8/UTF8Test.java deleted file mode 100644 index 8357d7fe..00000000 --- a/src/test/java/io/socket/utf8/UTF8Test.java +++ /dev/null @@ -1,114 +0,0 @@ -package io.socket.utf8; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -@RunWith(JUnit4.class) -public class UTF8Test { - private static final Data[] DATA = new Data[] { - // 1-byte - new Data(0x0000, "\u0000", "\u0000"), - new Data(0x005c, "\u005C\u005C", "\u005C\u005C"), // = backslash - new Data(0x007f, "\u007F", "\u007F"), - // 2-byte - new Data(0x0080, "\u0080", "\u00C2\u0080"), - new Data(0x05CA, "\u05CA", "\u00D7\u008A"), - new Data(0x07FF, "\u07FF", "\u00DF\u00BF"), - // 3-byte - new Data(0x0800, "\u0800", "\u00E0\u00A0\u0080"), - new Data(0x2C3C, "\u2C3C", "\u00E2\u00B0\u00BC"), - new Data(0x07FF, "\uFFFF", "\u00EF\u00BF\u00BF"), - // unmatched surrogate halves - // high surrogates: 0xD800 to 0xDBFF - new Data(0xD800, "\uD800", "\u00ED\u00A0\u0080", true), - new Data("High surrogate followed by another high surrogate", - "\uD800\uD800", "\u00ED\u00A0\u0080\u00ED\u00A0\u0080", true), - new Data("High surrogate followed by a symbol that is not a surrogate", - "\uD800A", "\u00ED\u00A0\u0080A", true), - new Data("Unmatched high surrogate, followed by a surrogate pair, followed by an unmatched high surrogate", - "\uD800\uD834\uDF06\uD800", "\u00ED\u00A0\u0080\u00F0\u009D\u008C\u0086\u00ED\u00A0\u0080", true), - new Data(0xD9AF, "\uD9AF", "\u00ED\u00A6\u00AF", true), - new Data(0xDBFF, "\uDBFF", "\u00ED\u00AF\u00BF", true), - // low surrogates: 0xDC00 to 0xDFFF - new Data(0xDC00, "\uDC00", "\u00ED\u00B0\u0080", true), - new Data("Low surrogate followed by another low surrogate", - "\uDC00\uDC00", "\u00ED\u00B0\u0080\u00ED\u00B0\u0080", true), - new Data("Low surrogate followed by a symbol that is not a surrogate", - "\uDC00A", "\u00ED\u00B0\u0080A", true), - new Data("Unmatched low surrogate, followed by a surrogate pair, followed by an unmatched low surrogate", - "\uDC00\uD834\uDF06\uDC00", "\u00ED\u00B0\u0080\u00F0\u009D\u008C\u0086\u00ED\u00B0\u0080", true), - new Data(0xDEEE, "\uDEEE", "\u00ED\u00BB\u00AE", true), - new Data(0xDFFF, "\uDFFF", "\u00ED\u00BF\u00BF", true), - // 4-byte - new Data(0x010000, "\uD800\uDC00", "\u00F0\u0090\u0080\u0080"), - new Data(0x01D306, "\uD834\uDF06", "\u00F0\u009D\u008C\u0086"), - new Data(0x010FFF, "\uDBFF\uDFFF", "\u00F4\u008F\u00BF\u00BF"), - }; - - @Rule - public ExpectedException exception = ExpectedException.none(); - - @Test - public void encodeAndDecode() throws UTF8Exception { - for (Data data : DATA) { - String reason = data.description != null? data.description : "U+" + Integer.toHexString(data.codePoint).toUpperCase(); - if (data.error) { - exception.expect(UTF8Exception.class); - UTF8.decode(data.encoded); - exception.expect(UTF8Exception.class); - UTF8.encode(data.decoded); - } else { - assertThat("Encoding: " + reason, data.encoded, is(UTF8.encode(data.decoded))); - assertThat("Decoding: " + reason, data.decoded, is(UTF8.decode(data.encoded))); - } - } - - exception.expect(UTF8Exception.class); - UTF8.decode("\uFFFF"); - - exception.expect(UTF8Exception.class); - UTF8.decode("\u00E9\u0000\u0000"); - - exception.expect(UTF8Exception.class); - UTF8.decode("\u00C2\uFFFF"); - - exception.expect(UTF8Exception.class); - UTF8.decode("\u00F0\u009D"); - } - - private static class Data { - public int codePoint = -1; - public String description; - public String decoded; - public String encoded; - public boolean error; - - public Data(int codePoint, String decoded, String encoded) { - this(codePoint, decoded, encoded, false); - } - - public Data(int codePoint, String decoded, String encoded, boolean error) { - this.codePoint = codePoint; - this.decoded = decoded; - this.encoded = encoded; - this.error = error; - } - - public Data(String description, String decoded, String encoded) { - this(description, decoded, encoded, false); - } - - public Data(String description, String decoded, String encoded, boolean error) { - this.description = description; - this.decoded = decoded; - this.encoded = encoded; - this.error = error; - } - } -} diff --git a/src/test/resources/package-lock.json b/src/test/resources/package-lock.json index 72697128..c37c07d9 100644 --- a/src/test/resources/package-lock.json +++ b/src/test/resources/package-lock.json @@ -11,16 +11,6 @@ "negotiator": "0.6.2" } }, - "after": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" - }, - "arraybuffer.slice": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" - }, "base64-arraybuffer": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", @@ -31,15 +21,19 @@ "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" }, - "blob": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", - "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" - }, "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } }, "debug": { "version": "4.1.1", @@ -50,43 +44,27 @@ } }, "engine.io": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.2.tgz", - "integrity": "sha512-b4Q85dFkGw+TqgytGPrGgACRUhsdKc9S9ErRAXpPGy/CXKs4tYoHDkvIRdsseAF7NjfVwjRFIn6KTnbw7LwJZg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-4.0.5.tgz", + "integrity": "sha512-Ri+whTNr2PKklxQkfbGjwEo+kCBUM4Qxk4wtLqLrhH+b1up2NFL9g9pjYWiCV/oazwB0rArnvF/ZmZN2ab5Hpg==", "requires": { "accepts": "~1.3.4", "base64id": "2.0.0", - "cookie": "0.3.1", + "cookie": "~0.4.1", + "cors": "~2.8.5", "debug": "~4.1.0", - "engine.io-parser": "~2.2.0", + "engine.io-parser": "~4.0.0", "ws": "^7.1.2" } }, "engine.io-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz", - "integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==", - "requires": { - "after": "0.8.2", - "arraybuffer.slice": "~0.0.7", - "base64-arraybuffer": "0.1.4", - "blob": "0.0.5", - "has-binary2": "~1.0.2" - } - }, - "has-binary2": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", - "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.2.tgz", + "integrity": "sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/MqJdZbUjW97JU72iYg==", "requires": { - "isarray": "2.0.1" + "base64-arraybuffer": "0.1.4" } }, - "isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" - }, "mime-db": { "version": "1.44.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", @@ -101,15 +79,25 @@ } }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, "ws": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", diff --git a/src/test/resources/package.json b/src/test/resources/package.json index d60498e5..3b4d8a18 100644 --- a/src/test/resources/package.json +++ b/src/test/resources/package.json @@ -1,6 +1,6 @@ { "private": true, "dependencies": { - "engine.io": "^3.4.2" + "engine.io": "^4.0.5" } } From dfe65e3b3b5eab4c3fddb9dfbf53d684fe461043 Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Fri, 11 Dec 2020 12:24:07 +0100 Subject: [PATCH 66/72] feat: add an extraHeaders option Similar to the option of the JS client: ```java opts = new Socket.Options(); opts.extraHeaders = singletonMap("authorization", singletonList("bearer abcd")); socket = new Socket(opts); ``` Note: the refactor of the options (similar to [1]) will be done in a future step. [1] https://github.com/socketio/engine.io-client/commit/5f47a50ee5dc47962f3823f4e8dde0b4b407eccd --- .../io/socket/engineio/client/Socket.java | 3 + .../io/socket/engineio/client/Transport.java | 4 ++ .../client/transports/PollingXHR.java | 9 ++- .../engineio/client/transports/WebSocket.java | 3 + .../engineio/client/ServerConnectionTest.java | 67 +++++++++++++++++++ 5 files changed, 85 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/socket/engineio/client/Socket.java b/src/main/java/io/socket/engineio/client/Socket.java index 9b0423ed..2d86e31a 100644 --- a/src/main/java/io/socket/engineio/client/Socket.java +++ b/src/main/java/io/socket/engineio/client/Socket.java @@ -130,6 +130,7 @@ public String toString() { private Future pingTimeoutTimer; private okhttp3.WebSocket.Factory webSocketFactory; private okhttp3.Call.Factory callFactory; + private final Map> extraHeaders; private ReadyState readyState; private ScheduledExecutorService heartbeatScheduler; @@ -221,6 +222,7 @@ public Socket(Options opts) { } webSocketFactory = defaultOkHttpClient; } + this.extraHeaders = opts.extraHeaders; } public static void setDefaultOkHttpWebSocketFactory(okhttp3.WebSocket.Factory factory) { @@ -293,6 +295,7 @@ private Transport createTransport(String name) { opts.policyPort = options != null ? options.policyPort : this.policyPort; opts.callFactory = options != null ? options.callFactory : this.callFactory; opts.webSocketFactory = options != null ? options.webSocketFactory : this.webSocketFactory; + opts.extraHeaders = this.extraHeaders; Transport transport; if (WebSocket.NAME.equals(name)) { diff --git a/src/main/java/io/socket/engineio/client/Transport.java b/src/main/java/io/socket/engineio/client/Transport.java index 56b921cc..7a8ce5cf 100644 --- a/src/main/java/io/socket/engineio/client/Transport.java +++ b/src/main/java/io/socket/engineio/client/Transport.java @@ -1,6 +1,7 @@ package io.socket.engineio.client; +import java.util.List; import java.util.Map; import io.socket.emitter.Emitter; @@ -43,6 +44,7 @@ public String toString() { protected ReadyState readyState; protected WebSocket.Factory webSocketFactory; protected Call.Factory callFactory; + protected Map> extraHeaders; public Transport(Options opts) { this.path = opts.path; @@ -55,6 +57,7 @@ public Transport(Options opts) { this.socket = opts.socket; this.webSocketFactory = opts.webSocketFactory; this.callFactory = opts.callFactory; + this.extraHeaders = opts.extraHeaders; } protected Transport onError(String msg, Exception desc) { @@ -146,5 +149,6 @@ public static class Options { protected Socket socket; public WebSocket.Factory webSocketFactory; public Call.Factory callFactory; + public Map> extraHeaders; } } diff --git a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java index 64b3cda7..11ec6b38 100644 --- a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java +++ b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java @@ -43,6 +43,7 @@ protected Request request(Request.Options opts) { } opts.uri = this.uri(); opts.callFactory = this.callFactory; + opts.extraHeaders = this.extraHeaders; Request req = new Request(opts); @@ -72,6 +73,7 @@ protected void doWrite(String data, final Runnable fn) { Request.Options opts = new Request.Options(); opts.method = "POST"; opts.data = data; + opts.extraHeaders = this.extraHeaders; Request req = this.request(opts); final PollingXHR self = this; req.on(Request.EVENT_SUCCESS, new Emitter.Listener() { @@ -150,6 +152,7 @@ public static class Request extends Emitter { private String data; private Call.Factory callFactory; + private Map> extraHeaders; private Response response; private Call requestCall; @@ -158,13 +161,16 @@ public Request(Options opts) { this.uri = opts.uri; this.data = opts.data; this.callFactory = opts.callFactory != null ? opts.callFactory : new OkHttpClient(); + this.extraHeaders = opts.extraHeaders; } public void create() { final Request self = this; if (LOGGABLE_FINE) logger.fine(String.format("xhr open %s: %s", this.method, this.uri)); Map> headers = new TreeMap>(String.CASE_INSENSITIVE_ORDER); - + if (this.extraHeaders != null) { + headers.putAll(this.extraHeaders); + } if ("POST".equals(this.method)) { headers.put("Content-type", new LinkedList(Collections.singletonList(TEXT_CONTENT_TYPE))); } @@ -255,6 +261,7 @@ public static class Options { public String method; public String data; public Call.Factory callFactory; + public Map> extraHeaders; } } } diff --git a/src/main/java/io/socket/engineio/client/transports/WebSocket.java b/src/main/java/io/socket/engineio/client/transports/WebSocket.java index 74cf65ff..c2153c35 100644 --- a/src/main/java/io/socket/engineio/client/transports/WebSocket.java +++ b/src/main/java/io/socket/engineio/client/transports/WebSocket.java @@ -35,6 +35,9 @@ public WebSocket(Options opts) { protected void doOpen() { Map> headers = new TreeMap>(String.CASE_INSENSITIVE_ORDER); + if (this.extraHeaders != null) { + headers.putAll(this.extraHeaders); + } this.emit(EVENT_REQUEST_HEADERS, headers); final WebSocket self = this; diff --git a/src/test/java/io/socket/engineio/client/ServerConnectionTest.java b/src/test/java/io/socket/engineio/client/ServerConnectionTest.java index 2beb744a..e7a9e73d 100644 --- a/src/test/java/io/socket/engineio/client/ServerConnectionTest.java +++ b/src/test/java/io/socket/engineio/client/ServerConnectionTest.java @@ -10,11 +10,14 @@ import java.net.URISyntaxException; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.notNullValue; @@ -168,6 +171,38 @@ public void call(Object... args) { socket.close(); } + @Test(timeout = TIMEOUT) + public void pollingHeaders_withExtraHeadersOption() throws URISyntaxException, InterruptedException { + final BlockingQueue messages = new LinkedBlockingQueue(); + + Socket.Options opts = createOptions(); + opts.transports = new String[] {Polling.NAME}; + opts.extraHeaders = singletonMap("X-EngineIO", singletonList("bar")); + + socket = new Socket(opts); + socket.on(Socket.EVENT_TRANSPORT, new Emitter.Listener() { + @Override + public void call(Object... args) { + Transport transport = (Transport)args[0]; + transport.on(Transport.EVENT_RESPONSE_HEADERS, new Emitter.Listener() { + @Override + public void call(Object... args) { + @SuppressWarnings("unchecked") + Map> headers = (Map>)args[0]; + List values = headers.get("X-EngineIO"); + messages.offer(values.get(0)); + messages.offer(values.get(1)); + } + }); + } + }); + socket.open(); + + assertThat(messages.take(), is("hi")); + assertThat(messages.take(), is("bar")); + socket.close(); + } + @Test(timeout = TIMEOUT) public void websocketHandshakeHeaders() throws URISyntaxException, InterruptedException { final BlockingQueue messages = new LinkedBlockingQueue(); @@ -206,6 +241,38 @@ public void call(Object... args) { socket.close(); } + @Test(timeout = TIMEOUT) + public void websocketHandshakeHeaders_withExtraHeadersOption() throws URISyntaxException, InterruptedException { + final BlockingQueue messages = new LinkedBlockingQueue(); + + Socket.Options opts = createOptions(); + opts.transports = new String[] {WebSocket.NAME}; + opts.extraHeaders = singletonMap("X-EngineIO", singletonList("bar")); + + socket = new Socket(opts); + socket.on(Socket.EVENT_TRANSPORT, new Emitter.Listener() { + @Override + public void call(Object... args) { + Transport transport = (Transport)args[0]; + transport.on(Transport.EVENT_RESPONSE_HEADERS, new Emitter.Listener() { + @Override + public void call(Object... args) { + @SuppressWarnings("unchecked") + Map> headers = (Map>)args[0]; + List values = headers.get("X-EngineIO"); + messages.offer(values.get(0)); + messages.offer(values.get(1)); + } + }); + } + }); + socket.open(); + + assertThat(messages.take(), is("hi")); + assertThat(messages.take(), is("bar")); + socket.close(); + } + @Test(timeout = TIMEOUT) public void rememberWebsocket() throws InterruptedException { final BlockingQueue values = new LinkedBlockingQueue(); From 2b5dfb99f8f865362ddc0a17f52e8b70269d7572 Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Fri, 11 Dec 2020 15:02:48 +0100 Subject: [PATCH 67/72] fix: check the type of the initial packet Before this fix, the client could mark the polling transport as open even though the handshake packet was not received properly (for example, after a parsing error). See also: https://github.com/socketio/engine.io-client/commit/1c8cba8818e930205918a70f05c1164865842a48 --- src/main/java/io/socket/engineio/client/transports/Polling.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/socket/engineio/client/transports/Polling.java b/src/main/java/io/socket/engineio/client/transports/Polling.java index 9aa73cc3..3ac62f27 100644 --- a/src/main/java/io/socket/engineio/client/transports/Polling.java +++ b/src/main/java/io/socket/engineio/client/transports/Polling.java @@ -114,7 +114,7 @@ private void _onData(Object data) { Parser.DecodePayloadCallback callback = new Parser.DecodePayloadCallback() { @Override public boolean call(Packet packet, int index, int total) { - if (self.readyState == ReadyState.OPENING) { + if (self.readyState == ReadyState.OPENING && Packet.OPEN.equals(packet.type)) { self.onOpen(); } From cbd341c2c9f723007f79b2e53dd29fd306ffe7cc Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Fri, 11 Dec 2020 15:16:25 +0100 Subject: [PATCH 68/72] docs: update website --- Makefile | 7 +++ README.md | 39 +-------------- pom.xml | 17 ++----- src/site/markdown/installation.md | 33 +++++++++++++ src/site/markdown/usage.md | 82 +++++++++++++++++++++++++++++++ src/site/site.xml | 30 +++++++++++ 6 files changed, 156 insertions(+), 52 deletions(-) create mode 100644 Makefile create mode 100644 src/site/markdown/installation.md create mode 100644 src/site/markdown/usage.md create mode 100644 src/site/site.xml diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..cc752f8b --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +help: ## print this message + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' + +build-site: ## build the site + mvn javadoc:javadoc site -DskipTests + +.PHONY: build-site diff --git a/README.md b/README.md index 39dd81e8..27957ed9 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ See also: [Socket.IO-client Java](https://github.com/socketio/socket.io-client-j | -------------- | ---------------- | ---------------- | | 0.9.x | 1.x | 1.x | | 1.x | 3.x | 2.x | -| - | 4.x | 3.x | +| WIP | 4.x | 3.x | ## Installation The latest artifact is available on Maven Central. @@ -132,43 +132,6 @@ socket = new Socket(opts); ## Features This library supports all of the features the JS client does, including events, options and upgrading transport. Android is fully supported. -### Extra features only for Java client - -#### Accessing HTTP Headers -You can access HTTP headers like the following. - -```java -socket.on(Socket.EVENT_TRANSPORT, new Emitter.listener() { - @Override - public void call(Object... args) { - // Called on a new transport created. - Transport transport = (Transport)args[0]; - - transport.on(Transport.EVENT_REQUEST_HEADERS, new Emitter.Listener() { - @Override - public void call(Object... args) { - @SuppressWarnings("unchecked") - Map> headers = (Map>)args[0]; - // send cookie value to server. - headers.put("Cookie", Arrays.asList("foo=1;")); - } - }).on(Transport.EVENT_RESPONSE_HEADERS, new Emitter.Listener() { - @Override - public void call(Object... args) { - @SuppressWarnings("unchecked") - Map> headers = (Map>)args[0]; - // receive cookie value from server. - String cookie = headers.get("Set-Cookie").get(0); - } - }); - } -}); -``` - -See the Javadoc for more details. - -http://socketio.github.io/engine.io-client-java/apidocs/ - ## License MIT diff --git a/pom.xml b/pom.xml index 240af40e..863583b7 100644 --- a/pom.xml +++ b/pom.xml @@ -200,20 +200,9 @@ 2.3 - com.github.github - site-maven-plugin - 0.12 - - Creating site for ${project.version} - - - - - site - - site - - + org.apache.maven.plugins + maven-site-plugin + 3.9.1 diff --git a/src/site/markdown/installation.md b/src/site/markdown/installation.md new file mode 100644 index 00000000..7b3cabb1 --- /dev/null +++ b/src/site/markdown/installation.md @@ -0,0 +1,33 @@ +## Compatibility + +| Client version | Engine.IO server | Socket.IO server | +| -------------- | ---------------- | ---------------- | +| 0.9.x | 1.x | 1.x | +| 1.x | 3.x | 2.x | +| WIP | 4.x | 3.x | + +## Installation +The latest artifact is available on Maven Central. + +### Maven +Add the following dependency to your `pom.xml`. + +```xml + + + io.socket + engine.io-client + 1.0.1 + + +``` + +### Gradle +Add it as a gradle dependency for Android Studio, in `build.gradle`: + +```groovy +compile ('io.socket:engine.io-client:1.0.1') { + // excluding org.json which is provided by Android + exclude group: 'org.json', module: 'json' +} +``` diff --git a/src/site/markdown/usage.md b/src/site/markdown/usage.md new file mode 100644 index 00000000..4299cac2 --- /dev/null +++ b/src/site/markdown/usage.md @@ -0,0 +1,82 @@ +## Usage +Engine.IO-client Java has the similar api with the JS client. You can use `Socket` to connect: + +```java +socket = new Socket("ws://localhost"); +socket.on(Socket.EVENT_OPEN, new Emitter.Listener() { + @Override + public void call(Object... args) { + socket.send("hi"); + socket.close(); + } +}); +socket.open(); +``` + +You can listen events as follows: + +```java +socket.on(Socket.EVENT_MESSAGE, new Emitter.Listener() { + @Override + public void call(Object... args) { + String data = (String)args[0]; + } +}).on(Socket.EVENT_ERROR, new Emitter.Listener() { + @Override + public void call(Object... args) { + Exception err = (Exception)args[0]; + } +}); +``` + +How to set options: + +```java +opts = new Socket.Options(); +opts.transports = new String[] {WebSocket.NAME}; + +socket = new Socket(opts); +``` + +Sending and receiving binary data: + +```java +socket = new Socket(); +socket.on(Socket.EVENT_OPEN, new Emitter.Listener() { + @Override + public void call(Object... args) { + // send binary data + byte[] data = new byte[42]; + socket.send(data); + } +}).on(Socket.EVENT_MESSAGE, new Emitter.Listener() { + @Override + public void call(Object... args) { + // receive binary data + byte[] data = (byte[])args[0]; + } +}); +``` + +Use custom SSL settings: + +```java +OkHttpClient okHttpClient = new OkHttpClient.Builder() + .hostnameVerifier(myHostnameVerifier) + .sslSocketFactory(mySSLContext.getSocketFactory(), myX509TrustManager) + .build(); + +// default SSLContext for all sockets +Socket.setDefaultOkHttpWebSocketFactory(okHttpClient); +Socket.setDefaultOkHttpCallFactory(okHttpClient); + +// set as an option +opts = new Socket.Options(); +opts.callFactory = okHttpClient; +opts.webSocketFactory = okHttpClient; +socket = new Socket(opts); +``` + +## Features + +This library supports all of the features the JS client does, including events, options and upgrading transport. Android is fully supported. diff --git a/src/site/site.xml b/src/site/site.xml new file mode 100644 index 00000000..27b861d4 --- /dev/null +++ b/src/site/site.xml @@ -0,0 +1,30 @@ + + + + + org.apache.maven.skins + maven-fluido-skin + 1.9 + + + + + + socketio/engine.io-client-java + right + gray + + + + + + + + + + + + + + \ No newline at end of file From 62f13846d73a25e39408a6633b4c3451f6f1058c Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Fri, 11 Dec 2020 15:19:59 +0100 Subject: [PATCH 69/72] chore(release): prepare release engine.io-client-2.0.0 --- History.md | 13 +++++++++++++ README.md | 6 +++--- pom.xml | 4 ++-- src/site/markdown/installation.md | 6 +++--- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/History.md b/History.md index f2088196..6adbf3cf 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,17 @@ +2.0.0 / 2020-12-11 +================== + +### Features + +* add an extraHeaders option ([dfe65e3](https://github.com/socketio/engine.io-client-java/commit/dfe65e3b3b5eab4c3fddb9dfbf53d684fe461043)) +* add support for Engine.IO v4 ([41f89a3](https://github.com/socketio/engine.io-client-java/commit/41f89a38b7594f54ee9906bc91051874a60b690d)) + +### Bug Fixes + +* check the type of the initial packet ([2b5dfb9](https://github.com/socketio/engine.io-client-java/commit/2b5dfb99f8f865362ddc0a17f52e8b70269d7572)) + + 1.0.1 / 2020-12-10 ================== diff --git a/README.md b/README.md index 27957ed9..643fbdc4 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ See also: [Socket.IO-client Java](https://github.com/socketio/socket.io-client-j | -------------- | ---------------- | ---------------- | | 0.9.x | 1.x | 1.x | | 1.x | 3.x | 2.x | -| WIP | 4.x | 3.x | +| 2.x | 4.x | 3.x | ## Installation The latest artifact is available on Maven Central. @@ -35,7 +35,7 @@ Add the following dependency to your `pom.xml`. io.socket engine.io-client - 1.0.1 + 2.0.0 ``` @@ -44,7 +44,7 @@ Add the following dependency to your `pom.xml`. Add it as a gradle dependency for Android Studio, in `build.gradle`: ```groovy -compile ('io.socket:engine.io-client:1.0.1') { +compile ('io.socket:engine.io-client:2.0.0') { // excluding org.json which is provided by Android exclude group: 'org.json', module: 'json' } diff --git a/pom.xml b/pom.xml index 863583b7..965b93ee 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 1.0.2-SNAPSHOT + 2.0.0 jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:https://github.com/socketio/engine.io-client-java.git scm:git:https://github.com/socketio/engine.io-client-java.git - HEAD + engine.io-client-2.0.0 diff --git a/src/site/markdown/installation.md b/src/site/markdown/installation.md index 7b3cabb1..8b6f845a 100644 --- a/src/site/markdown/installation.md +++ b/src/site/markdown/installation.md @@ -4,7 +4,7 @@ | -------------- | ---------------- | ---------------- | | 0.9.x | 1.x | 1.x | | 1.x | 3.x | 2.x | -| WIP | 4.x | 3.x | +| 2.x | 4.x | 3.x | ## Installation The latest artifact is available on Maven Central. @@ -17,7 +17,7 @@ Add the following dependency to your `pom.xml`. io.socket engine.io-client - 1.0.1 + 2.0.0 ``` @@ -26,7 +26,7 @@ Add the following dependency to your `pom.xml`. Add it as a gradle dependency for Android Studio, in `build.gradle`: ```groovy -compile ('io.socket:engine.io-client:1.0.1') { +compile ('io.socket:engine.io-client:2.0.0') { // excluding org.json which is provided by Android exclude group: 'org.json', module: 'json' } From 686ac08a6e7e4f2a8e0ff2bc13b3c8f7fb75718a Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Fri, 11 Dec 2020 15:33:10 +0100 Subject: [PATCH 70/72] chore(release): prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 965b93ee..3e9e3c97 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket engine.io-client - 2.0.0 + 2.0.1-SNAPSHOT jar engine.io-client Engine.IO Client Library for Java @@ -30,7 +30,7 @@ https://github.com/socketio/engine.io-client-java scm:git:https://github.com/socketio/engine.io-client-java.git scm:git:https://github.com/socketio/engine.io-client-java.git - engine.io-client-2.0.0 + HEAD From 7c9c382505f7411544add5a68fa326df3b82d2c1 Mon Sep 17 00:00:00 2001 From: valodzka Date: Fri, 22 Jan 2021 12:41:06 +0300 Subject: [PATCH 71/72] feat: create heartbeat scheduler with named threads and as daemon (#106) Co-authored-by: Pavel Valodzka --- .../io/socket/engineio/client/Socket.java | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/main/java/io/socket/engineio/client/Socket.java b/src/main/java/io/socket/engineio/client/Socket.java index 2d86e31a..02de6bd5 100644 --- a/src/main/java/io/socket/engineio/client/Socket.java +++ b/src/main/java/io/socket/engineio/client/Socket.java @@ -4,16 +4,9 @@ import java.net.URI; import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; @@ -37,6 +30,8 @@ public class Socket extends Emitter { private static final Logger logger = Logger.getLogger(Socket.class.getName()); + private static final AtomicInteger HEARTBEAT_THREAD_COUNTER = new AtomicInteger(); + private static final String PROBE_ERROR = "probe error"; @@ -848,11 +843,22 @@ public String id() { private ScheduledExecutorService getHeartbeatScheduler() { if (this.heartbeatScheduler == null || this.heartbeatScheduler.isShutdown()) { - this.heartbeatScheduler = Executors.newSingleThreadScheduledExecutor(); + this.heartbeatScheduler = createHeartbeatScheduler(); } return this.heartbeatScheduler; } + private ScheduledExecutorService createHeartbeatScheduler() { + return Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r, "engine.io-client.heartbeat-" + HEARTBEAT_THREAD_COUNTER.getAndIncrement()); + thread.setDaemon(true); + return thread; + } + }); + } + public static class Options extends Transport.Options { /** From 9be533fdf37a95894166d764de362fb8e5c06851 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 22:31:39 +0100 Subject: [PATCH 72/72] chore: bump engine.io from 4.0.5 to 4.1.2 in /src/test/resources (#110) Bumps [engine.io](https://github.com/socketio/engine.io) from 4.0.5 to 4.1.2. - [Release notes](https://github.com/socketio/engine.io/releases) - [Changelog](https://github.com/socketio/engine.io/blob/4.1.2/CHANGELOG.md) - [Commits](https://github.com/socketio/engine.io/compare/4.0.5...4.1.2) --- updated-dependencies: - dependency-name: engine.io dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/test/resources/package-lock.json | 50 ++++++++++++++-------------- src/test/resources/package.json | 2 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/test/resources/package-lock.json b/src/test/resources/package-lock.json index c37c07d9..407af578 100644 --- a/src/test/resources/package-lock.json +++ b/src/test/resources/package-lock.json @@ -36,52 +36,52 @@ } }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "engine.io": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-4.0.5.tgz", - "integrity": "sha512-Ri+whTNr2PKklxQkfbGjwEo+kCBUM4Qxk4wtLqLrhH+b1up2NFL9g9pjYWiCV/oazwB0rArnvF/ZmZN2ab5Hpg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-4.1.2.tgz", + "integrity": "sha512-t5z6zjXuVLhXDMiFJPYsPOWEER8B0tIsD3ETgw19S1yg9zryvUfY3Vhtk3Gf4sihw/bQGIqQ//gjvVlu+Ca0bQ==", "requires": { "accepts": "~1.3.4", "base64id": "2.0.0", "cookie": "~0.4.1", "cors": "~2.8.5", - "debug": "~4.1.0", + "debug": "~4.3.1", "engine.io-parser": "~4.0.0", - "ws": "^7.1.2" + "ws": "~7.4.2" } }, "engine.io-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.2.tgz", - "integrity": "sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/MqJdZbUjW97JU72iYg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.3.tgz", + "integrity": "sha512-xEAAY0msNnESNPc00e19y5heTPX4y/TJ36gr8t1voOaNmTojP9b3oK3BbJLFufW2XFPQaaijpFewm2g2Um3uqA==", "requires": { "base64-arraybuffer": "0.1.4" } }, "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" }, "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", "requires": { - "mime-db": "1.44.0" + "mime-db": "1.51.0" } }, "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "negotiator": { "version": "0.6.2", @@ -99,9 +99,9 @@ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, "ws": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", - "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==" + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" } } } diff --git a/src/test/resources/package.json b/src/test/resources/package.json index 3b4d8a18..12fe5afa 100644 --- a/src/test/resources/package.json +++ b/src/test/resources/package.json @@ -1,6 +1,6 @@ { "private": true, "dependencies": { - "engine.io": "^4.0.5" + "engine.io": "^4.1.2" } }