Skip to content

Commit 50d9fa3

Browse files
committed
Merge branch '4.x' of https://github.com/vert-x3/vertx-stomp into text_payload
2 parents 96338cd + d818eed commit 50d9fa3

12 files changed

+157
-23
lines changed

pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
</parent>
1010

1111
<artifactId>vertx-stomp</artifactId>
12-
<version>4.4.3-SNAPSHOT</version>
12+
<version>4.5.2-SNAPSHOT</version>
1313

1414
<name>Vert.x Stomp</name>
1515
<description>Stomp support for Vert.x 3</description>
1616

1717
<properties>
18-
<stack.version>4.4.3-SNAPSHOT</stack.version>
18+
<stack.version>4.5.2-SNAPSHOT</stack.version>
1919
<jar.manifest>${project.basedir}/src/main/resources/META-INF/MANIFEST.MF</jar.manifest>
2020
</properties>
2121

src/main/generated/io/vertx/ext/stomp/FrameConverter.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class FrameConverter {
1717
private static final Base64.Decoder BASE64_DECODER = JsonUtil.BASE64_DECODER;
1818
private static final Base64.Encoder BASE64_ENCODER = JsonUtil.BASE64_ENCODER;
1919

20-
public static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, Frame obj) {
20+
static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, Frame obj) {
2121
for (java.util.Map.Entry<String, Object> member : json) {
2222
switch (member.getKey()) {
2323
case "ack":
@@ -63,11 +63,11 @@ public static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json,
6363
}
6464
}
6565

66-
public static void toJson(Frame obj, JsonObject json) {
66+
static void toJson(Frame obj, JsonObject json) {
6767
toJson(obj, json.getMap());
6868
}
6969

70-
public static void toJson(Frame obj, java.util.Map<String, Object> json) {
70+
static void toJson(Frame obj, java.util.Map<String, Object> json) {
7171
if (obj.getAck() != null) {
7272
json.put("ack", obj.getAck());
7373
}

src/main/generated/io/vertx/ext/stomp/StompClientOptionsConverter.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class StompClientOptionsConverter {
1717
private static final Base64.Decoder BASE64_DECODER = JsonUtil.BASE64_DECODER;
1818
private static final Base64.Encoder BASE64_ENCODER = JsonUtil.BASE64_ENCODER;
1919

20-
public static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, StompClientOptions obj) {
20+
static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, StompClientOptions obj) {
2121
for (java.util.Map.Entry<String, Object> member : json) {
2222
switch (member.getKey()) {
2323
case "acceptedVersions":
@@ -84,11 +84,11 @@ public static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json,
8484
}
8585
}
8686

87-
public static void toJson(StompClientOptions obj, JsonObject json) {
87+
static void toJson(StompClientOptions obj, JsonObject json) {
8888
toJson(obj, json.getMap());
8989
}
9090

91-
public static void toJson(StompClientOptions obj, java.util.Map<String, Object> json) {
91+
static void toJson(StompClientOptions obj, java.util.Map<String, Object> json) {
9292
if (obj.getAcceptedVersions() != null) {
9393
JsonArray array = new JsonArray();
9494
obj.getAcceptedVersions().forEach(item -> array.add(item));

src/main/generated/io/vertx/ext/stomp/StompServerOptionsConverter.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class StompServerOptionsConverter {
1717
private static final Base64.Decoder BASE64_DECODER = JsonUtil.BASE64_DECODER;
1818
private static final Base64.Encoder BASE64_ENCODER = JsonUtil.BASE64_ENCODER;
1919

20-
public static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, StompServerOptions obj) {
20+
static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, StompServerOptions obj) {
2121
for (java.util.Map.Entry<String, Object> member : json) {
2222
switch (member.getKey()) {
2323
case "heartbeat":
@@ -104,11 +104,11 @@ public static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json,
104104
}
105105
}
106106

107-
public static void toJson(StompServerOptions obj, JsonObject json) {
107+
static void toJson(StompServerOptions obj, JsonObject json) {
108108
toJson(obj, json.getMap());
109109
}
110110

111-
public static void toJson(StompServerOptions obj, java.util.Map<String, Object> json) {
111+
static void toJson(StompServerOptions obj, java.util.Map<String, Object> json) {
112112
if (obj.getHeartbeat() != null) {
113113
json.put("heartbeat", obj.getHeartbeat());
114114
}

src/main/java/io/vertx/ext/stomp/DefaultConnectHandler.java

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
* @author <a href="http://escoffier.me">Clement Escoffier</a>
4040
*/
4141
public class DefaultConnectHandler implements Handler<ServerFrame> {
42+
4243
@Override
4344
public void handle(ServerFrame sf) {
4445
// Server negotiation

src/main/java/io/vertx/ext/stomp/Frame.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import io.vertx.codegen.annotations.DataObject;
2020
import io.vertx.codegen.annotations.GenIgnore;
21+
import io.vertx.codegen.json.annotations.JsonGen;
2122
import io.vertx.core.buffer.Buffer;
2223
import io.vertx.core.json.JsonObject;
2324
import io.vertx.ext.stomp.impl.FrameException;
@@ -41,7 +42,8 @@
4142
*
4243
* @author <a href="http://escoffier.me">Clement Escoffier</a>
4344
*/
44-
@DataObject(generateConverter = true)
45+
@DataObject
46+
@JsonGen(publicConverter = false)
4547
public class Frame {
4648

4749
// General headers

src/main/java/io/vertx/ext/stomp/StompClientOptions.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package io.vertx.ext.stomp;
1818

1919
import io.vertx.codegen.annotations.DataObject;
20+
import io.vertx.codegen.json.annotations.JsonGen;
2021
import io.vertx.core.json.JsonObject;
2122
import io.vertx.core.net.NetClientOptions;
2223

@@ -30,7 +31,8 @@
3031
*
3132
* @author <a href="http://escoffier.me">Clement Escoffier</a>
3233
*/
33-
@DataObject(generateConverter = true)
34+
@DataObject
35+
@JsonGen(publicConverter = false)
3436
public class StompClientOptions extends NetClientOptions implements StompOptions {
3537

3638
// The default value of reuse address for stomp client

src/main/java/io/vertx/ext/stomp/StompServerConnection.java

+1
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,5 @@ public interface StompServerConnection {
106106
* @param pingHandler the ping handler
107107
*/
108108
void configureHeartbeat(long ping, long pong, Handler<StompServerConnection> pingHandler);
109+
109110
}

src/main/java/io/vertx/ext/stomp/StompServerOptions.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package io.vertx.ext.stomp;
1818

1919
import io.vertx.codegen.annotations.DataObject;
20+
import io.vertx.codegen.json.annotations.JsonGen;
2021
import io.vertx.core.Handler;
2122
import io.vertx.core.json.JsonObject;
2223
import io.vertx.core.net.NetServerOptions;
@@ -29,7 +30,8 @@
2930
*
3031
* @author <a href="http://escoffier.me">Clement Escoffier</a>
3132
*/
32-
@DataObject(generateConverter = true)
33+
@DataObject
34+
@JsonGen(publicConverter = false)
3335
public class StompServerOptions extends NetServerOptions implements StompOptions {
3436

3537
public static final int DEFAULT_MAX_HEADER_LENGTH = 1024 * 10;

src/main/java/io/vertx/ext/stomp/impl/DefaultStompHandler.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public class DefaultStompHandler implements StompServerHandler {
7070
private final Vertx vertx;
7171
private final Context context;
7272

73-
private Handler<ServerFrame> connectHandler = new DefaultConnectHandler();
73+
private Handler<ServerFrame> connectHandler;
7474

7575
private Handler<ServerFrame> stompHandler;
7676

@@ -125,6 +125,7 @@ public DefaultStompHandler(Vertx vertx) {
125125
this.context = Vertx.currentContext();
126126
this.destinations = vertx.sharedData().getLocalMap("stomp.destinations");
127127
this.users = new ConcurrentHashMap<>();
128+
this.connectHandler = new DefaultConnectHandler();
128129
}
129130

130131
@Override

src/main/java/io/vertx/ext/stomp/impl/StompServerImpl.java

+54-4
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
import io.vertx.core.net.NetServer;
2828
import io.vertx.ext.stomp.*;
2929

30+
import java.util.Collections;
3031
import java.util.Objects;
32+
import java.util.concurrent.atomic.AtomicBoolean;
3133

3234
/**
3335
* Default implementation of the {@link StompServer}.
@@ -116,7 +118,17 @@ public StompServer listen(int port, String host, Handler<AsyncResult<StompServer
116118
"server.");
117119
server
118120
.connectHandler(socket -> {
119-
StompServerConnection connection = new StompServerTCPConnectionImpl(socket, this, writingFrameHandler);
121+
AtomicBoolean connected = new AtomicBoolean();
122+
AtomicBoolean firstFrame = new AtomicBoolean();
123+
StompServerConnection connection = new StompServerTCPConnectionImpl(socket, this, frame -> {
124+
if (frame.frame().getCommand() == Command.CONNECTED) {
125+
connected.set(true);
126+
}
127+
Handler<ServerFrame> h = writingFrameHandler;
128+
if (h != null) {
129+
h.handle(frame);
130+
}
131+
});
120132
FrameParser parser = new FrameParser(options);
121133
socket.exceptionHandler((exception) -> {
122134
LOGGER.error("The STOMP server caught a TCP socket error - closing connection", exception);
@@ -130,7 +142,21 @@ public StompServer listen(int port, String host, Handler<AsyncResult<StompServer
130142
connection.close();
131143
}
132144
)
133-
.handler(frame -> stomp.handle(new ServerFrameImpl(frame, connection)));
145+
.handler(frame -> {
146+
if (frame.getCommand() == Command.CONNECT || frame.getCommand() == Command.STOMP) {
147+
if (firstFrame.compareAndSet(false, true)) {
148+
stomp.handle(new ServerFrameImpl(frame, connection));
149+
} else {
150+
connection.write(Frames.createErrorFrame("Already connected", Collections.emptyMap(), ""));
151+
connection.close();
152+
}
153+
} else if (connected.get()) {
154+
stomp.handle(new ServerFrameImpl(frame, connection));
155+
} else {
156+
connection.write(Frames.createErrorFrame("Not connected", Collections.emptyMap(), ""));
157+
connection.close();
158+
}
159+
});
134160
socket.handler(parser);
135161
})
136162
.listen(port, host, ar -> {
@@ -227,7 +253,17 @@ public Handler<ServerWebSocket> webSocketHandler() {
227253
socket.reject();
228254
return;
229255
}
230-
StompServerConnection connection = new StompServerWebSocketConnectionImpl(socket, this, writingFrameHandler);
256+
AtomicBoolean connected = new AtomicBoolean();
257+
AtomicBoolean firstFrame = new AtomicBoolean();
258+
StompServerConnection connection = new StompServerWebSocketConnectionImpl(socket, this, frame -> {
259+
if (frame.frame().getCommand() == Command.CONNECTED || frame.frame().getCommand() == Command.STOMP) {
260+
connected.set(true);
261+
}
262+
Handler<ServerFrame> h = writingFrameHandler;
263+
if (h != null) {
264+
h.handle(frame);
265+
}
266+
});
231267
FrameParser parser = new FrameParser(options);
232268
socket.exceptionHandler((exception) -> {
233269
LOGGER.error("The STOMP server caught a WebSocket error - closing connection", exception);
@@ -241,7 +277,21 @@ public Handler<ServerWebSocket> webSocketHandler() {
241277
connection.close();
242278
}
243279
)
244-
.handler(frame -> stomp.handle(new ServerFrameImpl(frame, connection)));
280+
.handler(frame -> {
281+
if (frame.getCommand() == Command.CONNECT) {
282+
if (firstFrame.compareAndSet(false, true)) {
283+
stomp.handle(new ServerFrameImpl(frame, connection));
284+
} else {
285+
connection.write(Frames.createErrorFrame("Already connected", Collections.emptyMap(), ""));
286+
connection.close();
287+
}
288+
} else if (connected.get()) {
289+
stomp.handle(new ServerFrameImpl(frame, connection));
290+
} else {
291+
connection.write(Frames.createErrorFrame("Not connected", Collections.emptyMap(), ""));
292+
connection.close();
293+
}
294+
});
245295
socket.handler(parser);
246296
};
247297
}

src/test/java/io/vertx/ext/stomp/impl/SecuredServerConnectionTest.java

+79-4
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,14 @@
1616

1717
package io.vertx.ext.stomp.impl;
1818

19+
import io.vertx.core.Future;
20+
import io.vertx.core.Handler;
1921
import io.vertx.core.Vertx;
2022
import io.vertx.core.buffer.Buffer;
23+
import io.vertx.core.http.HttpClient;
24+
import io.vertx.core.http.HttpServer;
25+
import io.vertx.core.http.HttpServerOptions;
26+
import io.vertx.core.net.NetClient;
2127
import io.vertx.core.net.NetSocket;
2228
import io.vertx.ext.auth.User;
2329
import io.vertx.ext.auth.authentication.AuthenticationProvider;
@@ -38,15 +44,21 @@
3844
import org.junit.Test;
3945
import org.junit.runner.RunWith;
4046

47+
import java.util.Arrays;
48+
4149
/**
4250
* Tests STOMP server with security.
4351
*
4452
* @author <a href="http://escoffier.me">Clement Escoffier</a>
4553
*/
4654
@RunWith(VertxUnitRunner.class)
4755
public class SecuredServerConnectionTest {
56+
4857
private Vertx vertx;
4958
private StompServer server;
59+
private HttpServer wsServer;
60+
private HttpClient wsClient;
61+
private StompClient client;
5062

5163
@Rule
5264
public RunTestOnContext rule = new RunTestOnContext();
@@ -55,9 +67,17 @@ public class SecuredServerConnectionTest {
5567
public void setUp(TestContext context) {
5668
vertx = rule.vertx();
5769
AuthenticationProvider provider = PropertyFileAuthentication.create(vertx, "test-auth.properties");
58-
server = StompServer.create(vertx, new StompServerOptions().setSecured(true))
59-
.handler(StompServerHandler.create(vertx).authProvider(provider))
60-
.listen(context.asyncAssertSuccess());
70+
server = StompServer.create(vertx, new StompServerOptions()
71+
.setSecured(true)
72+
.setWebsocketBridge(true)
73+
.setWebsocketPath("/stomp"))
74+
.handler(StompServerHandler.create(vertx).authProvider(provider));
75+
server.listen(StompServerOptions.DEFAULT_STOMP_PORT).onComplete(context.asyncAssertSuccess());
76+
wsServer = vertx.createHttpServer(new HttpServerOptions().setWebSocketSubProtocols(Arrays.asList("v10.stomp", "v11.stomp")))
77+
.webSocketHandler(server.webSocketHandler());
78+
wsServer.listen(8080).onComplete(context.asyncAssertSuccess());
79+
wsClient = vertx.createHttpClient();
80+
client = StompClient.create(vertx, new StompClientOptions().setLogin("admin").setPasscode("admin"));
6181
}
6282

6383
@After
@@ -158,11 +178,66 @@ public void testFailedAuthenticationWithClient(TestContext context) {
158178
}
159179

160180
void validate(TestContext context, Buffer buffer) {
161-
context.assertTrue(buffer.toString().contains("CONNECTED"));
181+
context.assertTrue(buffer.toString().contains("CONNECTED"), "Was expected <" + buffer.toString() + "> to contain 'CONNECTED'");
162182
context.assertTrue(buffer.toString().contains("version:1.2"));
163183

164184
User user = server.stompHandler().getUserBySession(extractSession(buffer.toString()));
165185
context.assertNotNull(user);
166186
}
167187

188+
@Test
189+
public void testTCPClientMustBeConnected(TestContext context) {
190+
Async async = context.async();
191+
NetClient client = vertx.createNetClient();
192+
testClientMustBeConnected(context, v -> {
193+
client.connect(server.actualPort(), "0.0.0.0").onComplete(context.asyncAssertSuccess(so -> {
194+
Buffer received = Buffer.buffer();
195+
so.handler(received::appendBuffer);
196+
so.write(
197+
"SEND\n" +
198+
"destination:/test\n" +
199+
"\n" +
200+
"hello" +
201+
FrameParser.NULL);
202+
so.endHandler(v2 -> {
203+
context.assertTrue(received.toString().startsWith("ERROR\n"));
204+
async.complete();
205+
});
206+
}));
207+
});
208+
}
209+
210+
@Test
211+
public void testWebSocketClientMustBeConnected(TestContext context) {
212+
Async async = context.async();
213+
testClientMustBeConnected(context, v -> {
214+
wsClient.webSocket(8080, "localhost", "/stomp").onComplete(context.asyncAssertSuccess(ws -> {
215+
Buffer received = Buffer.buffer();
216+
ws.binaryMessageHandler(received::appendBuffer);
217+
ws.writeBinaryMessage(
218+
Buffer.buffer("SEND\n" +
219+
"destination:/test\n" +
220+
"\n" +
221+
"hello" +
222+
FrameParser.NULL));
223+
ws.endHandler(v2 -> {
224+
context.assertTrue(received.toString().startsWith("ERROR\n"));
225+
async.complete();
226+
});
227+
}));
228+
});
229+
}
230+
231+
private void testClientMustBeConnected(TestContext context, Handler<Void> cont) {
232+
client
233+
.connect(server.actualPort(), "localhost")
234+
.onComplete(context.asyncAssertSuccess(conn -> {
235+
Future<String> fut = conn.subscribe("/test", frame -> {
236+
context.fail("Should not receive a messsage");
237+
});
238+
fut.onComplete(context.asyncAssertSuccess(v2 -> {
239+
cont.handle(null);
240+
}));
241+
}));
242+
}
168243
}

0 commit comments

Comments
 (0)