@@ -2,7 +2,6 @@ package io.micronaut.http.server.netty.websocket
2
2
3
3
import io.micronaut.context.ApplicationContext
4
4
import io.micronaut.context.annotation.Requires
5
- import io.micronaut.core.annotation.NonNull
6
5
import io.micronaut.http.HttpRequest
7
6
import io.micronaut.http.HttpResponse
8
7
import io.micronaut.http.annotation.Filter
@@ -11,26 +10,29 @@ import io.micronaut.http.filter.HttpFilter
11
10
import io.micronaut.http.server.netty.EmbeddedTestUtil
12
11
import io.micronaut.http.server.netty.NettyHttpServer
13
12
import io.micronaut.runtime.server.EmbeddedServer
13
+ import io.micronaut.websocket.WebSocketClient
14
14
import io.micronaut.websocket.WebSocketSession
15
+ import io.micronaut.websocket.annotation.ClientWebSocket
15
16
import io.micronaut.websocket.annotation.OnMessage
16
17
import io.micronaut.websocket.annotation.ServerWebSocket
17
- import io.netty.channel.ChannelHandlerContext
18
- import io.netty.channel.SimpleChannelInboundHandler
19
18
import io.netty.channel.embedded.EmbeddedChannel
20
19
import io.netty.handler.codec.http.DefaultHttpHeaders
21
- import io.netty.handler.codec.http.FullHttpResponse
22
20
import io.netty.handler.codec.http.HttpClientCodec
23
21
import io.netty.handler.codec.http.HttpObjectAggregator
24
22
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame
25
23
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory
24
+ import io.netty.handler.codec.http.websocketx.WebSocketFrame
26
25
import io.netty.handler.codec.http.websocketx.WebSocketVersion
27
26
import jakarta.inject.Singleton
28
27
import org.reactivestreams.Publisher
29
28
import reactor.core.publisher.Flux
29
+ import reactor.core.publisher.Mono
30
30
import reactor.core.publisher.Sinks
31
31
import spock.lang.Issue
32
32
import spock.lang.Specification
33
33
34
+ import java.util.concurrent.CompletableFuture
35
+
34
36
class WebSocketSpec extends Specification {
35
37
@Issue (' https://github.com/micronaut-projects/micronaut-core/issues/7920' )
36
38
def ' race condition with channel close from http filter' () {
@@ -99,4 +101,50 @@ class WebSocketSpec extends Specification {
99
101
return Flux . concat(delay. asMono(), Flux . defer(() -> chain. proceed(request)))
100
102
}
101
103
}
104
+
105
+ @Issue (' https://github.com/micronaut-projects/micronaut-core/issues/11506' )
106
+ def ' netty WebSocketFrame' () {
107
+ given :
108
+ ApplicationContext ctx = ApplicationContext . run([
109
+ ' spec.name' : ' WebSocketSpec2' ,
110
+ ])
111
+ def embeddedServer = ctx. getBean(EmbeddedServer )
112
+ embeddedServer. start()
113
+ def client = ctx. createBean(WebSocketClient , embeddedServer.URI )
114
+
115
+ when :
116
+ def sock = Mono . from(client. connect(ClientSocket , " /ServerSocket" )). block()
117
+ sock. send(" foo" )
118
+ then :
119
+ sock. reply. get() == " reply: foo"
120
+
121
+ cleanup :
122
+ sock. close()
123
+ client. close()
124
+ embeddedServer. close()
125
+ ctx. close()
126
+ }
127
+
128
+ @ServerWebSocket (' /ServerSocket' )
129
+ @Requires (property = ' spec.name' , value = ' WebSocketSpec2' )
130
+ static class ServerSocket {
131
+ @OnMessage
132
+ def onMessage (WebSocketFrame message , WebSocketSession session ) {
133
+ def text = ((TextWebSocketFrame ) message). text()
134
+ message. release()
135
+ return session. send(' reply: ' + text)
136
+ }
137
+ }
138
+
139
+ @ClientWebSocket
140
+ static abstract class ClientSocket implements AutoCloseable {
141
+ def reply = new CompletableFuture<String > ()
142
+
143
+ abstract void send (String message );
144
+
145
+ @OnMessage
146
+ public void onMessage (String message ) {
147
+ reply. complete(message)
148
+ }
149
+ }
102
150
}
0 commit comments