utils::Status NgxEspRequest::AddHeaderToBackend(const std::string &key,
                                                const std::string &value) {
  ngx_table_elt_t *h = nullptr;
  for (auto &h_in : r_->headers_in) {
    if (key.size() == h_in.key.len &&
        strncasecmp(key.c_str(), reinterpret_cast<const char *>(h_in.key.data),
                    h_in.key.len) == 0) {
      h = &h_in;
      break;
    }
  }
  if (h == nullptr) {
    h = reinterpret_cast<ngx_table_elt_t *>(
        ngx_list_push(&r_->headers_in.headers));
    if (h == nullptr) {
      return utils::Status(Code::INTERNAL, "Out of memory");
    }

    h->lowcase_key =
        reinterpret_cast<u_char *>(ngx_pcalloc(r_->pool, key.size()));
    if (h->lowcase_key == nullptr) {
      return utils::Status(Code::INTERNAL, "Out of memory");
    }
    h->hash = ngx_hash_strlow(
        h->lowcase_key,
        reinterpret_cast<u_char *>(const_cast<char *>(key.c_str())),
        key.size());
  }

  if (ngx_str_copy_from_std(r_->pool, key, &h->key) != NGX_OK ||
      ngx_str_copy_from_std(r_->pool, value, &h->value) != NGX_OK) {
    return utils::Status(Code::INTERNAL, "Out of memory");
  }
  ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r_->connection->log, 0,
                 "updates header to backend: \"%V: %V\"", &h->key, &h->value);
  return utils::Status::OK;
}