@Override
  public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
    Channel channel = ctx.getChannel();
    if (channel.getAttachment() != null
        && (Error.class.isAssignableFrom(channel.getAttachment().getClass())
            || WRITING.equals(channel.getAttachment().toString()))) {
      return;
    }

    if (!isReceived(ctx)) {
      return;
    }

    try {
      log.error(e.getCause().getMessage(), e.getCause());
      channel.setAttachment(new Error());
      DefaultHttpResponse response =
          new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR);
      response.setContent(
          ChannelBuffers.copiedBuffer(
              response.getStatus().toString() + ":" + e.getCause().getMessage(),
              CharsetUtil.UTF_8));
      response.headers().set(Names.CONTENT_LENGTH, response.getContent().readableBytes());
      response.headers().set(Names.SERVER, "NAVI/1.1.4(UNIX)");
      response.headers().set(Names.CONNECTION, "close");
      ChannelFuture f = channel.write(response);
      f.addListener(ChannelFutureListener.CLOSE);
      f.addListener(
          new ChannelFutureListener() {

            public void operationComplete(ChannelFuture f) throws Exception {
              if (!f.isSuccess()) {
                log.error(f.getCause().getMessage(), f.getCause());
              }
            }
          });
    } catch (Exception ex) {
      log.error(e.getCause().getMessage(), e.getCause());
      e.getFuture().addListener(ChannelFutureListener.CLOSE);
    }
  }