@SuppressWarnings("unchecked")
  @Override
  public NextAction handleEvent(final FilterChainContext ctx, final FilterChainEvent event)
      throws IOException {

    final Object type = event.type();
    if (type == ContinueEvent.class) {
      final ContinueEvent continueEvent = (ContinueEvent) event;
      ((ExpectHandler) continueEvent.getContext().getBodyHandler()).finish(ctx);
    } else if (type == TunnelRequestEvent.class) {
      // Disable SSL for the time being...
      ctx.notifyDownstream(new SSLSwitchingEvent(false, ctx.getConnection()));
      ctx.suspend();
      TunnelRequestEvent tunnelRequestEvent = (TunnelRequestEvent) event;
      final ProxyServer proxyServer = tunnelRequestEvent.getProxyServer();
      final URI requestUri = tunnelRequestEvent.getUri();

      RequestBuilder builder = new RequestBuilder();
      builder.setMethod(Method.CONNECT.getMethodString());
      builder.setUrl("http://" + getAuthority(requestUri));
      Request request = builder.build();

      AsyncHandler handler =
          new AsyncCompletionHandler() {
            @Override
            public Object onCompleted(Response response) throws Exception {
              if (response.getStatusCode() != 200) {
                PROXY_AUTH_FAILURE.set(ctx.getConnection(), Boolean.TRUE);
              }
              ctx.notifyDownstream(new SSLSwitchingEvent(true, ctx.getConnection()));
              ctx.notifyDownstream(event);
              return response;
            }
          };
      final GrizzlyResponseFuture future =
          new GrizzlyResponseFuture(grizzlyAsyncHttpProvider, request, handler, proxyServer);
      future.setDelegate(SafeFutureImpl.create());

      grizzlyAsyncHttpProvider.execute(
          ctx.getConnection(), request, handler, future, HttpTxContext.get(ctx));
      return ctx.getSuspendAction();
    }

    return ctx.getStopAction();
  }