/** Free any request/response handlers related to the current channel handler context. */
  public void freeHandlers(final ChannelHandlerContext ctx) {

    final PooledServerResponse response = ctx.attr(ATTR_RESPONSE).getAndRemove();

    if (response != null) {

      try {

        final RequestHandler handler = response.handler();

        if (handler != null) {
          handler.onComplete(response.request(), response);
        }

      } finally {

        response.request().release();
        messagePool.makeAvailable(response.request());

        response.close();

        messagePool.makeAvailable(response);
      }
    }
  }
  @Override
  public void channelInactive(final ChannelHandlerContext ctx) {

    final PooledServerResponse response = ctx.attr(ATTR_RESPONSE).get();

    if (response != null) {

      try {

        if (!response.isFinished()) {

          response.close();

          final RequestHandler handler = response.handler();

          if (handler != null) {
            handler.onAbort(response.request(), response);
          }
        }

      } finally {

        freeHandlers(ctx);
      }
    }
  }
  @Override
  public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable exception)
      throws Exception {

    final PooledServerResponse response = ctx.attr(ATTR_RESPONSE).get();

    if (response != null) {

      try {

        try {

          if (!response.isFinished()) {

            response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);

            config.errorHandler().onError(response.request(), response, exception);

            response.close();

            final RequestHandler handler = response.handler();

            if (handler != null) {
              handler.onException(response.request(), response, exception);
            }
          }

        } finally {

          config.logger().error(response.request(), response, exception);
        }

      } finally {

        freeHandlers(ctx);
      }
    }
  }