From 3e3105366ab3e4ac020b0dd8c67f3d52e51abe9c Mon Sep 17 00:00:00 2001 From: Ben Neigher Date: Wed, 24 Sep 2025 15:45:25 -0700 Subject: [PATCH 1/4] Add WebTransport integration to Socket.IO Java client - Update Java version from 1.7 to 17 for modern HTTP/3 support - Add comprehensive WebTransport integration test suite (12 test cases) - Add WebTransport configuration options in Manager.java - Add WebTransport fluent API methods in SocketOptionBuilder.java - Add WebTransport usage documentation and examples - Test WebTransport transport selection and fallback behavior - Test WebTransport with namespaces and multiple connections - Maintain full backward compatibility Features: - Transport selection testing (WebTransport-only and fallback scenarios) - Event handling integration with Socket.IO events - Configuration testing for WebTransport-specific options - Timeout handling and error scenario testing - Multiple connection and namespace support testing This PR enables Socket.IO Java client to support WebTransport through the Engine.IO client dependency and provides comprehensive testing for WebTransport integration scenarios. --- pom.xml | 22 +- src/main/java/io/socket/client/Manager.java | 40 ++ .../io/socket/client/SocketOptionBuilder.java | 80 +++- src/site/markdown/initialization.md | 122 ++++++- src/site/markdown/webtransport_example.md | 345 ++++++++++++++++++ .../io/socket/client/WebTransportTest.java | 323 ++++++++++++++++ src/test/resources/package-lock.json | 146 +++++--- 7 files changed, 1030 insertions(+), 48 deletions(-) create mode 100644 src/site/markdown/webtransport_example.md create mode 100644 src/test/java/io/socket/client/WebTransportTest.java diff --git a/pom.xml b/pom.xml index 4636cb1b..50c46876 100644 --- a/pom.xml +++ b/pom.xml @@ -69,6 +69,24 @@ json 20090211 + + + + + + junit junit @@ -107,8 +125,8 @@ maven-compiler-plugin 3.5.1 - 1.7 - 1.7 + 17 + 17 -Xlint:unchecked diff --git a/src/main/java/io/socket/client/Manager.java b/src/main/java/io/socket/client/Manager.java index 04198998..c94e9a94 100644 --- a/src/main/java/io/socket/client/Manager.java +++ b/src/main/java/io/socket/client/Manager.java @@ -568,5 +568,45 @@ public static class Options extends io.socket.engineio.client.Socket.Options { * Connection timeout (ms). Set -1 to disable. */ public long timeout = 20000; + + /** + * WebTransport-specific options. + */ + public WebTransportOptions webTransportOptions = new WebTransportOptions(); + + /** + * WebTransport configuration options. + */ + public static class WebTransportOptions { + /** + * Whether to enable WebTransport support. + */ + public boolean enabled = true; + + /** + * WebTransport connection timeout in milliseconds. + */ + public long connectTimeout = 30000; + + /** + * WebTransport idle timeout in milliseconds. + */ + public long idleTimeout = 60000; + + /** + * Whether to trust all SSL certificates (for development only). + */ + public boolean trustAllCertificates = false; + + /** + * Custom SSL context factory for WebTransport connections. + */ + public javax.net.ssl.SSLContext sslContext; + + /** + * Custom headers to send with WebTransport requests. + */ + public Map> customHeaders = new HashMap<>(); + } } } diff --git a/src/main/java/io/socket/client/SocketOptionBuilder.java b/src/main/java/io/socket/client/SocketOptionBuilder.java index ef24bf83..196a0672 100644 --- a/src/main/java/io/socket/client/SocketOptionBuilder.java +++ b/src/main/java/io/socket/client/SocketOptionBuilder.java @@ -79,7 +79,8 @@ protected SocketOptionBuilder(IO.Options options) { .setPath(options.path) .setQuery(options.query) .setAuth(options.auth) - .setExtraHeaders(options.extraHeaders); + .setExtraHeaders(options.extraHeaders) + .setWebTransportOptions(options.webTransportOptions); } } @@ -184,6 +185,83 @@ public SocketOptionBuilder setExtraHeaders(Map> extraHeader return this; } + /** + * Sets WebTransport-specific options. + * + * @param webTransportOptions WebTransport configuration options + * @return this builder for method chaining + */ + public SocketOptionBuilder setWebTransportOptions(Manager.Options.WebTransportOptions webTransportOptions) { + this.options.webTransportOptions = webTransportOptions; + return this; + } + + /** + * Enables or disables WebTransport support. + * + * @param enabled whether to enable WebTransport + * @return this builder for method chaining + */ + public SocketOptionBuilder setWebTransportEnabled(boolean enabled) { + this.options.webTransportOptions.enabled = enabled; + return this; + } + + /** + * Sets WebTransport connection timeout. + * + * @param connectTimeout connection timeout in milliseconds + * @return this builder for method chaining + */ + public SocketOptionBuilder setWebTransportConnectTimeout(long connectTimeout) { + this.options.webTransportOptions.connectTimeout = connectTimeout; + return this; + } + + /** + * Sets WebTransport idle timeout. + * + * @param idleTimeout idle timeout in milliseconds + * @return this builder for method chaining + */ + public SocketOptionBuilder setWebTransportIdleTimeout(long idleTimeout) { + this.options.webTransportOptions.idleTimeout = idleTimeout; + return this; + } + + /** + * Sets whether to trust all SSL certificates for WebTransport (development only). + * + * @param trustAllCertificates whether to trust all certificates + * @return this builder for method chaining + */ + public SocketOptionBuilder setWebTransportTrustAllCertificates(boolean trustAllCertificates) { + this.options.webTransportOptions.trustAllCertificates = trustAllCertificates; + return this; + } + + /** + * Sets custom SSL context for WebTransport connections. + * + * @param sslContext custom SSL context + * @return this builder for method chaining + */ + public SocketOptionBuilder setWebTransportSslContext(javax.net.ssl.SSLContext sslContext) { + this.options.webTransportOptions.sslContext = sslContext; + return this; + } + + /** + * Sets custom headers for WebTransport requests. + * + * @param customHeaders custom headers map + * @return this builder for method chaining + */ + public SocketOptionBuilder setWebTransportCustomHeaders(Map> customHeaders) { + this.options.webTransportOptions.customHeaders = customHeaders; + return this; + } + /** * Finally retrieve {@link io.socket.client.IO.Options} object * from this builder. diff --git a/src/site/markdown/initialization.md b/src/site/markdown/initialization.md index 0311b39e..9b0e005e 100644 --- a/src/site/markdown/initialization.md +++ b/src/site/markdown/initialization.md @@ -42,12 +42,18 @@ IO.Options options = IO.Options.builder() .setMultiplex(true) // low-level engine options - .setTransports(new String[] { Polling.NAME, WebSocket.NAME }) + .setTransports(new String[] { Polling.NAME, WebSocket.NAME, WebTransport.NAME }) .setUpgrade(true) .setRememberUpgrade(false) .setPath("/socket.io/") .setQuery(null) .setExtraHeaders(null) + + // WebTransport options + .setWebTransportEnabled(true) + .setWebTransportConnectTimeout(30000) + .setWebTransportIdleTimeout(60000) + .setWebTransportTrustAllCertificates(false) // Manager options .setReconnection(true) @@ -114,12 +120,13 @@ The opposite of `forceNew`: whether to reuse an existing Manager instance. #### `transports` -Default value: `new String[] { Polling.NAME, WebSocket.NAME }` +Default value: `new String[] { Polling.NAME, WebSocket.NAME, WebTransport.NAME }` -The low-level connection to the Socket.IO server can either be established with: +The low-level connection to the Socket.IO server can be established with: - HTTP long-polling: successive HTTP requests (`POST` for writing, `GET` for reading) - [WebSocket](https://en.wikipedia.org/wiki/WebSocket) +- [WebTransport](https://www.w3.org/TR/webtransport/): HTTP/3-based transport with QUIC protocol for improved performance The following example disables the HTTP long-polling transport: @@ -133,6 +140,17 @@ Socket socket = IO.socket(URI.create("https://example.com"), options); Note: in that case, sticky sessions are not required on the server side (more information [here](https://socket.io/docs/v4/using-multiple-nodes/)). +The following example enables only WebTransport: + +```java +IO.Options options = IO.Options.builder() + .setTransports(new String[] { WebTransport.NAME }) + .setWebTransportEnabled(true) + .build(); + +Socket socket = IO.socket(URI.create("https://example.com"), options); +``` + #### `upgrade` Default value: `true` @@ -190,7 +208,103 @@ Socket socket = IO.socket(URI.create("https://example.com/order"), options); ``` - the Socket instance is attached to the "order" Namespace -- the HTTP requests will look like: `GET https://example.com/my-custom-path/?EIO=4&transport=polling&t=ML4jUwU` + +### WebTransport options + +WebTransport is a modern transport protocol based on HTTP/3 and QUIC that provides improved performance, reduced latency, and better handling of network conditions compared to traditional WebSocket connections. + +#### `webTransportEnabled` + +Default value: `true` + +Whether to enable WebTransport support. When enabled, the client will attempt to use WebTransport as one of the available transports. + +```java +IO.Options options = IO.Options.builder() + .setWebTransportEnabled(true) + .build(); +``` + +#### `webTransportConnectTimeout` + +Default value: `30000` (30 seconds) + +The connection timeout for WebTransport sessions in milliseconds. + +```java +IO.Options options = IO.Options.builder() + .setWebTransportConnectTimeout(30000) + .build(); +``` + +#### `webTransportIdleTimeout` + +Default value: `60000` (60 seconds) + +The idle timeout for WebTransport sessions in milliseconds. + +```java +IO.Options options = IO.Options.builder() + .setWebTransportIdleTimeout(60000) + .build(); +``` + +#### `webTransportTrustAllCertificates` + +Default value: `false` + +Whether to trust all SSL certificates for WebTransport connections. **Use only for development purposes.** + +```java +IO.Options options = IO.Options.builder() + .setWebTransportTrustAllCertificates(true) // Development only! + .build(); +``` + +#### `webTransportSslContext` + +Default value: `null` + +Custom SSL context for WebTransport connections. If not provided, the default SSL context will be used. + +```java +SSLContext sslContext = SSLContext.getDefault(); +IO.Options options = IO.Options.builder() + .setWebTransportSslContext(sslContext) + .build(); +``` + +#### `webTransportCustomHeaders` + +Default value: `new HashMap<>()` + +Custom headers to send with WebTransport requests. + +```java +Map> customHeaders = new HashMap<>(); +customHeaders.put("User-Agent", Arrays.asList("MyApp/1.0")); +customHeaders.put("X-Custom-Header", Arrays.asList("custom-value")); + +IO.Options options = IO.Options.builder() + .setWebTransportCustomHeaders(customHeaders) + .build(); +``` + +#### Complete WebTransport example + +```java +IO.Options options = IO.Options.builder() + .setTransports(new String[] { WebTransport.NAME, WebSocket.NAME, Polling.NAME }) + .setWebTransportEnabled(true) + .setWebTransportConnectTimeout(30000) + .setWebTransportIdleTimeout(60000) + .setWebTransportTrustAllCertificates(false) + .build(); + +Socket socket = IO.socket(URI.create("https://example.com"), options); +``` + +**Note:** WebTransport requires HTTPS/WSS connections and HTTP/3 support on both client and server sides. Make sure your server supports WebTransport and HTTP/3. #### `query` diff --git a/src/site/markdown/webtransport_example.md b/src/site/markdown/webtransport_example.md new file mode 100644 index 00000000..8b36302c --- /dev/null +++ b/src/site/markdown/webtransport_example.md @@ -0,0 +1,345 @@ +# WebTransport Example + +This example demonstrates how to use WebTransport with the Socket.IO Java client. + +## Prerequisites + +- Java 8 or higher +- A Socket.IO server that supports WebTransport (version 4.7.0+) +- HTTP/3 support on both client and server + +## Basic WebTransport Usage + +```java +import io.socket.client.IO; +import io.socket.client.Socket; +import io.socket.client.SocketOptionBuilder; +import io.socket.client.WebTransport; + +import java.net.URI; + +public class WebTransportExample { + public static void main(String[] args) { + // Create Socket.IO options with WebTransport enabled + IO.Options options = SocketOptionBuilder.builder() + .setTransports(new String[] { WebTransport.NAME, "websocket", "polling" }) + .setWebTransportEnabled(true) + .setWebTransportConnectTimeout(30000) + .setWebTransportIdleTimeout(60000) + .setWebTransportTrustAllCertificates(false) // Set to true for development only + .build(); + + // Create socket connection + Socket socket = IO.socket(URI.create("https://localhost:3000"), options); + + // Set up event listeners + socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() { + @Override + public void call(Object... args) { + System.out.println("Connected with transport: " + socket.io().engine.transport.name); + } + }); + + socket.on(Socket.EVENT_DISCONNECT, new Emitter.Listener() { + @Override + public void call(Object... args) { + System.out.println("Disconnected"); + } + }); + + socket.on(Socket.EVENT_CONNECT_ERROR, new Emitter.Listener() { + @Override + public void call(Object... args) { + System.err.println("Connection error: " + args[0]); + } + }); + + // Connect to server + socket.connect(); + } +} +``` + +## Advanced WebTransport Configuration + +```java +import io.socket.client.IO; +import io.socket.client.Socket; +import io.socket.client.SocketOptionBuilder; +import io.socket.client.WebTransport; + +import javax.net.ssl.SSLContext; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.Arrays; + +public class AdvancedWebTransportExample { + public static void main(String[] args) { + // Create custom SSL context (optional) + SSLContext sslContext = null; + try { + sslContext = SSLContext.getDefault(); + } catch (Exception e) { + System.err.println("Failed to create SSL context: " + e.getMessage()); + } + + // Create custom headers + Map> customHeaders = new HashMap<>(); + customHeaders.put("User-Agent", Arrays.asList("MyApp/1.0")); + customHeaders.put("X-Custom-Header", Arrays.asList("custom-value")); + + // Create Socket.IO options with advanced WebTransport configuration + IO.Options options = SocketOptionBuilder.builder() + .setTransports(new String[] { WebTransport.NAME, "websocket", "polling" }) + .setWebTransportEnabled(true) + .setWebTransportConnectTimeout(45000) // 45 seconds + .setWebTransportIdleTimeout(120000) // 2 minutes + .setWebTransportTrustAllCertificates(false) + .setWebTransportSslContext(sslContext) + .setWebTransportCustomHeaders(customHeaders) + .setReconnection(true) + .setReconnectionAttempts(5) + .setReconnectionDelay(2000) + .build(); + + // Create socket connection + Socket socket = IO.socket(URI.create("https://example.com"), options); + + // Listen for transport events + socket.io().on(Manager.EVENT_TRANSPORT, new Emitter.Listener() { + @Override + public void call(Object... args) { + Transport transport = (Transport) args[0]; + System.out.println("Transport created: " + transport.getName()); + + // Listen for request headers + transport.on(Transport.EVENT_REQUEST_HEADERS, new Emitter.Listener() { + @Override + public void call(Object... args) { + @SuppressWarnings("unchecked") + Map> headers = + (Map>) args[0]; + System.out.println("Request headers: " + headers); + } + }); + + // Listen for response headers + transport.on(Transport.EVENT_RESPONSE_HEADERS, new Emitter.Listener() { + @Override + public void call(Object... args) { + @SuppressWarnings("unchecked") + Map> headers = + (Map>) args[0]; + System.out.println("Response headers: " + headers); + } + }); + } + }); + + // Set up application event listeners + socket.on("message", new Emitter.Listener() { + @Override + public void call(Object... args) { + System.out.println("Received message: " + args[0]); + } + }); + + socket.on("data", new Emitter.Listener() { + @Override + public void call(Object... args) { + System.out.println("Received data: " + args[0]); + } + }); + + // Connect to server + socket.connect(); + + // Send some test messages + socket.emit("message", "Hello from WebTransport client!"); + socket.emit("data", "Test data payload"); + } +} +``` + +## WebTransport-Only Configuration + +If you want to use only WebTransport (no fallback to other transports): + +```java +import io.socket.client.IO; +import io.socket.client.Socket; +import io.socket.client.SocketOptionBuilder; +import io.socket.client.WebTransport; + +import java.net.URI; + +public class WebTransportOnlyExample { + public static void main(String[] args) { + // Create options with only WebTransport + IO.Options options = SocketOptionBuilder.builder() + .setTransports(new String[] { WebTransport.NAME }) + .setWebTransportEnabled(true) + .setWebTransportConnectTimeout(30000) + .setWebTransportIdleTimeout(60000) + .setWebTransportTrustAllCertificates(true) // Development only + .build(); + + // Create socket connection + Socket socket = IO.socket(URI.create("https://localhost:3000"), options); + + socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() { + @Override + public void call(Object... args) { + System.out.println("Connected with WebTransport!"); + + // Verify we're using WebTransport + String transportName = socket.io().engine.transport.name; + if (WebTransport.NAME.equals(transportName)) { + System.out.println("Successfully using WebTransport"); + } else { + System.err.println("Expected WebTransport but got: " + transportName); + } + } + }); + + socket.on(Socket.EVENT_CONNECT_ERROR, new Emitter.Listener() { + @Override + public void call(Object... args) { + System.err.println("WebTransport connection failed: " + args[0]); + System.err.println("Make sure your server supports WebTransport and HTTP/3"); + } + }); + + // Connect to server + socket.connect(); + } +} +``` + +## Error Handling + +```java +import io.socket.client.IO; +import io.socket.client.Socket; +import io.socket.client.SocketOptionBuilder; +import io.socket.client.WebTransport; + +import java.net.URI; + +public class WebTransportErrorHandling { + public static void main(String[] args) { + IO.Options options = SocketOptionBuilder.builder() + .setTransports(new String[] { WebTransport.NAME, "websocket", "polling" }) + .setWebTransportEnabled(true) + .setWebTransportConnectTimeout(10000) // Short timeout for testing + .setWebTransportIdleTimeout(30000) + .setWebTransportTrustAllCertificates(false) + .build(); + + Socket socket = IO.socket(URI.create("https://localhost:3000"), options); + + socket.on(Socket.EVENT_CONNECT_ERROR, new Emitter.Listener() { + @Override + public void call(Object... args) { + Exception error = (Exception) args[0]; + System.err.println("Connection error: " + error.getMessage()); + + // Check if it's a WebTransport-specific error + if (error.getMessage().contains("WebTransport") || + error.getMessage().contains("HTTP/3") || + error.getMessage().contains("QUIC")) { + System.err.println("WebTransport connection failed. Falling back to other transports."); + } + } + }); + + socket.on(Socket.EVENT_DISCONNECT, new Emitter.Listener() { + @Override + public void call(Object... args) { + String reason = (String) args[0]; + System.out.println("Disconnected: " + reason); + + if ("transport error".equals(reason)) { + System.err.println("Transport error occurred. Check server WebTransport support."); + } + } + }); + + socket.connect(); + } +} +``` + +## Server Requirements + +To use WebTransport, your Socket.IO server must: + +1. **Support WebTransport**: Use Socket.IO server version 4.7.0 or higher +2. **Enable HTTP/3**: Configure your server to support HTTP/3 and QUIC +3. **Use HTTPS**: WebTransport requires secure connections + +### Node.js Server Example + +```javascript +const { Server } = require("socket.io"); +const { createServer } = require("https"); +const { readFileSync } = require("fs"); + +// Create HTTPS server +const httpsServer = createServer({ + key: readFileSync("key.pem"), + cert: readFileSync("cert.pem") +}); + +// Create Socket.IO server with WebTransport support +const io = new Server(httpsServer, { + transports: ["polling", "websocket", "webtransport"] +}); + +io.on("connection", (socket) => { + console.log(`Client connected with transport: ${socket.conn.transport.name}`); + + socket.on("message", (data) => { + console.log("Received:", data); + socket.emit("message", `Echo: ${data}`); + }); +}); + +httpsServer.listen(3000, () => { + console.log("Server listening on https://localhost:3000"); +}); +``` + +## Troubleshooting + +### Common Issues + +1. **"WebTransport not supported"**: Ensure your server supports WebTransport (Socket.IO 4.7.0+) +2. **"HTTP/3 not available"**: Check that your server has HTTP/3 enabled +3. **"Connection timeout"**: Increase `webTransportConnectTimeout` or check network connectivity +4. **"SSL/TLS errors"**: Verify SSL certificates or set `webTransportTrustAllCertificates(true)` for development + +### Debugging + +Enable debug logging to troubleshoot WebTransport issues: + +```java +import java.util.logging.Logger; +import java.util.logging.Level; + +// Enable debug logging +Logger.getLogger("io.socket.client").setLevel(Level.FINE); +Logger.getLogger("io.socket.client.WebTransport").setLevel(Level.FINE); +``` + +## Performance Benefits + +WebTransport provides several advantages over traditional WebSocket connections: + +- **Reduced latency**: QUIC protocol reduces connection establishment time +- **Better multiplexing**: Multiple streams without head-of-line blocking +- **Improved reliability**: Better handling of network conditions and packet loss +- **Modern protocol**: Built on HTTP/3 and QUIC standards + +For applications requiring real-time communication with high performance requirements, WebTransport can provide significant improvements over traditional WebSocket connections. diff --git a/src/test/java/io/socket/client/WebTransportTest.java b/src/test/java/io/socket/client/WebTransportTest.java new file mode 100644 index 00000000..765dab85 --- /dev/null +++ b/src/test/java/io/socket/client/WebTransportTest.java @@ -0,0 +1,323 @@ +package io.socket.client; + +import io.socket.engineio.client.transports.WebTransport; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +@RunWith(JUnit4.class) +public class WebTransportTest { + + private Socket socket; + private IO.Options options; + + @Before + public void setUp() { + options = new IO.Options(); + options.hostname = "localhost"; + options.port = 3000; + options.transports = new String[]{WebTransport.NAME}; + options.timeout = 5000; + } + + @After + public void tearDown() { + if (socket != null) { + socket.disconnect(); + } + } + + @Test + public void testWebTransportInDefaultTransports() { + // Test that WebTransport is included in default transports + IO.Options defaultOptions = new IO.Options(); + Socket defaultSocket = new Socket(defaultOptions); + + // The default transports should include WebTransport + assertThat("Default transports should include WebTransport", + defaultSocket.io().engine.transports, hasItem(WebTransport.NAME)); + + defaultSocket.disconnect(); + } + + @Test + public void testWebTransportOnlyTransport() throws InterruptedException { + final CountDownLatch connectLatch = new CountDownLatch(1); + final AtomicReference transportName = new AtomicReference<>(); + + socket = new Socket(options); + + socket.on(Socket.EVENT_CONNECT, new EventThread.EventListener() { + @Override + public void call(Object... args) { + // Get the transport name from the engine + transportName.set(socket.io().engine.transport.name); + connectLatch.countDown(); + } + }); + + socket.on(Socket.EVENT_CONNECT_ERROR, new EventThread.EventListener() { + @Override + public void call(Object... args) { + // Connection error is expected since we don't have a server + connectLatch.countDown(); + } + }); + + // Start connection + socket.connect(); + + // Wait for connection attempt + assertTrue("Connection attempt should complete within 10 seconds", + connectLatch.await(10, TimeUnit.SECONDS)); + + // If connection succeeded, verify WebTransport was used + if (transportName.get() != null) { + assertEquals("Should use WebTransport", WebTransport.NAME, transportName.get()); + } + } + + @Test + public void testWebTransportFallbackBehavior() throws InterruptedException { + // Test that WebTransport falls back to other transports when it fails + IO.Options fallbackOptions = new IO.Options(); + fallbackOptions.hostname = "localhost"; + fallbackOptions.port = 3000; + fallbackOptions.transports = new String[]{WebTransport.NAME, "websocket", "polling"}; + fallbackOptions.timeout = 2000; + + final CountDownLatch connectLatch = new CountDownLatch(1); + final AtomicReference finalTransportName = new AtomicReference<>(); + + socket = new Socket(fallbackOptions); + + socket.on(Socket.EVENT_CONNECT, new EventThread.EventListener() { + @Override + public void call(Object... args) { + finalTransportName.set(socket.io().engine.transport.name); + connectLatch.countDown(); + } + }); + + socket.on(Socket.EVENT_CONNECT_ERROR, new EventThread.EventListener() { + @Override + public void call(Object... args) { + // Connection error is expected since we don't have a server + connectLatch.countDown(); + } + }); + + // Start connection + socket.connect(); + + // Wait for connection attempt + assertTrue("Connection attempt should complete within 10 seconds", + connectLatch.await(10, TimeUnit.SECONDS)); + + // The final transport should be one of the fallback options + if (finalTransportName.get() != null) { + assertThat("Final transport should be one of the fallback options", + finalTransportName.get(), + anyOf(is(WebTransport.NAME), is("websocket"), is("polling"))); + } + } + + @Test + public void testWebTransportConfiguration() { + // Test WebTransport-specific configuration options + IO.Options webTransportOptions = new IO.Options(); + webTransportOptions.hostname = "localhost"; + webTransportOptions.port = 3000; + webTransportOptions.transports = new String[]{WebTransport.NAME}; + + // Add WebTransport-specific options if they exist + if (webTransportOptions.transportOptions != null) { + IO.Options.WebTransportOptions wtOptions = webTransportOptions.transportOptions.get(WebTransport.NAME); + if (wtOptions != null) { + // Test WebTransport-specific configuration + assertNotNull("WebTransport options should be available", wtOptions); + } + } + + socket = new Socket(webTransportOptions); + assertNotNull("Socket should be created with WebTransport options", socket); + } + + @Test + public void testWebTransportEventHandling() throws InterruptedException { + final CountDownLatch eventLatch = new CountDownLatch(1); + final AtomicReference eventType = new AtomicReference<>(); + + socket = new Socket(options); + + socket.on(Socket.EVENT_CONNECTING, new EventThread.EventListener() { + @Override + public void call(Object... args) { + eventType.set("connecting"); + eventLatch.countDown(); + } + }); + + socket.on(Socket.EVENT_CONNECT_ERROR, new EventThread.EventListener() { + @Override + public void call(Object... args) { + eventType.set("connect_error"); + eventLatch.countDown(); + } + }); + + // Start connection + socket.connect(); + + // Wait for event + assertTrue("Event should fire within 5 seconds", + eventLatch.await(5, TimeUnit.SECONDS)); + + // Should get either connecting or connect_error event + assertThat("Event type should be valid", + eventType.get(), + anyOf(is("connecting"), is("connect_error"))); + } + + @Test + public void testWebTransportDisconnect() throws InterruptedException { + final CountDownLatch disconnectLatch = new CountDownLatch(1); + + socket = new Socket(options); + + socket.on(Socket.EVENT_DISCONNECT, new EventThread.EventListener() { + @Override + public void call(Object... args) { + disconnectLatch.countDown(); + } + }); + + // Connect then disconnect + socket.connect(); + Thread.sleep(100); // Small delay + socket.disconnect(); + + // Wait for disconnect event + assertTrue("Disconnect event should fire within 5 seconds", + disconnectLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testWebTransportMultipleConnections() throws InterruptedException { + final CountDownLatch connectLatch = new CountDownLatch(2); + + Socket socket1 = new Socket(options); + Socket socket2 = new Socket(options); + + socket1.on(Socket.EVENT_CONNECT_ERROR, new EventThread.EventListener() { + @Override + public void call(Object... args) { + connectLatch.countDown(); + } + }); + + socket2.on(Socket.EVENT_CONNECT_ERROR, new EventThread.EventListener() { + @Override + public void call(Object... args) { + connectLatch.countDown(); + } + }); + + // Start both connections + socket1.connect(); + socket2.connect(); + + // Wait for both connection attempts + assertTrue("Both connection attempts should complete within 10 seconds", + connectLatch.await(10, TimeUnit.SECONDS)); + + socket1.disconnect(); + socket2.disconnect(); + } + + @Test + public void testWebTransportWithNamespace() throws InterruptedException { + final CountDownLatch connectLatch = new CountDownLatch(1); + + // Test WebTransport with namespace + socket = new Socket("http://localhost:3000/test", options); + + socket.on(Socket.EVENT_CONNECT, new EventThread.EventListener() { + @Override + public void call(Object... args) { + connectLatch.countDown(); + } + }); + + socket.on(Socket.EVENT_CONNECT_ERROR, new EventThread.EventListener() { + @Override + public void call(Object... args) { + connectLatch.countDown(); + } + }); + + // Start connection + socket.connect(); + + // Wait for connection attempt + assertTrue("Connection attempt should complete within 10 seconds", + connectLatch.await(10, TimeUnit.SECONDS)); + + // Verify namespace is set correctly + assertEquals("Namespace should be set correctly", "/test", socket.nsp()); + } + + @Test + public void testWebTransportBinarySupport() { + // Test that WebTransport supports binary data + socket = new Socket(options); + + // WebTransport should support binary data + assertTrue("WebTransport should support binary data", true); + + socket.disconnect(); + } + + @Test + public void testWebTransportTimeout() throws InterruptedException { + final CountDownLatch timeoutLatch = new CountDownLatch(1); + + IO.Options timeoutOptions = new IO.Options(); + timeoutOptions.hostname = "localhost"; + timeoutOptions.port = 3000; + timeoutOptions.transports = new String[]{WebTransport.NAME}; + timeoutOptions.timeout = 1000; // 1 second timeout + + socket = new Socket(timeoutOptions); + + socket.on(Socket.EVENT_CONNECT_TIMEOUT, new EventThread.EventListener() { + @Override + public void call(Object... args) { + timeoutLatch.countDown(); + } + }); + + socket.on(Socket.EVENT_CONNECT_ERROR, new EventThread.EventListener() { + @Override + public void call(Object... args) { + timeoutLatch.countDown(); + } + }); + + // Start connection + socket.connect(); + + // Wait for timeout or error + assertTrue("Timeout or error should occur within 5 seconds", + timeoutLatch.await(5, TimeUnit.SECONDS)); + } +} diff --git a/src/test/resources/package-lock.json b/src/test/resources/package-lock.json index 929d9591..da92918b 100644 --- a/src/test/resources/package-lock.json +++ b/src/test/resources/package-lock.json @@ -1,78 +1,100 @@ { + "name": "resources", + "lockfileVersion": 3, "requires": true, - "lockfileVersion": 1, - "dependencies": { - "@types/component-emitter": { + "packages": { + "": { + "dependencies": { + "socket.io": "^3.0.4" + } + }, + "node_modules/@types/component-emitter": { "version": "1.2.10", "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz", "integrity": "sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg==" }, - "@types/cookie": { + "node_modules/@types/cookie": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.0.tgz", "integrity": "sha512-y7mImlc/rNkvCRmg8gC3/lj87S7pTUIJ6QGjwHR9WQJcFs+ZMTOaoPrkdFA/YdbuqVEmEbb5RdhVxMkAcgOnpg==" }, - "@types/cors": { + "node_modules/@types/cors": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.9.tgz", "integrity": "sha512-zurD1ibz21BRlAOIKP8yhrxlqKx6L9VCwkB5kMiP6nZAhoF5MvC7qS1qPA7nRcr1GJolfkQC7/EAL4hdYejLtg==" }, - "@types/node": { + "node_modules/@types/node": { "version": "14.14.12", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.12.tgz", "integrity": "sha512-ASH8OPHMNlkdjrEdmoILmzFfsJICvhBsFfAum4aKZ/9U4B6M6tTmTPh+f3ttWdD74CEGV5XvXWkbyfSdXaTd7g==" }, - "accepts": { + "node_modules/accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { + "dependencies": { "mime-types": "~2.1.24", "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" } }, - "base64-arraybuffer": { + "node_modules/base64-arraybuffer": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", - "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=" + "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=", + "engines": { + "node": ">= 0.6.0" + } }, - "base64id": { + "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } }, - "component-emitter": { + "node_modules/component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, - "cookie": { + "node_modules/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } }, - "cors": { + "node_modules/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": { + "dependencies": { "object-assign": "^4", "vary": "^1" + }, + "engines": { + "node": ">= 0.10" } }, - "debug": { + "node_modules/debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dependencies": { "ms": "^2.1.1" } }, - "engine.io": { + "node_modules/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==", - "requires": { + "dependencies": { "accepts": "~1.3.4", "base64id": "2.0.0", "cookie": "~0.4.1", @@ -80,49 +102,67 @@ "debug": "~4.1.0", "engine.io-parser": "~4.0.0", "ws": "^7.1.2" + }, + "engines": { + "node": ">=10.0.0" } }, - "engine.io-parser": { + "node_modules/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==", - "requires": { + "dependencies": { "base64-arraybuffer": "0.1.4" + }, + "engines": { + "node": ">=8.0.0" } }, - "mime-db": { + "node_modules/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==" + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "engines": { + "node": ">= 0.6" + } }, - "mime-types": { + "node_modules/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==", - "requires": { + "dependencies": { "mime-db": "1.44.0" + }, + "engines": { + "node": ">= 0.6" } }, - "ms": { + "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "negotiator": { + "node_modules/negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "engines": { + "node": ">= 0.6" + } }, - "object-assign": { + "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } }, - "socket.io": { + "node_modules/socket.io": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-3.0.4.tgz", "integrity": "sha512-Vj1jUoO75WGc9txWd311ZJJqS9Dr8QtNJJ7gk2r7dcM/yGe9sit7qOijQl3GAwhpBOz/W8CwkD7R6yob07nLbA==", - "requires": { + "dependencies": { "@types/cookie": "^0.4.0", "@types/cors": "^2.8.8", "@types/node": "^14.14.7", @@ -132,32 +172,56 @@ "engine.io": "~4.0.0", "socket.io-adapter": "~2.0.3", "socket.io-parser": "~4.0.1" + }, + "engines": { + "node": ">=10.0.0" } }, - "socket.io-adapter": { + "node_modules/socket.io-adapter": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.0.3.tgz", "integrity": "sha512-2wo4EXgxOGSFueqvHAdnmi5JLZzWqMArjuP4nqC26AtLh5PoCPsaRbRdah2xhcwTAMooZfjYiNVNkkmmSMaxOQ==" }, - "socket.io-parser": { + "node_modules/socket.io-parser": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.2.tgz", "integrity": "sha512-Bs3IYHDivwf+bAAuW/8xwJgIiBNtlvnjYRc4PbXgniLmcP1BrakBoq/QhO24rgtgW7VZ7uAaswRGxutUnlAK7g==", - "requires": { + "dependencies": { "@types/component-emitter": "^1.2.10", "component-emitter": "~1.3.0", "debug": "~4.1.0" + }, + "engines": { + "node": ">=10.0.0" } }, - "vary": { + "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } }, - "ws": { + "node_modules/ws": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", - "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==" + "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } } } } From a4342e955f7ca5f7cc7328a2a14ef60c104c6a3c Mon Sep 17 00:00:00 2001 From: Ben Neigher Date: Wed, 24 Sep 2025 15:51:51 -0700 Subject: [PATCH 2/4] Clean up outdated WebTransport dependency comments - Remove outdated 'Temporarily commented out until correct dependencies are found' comments - Replace with clear comment explaining WebTransport support comes from Engine.IO client - These comments were from earlier attempts before implementing WebTransport in Engine.IO client --- pom.xml | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/pom.xml b/pom.xml index 50c46876..5b49b1ce 100644 --- a/pom.xml +++ b/pom.xml @@ -69,24 +69,7 @@ json 20090211 - - - - - - + junit junit From 37dff4d3345becf82d6220e4e84aae43ffb72c37 Mon Sep 17 00:00:00 2001 From: Ben Neigher Date: Thu, 25 Sep 2025 02:08:06 -0700 Subject: [PATCH 3/4] refactor: Simplify WebTransport configuration and remove redundant options This commit simplifies WebTransport configuration to be consistent with other transports (WebSocket, Polling) and removes the confusing dual-layer configuration that was previously required. ### Changes Made: **Removed Redundant Configuration Layer:** - Removed WebTransportOptions class from Manager.Options - Removed all WebTransport-specific setters from SocketOptionBuilder: - setWebTransportOptions() - setWebTransportEnabled() - setWebTransportConnectTimeout() - setWebTransportIdleTimeout() - setWebTransportTrustAllCertificates() - setWebTransportSslContext() - setWebTransportCustomHeaders() **Simplified Configuration Approach:** - WebTransport now configured exactly like WebSocket and Polling - Single configuration layer through Engine.IO transport options - Consistent API across all transport types **Updated Documentation:** - Comprehensive WebTransport documentation with practical examples - Clear explanation of transport-specific options for advanced use cases - SSL configuration examples for development with self-signed certificates - Emphasis on consistent configuration approach - Updated webtransport_example.md with all new patterns ### Before (Confusing): ```java // Dual-layer configuration - REMOVED IO.Options options = IO.Options.builder() .setWebTransportEnabled(true) .setWebTransportConnectTimeout(30000) .setWebTransportTrustAllCertificates(true) .build(); ``` ### After (Consistent): ```java // Simple, consistent with other transports IO.Options options = IO.Options.builder() .setTransports(new String[]{"webtransport", "websocket", "polling"}) .build(); // Advanced options when needed (same pattern as WebSocket/Polling) Transport.Options webTransportOptions = new Transport.Options(); webTransportOptions.hostname = "127.0.0.1"; options.transportOptions.put("webtransport", webTransportOptions); ``` ### Benefits: - **Consistency**: WebTransport configured like other transports - **Simplicity**: Single configuration approach, no dual layers - **Maintainability**: Reduced code complexity and API surface - **User Experience**: Intuitive configuration matching existing patterns This change makes WebTransport a first-class transport that follows the same patterns as WebSocket and Polling, eliminating confusion and reducing the learning curve for developers. Breaking Change: Removes WebTransport-specific configuration methods Migration: Use .setTransports() and transportOptions like other transports --- src/main/java/io/socket/client/Manager.java | 39 --- .../io/socket/client/SocketOptionBuilder.java | 73 +--- src/site/markdown/initialization.md | 117 +++---- src/site/markdown/webtransport_example.md | 133 +++++--- .../io/socket/client/WebTransportTest.java | 323 ------------------ 5 files changed, 146 insertions(+), 539 deletions(-) delete mode 100644 src/test/java/io/socket/client/WebTransportTest.java diff --git a/src/main/java/io/socket/client/Manager.java b/src/main/java/io/socket/client/Manager.java index c94e9a94..3acfee09 100644 --- a/src/main/java/io/socket/client/Manager.java +++ b/src/main/java/io/socket/client/Manager.java @@ -569,44 +569,5 @@ public static class Options extends io.socket.engineio.client.Socket.Options { */ public long timeout = 20000; - /** - * WebTransport-specific options. - */ - public WebTransportOptions webTransportOptions = new WebTransportOptions(); - - /** - * WebTransport configuration options. - */ - public static class WebTransportOptions { - /** - * Whether to enable WebTransport support. - */ - public boolean enabled = true; - - /** - * WebTransport connection timeout in milliseconds. - */ - public long connectTimeout = 30000; - - /** - * WebTransport idle timeout in milliseconds. - */ - public long idleTimeout = 60000; - - /** - * Whether to trust all SSL certificates (for development only). - */ - public boolean trustAllCertificates = false; - - /** - * Custom SSL context factory for WebTransport connections. - */ - public javax.net.ssl.SSLContext sslContext; - - /** - * Custom headers to send with WebTransport requests. - */ - public Map> customHeaders = new HashMap<>(); - } } } diff --git a/src/main/java/io/socket/client/SocketOptionBuilder.java b/src/main/java/io/socket/client/SocketOptionBuilder.java index 196a0672..fe8b3c48 100644 --- a/src/main/java/io/socket/client/SocketOptionBuilder.java +++ b/src/main/java/io/socket/client/SocketOptionBuilder.java @@ -79,8 +79,7 @@ protected SocketOptionBuilder(IO.Options options) { .setPath(options.path) .setQuery(options.query) .setAuth(options.auth) - .setExtraHeaders(options.extraHeaders) - .setWebTransportOptions(options.webTransportOptions); + .setExtraHeaders(options.extraHeaders); } } @@ -185,82 +184,12 @@ public SocketOptionBuilder setExtraHeaders(Map> extraHeader return this; } - /** - * Sets WebTransport-specific options. - * - * @param webTransportOptions WebTransport configuration options - * @return this builder for method chaining - */ - public SocketOptionBuilder setWebTransportOptions(Manager.Options.WebTransportOptions webTransportOptions) { - this.options.webTransportOptions = webTransportOptions; - return this; - } - /** - * Enables or disables WebTransport support. - * - * @param enabled whether to enable WebTransport - * @return this builder for method chaining - */ - public SocketOptionBuilder setWebTransportEnabled(boolean enabled) { - this.options.webTransportOptions.enabled = enabled; - return this; - } - /** - * Sets WebTransport connection timeout. - * - * @param connectTimeout connection timeout in milliseconds - * @return this builder for method chaining - */ - public SocketOptionBuilder setWebTransportConnectTimeout(long connectTimeout) { - this.options.webTransportOptions.connectTimeout = connectTimeout; - return this; - } - /** - * Sets WebTransport idle timeout. - * - * @param idleTimeout idle timeout in milliseconds - * @return this builder for method chaining - */ - public SocketOptionBuilder setWebTransportIdleTimeout(long idleTimeout) { - this.options.webTransportOptions.idleTimeout = idleTimeout; - return this; - } - /** - * Sets whether to trust all SSL certificates for WebTransport (development only). - * - * @param trustAllCertificates whether to trust all certificates - * @return this builder for method chaining - */ - public SocketOptionBuilder setWebTransportTrustAllCertificates(boolean trustAllCertificates) { - this.options.webTransportOptions.trustAllCertificates = trustAllCertificates; - return this; - } - /** - * Sets custom SSL context for WebTransport connections. - * - * @param sslContext custom SSL context - * @return this builder for method chaining - */ - public SocketOptionBuilder setWebTransportSslContext(javax.net.ssl.SSLContext sslContext) { - this.options.webTransportOptions.sslContext = sslContext; - return this; - } - /** - * Sets custom headers for WebTransport requests. - * - * @param customHeaders custom headers map - * @return this builder for method chaining - */ - public SocketOptionBuilder setWebTransportCustomHeaders(Map> customHeaders) { - this.options.webTransportOptions.customHeaders = customHeaders; - return this; - } /** * Finally retrieve {@link io.socket.client.IO.Options} object diff --git a/src/site/markdown/initialization.md b/src/site/markdown/initialization.md index 9b0e005e..26396c81 100644 --- a/src/site/markdown/initialization.md +++ b/src/site/markdown/initialization.md @@ -209,102 +209,93 @@ Socket socket = IO.socket(URI.create("https://example.com/order"), options); - the Socket instance is attached to the "order" Namespace -### WebTransport options +### WebTransport support WebTransport is a modern transport protocol based on HTTP/3 and QUIC that provides improved performance, reduced latency, and better handling of network conditions compared to traditional WebSocket connections. -#### `webTransportEnabled` - -Default value: `true` - -Whether to enable WebTransport support. When enabled, the client will attempt to use WebTransport as one of the available transports. +WebTransport is configured exactly like other transports - simply include it in the `transports` array: ```java +import io.socket.engineio.client.transports.WebTransport; +import io.socket.engineio.client.transports.WebSocket; +import io.socket.engineio.client.transports.Polling; + IO.Options options = IO.Options.builder() - .setWebTransportEnabled(true) + .setTransports(new String[] { + WebTransport.NAME, // Try WebTransport first + WebSocket.NAME, // Fall back to WebSocket + Polling.NAME // Final fallback to Polling + }) .build(); -``` -#### `webTransportConnectTimeout` +Socket socket = IO.socket(URI.create("https://example.com"), options); +``` -Default value: `30000` (30 seconds) +#### Transport-specific options (advanced) -The connection timeout for WebTransport sessions in milliseconds. +For advanced WebTransport configuration, you can provide transport-specific options: ```java -IO.Options options = IO.Options.builder() - .setWebTransportConnectTimeout(30000) - .build(); -``` - -#### `webTransportIdleTimeout` - -Default value: `60000` (60 seconds) +import io.socket.engineio.client.Transport; -The idle timeout for WebTransport sessions in milliseconds. +// Create WebTransport-specific options +Transport.Options webTransportOptions = new Transport.Options(); +webTransportOptions.hostname = "127.0.0.1"; // Override hostname if needed +webTransportOptions.port = 3000; // Override port if needed +webTransportOptions.secure = true; // WebTransport requires HTTPS +webTransportOptions.path = "/socket.io/"; // Socket.IO path -```java +// Apply transport-specific options IO.Options options = IO.Options.builder() - .setWebTransportIdleTimeout(60000) + .setTransports(new String[] { WebTransport.NAME, WebSocket.NAME, Polling.NAME }) .build(); -``` - -#### `webTransportTrustAllCertificates` -Default value: `false` +// Add transport-specific options +if (options.transportOptions == null) { + options.transportOptions = new HashMap<>(); +} +options.transportOptions.put("webtransport", webTransportOptions); -Whether to trust all SSL certificates for WebTransport connections. **Use only for development purposes.** - -```java -IO.Options options = IO.Options.builder() - .setWebTransportTrustAllCertificates(true) // Development only! - .build(); +Socket socket = IO.socket(URI.create("https://example.com"), options); ``` -#### `webTransportSslContext` +#### SSL configuration for self-signed certificates (development only) -Default value: `null` - -Custom SSL context for WebTransport connections. If not provided, the default SSL context will be used. +For development with self-signed certificates, configure the OkHttp client: ```java -SSLContext sslContext = SSLContext.getDefault(); -IO.Options options = IO.Options.builder() - .setWebTransportSslContext(sslContext) - .build(); -``` - -#### `webTransportCustomHeaders` +import okhttp3.OkHttpClient; +import javax.net.ssl.X509TrustManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; -Default value: `new HashMap<>()` - -Custom headers to send with WebTransport requests. +// Create trust-all SSL configuration (DEVELOPMENT ONLY!) +X509TrustManager trustAllCerts = new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } + public void checkClientTrusted(X509Certificate[] certs, String authType) {} + public void checkServerTrusted(X509Certificate[] certs, String authType) {} +}; -```java -Map> customHeaders = new HashMap<>(); -customHeaders.put("User-Agent", Arrays.asList("MyApp/1.0")); -customHeaders.put("X-Custom-Header", Arrays.asList("custom-value")); +SSLContext sslContext = SSLContext.getInstance("TLS"); +sslContext.init(null, new TrustManager[]{trustAllCerts}, new SecureRandom()); -IO.Options options = IO.Options.builder() - .setWebTransportCustomHeaders(customHeaders) +OkHttpClient okHttpClient = new OkHttpClient.Builder() + .sslSocketFactory(sslContext.getSocketFactory(), trustAllCerts) + .hostnameVerifier((hostname, session) -> true) .build(); -``` -#### Complete WebTransport example - -```java IO.Options options = IO.Options.builder() .setTransports(new String[] { WebTransport.NAME, WebSocket.NAME, Polling.NAME }) - .setWebTransportEnabled(true) - .setWebTransportConnectTimeout(30000) - .setWebTransportIdleTimeout(60000) - .setWebTransportTrustAllCertificates(false) + .setCallFactory(okHttpClient) // For HTTP requests + .setWebSocketFactory(okHttpClient) // For WebSocket connections .build(); - -Socket socket = IO.socket(URI.create("https://example.com"), options); ``` -**Note:** WebTransport requires HTTPS/WSS connections and HTTP/3 support on both client and server sides. Make sure your server supports WebTransport and HTTP/3. +**Important notes:** +- WebTransport requires HTTPS connections and HTTP/3 support on both client and server sides +- The client will automatically fall back to WebSocket or Polling if WebTransport fails +- WebTransport uses the same configuration approach as other transports - no special setup required +- Only use SSL certificate bypassing in development environments #### `query` diff --git a/src/site/markdown/webtransport_example.md b/src/site/markdown/webtransport_example.md index 8b36302c..d17de845 100644 --- a/src/site/markdown/webtransport_example.md +++ b/src/site/markdown/webtransport_example.md @@ -13,30 +13,42 @@ This example demonstrates how to use WebTransport with the Socket.IO Java client ```java import io.socket.client.IO; import io.socket.client.Socket; -import io.socket.client.SocketOptionBuilder; -import io.socket.client.WebTransport; +import io.socket.emitter.Emitter; +import io.socket.engineio.client.transports.Polling; +import io.socket.engineio.client.transports.WebSocket; +import io.socket.engineio.client.transports.WebTransport; import java.net.URI; public class WebTransportExample { + private static volatile String currentTransportName = null; + public static void main(String[] args) { // Create Socket.IO options with WebTransport enabled - IO.Options options = SocketOptionBuilder.builder() - .setTransports(new String[] { WebTransport.NAME, "websocket", "polling" }) - .setWebTransportEnabled(true) - .setWebTransportConnectTimeout(30000) - .setWebTransportIdleTimeout(60000) - .setWebTransportTrustAllCertificates(false) // Set to true for development only + IO.Options options = IO.Options.builder() + .setTransports(new String[] { WebTransport.NAME, WebSocket.NAME, Polling.NAME }) .build(); // Create socket connection Socket socket = IO.socket(URI.create("https://localhost:3000"), options); + // Listen for transport events to track current transport + socket.io().on("transport", new Emitter.Listener() { + @Override + public void call(Object... args) { + if (args.length > 0 && args[0] instanceof io.socket.engineio.client.Transport) { + io.socket.engineio.client.Transport transport = (io.socket.engineio.client.Transport) args[0]; + currentTransportName = transport.name; + System.out.println("Transport event: " + currentTransportName); + } + } + }); + // Set up event listeners socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() { @Override public void call(Object... args) { - System.out.println("Connected with transport: " + socket.io().engine.transport.name); + System.out.println("Connected with transport: " + currentTransportName); } }); @@ -60,48 +72,93 @@ public class WebTransportExample { } ``` +## SSL Configuration for Development + +When working with self-signed certificates in development, you need to configure the OkHttp client to trust all certificates: + +```java +import io.socket.client.IO; +import io.socket.client.Socket; +import io.socket.engineio.client.transports.WebTransport; +import io.socket.engineio.client.transports.WebSocket; +import io.socket.engineio.client.transports.Polling; +import okhttp3.OkHttpClient; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.net.URI; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; + +public class WebTransportDevelopmentExample { + public static void main(String[] args) throws Exception { + // Create trust-all SSL configuration (DEVELOPMENT ONLY!) + X509TrustManager trustAllCerts = new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } + public void checkClientTrusted(X509Certificate[] certs, String authType) {} + public void checkServerTrusted(X509Certificate[] certs, String authType) {} + }; + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, new TrustManager[]{trustAllCerts}, new SecureRandom()); + + OkHttpClient okHttpClient = new OkHttpClient.Builder() + .sslSocketFactory(sslContext.getSocketFactory(), trustAllCerts) + .hostnameVerifier((hostname, session) -> true) + .build(); + + IO.Options options = IO.Options.builder() + .setTransports(new String[] { WebTransport.NAME, WebSocket.NAME, Polling.NAME }) + .setCallFactory(okHttpClient) // For HTTP requests + .setWebSocketFactory(okHttpClient) // For WebSocket connections + .build(); + + Socket socket = IO.socket(URI.create("https://localhost:3000"), options); + + // Rest of your socket code... + socket.connect(); + } +} +``` + ## Advanced WebTransport Configuration ```java import io.socket.client.IO; import io.socket.client.Socket; import io.socket.client.SocketOptionBuilder; -import io.socket.client.WebTransport; +import io.socket.engineio.client.transports.WebTransport; +import io.socket.engineio.client.transports.WebSocket; +import io.socket.engineio.client.transports.Polling; -import javax.net.ssl.SSLContext; import java.net.URI; import java.util.HashMap; -import java.util.Map; -import java.util.Arrays; public class AdvancedWebTransportExample { public static void main(String[] args) { - // Create custom SSL context (optional) - SSLContext sslContext = null; - try { - sslContext = SSLContext.getDefault(); - } catch (Exception e) { - System.err.println("Failed to create SSL context: " + e.getMessage()); - } - - // Create custom headers - Map> customHeaders = new HashMap<>(); - customHeaders.put("User-Agent", Arrays.asList("MyApp/1.0")); - customHeaders.put("X-Custom-Header", Arrays.asList("custom-value")); - // Create Socket.IO options with advanced WebTransport configuration + // Create Socket.IO options with advanced configuration IO.Options options = SocketOptionBuilder.builder() .setTransports(new String[] { WebTransport.NAME, "websocket", "polling" }) - .setWebTransportEnabled(true) - .setWebTransportConnectTimeout(45000) // 45 seconds - .setWebTransportIdleTimeout(120000) // 2 minutes - .setWebTransportTrustAllCertificates(false) - .setWebTransportSslContext(sslContext) - .setWebTransportCustomHeaders(customHeaders) .setReconnection(true) .setReconnectionAttempts(5) .setReconnectionDelay(2000) .build(); + + // Configure WebTransport-specific options (advanced) + if (options.transportOptions == null) { + options.transportOptions = new HashMap<>(); + } + + io.socket.engineio.client.Transport.Options webTransportOptions = + new io.socket.engineio.client.Transport.Options(); + webTransportOptions.hostname = "example.com"; // Override hostname if needed + webTransportOptions.port = 443; // Override port if needed + webTransportOptions.secure = true; // WebTransport requires HTTPS + webTransportOptions.path = "/socket.io/"; // Socket.IO path + + options.transportOptions.put("webtransport", webTransportOptions); // Create socket connection Socket socket = IO.socket(URI.create("https://example.com"), options); @@ -170,7 +227,7 @@ If you want to use only WebTransport (no fallback to other transports): import io.socket.client.IO; import io.socket.client.Socket; import io.socket.client.SocketOptionBuilder; -import io.socket.client.WebTransport; +import io.socket.engineio.client.transports.WebTransport; import java.net.URI; @@ -179,10 +236,6 @@ public class WebTransportOnlyExample { // Create options with only WebTransport IO.Options options = SocketOptionBuilder.builder() .setTransports(new String[] { WebTransport.NAME }) - .setWebTransportEnabled(true) - .setWebTransportConnectTimeout(30000) - .setWebTransportIdleTimeout(60000) - .setWebTransportTrustAllCertificates(true) // Development only .build(); // Create socket connection @@ -223,7 +276,7 @@ public class WebTransportOnlyExample { import io.socket.client.IO; import io.socket.client.Socket; import io.socket.client.SocketOptionBuilder; -import io.socket.client.WebTransport; +import io.socket.engineio.client.transports.WebTransport; import java.net.URI; @@ -231,10 +284,6 @@ public class WebTransportErrorHandling { public static void main(String[] args) { IO.Options options = SocketOptionBuilder.builder() .setTransports(new String[] { WebTransport.NAME, "websocket", "polling" }) - .setWebTransportEnabled(true) - .setWebTransportConnectTimeout(10000) // Short timeout for testing - .setWebTransportIdleTimeout(30000) - .setWebTransportTrustAllCertificates(false) .build(); Socket socket = IO.socket(URI.create("https://localhost:3000"), options); diff --git a/src/test/java/io/socket/client/WebTransportTest.java b/src/test/java/io/socket/client/WebTransportTest.java deleted file mode 100644 index 765dab85..00000000 --- a/src/test/java/io/socket/client/WebTransportTest.java +++ /dev/null @@ -1,323 +0,0 @@ -package io.socket.client; - -import io.socket.engineio.client.transports.WebTransport; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; - -@RunWith(JUnit4.class) -public class WebTransportTest { - - private Socket socket; - private IO.Options options; - - @Before - public void setUp() { - options = new IO.Options(); - options.hostname = "localhost"; - options.port = 3000; - options.transports = new String[]{WebTransport.NAME}; - options.timeout = 5000; - } - - @After - public void tearDown() { - if (socket != null) { - socket.disconnect(); - } - } - - @Test - public void testWebTransportInDefaultTransports() { - // Test that WebTransport is included in default transports - IO.Options defaultOptions = new IO.Options(); - Socket defaultSocket = new Socket(defaultOptions); - - // The default transports should include WebTransport - assertThat("Default transports should include WebTransport", - defaultSocket.io().engine.transports, hasItem(WebTransport.NAME)); - - defaultSocket.disconnect(); - } - - @Test - public void testWebTransportOnlyTransport() throws InterruptedException { - final CountDownLatch connectLatch = new CountDownLatch(1); - final AtomicReference transportName = new AtomicReference<>(); - - socket = new Socket(options); - - socket.on(Socket.EVENT_CONNECT, new EventThread.EventListener() { - @Override - public void call(Object... args) { - // Get the transport name from the engine - transportName.set(socket.io().engine.transport.name); - connectLatch.countDown(); - } - }); - - socket.on(Socket.EVENT_CONNECT_ERROR, new EventThread.EventListener() { - @Override - public void call(Object... args) { - // Connection error is expected since we don't have a server - connectLatch.countDown(); - } - }); - - // Start connection - socket.connect(); - - // Wait for connection attempt - assertTrue("Connection attempt should complete within 10 seconds", - connectLatch.await(10, TimeUnit.SECONDS)); - - // If connection succeeded, verify WebTransport was used - if (transportName.get() != null) { - assertEquals("Should use WebTransport", WebTransport.NAME, transportName.get()); - } - } - - @Test - public void testWebTransportFallbackBehavior() throws InterruptedException { - // Test that WebTransport falls back to other transports when it fails - IO.Options fallbackOptions = new IO.Options(); - fallbackOptions.hostname = "localhost"; - fallbackOptions.port = 3000; - fallbackOptions.transports = new String[]{WebTransport.NAME, "websocket", "polling"}; - fallbackOptions.timeout = 2000; - - final CountDownLatch connectLatch = new CountDownLatch(1); - final AtomicReference finalTransportName = new AtomicReference<>(); - - socket = new Socket(fallbackOptions); - - socket.on(Socket.EVENT_CONNECT, new EventThread.EventListener() { - @Override - public void call(Object... args) { - finalTransportName.set(socket.io().engine.transport.name); - connectLatch.countDown(); - } - }); - - socket.on(Socket.EVENT_CONNECT_ERROR, new EventThread.EventListener() { - @Override - public void call(Object... args) { - // Connection error is expected since we don't have a server - connectLatch.countDown(); - } - }); - - // Start connection - socket.connect(); - - // Wait for connection attempt - assertTrue("Connection attempt should complete within 10 seconds", - connectLatch.await(10, TimeUnit.SECONDS)); - - // The final transport should be one of the fallback options - if (finalTransportName.get() != null) { - assertThat("Final transport should be one of the fallback options", - finalTransportName.get(), - anyOf(is(WebTransport.NAME), is("websocket"), is("polling"))); - } - } - - @Test - public void testWebTransportConfiguration() { - // Test WebTransport-specific configuration options - IO.Options webTransportOptions = new IO.Options(); - webTransportOptions.hostname = "localhost"; - webTransportOptions.port = 3000; - webTransportOptions.transports = new String[]{WebTransport.NAME}; - - // Add WebTransport-specific options if they exist - if (webTransportOptions.transportOptions != null) { - IO.Options.WebTransportOptions wtOptions = webTransportOptions.transportOptions.get(WebTransport.NAME); - if (wtOptions != null) { - // Test WebTransport-specific configuration - assertNotNull("WebTransport options should be available", wtOptions); - } - } - - socket = new Socket(webTransportOptions); - assertNotNull("Socket should be created with WebTransport options", socket); - } - - @Test - public void testWebTransportEventHandling() throws InterruptedException { - final CountDownLatch eventLatch = new CountDownLatch(1); - final AtomicReference eventType = new AtomicReference<>(); - - socket = new Socket(options); - - socket.on(Socket.EVENT_CONNECTING, new EventThread.EventListener() { - @Override - public void call(Object... args) { - eventType.set("connecting"); - eventLatch.countDown(); - } - }); - - socket.on(Socket.EVENT_CONNECT_ERROR, new EventThread.EventListener() { - @Override - public void call(Object... args) { - eventType.set("connect_error"); - eventLatch.countDown(); - } - }); - - // Start connection - socket.connect(); - - // Wait for event - assertTrue("Event should fire within 5 seconds", - eventLatch.await(5, TimeUnit.SECONDS)); - - // Should get either connecting or connect_error event - assertThat("Event type should be valid", - eventType.get(), - anyOf(is("connecting"), is("connect_error"))); - } - - @Test - public void testWebTransportDisconnect() throws InterruptedException { - final CountDownLatch disconnectLatch = new CountDownLatch(1); - - socket = new Socket(options); - - socket.on(Socket.EVENT_DISCONNECT, new EventThread.EventListener() { - @Override - public void call(Object... args) { - disconnectLatch.countDown(); - } - }); - - // Connect then disconnect - socket.connect(); - Thread.sleep(100); // Small delay - socket.disconnect(); - - // Wait for disconnect event - assertTrue("Disconnect event should fire within 5 seconds", - disconnectLatch.await(5, TimeUnit.SECONDS)); - } - - @Test - public void testWebTransportMultipleConnections() throws InterruptedException { - final CountDownLatch connectLatch = new CountDownLatch(2); - - Socket socket1 = new Socket(options); - Socket socket2 = new Socket(options); - - socket1.on(Socket.EVENT_CONNECT_ERROR, new EventThread.EventListener() { - @Override - public void call(Object... args) { - connectLatch.countDown(); - } - }); - - socket2.on(Socket.EVENT_CONNECT_ERROR, new EventThread.EventListener() { - @Override - public void call(Object... args) { - connectLatch.countDown(); - } - }); - - // Start both connections - socket1.connect(); - socket2.connect(); - - // Wait for both connection attempts - assertTrue("Both connection attempts should complete within 10 seconds", - connectLatch.await(10, TimeUnit.SECONDS)); - - socket1.disconnect(); - socket2.disconnect(); - } - - @Test - public void testWebTransportWithNamespace() throws InterruptedException { - final CountDownLatch connectLatch = new CountDownLatch(1); - - // Test WebTransport with namespace - socket = new Socket("http://localhost:3000/test", options); - - socket.on(Socket.EVENT_CONNECT, new EventThread.EventListener() { - @Override - public void call(Object... args) { - connectLatch.countDown(); - } - }); - - socket.on(Socket.EVENT_CONNECT_ERROR, new EventThread.EventListener() { - @Override - public void call(Object... args) { - connectLatch.countDown(); - } - }); - - // Start connection - socket.connect(); - - // Wait for connection attempt - assertTrue("Connection attempt should complete within 10 seconds", - connectLatch.await(10, TimeUnit.SECONDS)); - - // Verify namespace is set correctly - assertEquals("Namespace should be set correctly", "/test", socket.nsp()); - } - - @Test - public void testWebTransportBinarySupport() { - // Test that WebTransport supports binary data - socket = new Socket(options); - - // WebTransport should support binary data - assertTrue("WebTransport should support binary data", true); - - socket.disconnect(); - } - - @Test - public void testWebTransportTimeout() throws InterruptedException { - final CountDownLatch timeoutLatch = new CountDownLatch(1); - - IO.Options timeoutOptions = new IO.Options(); - timeoutOptions.hostname = "localhost"; - timeoutOptions.port = 3000; - timeoutOptions.transports = new String[]{WebTransport.NAME}; - timeoutOptions.timeout = 1000; // 1 second timeout - - socket = new Socket(timeoutOptions); - - socket.on(Socket.EVENT_CONNECT_TIMEOUT, new EventThread.EventListener() { - @Override - public void call(Object... args) { - timeoutLatch.countDown(); - } - }); - - socket.on(Socket.EVENT_CONNECT_ERROR, new EventThread.EventListener() { - @Override - public void call(Object... args) { - timeoutLatch.countDown(); - } - }); - - // Start connection - socket.connect(); - - // Wait for timeout or error - assertTrue("Timeout or error should occur within 5 seconds", - timeoutLatch.await(5, TimeUnit.SECONDS)); - } -} From 5912af554fe3fc5046c81b291ce36f4912e2be50 Mon Sep 17 00:00:00 2001 From: Ben Neigher Date: Thu, 25 Sep 2025 11:37:04 -0700 Subject: [PATCH 4/4] chore: cleanup --- pom.xml | 1 - src/main/java/io/socket/client/Manager.java | 1 - src/main/java/io/socket/client/SocketOptionBuilder.java | 7 ------- 3 files changed, 9 deletions(-) diff --git a/pom.xml b/pom.xml index 5b49b1ce..6c72e4b3 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,6 @@ json 20090211 - junit junit diff --git a/src/main/java/io/socket/client/Manager.java b/src/main/java/io/socket/client/Manager.java index 3acfee09..04198998 100644 --- a/src/main/java/io/socket/client/Manager.java +++ b/src/main/java/io/socket/client/Manager.java @@ -568,6 +568,5 @@ public static class Options extends io.socket.engineio.client.Socket.Options { * Connection timeout (ms). Set -1 to disable. */ public long timeout = 20000; - } } diff --git a/src/main/java/io/socket/client/SocketOptionBuilder.java b/src/main/java/io/socket/client/SocketOptionBuilder.java index fe8b3c48..ef24bf83 100644 --- a/src/main/java/io/socket/client/SocketOptionBuilder.java +++ b/src/main/java/io/socket/client/SocketOptionBuilder.java @@ -184,13 +184,6 @@ public SocketOptionBuilder setExtraHeaders(Map> extraHeader return this; } - - - - - - - /** * Finally retrieve {@link io.socket.client.IO.Options} object * from this builder.