private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
    // Handle a bad request.
    if (!req.getDecoderResult().isSuccess()) {
      sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));
      req.release();
      return;
    }

    // Allow only GET methods.
    if (req.getMethod() != GET) {
      sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
      req.release();
      return;
    }

    // Handshake
    WebSocketServerHandshakerFactory wsFactory =
        new WebSocketServerHandshakerFactory(
            getWebSocketLocation(req), null, false, Integer.MAX_VALUE);
    handshaker = wsFactory.newHandshaker(req);
    if (handshaker == null) {
      WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel());
    } else {
      handshaker.handshake(ctx.channel(), req);
    }
    req.release();
  }
  @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);
    }
  }
  private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
    // Allow only GET methods.
    if (req.getMethod() != GET) {
      sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN));
      return;
    }

    // Handshake
    WebSocketServerHandshakerFactory wsFactory =
        new WebSocketServerHandshakerFactory(this.getWebSocketLocation(req), null, false);
    this.handshaker = wsFactory.newHandshaker(ctx, req);
    if (this.handshaker == null) {
      wsFactory.sendUnsupportedWebSocketVersionResponse(ctx);
    } else {
      this.handshaker.performOpeningHandshake(ctx, req);
    }
  }
  private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
    // Handle a bad request.
    if (!req.getDecoderResult().isSuccess()) {
      sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));
      return;
    }

    // Allow only GET methods.
    if (req.getMethod() != GET) {
      sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
      return;
    }

    // Send the demo page and favicon.ico
    if ("/".equals(req.getUri())) {
      ByteBuf content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req));
      FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, OK, content);

      res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
      HttpHeaders.setContentLength(res, content.readableBytes());

      sendHttpResponse(ctx, req, res);
      return;
    }
    if ("/favicon.ico".equals(req.getUri())) {
      FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND);
      sendHttpResponse(ctx, req, res);
      return;
    }

    // Handshake
    WebSocketServerHandshakerFactory wsFactory =
        new WebSocketServerHandshakerFactory(getWebSocketLocation(req), null, true);
    handshaker = wsFactory.newHandshaker(req);
    if (handshaker == null) {
      WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
    } else {
      handshaker.handshake(ctx.channel(), req);
    }
  }
  private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {

    if (!req.getDecoderResult().isSuccess()
        || (!"websocket".equals(req.headers().get("Upgrade")))) {

      sendHttpResponse(
          ctx,
          req,
          new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));

      return;
    }

    WebSocketServerHandshakerFactory wsFactory =
        new WebSocketServerHandshakerFactory("ws://localhost:7397/websocket", null, false);

    handshaker = wsFactory.newHandshaker(req);

    if (handshaker == null) {
      WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel());
    } else {
      handshaker.handshake(ctx.channel(), req);
    }
  }
  private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest request) {
    // Handle a bad request.
    if (!request.getDecoderResult().isSuccess()) {
      sendHttpResponse(
          ctx, request, new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
      return;
    }

    if (RouterHits.checkIfMappingExit(request)) {
      // Do Router Mapping First
      RouterHits.execute(ctx, request);
      return;
    }

    if ("/websocket".equals(request.getUri())) {
      // Handshake
      WebSocketServerHandshakerFactory wsFactory =
          new WebSocketServerHandshakerFactory(getWebSocketLocation(request), null, true);
      handshaker = wsFactory.newHandshaker(request);
      if (handshaker == null) {
        WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
      } else {
        handshaker.handshake(ctx.channel(), request);
        channels.add(ctx.channel());
      }
      return;
    }

    final String uri = request.getUri();
    // System.out.println("uri: " + uri);
    final String path = sanitizeUri("www", uri);
    // System.out.println("path: " + path);
    if (path == null) {
      sendHttpResponse(
          ctx, request, new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.FORBIDDEN));

      return;
    }

    File file = new File(path);
    if (file.isHidden() || !file.exists()) {
      sendHttpResponse(
          ctx, request, new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.NOT_FOUND));
      return;
    }

    if (file.isDirectory()) {
      if (uri.endsWith("/")) {

        File checkIndexFile = new File(file.getAbsolutePath() + File.separator + "index.html");

        System.out.println(checkIndexFile.exists());
        if (checkIndexFile.exists()) {
          file = checkIndexFile;
        } else {
          sendListing(ctx, file);
          return;
        }
      } else {
        sendRedirect(ctx, uri + '/');
      }
    }

    if (!file.isFile()) {
      sendHttpResponse(
          ctx, request, new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.FORBIDDEN));
      return;
    }

    // Cache Validation
    String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE);
    if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) {
      SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
      Date ifModifiedSinceDate = null;
      try {
        ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince);
      } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }

      // Only compare up to the second because the datetime format we send to the client
      // does not have milliseconds
      long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000;
      long fileLastModifiedSeconds = file.lastModified() / 1000;
      if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) {
        sendNotModified(ctx);
        return;
      }
    }

    RandomAccessFile raf;
    try {
      raf = new RandomAccessFile(file, "r");
    } catch (FileNotFoundException ignore) {
      sendHttpResponse(
          ctx, request, new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.NOT_FOUND));
      return;
    }
    long fileLength = 0;
    try {
      fileLength = raf.length();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

    HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
    HttpHeaders.setContentLength(response, fileLength);
    setContentTypeHeader(response, file);
    setDateAndCacheHeaders(response, file);
    if (HttpHeaders.isKeepAlive(request)) {
      response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
    }

    // Write the initial line and the header.
    ctx.write(response);

    // Write the content.
    ChannelFuture sendFileFuture = null;
    ChannelFuture lastContentFuture;
    if (ctx.pipeline().get(SslHandler.class) == null) {
      sendFileFuture =
          ctx.write(
              new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise());
      // Write the end marker.
      lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
    } else {
      try {
        sendFileFuture =
            ctx.writeAndFlush(
                new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)),
                ctx.newProgressivePromise());
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
      // HttpChunkedInput will write the end marker (LastHttpContent) for us.
      lastContentFuture = sendFileFuture;
    }

    sendFileFuture.addListener(
        new ChannelProgressiveFutureListener() {
          @Override
          public void operationProgressed(
              ChannelProgressiveFuture future, long progress, long total) {
            if (total < 0) { // total unknown
              System.err.println(future.channel() + " Transfer progress: " + progress);
            } else {
              System.err.println(
                  future.channel() + " Transfer progress: " + progress + " / " + total);
            }
          }

          @Override
          public void operationComplete(ChannelProgressiveFuture future) {
            System.err.println(future.channel() + " Transfer complete.");
          }
        });

    // Decide whether to close the connection or not.
    if (!HttpHeaders.isKeepAlive(request)) {
      // Close the connection when the whole content is written out.
      lastContentFuture.addListener(ChannelFutureListener.CLOSE);
    }

    //        // Send the demo page and favicon.ico
    //        if ("/".equals(req.getUri()) && req.getMethod() == GET) {
    //            ByteBuf content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req));
    //            FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
    //
    //            res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
    //            HttpHeaders.setContentLength(res, content.readableBytes());
    //
    //            sendHttpResponse(ctx, req, res);
    //            return;
    //        }
    //
    //        if ("/favicon.ico".equals(req.getUri())) {
    //            FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND);
    //            sendHttpResponse(ctx, req, res);
    //            return;
    //        }

    sendHttpResponse(
        ctx, request, new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.FORBIDDEN));
    return;
  }
  private ChannelFuture handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest request) {
    if (request.method() == HttpMethod.OPTIONS) {
      return HttpHelpers.sendPreflightApproval(ctx);
    }

    HttpRequestInfo CurrRequest = new HttpRequestInfo();

    try {
      CurrRequest.init(Info, request, SVID.makeSVID());
    } catch (URISyntaxException e1) {
      return HttpHelpers.sendError(CurrRequest, ApiErrors.HTTP_DECODE_ERROR);
    }

    URI uri = CurrRequest.RequestURI;

    l.debug(new SVLog("Agent HTTP request", CurrRequest));

    if (!request.decoderResult().isSuccess()) {
      return HttpHelpers.sendError(CurrRequest, ApiErrors.HTTP_DECODE_ERROR);
    }

    if (!authenticate(request, (InetSocketAddress) ctx.channel().remoteAddress())) {
      return HttpHelpers.sendError(CurrRequest, ApiErrors.BAD_AUTH);
    }

    String uriPath = uri.getPath();

    if (uriPath.equals(WEBSOCKET_PATH)) {
      String websockUrl = request.headers().get(HttpHeaderNames.HOST) + WEBSOCKET_PATH;
      WebSocketServerHandshakerFactory wsFactory =
          new WebSocketServerHandshakerFactory(websockUrl, null, false);

      Handshaker = wsFactory.newHandshaker(request);
      if (Handshaker == null) {
        return WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
      } else {
        WebsocketConnected = true;
        return Handshaker.handshake(ctx.channel(), request);
      }
    }

    if (uriPath.startsWith("/api/")) {
      // Invoking an API directly over HTTP

      String messageType = uriPath.substring(5);
      String messageBody = null;
      if (request.method() == HttpMethod.POST && request.content() != null) {
        messageBody = request.content().toString(StandardCharsets.UTF_8);
      }

      ByteBuf reply = null;
      try {
        reply = Dispatcher.dispatch(messageType, messageBody);
      } catch (JsonProcessingException e) {
        return HttpHelpers.sendError(CurrRequest, ApiErrors.JSON_ERROR, e.getMessage());
      } catch (SQLException e) {
        return HttpHelpers.sendError(CurrRequest, ApiErrors.DB_ERROR, e.getMessage());
      } catch (JsonApiException e) {
        return HttpHelpers.sendErrorJson(CurrRequest, e.Error, e.HttpStatus);
      } catch (Exception e) {
        return HttpHelpers.sendError(CurrRequest, ApiErrors.INTERNAL_SERVER_ERROR, e.getMessage());
      }

      HttpResponse response =
          new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, reply);

      if (reply != null) {
        HttpHelpers.setContentTypeHeader(response, "application/json");
        HttpUtil.setContentLength(response, reply.readableBytes());
      }

      response.headers().set(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN, "*");

      return ctx.writeAndFlush(response);
    }

    return HttpHelpers.sendError(CurrRequest, ApiErrors.NOT_FOUND);
  }
  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;
  }
  private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req)
      throws SuspendExecution {
    // Handle a bad request.
    if (!req.getDecoderResult().isSuccess()) {
      sendHttpResponse(
          ctx, req, new DefaultFullHttpResponse(req.getProtocolVersion(), BAD_REQUEST), false);
      return;
    }

    final String uri = req.getUri();

    final Context actorCtx = selector.get(ctx, req);
    assert actorCtx != null;

    final ReentrantLock lock = actorCtx.getLock();
    assert lock != null;

    lock.lock();

    try {
      final ActorRef<? extends WebMessage> userActorRef = actorCtx.getRef();
      ActorImpl internalActor = (ActorImpl) actorCtx.getAttachments().get(ACTOR_KEY);

      if (userActorRef != null) {
        if (actorCtx.handlesWithWebSocket(uri)) {
          if (internalActor == null || !(internalActor instanceof WebSocketActorAdapter)) {
            //noinspection unchecked
            webSocketActor =
                new WebSocketActorAdapter(ctx, (ActorRef<? super WebMessage>) userActorRef);
            addActorToContextAndUnlock(actorCtx, webSocketActor, lock);
          }
          // Handshake
          final WebSocketServerHandshakerFactory wsFactory =
              new WebSocketServerHandshakerFactory(uri, null, true);
          handshaker = wsFactory.newHandshaker(req);
          if (handshaker == null) {
            WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
          } else {
            @SuppressWarnings("unchecked")
            final ActorRef<WebMessage> userActorRef0 =
                (ActorRef<WebMessage>) webSocketActor.userActor;
            handshaker
                .handshake(ctx.channel(), req)
                .addListener(
                    new GenericFutureListener<ChannelFuture>() {
                      @Override
                      public void operationComplete(ChannelFuture future) throws Exception {
                        FiberUtil.runInFiber(
                            new SuspendableRunnable() {
                              @Override
                              public void run() throws SuspendExecution, InterruptedException {
                                userActorRef0.send(
                                    new WebSocketOpened(WebActorHandler.this.webSocketActor.ref()));
                              }
                            });
                      }
                    });
          }
          return;
        } else if (actorCtx.handlesWithHttp(uri)) {
          if (internalActor == null || !(internalActor instanceof HttpActorAdapter)) {
            //noinspection unchecked
            internalActor =
                new HttpActorAdapter(
                    (ActorRef<HttpRequest>) userActorRef, actorCtx, httpResponseEncoderName);
            addActorToContextAndUnlock(actorCtx, internalActor, lock);
          }
          //noinspection unchecked
          ((HttpActorAdapter) internalActor).service(ctx, req);
          return;
        }
      }
    } finally {
      if (lock.isHeldByCurrentStrand() && lock.isLocked()) lock.unlock();
    }

    sendHttpResponse(
        ctx, req, new DefaultFullHttpResponse(req.getProtocolVersion(), NOT_FOUND), false);
  }