@Override
  protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {

    FullHttpRequest req = (FullHttpRequest) msg;
    String upgrade = req.headers().get(HttpHeaders.Names.UPGRADE);
    if (HttpHeaders.Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
      WebSocketServerHandshakerFactory wsFactory =
          new WebSocketServerHandshakerFactory(req.getUri(), null, false);
      WebSocketServerHandshaker handshaker = wsFactory.newHandshaker(req);
      if (handshaker == null) {
        WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel());
      } else {
        ChannelFuture future = handshaker.handshake(ctx.channel(), req);
        future.addListener(
            f -> {
              this.configurator.switchToWebSockets(ctx.pipeline());
            });
      }
    } else {
      ReferenceCountUtil.retain(msg);
      this.configurator.switchToPlainHttp(ctx.pipeline());
      ChannelHandlerContext agg = ctx.pipeline().context(HttpObjectAggregator.class);
      agg.fireChannelRead(msg);
    }
  }
  public static ChannelFuture handshake(
      final ChannelHandlerContext ctx,
      final HttpRequest request,
      final String websocketPath,
      final ChannelHandler handler) {

    final String connHead = request.getHttpHeaders().getHeaderString(HttpHeaders.Names.CONNECTION);
    final String upHead = request.getHttpHeaders().getHeaderString(HttpHeaders.Names.UPGRADE);
    final String sockHead =
        request.getHttpHeaders().getHeaderString(HttpHeaders.Names.SEC_WEBSOCKET_VERSION);
    final String keyHead =
        request.getHttpHeaders().getHeaderString(HttpHeaders.Names.SEC_WEBSOCKET_KEY);

    try {
      DefaultHttpRequest req =
          new DefaultHttpRequest(
              HttpVersion.HTTP_1_0, HttpMethod.GET, request.getUri().getAbsolutePath().toString());
      req.setHeader(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, sockHead);
      req.setHeader(HttpHeaders.Names.SEC_WEBSOCKET_KEY, keyHead);

      final Channel channel = ctx.channel();

      final String location = getWebSocketLocation(channel.pipeline(), request, websocketPath);
      final WebSocketServerHandshakerFactory wsFactory =
          new WebSocketServerHandshakerFactory(location, null, false);

      final WebSocketServerHandshaker handshaker = wsFactory.newHandshaker(req);

      if (handshaker == null) {
        WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(channel);
        return null;

      } else if (!connHead.toLowerCase().contains(HttpHeaders.Values.UPGRADE.toLowerCase())
          || !upHead.toLowerCase().contains(HttpHeaders.Values.WEBSOCKET.toLowerCase())) {
        // Not a valid socket open request
        logger.info("Invalid request: " + request.getUri());
        return null;

      } else {
        // We need to remove the RESTEasy stuff otherwise the Netty logic to write the handshake to
        // the channel
        // will never make it back to the client
        channel.pipeline().remove("resteasyEncoder");
        channel.pipeline().remove("resteasyDecoder");

        final ChannelFuture handshakeFuture = handshaker.handshake(channel, req);

        handshakeFuture.addListener(
            new ChannelFutureListener() {
              @Override
              public void operationComplete(ChannelFuture future) throws Exception {
                if (!future.isSuccess()) {
                  ctx.fireExceptionCaught(future.cause());
                } else {
                  final ChannelPipeline pipeline = future.channel().pipeline();
                  pipeline.replace(pipeline.last(), "customSocketHandler", handler);
                  pipeline.addBefore(
                      "customSocketHandler", "socketHandler", new WebSocketProtocolHandler());
                }
              }
            });

        WebSocketProtocolHandler.setHandshaker(ctx, handshaker);
        return handshakeFuture;

        // channel.pipeline().addBefore("timeout", "WS403Responder",
        //    WebSocketProtocolHandler.forbiddenHttpRequestResponder());
      }

    } catch (Exception e) {
      logger.error("Error trying to upgrade the channel to a socket", e);
    }

    return null;
  }