Java tutorial
/* * Original Work: Copyright 2012 The Netty Project * * Modified Work: Copyright 2016 Tek Counsel LLC * * Both licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package com.tc.websocket.server.handler; import static io.netty.handler.codec.http.HttpMethod.GET; import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST; import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN; import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; import java.util.logging.Level; import java.util.logging.Logger; import com.google.inject.Inject; import com.tc.websocket.Config; import com.tc.websocket.Const; import com.tc.websocket.IConfig; import com.tc.websocket.server.IDominoWebSocketServer; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpUtil; import io.netty.util.CharsetUtil; import io.netty.util.ReferenceCountUtil; // TODO: Auto-generated Javadoc /** * The Class WebSocketValidationHandler. */ public class WebSocketValidationHandler extends SimpleChannelInboundHandler<FullHttpRequest> { /** The Constant LOG. */ private static final Logger LOG = Logger.getLogger(WebSocketValidationHandler.class.getName()); /** The server. */ @Inject private IDominoWebSocketServer server; /** The cfg. */ private IConfig cfg = Config.getInstance(); /* (non-Javadoc) * @see io.netty.channel.SimpleChannelInboundHandler#channelRead0(io.netty.channel.ChannelHandlerContext, java.lang.Object) */ @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception { if (this.isValidRequest(ctx, req)) { ReferenceCountUtil.retain(req); ctx.fireChannelRead(req); } } /** * Checks if is valid request. * * @param ctx the ctx * @param req the req * @return true, if is valid request */ public boolean isValidRequest(ChannelHandlerContext ctx, FullHttpRequest req) { // Handle a bad request. if (!req.decoderResult().isSuccess()) { sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST)); return false; } // Allow only GET methods. if (req.method() != GET) { sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN)); return false; } if ("/favicon.ico".equals(req.uri())) { FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND); sendHttpResponse(ctx, req, res); return false; } if (!req.uri().contains(Const.WEBSOCKET_URI)) { sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN)); return false; } if (server.getWebSocketCount() >= cfg.getMaxConnections()) { LOG.log(Level.SEVERE, "Maximum number of websockets " + cfg.getMaxConnections() + " created."); sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN)); return false; } String origin = req.headers().get(HttpHeaderNames.ORIGIN); if (origin != null && !Config.getInstance().isAllowedOrigin(origin)) { LOG.log(Level.SEVERE, "Invalid origin " + origin + " attempting to make websocket connection"); sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN)); return false; } return true; } /** * Send http response. * * @param ctx the ctx * @param req the req * @param res the res */ private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) { // Generate an error page if response getStatus code is not OK (200). if (res.status().code() != 200) { ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8); res.content().writeBytes(buf); buf.release(); HttpUtil.setContentLength(res, res.content().readableBytes()); } // Send the response and close the connection if necessary. ChannelFuture f = ctx.channel().writeAndFlush(res); if (!HttpUtil.isKeepAlive(req) || res.status().code() != 200) { f.addListener(ChannelFutureListener.CLOSE); } } }