static ngx_int_t
ngx_http_send_special_response(ngx_http_request_t *r,
    ngx_http_core_loc_conf_t *clcf, ngx_uint_t err)
{
    ngx_int_t     rc;
    ngx_str_t     tail, tokens;
    ngx_buf_t    *b;
    ngx_uint_t    msie_padding;
    ngx_chain_t   out[3];

    msie_padding = 0;

    if (ngx_http_error_pages[err].len) {

        if (clcf->server_tokens == 0) {
            ngx_str_set(&tail, ngx_http_error_tail);

        } else if (clcf->server_tokens == 1) {
            ngx_str_set(&tail, ngx_http_error_full_tail);

        } else {
            if (ngx_http_complex_value(r, &clcf->server_tokens_value, &tokens)
                != NGX_OK)
            {
                return NGX_ERROR;
            }

            if (tokens.len == 3
                && ngx_strncmp(tokens.data, "off", 3) == 0)
            {
                ngx_str_set(&tail, ngx_http_error_tail);

            } else if (tokens.len) {
                ngx_str_set(&tail, ngx_http_error_full_tail);

            } else {
                ngx_str_set(&tail, ngx_http_error_no_tail);
            }
        }

        r->headers_out.content_length_n = ngx_http_error_pages[err].len
                                          + tail.len;

        if (clcf->msie_padding
            && (r->headers_in.msie || r->headers_in.chrome)
            && r->http_version >= NGX_HTTP_VERSION_10
            && err >= NGX_HTTP_OFF_4XX)
        {
            r->headers_out.content_length_n +=
                                         sizeof(ngx_http_msie_padding) - 1;
            msie_padding = 1;
        }

        r->headers_out.content_type_len = sizeof("text/html") - 1;
        ngx_str_set(&r->headers_out.content_type, "text/html");
        r->headers_out.content_type_lowcase = NULL;

    } else {
        r->headers_out.content_length_n = 0;

#if (NGX_SUPPRESS_WARN)
        ngx_str_null(&tail);
#endif
    }

    if (r->headers_out.content_length) {
        r->headers_out.content_length->hash = 0;
        r->headers_out.content_length = NULL;
    }

    ngx_http_clear_accept_ranges(r);
    ngx_http_clear_last_modified(r);
    ngx_http_clear_etag(r);

    rc = ngx_http_send_header(r);

    if (rc == NGX_ERROR || r->header_only) {
        return rc;
    }

    if (ngx_http_error_pages[err].len == 0) {
        return ngx_http_send_special(r, NGX_HTTP_LAST);
    }

    b = ngx_calloc_buf(r->pool);
    if (b == NULL) {
        return NGX_ERROR;
    }

    b->memory = 1;
    b->pos = ngx_http_error_pages[err].data;
    b->last = ngx_http_error_pages[err].data + ngx_http_error_pages[err].len;

    out[0].buf = b;
    out[0].next = &out[1];

    b = ngx_calloc_buf(r->pool);
    if (b == NULL) {
        return NGX_ERROR;
    }

    b->memory = 1;
    b->pos = tail.data;
    b->last = tail.data + tail.len;

    out[1].buf = b;
    out[1].next = NULL;

    if (msie_padding) {
        b = ngx_calloc_buf(r->pool);
        if (b == NULL) {
            return NGX_ERROR;
        }

        b->memory = 1;
        b->pos = ngx_http_msie_padding;
        b->last = ngx_http_msie_padding + sizeof(ngx_http_msie_padding) - 1;

        out[1].next = &out[2];
        out[2].buf = b;
        out[2].next = NULL;
    }

    if (r == r->main) {
        b->last_buf = 1;
    }

    b->last_in_chain = 1;

    return ngx_http_output_filter(r, &out[0]);
}