This document is intended to explain a suggestion for an enhancement of the WebSocket support in Netty 4 and was only created to get feedback from the Netty team to see if this is a valid suggestion before putting any time and effort into it.
Netty has a very nice support for WebSockets and the examples provided work like a charm. This is one of the examples that come with Netty WebSocketServerHandler.java. In this example the WebSocketServerHandler takes care of everything in regard to the WebSocket request, and also acts as a simple web server to produce the html page used for running the example using a web browser.
The reason for this suggestion is that I wanted to implement a simple handler that receives a TextWebSocketFrame and not have to deal with other things like the Http Handshake.So I've created the following branch to show what I'm after.
To start with I'd like to show what a Netty server looks like in this case:
public static void main(String[] args) throws Exception {
final ServerBootstrap sb = new ServerBootstrap();
try {
sb.eventLoop(new NioEventLoop(), new NioEventLoop())
.channel(new NioServerSocketChannel())
.localAddress(new InetSocketAddress(8080))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(final SocketChannel ch) throws Exception {
ch.pipeline().addLast(new HttpRequestDecoder(),
new HttpChunkAggregator(65536),
new HttpResponseEncoder(),
new WebSocketHandshakeHandler("/websocket"),
new WebSocketProtocolHandler(),
new CustomTextFrameHandler());
}
});
final Channel ch = sb.bind().sync().channel();
System.out.println("Web socket server started at port 8080");
ch.closeFuture().sync();
} finally {
sb.shutdown();
}
}
Where CustomTextFrameHandler would look something like this:
public class CustomTextFrameHandler extends ChannelInboundMessageHandlerAdapter<TextWebSocketFrame> {
@Override
public void messageReceived(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception {
String request = ((TextWebSocketFrame) frame).getText();
ctx.channel().write(new TextWebSocketFrame(request.toUpperCase()));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
The code in messageReceived is from the original WebSocket example mentioned above. What is different is that there are two more handlers in the pipeline:
-
WebSocketHandshakeHandler.java
This handler takes care of the HTTP Upgrade request and after a successful handshake will remove itself from the pipeline.
-
This handler takes care of the WebSocket protocol by handling close, and ping requests. All other requests will be passed along to the next inbound handler in the chain.
WebSocketProtocolHandler
could insertWebSocketHandshakeHandler
right before itself when it's added, then we could hideWebSocketHandshakeHandler
completely (package private) unless there's a good use case to use it separately. I also would love to see some additional methods likeWebSocketProtocolHandler.handleNonWebSocketRequest(HttpRequest)
whose default implementation is to respond with 403. WDYT?