@Override
  public long buildOutputChain(NginxResponse response) {
    long r = response.request().nativeRequest();
    try {
      long pool = UNSAFE.getAddress(r + NGX_HTTP_CLOJURE_REQ_POOL_OFFSET);
      int status = response.fetchStatus(NGX_HTTP_OK);

      Object body = response.fetchBody();
      long chain = 0;

      if (body != null) {
        chain = buildResponseItemBuf(r, body, chain);
        if (chain == 0) {
          return -NGX_HTTP_INTERNAL_SERVER_ERROR;
        } else if (chain < 0 && chain != -204) {
          return chain;
        }
      } else {
        chain = -NGX_HTTP_NO_CONTENT;
      }

      if (chain == -NGX_HTTP_NO_CONTENT) {
        if (status == NGX_HTTP_OK) {
          status = NGX_HTTP_NO_CONTENT;
        }
        return -status;
      }

      return chain;

    } catch (Throwable e) {
      log.error("server unhandled exception!", e);
      return -NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
  }
  @Override
  public <K, V> long prepareHeaders(
      NginxRequest req, long status, Collection<Map.Entry<K, V>> headers) {
    long r = req.nativeRequest();
    long pool = UNSAFE.getAddress(r + NGX_HTTP_CLOJURE_REQ_POOL_OFFSET);
    long headers_out = r + NGX_HTTP_CLOJURE_REQ_HEADERS_OUT_OFFSET;

    String contentType = null;
    String server = null;
    if (headers != null) {
      for (Map.Entry<?, ?> hen : headers) {
        Object nameObj = hen.getKey();
        Object val = hen.getValue();

        if (nameObj == null || val == null) {
          continue;
        }

        String name = normalizeHeaderName(nameObj);
        if (name == null || name.length() == 0) {
          continue;
        }

        NginxHeaderHolder pusher = fetchResponseHeaderPusher(name);
        if (pusher == RESP_CONTENT_TYPE_HOLDER) {
          if (val instanceof String) {
            contentType = (String) val;
          } else { // TODO:support another types

          }
        }
        pusher.push(headers_out, pool, val);
      }
    }

    if (contentType == null && status != NGX_HTTP_SWITCHING_PROTOCOLS) {
      ngx_http_set_content_type(r);
    } else {
      int contentTypeLen =
          pushNGXString(
              headers_out + NGX_HTTP_CLOJURE_HEADERSO_CONTENT_TYPE_OFFSET,
              contentType,
              DEFAULT_ENCODING,
              pool);
      // be friendly to gzip module
      pushNGXSizet(headers_out + NGX_HTTP_CLOJURE_HEADERSO_CONTENT_TYPE_LEN_OFFSET, contentTypeLen);
    }

    pushNGXInt(headers_out + NGX_HTTP_CLOJURE_HEADERSO_STATUS_OFFSET, (int) status);
    return r;
  }