@@ -54,18 +54,6 @@ public WebSocketHandler(AsyncHttpClientConfig config,//
54
54
super (config , channelManager , requestSender );
55
55
}
56
56
57
- // We don't need to synchronize as replacing the "ws-decoder" will
58
- // process using the same thread.
59
- private void invokeOnSucces (Channel channel , WebSocketUpgradeHandler h ) {
60
- if (!h .touchSuccess ()) {
61
- try {
62
- h .onSuccess (new NettyWebSocket (channel , config ));
63
- } catch (Exception ex ) {
64
- logger .warn ("onSuccess unexpected exception" , ex );
65
- }
66
- }
67
- }
68
-
69
57
private class UpgradeCallback extends Callback {
70
58
71
59
private final Channel channel ;
@@ -84,6 +72,18 @@ public UpgradeCallback(NettyResponseFuture<?> future, Channel channel, HttpRespo
84
72
this .responseHeaders = responseHeaders ;
85
73
}
86
74
75
+ // We don't need to synchronize as replacing the "ws-decoder" will
76
+ // process using the same thread.
77
+ private void invokeOnSucces (Channel channel , WebSocketUpgradeHandler h ) {
78
+ if (!h .touchSuccess ()) {
79
+ try {
80
+ h .onSuccess (new NettyWebSocket (channel , config ));
81
+ } catch (Exception ex ) {
82
+ logger .warn ("onSuccess unexpected exception" , ex );
83
+ }
84
+ }
85
+ }
86
+
87
87
@ Override
88
88
public void call () throws Exception {
89
89
@@ -116,14 +116,16 @@ public void call() throws Exception {
116
116
requestSender .abort (channel , future , new IOException (String .format ("Invalid challenge. Actual: %s. Expected: %s" , accept , key )));
117
117
}
118
118
119
+ // set back the future so the protocol gets notified of frames
120
+ // removing the HttpClientCodec from the pipeline might trigger a read with a WebSocket message
121
+ // if it comes in the same frame as the HTTP Upgrade response
122
+ Channels .setAttribute (channel , future );
123
+
119
124
channelManager .upgradePipelineForWebSockets (channel .pipeline ());
120
125
121
126
invokeOnSucces (channel , handler );
122
127
future .done ();
123
- // set back the future so the protocol gets notified of frames
124
- Channels .setAttribute (channel , future );
125
128
}
126
-
127
129
}
128
130
129
131
@ Override
@@ -144,43 +146,61 @@ public void handleRead(Channel channel, NettyResponseFuture<?> future, Object e)
144
146
Channels .setAttribute (channel , new UpgradeCallback (future , channel , response , handler , status , responseHeaders ));
145
147
}
146
148
147
-
148
149
} else if (e instanceof WebSocketFrame ) {
149
-
150
150
final WebSocketFrame frame = (WebSocketFrame ) e ;
151
151
WebSocketUpgradeHandler handler = (WebSocketUpgradeHandler ) future .getAsyncHandler ();
152
152
NettyWebSocket webSocket = (NettyWebSocket ) handler .onCompleted ();
153
153
154
154
if (webSocket != null ) {
155
- if (frame instanceof CloseWebSocketFrame ) {
156
- Channels .setDiscard (channel );
157
- CloseWebSocketFrame closeFrame = (CloseWebSocketFrame ) frame ;
158
- webSocket .onClose (closeFrame .statusCode (), closeFrame .reasonText ());
159
- } else {
160
- ByteBuf buf = frame .content ();
161
- if (buf != null && buf .readableBytes () > 0 ) {
162
- HttpResponseBodyPart part = config .getResponseBodyPartFactory ().newResponseBodyPart (buf , frame .isFinalFragment ());
163
- handler .onBodyPartReceived (part );
164
-
165
- if (frame instanceof BinaryWebSocketFrame ) {
166
- webSocket .onBinaryFragment (part );
167
- } else if (frame instanceof TextWebSocketFrame ) {
168
- webSocket .onTextFragment (part );
169
- } else if (frame instanceof PingWebSocketFrame ) {
170
- webSocket .onPing (part );
171
- } else if (frame instanceof PongWebSocketFrame ) {
172
- webSocket .onPong (part );
173
- }
174
- }
175
- }
155
+ handleFrame (channel , frame , handler , webSocket );
176
156
} else {
177
- logger .debug ("UpgradeHandler returned a null NettyWebSocket" );
157
+ logger .debug ("Frame received but WebSocket is not available yet, buffering frame" );
158
+ frame .retain ();
159
+ Runnable bufferedFrame = new Runnable () {
160
+ public void run () {
161
+ try {
162
+ // WebSocket is now not null
163
+ NettyWebSocket webSocket = (NettyWebSocket ) handler .onCompleted ();
164
+ handleFrame (channel , frame , handler , webSocket );
165
+ } catch (Exception e ) {
166
+ logger .debug ("Failure while handling buffered frame" , e );
167
+ handler .onFailure (e );
168
+ } finally {
169
+ frame .release ();
170
+ }
171
+ };
172
+ };
173
+ handler .bufferFrame (bufferedFrame );
178
174
}
179
175
} else {
180
176
logger .error ("Invalid message {}" , e );
181
177
}
182
178
}
183
179
180
+ private void handleFrame (Channel channel , WebSocketFrame frame , WebSocketUpgradeHandler handler , NettyWebSocket webSocket ) throws Exception {
181
+ if (frame instanceof CloseWebSocketFrame ) {
182
+ Channels .setDiscard (channel );
183
+ CloseWebSocketFrame closeFrame = (CloseWebSocketFrame ) frame ;
184
+ webSocket .onClose (closeFrame .statusCode (), closeFrame .reasonText ());
185
+ } else {
186
+ ByteBuf buf = frame .content ();
187
+ if (buf != null && buf .readableBytes () > 0 ) {
188
+ HttpResponseBodyPart part = config .getResponseBodyPartFactory ().newResponseBodyPart (buf , frame .isFinalFragment ());
189
+ handler .onBodyPartReceived (part );
190
+
191
+ if (frame instanceof BinaryWebSocketFrame ) {
192
+ webSocket .onBinaryFragment (part );
193
+ } else if (frame instanceof TextWebSocketFrame ) {
194
+ webSocket .onTextFragment (part );
195
+ } else if (frame instanceof PingWebSocketFrame ) {
196
+ webSocket .onPing (part );
197
+ } else if (frame instanceof PongWebSocketFrame ) {
198
+ webSocket .onPong (part );
199
+ }
200
+ }
201
+ }
202
+ }
203
+
184
204
@ Override
185
205
public void handleException (NettyResponseFuture <?> future , Throwable e ) {
186
206
logger .warn ("onError {}" , e );
0 commit comments