@Override
  public void handle(Channel channel, NettyResponseFuture<?> future, Object e) throws Exception {

    if (e instanceof HttpResponse) {
      HttpResponse response = (HttpResponse) e;
      Channels.setAttribute(channel, new UpgradeCallback(future, channel, response));

    } else if (e instanceof WebSocketFrame) {

      final WebSocketFrame frame = (WebSocketFrame) e;
      WebSocketUpgradeHandler handler =
          WebSocketUpgradeHandler.class.cast(future.getAsyncHandler());
      NettyWebSocket webSocket = NettyWebSocket.class.cast(handler.onCompleted());
      invokeOnSucces(channel, handler);

      if (webSocket != null) {
        if (frame instanceof CloseWebSocketFrame) {
          Channels.setDiscard(channel);
          CloseWebSocketFrame closeFrame = CloseWebSocketFrame.class.cast(frame);
          webSocket.onClose(closeFrame.statusCode(), closeFrame.reasonText());
        } else {
          ByteBuf buf = frame.content();
          if (buf != null && buf.readableBytes() > 0) {
            try {
              NettyResponseBodyPart part =
                  nettyConfig
                      .getBodyPartFactory()
                      .newResponseBodyPart(buf, frame.isFinalFragment());
              handler.onBodyPartReceived(part);

              if (frame instanceof BinaryWebSocketFrame) {
                webSocket.onBinaryFragment(part);
              } else if (frame instanceof TextWebSocketFrame) {
                webSocket.onTextFragment(part);
              } else if (frame instanceof PingWebSocketFrame) {
                webSocket.onPing(part);
              } else if (frame instanceof PongWebSocketFrame) {
                webSocket.onPong(part);
              }
            } finally {
              buf.release();
            }
          }
        }
      } else {
        logger.debug("UpgradeHandler returned a null NettyWebSocket ");
      }
    } else {
      logger.error("Invalid message {}", e);
    }
  }
 private boolean exitAfterHandling100(
     final Channel channel, final NettyResponseFuture<?> future, int statusCode) {
   future.setHeadersAlreadyWrittenOnContinue(true);
   future.setDontWriteBodyBecauseExpectContinue(false);
   // directly send the body
   Channels.setAttribute(
       channel,
       new Callback(future) {
         @Override
         public void call() throws IOException {
           Channels.setAttribute(channel, future);
           requestSender.writeRequest(future, channel);
         }
       });
   return true;
 }
 private boolean exitAfterHandlingReactiveStreams(
     Channel channel,
     NettyResponseFuture<?> future,
     HttpResponse response,
     AsyncHandler<?> handler,
     HttpRequest httpRequest)
     throws IOException {
   if (handler instanceof StreamedAsyncHandler) {
     StreamedAsyncHandler<?> streamedAsyncHandler = (StreamedAsyncHandler<?>) handler;
     StreamedResponsePublisher publisher =
         new StreamedResponsePublisher(channel.eventLoop(), channelManager, future, channel);
     // FIXME do we really need to pass the event loop?
     // FIXME move this to ChannelManager
     channel.pipeline().addLast(channel.eventLoop(), "streamedAsyncHandler", publisher);
     Channels.setAttribute(channel, publisher);
     return streamedAsyncHandler.onStream(publisher) != State.CONTINUE;
   }
   return false;
 }
    @Override
    public void call() throws Exception {

      WebSocketUpgradeHandler handler =
          WebSocketUpgradeHandler.class.cast(future.getAsyncHandler());
      Request request = future.getRequest();

      HttpResponseStatus status =
          new NettyResponseStatus(future.getUri(), config, response, channel);
      HttpResponseHeaders responseHeaders = new NettyResponseHeaders(response.headers());
      Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm();

      if (exitAfterProcessingFilters(channel, future, handler, status, responseHeaders)) {
        return;
      }

      future.setHttpHeaders(response.headers());
      if (exitAfterHandlingRedirect(
          channel, future, response, request, response.getStatus().code(), realm)) return;

      boolean validStatus = response.getStatus().equals(SWITCHING_PROTOCOLS);
      boolean validUpgrade = response.headers().get(HttpHeaders.Names.UPGRADE) != null;
      String connection = response.headers().get(HttpHeaders.Names.CONNECTION);
      if (connection == null)
        connection =
            response.headers().get(HttpHeaders.Names.CONNECTION.toLowerCase(Locale.ENGLISH));
      boolean validConnection = HttpHeaders.Values.UPGRADE.equalsIgnoreCase(connection);
      boolean statusReceived = handler.onStatusReceived(status) == State.UPGRADE;

      if (!statusReceived) {
        try {
          handler.onCompleted();
        } finally {
          future.done();
        }
        return;
      }

      final boolean headerOK = handler.onHeadersReceived(responseHeaders) == State.CONTINUE;
      if (!headerOK || !validStatus || !validUpgrade || !validConnection) {
        requestSender.abort(channel, future, new IOException("Invalid handshake response"));
        return;
      }

      String accept = response.headers().get(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT);
      String key =
          getAcceptKey(
              future
                  .getNettyRequest()
                  .getHttpRequest()
                  .headers()
                  .get(HttpHeaders.Names.SEC_WEBSOCKET_KEY));
      if (accept == null || !accept.equals(key)) {
        requestSender.abort(
            channel,
            future,
            new IOException(
                String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key)));
      }

      channelManager.upgradePipelineForWebSockets(channel.pipeline());

      invokeOnSucces(channel, handler);
      future.done();
      // set back the future so the protocol gets notified of frames
      Channels.setAttribute(channel, future);
    }