static u_char *
ngx_http_vhost_traffic_status_display_set_server(ngx_http_request_t *r,
        ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel,
        const char *fmt, u_char *buf,
        ngx_http_vhost_traffic_status_loc_conf_t *vtscf)
{
    u_char                                  *p;
    ngx_str_t                               key;
    ngx_http_vhost_traffic_status_node_t    *vtsn;

    if (node != sentinel) {
        vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color;

        if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO) {
            key.len = ngx_strlen(vtsn->data) * 6;
            key.data = ngx_pcalloc(r->pool, key.len);
            if (key.data == NULL) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                        "ngx_pcalloc() failed");
                key.len = ngx_strlen(vtsn->data);
                key.data = vtsn->data;
                p = NULL;
                goto just_start;
            }
            p = key.data;

#if !defined(nginx_version) || nginx_version < 1007009
            p = (u_char *) ngx_http_vhost_traffic_status_escape_json(p, vtsn->data, ngx_strlen(vtsn->data));
#else
            p = (u_char *) ngx_escape_json(p, vtsn->data, ngx_strlen(vtsn->data));
#endif

just_start:

            buf = ngx_sprintf(buf, fmt,
                    key.data, vtsn->stat_request_counter, vtsn->stat_in_bytes, vtsn->stat_out_bytes,
                    vtsn->stat_1xx_counter, vtsn->stat_2xx_counter, vtsn->stat_3xx_counter,
                    vtsn->stat_4xx_counter, vtsn->stat_5xx_counter);

            vtscf->stats.stat_request_counter += vtsn->stat_request_counter;
            vtscf->stats.stat_in_bytes += vtsn->stat_in_bytes;
            vtscf->stats.stat_out_bytes += vtsn->stat_out_bytes;
            vtscf->stats.stat_1xx_counter += vtsn->stat_1xx_counter;
            vtscf->stats.stat_2xx_counter += vtsn->stat_2xx_counter;
            vtscf->stats.stat_3xx_counter += vtsn->stat_3xx_counter;
            vtscf->stats.stat_4xx_counter += vtsn->stat_4xx_counter;
            vtscf->stats.stat_5xx_counter += vtsn->stat_5xx_counter;

            if (p != NULL) {
                ngx_pfree(r->pool, key.data);
            }
        }

        buf = ngx_http_vhost_traffic_status_display_set_server(r, node->left, sentinel, fmt, buf, vtscf);
        buf = ngx_http_vhost_traffic_status_display_set_server(r, node->right, sentinel, fmt, buf, vtscf);
    }

    return buf;
}
static ngx_buf_t *
ngx_http_autoindex_json(ngx_http_request_t *r, ngx_array_t *entries,
    ngx_str_t *callback)
{
    size_t                       len;
    ngx_buf_t                   *b;
    ngx_uint_t                   i;
    ngx_http_autoindex_entry_t  *entry;

    len = sizeof("[" CRLF CRLF "]") - 1;

    if (callback) {
        len += sizeof("/* callback */" CRLF "();") - 1 + callback->len;
    }

    entry = entries->elts;

    for (i = 0; i < entries->nelts; i++) {
        entry[i].escape = ngx_escape_json(NULL, entry[i].name.data,
                                          entry[i].name.len);

        len += sizeof("{  }," CRLF) - 1
            + sizeof("\"name\":\"\"") - 1
            + entry[i].name.len + entry[i].escape
            + sizeof(", \"type\":\"directory\"") - 1
            + sizeof(", \"mtime\":\"Wed, 31 Dec 1986 10:00:00 GMT\"") - 1;

        if (entry[i].file) {
            len += sizeof(", \"size\":") - 1 + NGX_OFF_T_LEN;
        }
    }

    b = ngx_create_temp_buf(r->pool, len);
    if (b == NULL) {
        return NULL;
    }

    if (callback) {
        b->last = ngx_cpymem(b->last, "/* callback */" CRLF,
                             sizeof("/* callback */" CRLF) - 1);

        b->last = ngx_cpymem(b->last, callback->data, callback->len);

        *b->last++ = '(';
    }

    *b->last++ = '[';

    for (i = 0; i < entries->nelts; i++) {
        b->last = ngx_cpymem(b->last, CRLF "{ \"name\":\"",
                             sizeof(CRLF "{ \"name\":\"") - 1);

        if (entry[i].escape) {
            b->last = (u_char *) ngx_escape_json(b->last, entry[i].name.data,
                                                 entry[i].name.len);
        } else {
            b->last = ngx_cpymem(b->last, entry[i].name.data,
                                 entry[i].name.len);
        }

        b->last = ngx_cpymem(b->last, "\", \"type\":\"",
                             sizeof("\", \"type\":\"") - 1);

        if (entry[i].dir) {
            b->last = ngx_cpymem(b->last, "directory", sizeof("directory") - 1);

        } else if (entry[i].file) {
            b->last = ngx_cpymem(b->last, "file", sizeof("file") - 1);

        } else {
            b->last = ngx_cpymem(b->last, "other", sizeof("other") - 1);
        }

        b->last = ngx_cpymem(b->last, "\", \"mtime\":\"",
                             sizeof("\", \"mtime\":\"") - 1);

        b->last = ngx_http_time(b->last, entry[i].mtime);

        if (entry[i].file) {
            b->last = ngx_cpymem(b->last, "\", \"size\":",
                                 sizeof("\", \"size\":") - 1);
            b->last = ngx_sprintf(b->last, "%O", entry[i].size);

        } else {
            *b->last++ = '"';
        }

        b->last = ngx_cpymem(b->last, " },", sizeof(" },") - 1);
    }

    if (i > 0) {
        b->last--;  /* strip last comma */
    }

    b->last = ngx_cpymem(b->last, CRLF "]", sizeof(CRLF "]") - 1);

    if (callback) {
        *b->last++ = ')'; *b->last++ = ';';
    }

    return b;
}