[ARTEMIS-963] Prevent ClassCastException in ActiveMQChannelHandler
When HTTP Upgrade is enabled, update Netty's pipeline only after the HTTP Upgrade handshake is successful *and* the trailing EMPTY_LAST_CONTENT is received. Otherwise, this EMPTY_LAST_CONTENT is handled by ActiveMQChannelHandler which is only expected to handle ByteBuf JIRA: https://issues.apache.org/jira/browse/ARTEMIS-963
This commit is contained in:
parent
db2c711e24
commit
992dc2bc1b
|
@ -80,6 +80,7 @@ import io.netty.handler.codec.http.HttpResponse;
|
||||||
import io.netty.handler.codec.http.HttpResponseDecoder;
|
import io.netty.handler.codec.http.HttpResponseDecoder;
|
||||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||||
import io.netty.handler.codec.http.HttpVersion;
|
import io.netty.handler.codec.http.HttpVersion;
|
||||||
|
import io.netty.handler.codec.http.LastHttpContent;
|
||||||
import io.netty.handler.codec.http.cookie.ClientCookieEncoder;
|
import io.netty.handler.codec.http.cookie.ClientCookieEncoder;
|
||||||
import io.netty.handler.ssl.SslHandler;
|
import io.netty.handler.ssl.SslHandler;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
|
@ -745,36 +746,50 @@ public class NettyConnector extends AbstractConnector {
|
||||||
this.httpClientCodec = httpClientCodec;
|
this.httpClientCodec = httpClientCodec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP upgrade response will be decode by Netty as 2 objects:
|
||||||
|
* - 1 HttpObject corresponding to the 101 SWITCHING PROTOCOL headers
|
||||||
|
* - 1 EMPTY_LAST_CONTENT
|
||||||
|
*
|
||||||
|
* The HTTP upgrade is successful whne the 101 SWITCHING PROTOCOL has been received (handshakeComplete = true)
|
||||||
|
* but the latch is count down only when the following EMPTY_LAST_CONTENT is also received.
|
||||||
|
* Otherwise this ChannelHandler would be removed too soon and the ActiveMQChannelHandler would handle the
|
||||||
|
* EMPTY_LAST_CONTENT (while it is expecitng only ByteBuf).
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
|
public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Received msg=" + msg);
|
logger.debug("Received msg=" + msg);
|
||||||
}
|
}
|
||||||
try {
|
if (msg instanceof HttpResponse) {
|
||||||
if (msg instanceof HttpResponse) {
|
HttpResponse response = (HttpResponse) msg;
|
||||||
HttpResponse response = (HttpResponse) msg;
|
if (response.getStatus().code() == HttpResponseStatus.SWITCHING_PROTOCOLS.code() && response.headers().get(HttpHeaders.Names.UPGRADE).equals(ACTIVEMQ_REMOTING)) {
|
||||||
if (response.getStatus().code() == HttpResponseStatus.SWITCHING_PROTOCOLS.code() && response.headers().get(HttpHeaders.Names.UPGRADE).equals(ACTIVEMQ_REMOTING)) {
|
String accept = response.headers().get(SEC_ACTIVEMQ_REMOTING_ACCEPT);
|
||||||
String accept = response.headers().get(SEC_ACTIVEMQ_REMOTING_ACCEPT);
|
String expectedResponse = createExpectedResponse(MAGIC_NUMBER, ctx.channel().attr(REMOTING_KEY).get());
|
||||||
String expectedResponse = createExpectedResponse(MAGIC_NUMBER, ctx.channel().attr(REMOTING_KEY).get());
|
|
||||||
|
|
||||||
if (expectedResponse.equals(accept)) {
|
if (expectedResponse.equals(accept)) {
|
||||||
// remove the http handlers and flag the activemq channel handler as active
|
// HTTP upgrade is successful but let's wait to receive the EMPTY_LAST_CONTENT to count down the latch
|
||||||
pipeline.remove(httpClientCodec);
|
handshakeComplete = true;
|
||||||
pipeline.remove(this);
|
} else {
|
||||||
handshakeComplete = true;
|
// HTTP upgrade failed
|
||||||
ActiveMQChannelHandler channelHandler = pipeline.get(ActiveMQChannelHandler.class);
|
ActiveMQClientLogger.LOGGER.httpHandshakeFailed(msg);
|
||||||
channelHandler.active = true;
|
ctx.close();
|
||||||
return;
|
latch.countDown();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} finally {
|
} else if (msg == LastHttpContent.EMPTY_LAST_CONTENT && handshakeComplete) {
|
||||||
if (!handshakeComplete) {
|
// remove the http handlers and flag the activemq channel handler as active
|
||||||
ActiveMQClientLogger.LOGGER.httpHandshakeFailed(msg);
|
pipeline.remove(httpClientCodec);
|
||||||
ctx.close();
|
pipeline.remove(this);
|
||||||
}
|
ActiveMQChannelHandler channelHandler = pipeline.get(ActiveMQChannelHandler.class);
|
||||||
latch.countDown();
|
channelHandler.active = true;
|
||||||
}
|
}
|
||||||
|
if (!handshakeComplete) {
|
||||||
|
ActiveMQClientLogger.LOGGER.httpHandshakeFailed(msg);
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
latch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue