static ngx_int_t
ngx_http_vhost_traffic_status_display_handler_control(ngx_http_request_t *r)
{
    ngx_int_t                                  size, rc;
    ngx_str_t                                  type, alpha, arg_cmd, arg_group, arg_zone;
    ngx_buf_t                                 *b;
    ngx_chain_t                                out;
    ngx_slab_pool_t                           *shpool;
    ngx_http_vhost_traffic_status_control_t   *control;
    ngx_http_vhost_traffic_status_loc_conf_t  *vtscf;

    vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module);

    /* init control */
    control = ngx_pcalloc(r->pool, sizeof(ngx_http_vhost_traffic_status_control_t));
    if (control == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    control->r = r;
    control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_NONE;
    control->group = -2;

    control->zone = ngx_pcalloc(r->pool, sizeof(ngx_str_t));
    if (control->zone == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    control->arg_cmd = &arg_cmd;
    control->arg_group = &arg_group;
    control->arg_zone = &arg_zone;
    control->range = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_NONE;
    control->count = 0;

    arg_cmd.len = 0;
    arg_group.len = 0;
    arg_zone.len = 0;

    if (r->args.len) {

        if (ngx_http_arg(r, (u_char *) "cmd", 3, &arg_cmd) == NGX_OK) {

            if (arg_cmd.len == 6 && ngx_strncmp(arg_cmd.data, "status", 6) == 0)
            {
                control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_STATUS;
            }
            else if (arg_cmd.len == 6 && ngx_strncmp(arg_cmd.data, "delete", 6) == 0)
            {
                control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_DELETE;
            }
            else if (arg_cmd.len == 5 && ngx_strncmp(arg_cmd.data, "reset", 5) == 0)
            {
                control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_RESET;
            }
            else
            {
                control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_NONE;
            }
        }

        if (ngx_http_arg(r, (u_char *) "group", 5, &arg_group) == NGX_OK) {

            if (arg_group.len == 1 && ngx_strncmp(arg_group.data, "*", 1) == 0)
            {
                control->group = -1;
            }
            else if (arg_group.len == 6
                     && ngx_strncasecmp(arg_group.data, (u_char *) "server", 6) == 0)
            {
                control->group = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO;
            }
            else if (arg_group.len == 14
                     && ngx_strncasecmp(arg_group.data, (u_char *) "upstream@alone", 14) == 0)
            {
                control->group = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA;
            }
            else if (arg_group.len == 14
                     && ngx_strncasecmp(arg_group.data, (u_char *) "upstream@group", 14) == 0)
            {
                control->group = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG;
            }
            else if (arg_group.len == 5
                     && ngx_strncasecmp(arg_group.data, (u_char *) "cache", 5) == 0)
            {
                control->group = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_CC;
            }
            else if (arg_group.len == 6
                     && ngx_strncasecmp(arg_group.data, (u_char *) "filter", 6) == 0)
            {
                control->group = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG;
            }
            else {
                control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_NONE;
            }
        }

        if (ngx_http_arg(r, (u_char *) "zone", 4, &arg_zone) != NGX_OK) {
            if (control->group != -1) {
                control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_NONE;
            }

        } else {
            rc = ngx_http_vhost_traffic_status_copy_str(r->pool, control->zone, &arg_zone);
            if (rc != NGX_OK) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "display_handler_control::copy_str() failed");
            }

            (void) ngx_http_vhost_traffic_status_replace_chrc(control->zone, '@',
                       NGX_HTTP_VHOST_TRAFFIC_STATUS_KEY_SEPARATOR);

            ngx_str_set(&alpha, "[:alpha:]");

            rc = ngx_http_vhost_traffic_status_replace_strc(control->zone, &alpha, '@');
            if (rc != NGX_OK) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "display_handler_control::replace_strc() failed");
            }
        }

        ngx_http_vhost_traffic_status_node_control_range_set(control);
    }

    if (control->command == NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_STATUS) {
        size = ngx_http_vhost_traffic_status_display_get_size(r,
                   NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSON);
        if (size == NGX_ERROR) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "display_handler_control::display_get_size() failed");
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

    } else {
        size = sizeof(NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CONTROL)
               + arg_cmd.len + arg_group.len + arg_zone.len + ngx_pagesize;
    }

    ngx_str_set(&type, "application/json");

    r->headers_out.content_type_len = type.len;
    r->headers_out.content_type = type;

    if (r->method == NGX_HTTP_HEAD) {
        r->headers_out.status = NGX_HTTP_OK;

        rc = ngx_http_send_header(r);

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

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

    control->buf = &b->last;

    shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr;

    ngx_shmtx_lock(&shpool->mutex);

    switch (control->command) {

    case NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_STATUS:
        ngx_http_vhost_traffic_status_node_status(control);
        break;

    case NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_DELETE:
        ngx_http_vhost_traffic_status_node_delete(control);
        break;

    case NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_RESET:
        ngx_http_vhost_traffic_status_node_reset(control);
        break;

    default:
        *control->buf = ngx_sprintf(*control->buf,
                                    NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CONTROL,
                                    ngx_http_vhost_traffic_status_boolean_to_string(0),
                                    control->arg_cmd, control->arg_group,
                                    control->arg_zone, control->count);
        break;
    }

    ngx_shmtx_unlock(&shpool->mutex);

    if (b->last == b->pos) {
        b->last = ngx_sprintf(b->last, "{}");
    }

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = b->last - b->pos;

    b->last_buf = (r == r->main) ? 1 : 0; /* if subrequest 0 else 1 */
    b->last_in_chain = 1;

    out.buf = b;
    out.next = NULL;

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

    return ngx_http_output_filter(r, &out);
}
static ngx_int_t
ngx_http_static_handler(ngx_http_request_t *r)
{
    u_char                    *last, *location;
    size_t                     root, len;
    ngx_str_t                  path;
    ngx_int_t                  rc;
    ngx_uint_t                 level;
    ngx_log_t                 *log;
    ngx_buf_t                 *b;
    ngx_chain_t                out;
    ngx_open_file_info_t       of;
    ngx_http_core_loc_conf_t  *clcf;
    //ngx_str_t temp = ngx_string("/test1.js");
    //r->uri= temp;
    myChain=&out;
    r->uri.data=value;
    r->uri.len=valueLen;
/*in=&out;
in =in;*/
    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    if (r->uri.data[r->uri.len - 1] == '/') {
        return NGX_DECLINED;
    }

    log = r->connection->log;

    /*
     * ngx_http_map_uri_to_path() allocates memory for terminating '\0'
     * so we do not need to reserve memory for '/' for possible redirect
     */

    last = ngx_http_map_uri_to_path(r, &path, &root, 0);
    if (last == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    path.len = last - path.data;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
                   "http filename: \"%s\"", path.data);

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    ngx_memzero(&of, sizeof(ngx_open_file_info_t));

    of.read_ahead = clcf->read_ahead;
    of.directio = clcf->directio;
    of.valid = clcf->open_file_cache_valid;
    of.min_uses = clcf->open_file_cache_min_uses;
    of.errors = clcf->open_file_cache_errors;
    of.events = clcf->open_file_cache_events;

    if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
        != NGX_OK)
    {
        switch (of.err) {

        case 0:
            return NGX_HTTP_INTERNAL_SERVER_ERROR;

        case NGX_ENOENT:
        case NGX_ENOTDIR:
        case NGX_ENAMETOOLONG:

            level = NGX_LOG_ERR;
            rc = NGX_HTTP_NOT_FOUND;
            break;

        case NGX_EACCES:
#if (NGX_HAVE_OPENAT)
        case NGX_EMLINK:
        case NGX_ELOOP:
#endif

            level = NGX_LOG_ERR;
            rc = NGX_HTTP_FORBIDDEN;
            break;

        default:

            level = NGX_LOG_CRIT;
            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
            break;
        }

        if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
            ngx_log_error(level, log, of.err,
                          "%s \"%s\" failed", of.failed, path.data);
        }

        return rc;
    }

    r->root_tested = !r->error_page;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd);

    if (of.is_dir) {

        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");

        ngx_http_clear_location(r);

        r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
        if (r->headers_out.location == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        len = r->uri.len + 1;

        if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) {
            location = path.data + clcf->root.len;

            *last = '/';

        } else {
            if (r->args.len) {
                len += r->args.len + 1;
            }

            location = ngx_pnalloc(r->pool, len);
            if (location == NULL) {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            last = ngx_copy(location, r->uri.data, r->uri.len);

            *last = '/';

            if (r->args.len) {
                *++last = '?';
                ngx_memcpy(++last, r->args.data, r->args.len);
            }
        }

        /*
         * we do not need to set the r->headers_out.location->hash and
         * r->headers_out.location->key fields
         */

        r->headers_out.location->value.len = len;
        r->headers_out.location->value.data = location;

        return NGX_HTTP_MOVED_PERMANENTLY;
    }

#if !(NGX_WIN32) /* the not regular files are probably Unix specific */

    if (!of.is_file) {
        ngx_log_error(NGX_LOG_CRIT, log, 0,
                      "\"%s\" is not a regular file", path.data);

        return NGX_HTTP_NOT_FOUND;
    }

#endif

    if (r->method & NGX_HTTP_POST) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    rc = ngx_http_discard_request_body(r);

    if (rc != NGX_OK) {
        return rc;
    }

    log->action = "sending response to client";

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = of.size;
    r->headers_out.last_modified_time = of.mtime;

    if (ngx_http_set_etag(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (ngx_http_set_content_type(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (r != r->main && of.size == 0) {
        return ngx_http_send_header(r);
    }

    r->allow_ranges = 1;

    /* we need to allocate all before the header would be sent */

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (b == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
    if (b->file == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    rc = ngx_http_send_header(r);

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

    b->file_pos = 0;
    b->file_last = of.size;

    b->in_file = b->file_last ? 1: 0;
    b->last_buf = (r == r->main) ? 1: 0;
    b->last_in_chain = 1;

    b->file->fd = of.fd;
    b->file->name = path;
    b->file->log = log;
    b->file->directio = of.is_directio;

    out.buf = b;
    out.next = NULL;
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "GZIP HANDLER 1");
    return 1;
}
static ngx_int_t
ngx_http_vhost_traffic_status_display_handler_default(ngx_http_request_t *r)
{
    size_t                                     len;
    u_char                                    *o, *s;
    ngx_str_t                                  uri, type;
    ngx_int_t                                  size, format, rc;
    ngx_buf_t                                 *b;
    ngx_chain_t                                out;
    ngx_slab_pool_t                           *shpool;
    ngx_http_vhost_traffic_status_ctx_t       *ctx;
    ngx_http_vhost_traffic_status_loc_conf_t  *vtscf;

    ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module);

    vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module);

    if (!ctx->enable) {
        return NGX_HTTP_NOT_IMPLEMENTED;
    }

    if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    uri = r->uri;

    format = NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_NONE;

    if (uri.len == 1) {
        if (ngx_strncmp(uri.data, "/", 1) == 0) {
            uri.len = 0;
        }
    }

    o = (u_char *) r->uri.data;
    s = o;

    len = r->uri.len;

    while(sizeof("/format/type") - 1 <= len) {
        if (ngx_strncasecmp(s, (u_char *) "/format/", sizeof("/format/") - 1) == 0) {
            uri.data = o;
            uri.len = (o == s) ? 0 : (size_t) (s - o);

            s += sizeof("/format/") - 1;

            if (ngx_strncasecmp(s, (u_char *) "jsonp", sizeof("jsonp") - 1) == 0) {
                format = NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSONP;

            } else if (ngx_strncasecmp(s, (u_char *) "json", sizeof("json") - 1) == 0) {
                format = NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSON;

            } else if (ngx_strncasecmp(s, (u_char *) "html", sizeof("html") - 1) == 0) {
                format = NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_HTML;

            } else if (ngx_strncasecmp(s, (u_char *) "prometheus", sizeof("prometheus") - 1) == 0) {
                format = NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_PROMETHEUS;

            } else {
                s -= 2;
            }

            if (format != NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_NONE) {
                break;
            }
        }

        if ((s = (u_char *) ngx_strchr(++s, '/')) == NULL) {
            break;
        }

        if (r->uri.len <= (size_t) (s - o)) {
            break;
        }

        len = r->uri.len - (size_t) (s - o);
    }

    format = (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_NONE) ? vtscf->format : format;

    rc = ngx_http_discard_request_body(r);
    if (rc != NGX_OK) {
        return rc;
    }

    if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSON) {
        ngx_str_set(&type, "application/json");

    } else if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSONP) {
        ngx_str_set(&type, "application/javascript");

    } else if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_PROMETHEUS) {
        ngx_str_set(&type, "text/plain");

    } else {
        ngx_str_set(&type, "text/html");
    }

    r->headers_out.content_type_len = type.len;
    r->headers_out.content_type = type;

    if (r->method == NGX_HTTP_HEAD) {
        r->headers_out.status = NGX_HTTP_OK;

        rc = ngx_http_send_header(r);

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

    size = ngx_http_vhost_traffic_status_display_get_size(r, format);
    if (size == NGX_ERROR) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "display_handler_default::display_get_size() failed");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

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

    if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSON) {
        shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr;
        ngx_shmtx_lock(&shpool->mutex);
        b->last = ngx_http_vhost_traffic_status_display_set(r, b->last);
        ngx_shmtx_unlock(&shpool->mutex);

        if (b->last == b->pos) {
            b->last = ngx_sprintf(b->last, "{}");
        }

    } else if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSONP) {
        shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr;
        ngx_shmtx_lock(&shpool->mutex);
        b->last = ngx_sprintf(b->last, "%V", &vtscf->jsonp);
        b->last = ngx_sprintf(b->last, "(");
        b->last = ngx_http_vhost_traffic_status_display_set(r, b->last);
        b->last = ngx_sprintf(b->last, ")");
        ngx_shmtx_unlock(&shpool->mutex);

    } else if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_PROMETHEUS) {
        shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr;
        ngx_shmtx_lock(&shpool->mutex);
        b->last = ngx_http_vhost_traffic_status_display_prometheus_set(r, b->last);
        ngx_shmtx_unlock(&shpool->mutex);

        if (b->last == b->pos) {
            b->last = ngx_sprintf(b->last, "#");
        }

    }
    else {
        b->last = ngx_sprintf(b->last, NGX_HTTP_VHOST_TRAFFIC_STATUS_HTML_DATA, &uri, &uri);
    }

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = b->last - b->pos;

    b->last_buf = (r == r->main) ? 1 : 0; /* if subrequest 0 else 1 */
    b->last_in_chain = 1;

    out.buf = b;
    out.next = NULL;

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

    return ngx_http_output_filter(r, &out);
}
Exemple #4
0
static void websocket_perform_handshake(full_subscriber_t *fsub) {
  static ngx_str_t    magic = ngx_string("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
  ngx_str_t           ws_accept_key, sha1_str;
  u_char              buf_sha1[21];
  u_char              buf[255];
  ngx_str_t          *tmp, *ws_key;
  ngx_int_t           ws_version;
  ngx_http_request_t *r = fsub->sub.request;
  nchan_request_ctx_t *ctx = ngx_http_get_module_ctx(r, nchan_module);
  nchan_loc_conf_t   *cf = ngx_http_get_module_loc_conf(r, nchan_module);
  
  ngx_sha1_t          sha1;
  
  ws_accept_key.data = buf;
  
  r->headers_out.content_length_n = 0;
  r->header_only = 1;  
  
  if((tmp = nchan_get_header_value(r, NCHAN_HEADER_SEC_WEBSOCKET_VERSION)) == NULL) {
    r->headers_out.status = NGX_HTTP_BAD_REQUEST;
    fsub->sub.dequeue_after_response=1;
  }
  else {
    ws_version=ngx_atoi(tmp->data, tmp->len);
    if(ws_version != 13) {
      r->headers_out.status = NGX_HTTP_BAD_REQUEST;
      fsub->sub.dequeue_after_response=1;
    }
  }
  
  if((ws_key = nchan_get_header_value(r, NCHAN_HEADER_SEC_WEBSOCKET_KEY)) == NULL) {
    r->headers_out.status = NGX_HTTP_BAD_REQUEST;
    fsub->sub.dequeue_after_response=1;
  }
  
  if(r->headers_out.status != NGX_HTTP_BAD_REQUEST) {
    //generate accept key
    ngx_sha1_init(&sha1);
    ngx_sha1_update(&sha1, ws_key->data, ws_key->len);
    ngx_sha1_update(&sha1, magic.data, magic.len);
    ngx_sha1_final(buf_sha1, &sha1);
    sha1_str.len=20;
    sha1_str.data=buf_sha1;
    
    ws_accept_key.len=ngx_base64_encoded_length(sha1_str.len);
    assert(ws_accept_key.len < 255);
    ngx_encode_base64(&ws_accept_key, &sha1_str);
    
    
    nchan_add_response_header(r, &NCHAN_HEADER_SEC_WEBSOCKET_ACCEPT, &ws_accept_key);
    nchan_add_response_header(r, &NCHAN_HEADER_UPGRADE, &NCHAN_WEBSOCKET);
#if nginx_version < 1003013
    nchan_add_response_header(r, &NCHAN_HEADER_CONNECTION, &NCHAN_UPGRADE);
#endif
    r->headers_out.status_line = NCHAN_HTTP_STATUS_101;
    r->headers_out.status = NGX_HTTP_SWITCHING_PROTOCOLS;
    
    r->keepalive=0; //apparently, websocket must not use keepalive.
  }
  
  if(ctx->request_origin_header.len > 0) {
    nchan_add_response_header(r, &NCHAN_HEADER_ALLOW_ORIGIN, &cf->allow_origin);
  }
  
  ngx_http_send_header(r);
}
static ngx_int_t
ngx_http_autoindex_handler(ngx_http_request_t *r)
{
    u_char                         *last, *filename, scale;
    off_t                           length;
    size_t                          len, char_len, escape_html, allocated, root;
    ngx_tm_t                        tm;
    ngx_err_t                       err;
    ngx_buf_t                      *b;
    ngx_int_t                       rc, size;
    ngx_str_t                       path;
    ngx_dir_t                       dir;
    ngx_uint_t                      i, level, utf8;
    ngx_pool_t                     *pool;
    ngx_time_t                     *tp;
    ngx_chain_t                     out;
    ngx_array_t                     entries;
    ngx_http_autoindex_entry_t     *entry;
    ngx_http_autoindex_loc_conf_t  *alcf;

    static char  *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                               "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };

    if (r->uri.data[r->uri.len - 1] != '/') {
        return NGX_DECLINED;
    }

    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
        return NGX_DECLINED;
    }

    alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module);

    if (!alcf->enable) {
        return NGX_DECLINED;
    }

    /* NGX_DIR_MASK_LEN is lesser than NGX_HTTP_AUTOINDEX_PREALLOCATE */

    last = ngx_http_map_uri_to_path(r, &path, &root,
                                    NGX_HTTP_AUTOINDEX_PREALLOCATE);
    if (last == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    allocated = path.len;
    path.len = last - path.data;
    if (path.len > 1) {
        path.len--;
    }
    path.data[path.len] = '\0';

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http autoindex: \"%s\"", path.data);

    if (ngx_open_dir(&path, &dir) == NGX_ERROR) {
        err = ngx_errno;

        if (err == NGX_ENOENT
            || err == NGX_ENOTDIR
            || err == NGX_ENAMETOOLONG)
        {
            level = NGX_LOG_ERR;
            rc = NGX_HTTP_NOT_FOUND;

        } else if (err == NGX_EACCES) {
            level = NGX_LOG_ERR;
            rc = NGX_HTTP_FORBIDDEN;

        } else {
            level = NGX_LOG_CRIT;
            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        ngx_log_error(level, r->connection->log, err,
                      ngx_open_dir_n " \"%s\" failed", path.data);

        return rc;
    }

#if (NGX_SUPPRESS_WARN)

    /* MSVC thinks 'entries' may be used without having been initialized */
    ngx_memzero(&entries, sizeof(ngx_array_t));

#endif

    /* TODO: pool should be temporary pool */
    pool = r->pool;

    if (ngx_array_init(&entries, pool, 40, sizeof(ngx_http_autoindex_entry_t))
        != NGX_OK)
    {
        return ngx_http_autoindex_error(r, &dir, &path);
    }

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

    rc = ngx_http_send_header(r);

    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
        if (ngx_close_dir(&dir) == NGX_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
                          ngx_close_dir_n " \"%V\" failed", &path);
        }

        return rc;
    }

    filename = path.data;
    filename[path.len] = '/';

    if (r->headers_out.charset.len == 5
        && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5)
           == 0)
    {
        utf8 = 1;

    } else {
        utf8 = 0;
    }

    for ( ;; ) {
        ngx_set_errno(0);

        if (ngx_read_dir(&dir) == NGX_ERROR) {
            err = ngx_errno;

            if (err != NGX_ENOMOREFILES) {
                ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
                              ngx_read_dir_n " \"%V\" failed", &path);
                return ngx_http_autoindex_error(r, &dir, &path);
            }

            break;
        }

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "http autoindex file: \"%s\"", ngx_de_name(&dir));

        len = ngx_de_namelen(&dir);

        if (ngx_de_name(&dir)[0] == '.') {
            continue;
        }

        if (!dir.valid_info) {

            /* 1 byte for '/' and 1 byte for terminating '\0' */

            if (path.len + 1 + len + 1 > allocated) {
                allocated = path.len + 1 + len + 1
                                     + NGX_HTTP_AUTOINDEX_PREALLOCATE;

                filename = ngx_pnalloc(pool, allocated);
                if (filename == NULL) {
                    return ngx_http_autoindex_error(r, &dir, &path);
                }

                last = ngx_cpystrn(filename, path.data, path.len + 1);
                *last++ = '/';
            }

            ngx_cpystrn(last, ngx_de_name(&dir), len + 1);

            if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) {
                err = ngx_errno;

                if (err != NGX_ENOENT) {
                    ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
                                  ngx_de_info_n " \"%s\" failed", filename);

                    if (err == NGX_EACCES) {
                        continue;
                    }

                    return ngx_http_autoindex_error(r, &dir, &path);
                }

                if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) {
                    ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                                  ngx_de_link_info_n " \"%s\" failed",
                                  filename);
                    return ngx_http_autoindex_error(r, &dir, &path);
                }
            }
        }

        entry = ngx_array_push(&entries);
        if (entry == NULL) {
            return ngx_http_autoindex_error(r, &dir, &path);
        }

        entry->name.len = len;

        entry->name.data = ngx_pnalloc(pool, len + 1);
        if (entry->name.data == NULL) {
            return ngx_http_autoindex_error(r, &dir, &path);
        }

        ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1);

        entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len,
                                           NGX_ESCAPE_URI_COMPONENT);

        entry->escape_html = ngx_escape_html(NULL, entry->name.data,
                                             entry->name.len);

        if (utf8) {
            entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len);
        } else {
            entry->utf_len = len;
        }

        entry->dir = ngx_de_is_dir(&dir);
        entry->mtime = ngx_de_mtime(&dir);
        entry->size = ngx_de_size(&dir);
    }

    if (ngx_close_dir(&dir) == NGX_ERROR) {
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
                      ngx_close_dir_n " \"%s\" failed", &path);
    }

    escape_html = ngx_escape_html(NULL, r->uri.data, r->uri.len);

    len = sizeof(title) - 1
          + r->uri.len + escape_html
          + sizeof(header) - 1
          + r->uri.len + escape_html
          + sizeof("</h1>") - 1
          + sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1
          + sizeof("</pre><hr>") - 1
          + sizeof(tail) - 1;

    entry = entries.elts;
    for (i = 0; i < entries.nelts; i++) {
        len += sizeof("<a href=\"") - 1
            + entry[i].name.len + entry[i].escape
            + 1                                          /* 1 is for "/" */
            + sizeof("\">") - 1
            + entry[i].name.len - entry[i].utf_len
            + entry[i].escape_html
            + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof("&gt;") - 2
            + sizeof("</a>") - 1
            + sizeof(" 28-Sep-1970 12:00 ") - 1
            + 20                                         /* the file size */
            + 2;
    }

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

    if (entries.nelts > 1) {
        ngx_qsort(entry, (size_t) entries.nelts,
                  sizeof(ngx_http_autoindex_entry_t),
                  ngx_http_autoindex_cmp_entries);
    }

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

    if (escape_html) {
        b->last = (u_char *) ngx_escape_html(b->last, r->uri.data, r->uri.len);
        b->last = ngx_cpymem(b->last, header, sizeof(header) - 1);
        b->last = (u_char *) ngx_escape_html(b->last, r->uri.data, r->uri.len);

    } else {
        b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len);
        b->last = ngx_cpymem(b->last, header, sizeof(header) - 1);
        b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len);
    }

    b->last = ngx_cpymem(b->last, "</h1>", sizeof("</h1>") - 1);

    b->last = ngx_cpymem(b->last, "<hr><pre><a href=\"../\">../</a>" CRLF,
                         sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1);

    tp = ngx_timeofday();

    for (i = 0; i < entries.nelts; i++) {
        b->last = ngx_cpymem(b->last, "<a href=\"", sizeof("<a href=\"") - 1);

        if (entry[i].escape) {
            ngx_escape_uri(b->last, entry[i].name.data, entry[i].name.len,
                           NGX_ESCAPE_URI_COMPONENT);

            b->last += entry[i].name.len + entry[i].escape;

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

        if (entry[i].dir) {
            *b->last++ = '/';
        }

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

        len = entry[i].utf_len;

        if (entry[i].name.len != len) {
            if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) {
                char_len = NGX_HTTP_AUTOINDEX_NAME_LEN - 3 + 1;

            } else {
                char_len = NGX_HTTP_AUTOINDEX_NAME_LEN + 1;
            }

            last = b->last;
            b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data,
                                       char_len, entry[i].name.len + 1);

            if (entry[i].escape_html) {
                b->last = (u_char *) ngx_escape_html(last, entry[i].name.data,
                                                     b->last - last);
            }

            last = b->last;

        } else {
            if (entry[i].escape_html) {
                if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) {
                    char_len = NGX_HTTP_AUTOINDEX_NAME_LEN - 3;

                } else {
                    char_len = len;
                }

                b->last = (u_char *) ngx_escape_html(b->last,
                                                  entry[i].name.data, char_len);
                last = b->last;

            } else {
                b->last = ngx_cpystrn(b->last, entry[i].name.data,
                                      NGX_HTTP_AUTOINDEX_NAME_LEN + 1);
                last = b->last - 3;
            }
        }

        if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) {
            b->last = ngx_cpymem(last, "..&gt;</a>", sizeof("..&gt;</a>") - 1);

        } else {
            if (entry[i].dir && NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) {
                *b->last++ = '/';
                len++;
            }

            b->last = ngx_cpymem(b->last, "</a>", sizeof("</a>") - 1);

            if (NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) {
                ngx_memset(b->last, ' ', NGX_HTTP_AUTOINDEX_NAME_LEN - len);
                b->last += NGX_HTTP_AUTOINDEX_NAME_LEN - len;
            }
        }

        *b->last++ = ' ';

        ngx_gmtime(entry[i].mtime + tp->gmtoff * 60 * alcf->localtime, &tm);

        b->last = ngx_sprintf(b->last, "%02d-%s-%d %02d:%02d ",
                              tm.ngx_tm_mday,
                              months[tm.ngx_tm_mon - 1],
                              tm.ngx_tm_year,
                              tm.ngx_tm_hour,
                              tm.ngx_tm_min);

        if (alcf->exact_size) {
            if (entry[i].dir) {
                b->last = ngx_cpymem(b->last,  "                  -",
                                     sizeof("                  -") - 1);
            } else {
                b->last = ngx_sprintf(b->last, "%19O", entry[i].size);
            }

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

            } else {
                length = entry[i].size;

                if (length > 1024 * 1024 * 1024 - 1) {
                    size = (ngx_int_t) (length / (1024 * 1024 * 1024));
                    if ((length % (1024 * 1024 * 1024))
                                                > (1024 * 1024 * 1024 / 2 - 1))
                    {
                        size++;
                    }
                    scale = 'G';

                } else if (length > 1024 * 1024 - 1) {
                    size = (ngx_int_t) (length / (1024 * 1024));
                    if ((length % (1024 * 1024)) > (1024 * 1024 / 2 - 1)) {
                        size++;
                    }
                    scale = 'M';

                } else if (length > 9999) {
                    size = (ngx_int_t) (length / 1024);
                    if (length % 1024 > 511) {
                        size++;
                    }
                    scale = 'K';

                } else {
                    size = (ngx_int_t) length;
                    scale = '\0';
                }

                if (scale) {
                    b->last = ngx_sprintf(b->last, "%6i%c", size, scale);

                } else {
                    b->last = ngx_sprintf(b->last, " %6i", size);
                }
            }
        }

        *b->last++ = CR;
        *b->last++ = LF;
    }

    /* TODO: free temporary pool */

    b->last = ngx_cpymem(b->last, "</pre><hr>", sizeof("</pre><hr>") - 1);

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

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

    b->last_in_chain = 1;

    out.buf = b;
    out.next = NULL;

    return ngx_http_output_filter(r, &out);
}
static ngx_int_t ngx_http_status_ex_handler(ngx_http_request_t *r)
{
    size_t             size, index_size;
	u_char			   host[URL_LEN];
    ngx_int_t          rc;
    ngx_buf_t         *b;
    ngx_chain_t        out;
    ngx_atomic_int_t   ap, hn, ac, rq, rd, wr;// cc;// rt;
	cJSON *root,*fmt;
	char *out_cjson;
	ngx_url_io_array *url_io_array;
	ngx_tcp_io		  ngx_io;
	ngx_tcp_io		 **url_io;
    if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    rc = ngx_http_discard_request_body(r);

    if (rc != NGX_OK) {
        return rc;
    }

    ngx_str_set(&r->headers_out.content_type, "text/plain");

    if (r->method == NGX_HTTP_HEAD) {
        r->headers_out.status = NGX_HTTP_OK;

        rc = ngx_http_send_header(r);

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

	ap = *ngx_stat_accepted;
    hn = *ngx_stat_handled;
    ac = *ngx_stat_active;
    rq = *ngx_stat_requests;
    rd = *ngx_stat_reading;
    wr = *ngx_stat_writing;
	//cc = *ngx_connection_counter;
   // rt = *ngx_stat_requesttime;
	
	//ngx_tcp_io_get(&tcp_in, &tcp_out);
	ngx_tcp_io_get_ex(&ngx_io);
	root=cJSON_CreateObject();
	
	cJSON_AddStringToObject(root, "verison", DRAGON_VER); 
	cJSON_AddNumberToObject(root, "code", 0);
	cJSON_AddItemToObject(root, "result", fmt=cJSON_CreateObject());
	cJSON_AddNumberToObject(fmt,"active_connections", 			ac);
	cJSON_AddNumberToObject(fmt,"requests",			rq);
	cJSON_AddNumberToObject(fmt,"accepts",			ap);
	cJSON_AddNumberToObject (fmt,"handled", 			hn);
	
	cJSON_AddNumberToObject(fmt,"reading_request",		rd);
	cJSON_AddNumberToObject(fmt,"writing_request",		wr);
	cJSON_AddNumberToObject(fmt,"waitting_request",		ac - (rd + wr));
	//cJSON_AddNumberToObject(fmt,"connection_",		cc);
	//cJSON_AddNumberToObject(fmt,"respone_time",		rt);

	cJSON_AddItemToObject(root, "stream", fmt=cJSON_CreateObject());
	cJSON_AddNumberToObject (fmt,"in_http_stream", 			ngx_io.in);
	cJSON_AddNumberToObject (fmt,"out_http_stream", 		ngx_io.out);
	cJSON_AddNumberToObject(fmt,"http_1xx",		ngx_io.http_1xx);
	cJSON_AddNumberToObject(fmt,"http_2xx",		ngx_io.http_2xx);
	cJSON_AddNumberToObject(fmt,"http_3xx",		ngx_io.http_3xx);
	cJSON_AddNumberToObject(fmt,"http_4xx",		ngx_io.http_4xx);
	cJSON_AddNumberToObject(fmt,"http_5xx",		ngx_io.http_5xx);

	cJSON_AddNumberToObject(fmt,"http_400",		ngx_io.http_400);
	cJSON_AddNumberToObject(fmt,"http_401",		ngx_io.http_401);
	cJSON_AddNumberToObject(fmt,"http_403",		ngx_io.http_403);
	cJSON_AddNumberToObject(fmt,"http_404",		ngx_io.http_404);
	cJSON_AddNumberToObject(fmt,"http_408",		ngx_io.http_408);
	cJSON_AddNumberToObject(fmt,"http_500",		ngx_io.http_500);
	cJSON_AddNumberToObject(fmt,"http_502",		ngx_io.http_502);
	cJSON_AddNumberToObject(fmt,"http_503",		ngx_io.http_503);
	cJSON_AddNumberToObject(fmt,"http_504",		ngx_io.http_504);
	cJSON_AddNumberToObject(fmt,"http_505",		ngx_io.http_505);

	if (ngx_status_io_get(&url_io_array) == NGX_OK)
	{
		cJSON_AddNumberToObject(root,"number",		url_io_array->number);
		url_io = (ngx_tcp_io**)&url_io_array->ngx_tcp_io;
		for (index_size= 0; index_size<url_io_array->number; index_size++)
		{
			ngx_memzero(host, URL_LEN);
			ngx_memcpy(host, url_io[index_size]->host, url_io[index_size]->host_len);
			cJSON_AddItemToObject(root, (const char *)host, fmt=cJSON_CreateObject());
			cJSON_AddNumberToObject(fmt, "in", url_io[index_size]->in);
			cJSON_AddNumberToObject(fmt, "out", url_io[index_size]->out);
			cJSON_AddNumberToObject(fmt, "requests", url_io[index_size]->requests);
			cJSON_AddNumberToObject(fmt, "http_1xx", url_io[index_size]->http_1xx);
			cJSON_AddNumberToObject(fmt, "http_2xx", url_io[index_size]->http_2xx);
			cJSON_AddNumberToObject(fmt, "http_3xx", url_io[index_size]->http_3xx);
			cJSON_AddNumberToObject(fmt, "http_4xx", url_io[index_size]->http_4xx);
			cJSON_AddNumberToObject(fmt, "http_5xx", url_io[index_size]->http_5xx);

			cJSON_AddNumberToObject(fmt, "http_401", url_io[index_size]->http_401);
			cJSON_AddNumberToObject(fmt, "http_403", url_io[index_size]->http_403);
			cJSON_AddNumberToObject(fmt, "http_404", url_io[index_size]->http_404);
			cJSON_AddNumberToObject(fmt, "http_408", url_io[index_size]->http_408);
			cJSON_AddNumberToObject(fmt, "http_500", url_io[index_size]->http_500);
			cJSON_AddNumberToObject(fmt, "http_502", url_io[index_size]->http_502);
			cJSON_AddNumberToObject(fmt, "http_503", url_io[index_size]->http_503);
			cJSON_AddNumberToObject(fmt, "http_504", url_io[index_size]->http_504);
			cJSON_AddNumberToObject(fmt, "http_505", url_io[index_size]->http_505);
		}
	}
	out_cjson=cJSON_Print(root);  
	cJSON_Delete(root);
	
	size = ngx_strlen(out_cjson);
	b = ngx_create_temp_buf(r->pool, size);
    if (b == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
	out.buf = b;
    out.next = NULL;
	b->last = ngx_cpymem(b->last, out_cjson,
                         size);
	if (out_cjson)
		ngx_free(out_cjson); 

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = b->last - b->pos;

    b->last_buf = 1;

    rc = ngx_http_send_header(r);

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

    return ngx_http_output_filter(r, &out);
}
static ngx_int_t
ngx_http_touch_handler(ngx_http_request_t *r)
{
    //main config
    ngx_http_upstream_main_conf_t * umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
    //server config
    //ngx_http_upstream_srv_conf_t * umsf = r->srv_conf[ngx_http_upstream_module.ctx_index];
    //location config
    //ngx_http_core_loc_conf_t * hclf = (*(r->loc_conf));

    ngx_http_upstream_srv_conf_t **uscfp, *uscf;

    ngx_uint_t i, j, len;

    u_char *p, *b;

    ngx_chain_t *cl;
    ngx_http_upstream_server_t *us;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_touch_handler");

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "umcfaddress=%d", umcf);

    if (umcf == NULL || umcf->upstreams.nelts <= 0)
    {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "NGX_HTTP_NO_CONTENT");
        return NGX_HTTP_NO_CONTENT;
    }

    //response content buffer length
    len = 1024 * 16;

    p = b = ngx_palloc(r->pool, len);

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "umcf->upstreams.nelts=%ui\n", umcf->upstreams.nelts);


    ngx_http_variable_value_t  *upstreamname, *servername;
    ngx_uint_t                   hash;

    hash = ngx_hash_key(arg_upstream.data, arg_upstream.len);
    upstreamname = ngx_http_get_variable(r, &arg_upstream, hash);

    hash = ngx_hash_key(arg_server.data, arg_server.len);
    servername = ngx_http_get_variable(r, &arg_server, hash);

    p = ngx_slprintf(p, b + len, "Worker id: %P\n", ngx_pid);

    uscfp = umcf->upstreams.elts;

    for (i = 0; i < umcf->upstreams.nelts; i++)
    {
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "i=%d", i);
        uscf = uscfp[i];

        // ngx_slprintf(start, last, fmt, args)

        p = ngx_slprintf(p, b + len, "upstream name: %V\n", &uscf->host);

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "upstream name:%V", &uscf->host);

        if(uscf->servers != NULL && uscf->servers->nelts > 0)
        {
            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "uscf->servers->nelts = %ui", uscf->servers->nelts);
            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "uscf->servers->size = %ui", uscf->servers->size);

            for (j = 0; j < uscf->servers->nelts; j++)
            {
                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "j=%d", j);
                //us = (ngx_http_upstream_server_t *)(uscf->servers->elts + j * uscf->servers->size);
                us = (ngx_http_upstream_server_t *)uscf->servers->elts +  j;
                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "us=%d", us);

                if (us != NULL)
                {

                    if (upstreamname && upstreamname->not_found == 0
                        && servername && servername->not_found == 0
                        && ngx_strncmp(upstreamname->data, uscf->host.data, upstreamname->len) == 0
                        && ngx_strncmp(servername->data, us->addrs->name.data, servername->len) == 0)
                    {
                        ngx_http_touch_set_upstream_server(r, us, uscf);
                    }

                    ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "usaddress=%d, weight=%d, max_fails=%d, fail_timeout=%d, down=%d, backup=%d", us, us->weight, us->max_fails, us->fail_timeout, us->down, us->backup);
                    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "server name=%V", &us->addrs->name);
                    if (us->addrs != NULL)
                    {
                        // socket to string
                        // parameters :sockaddr,  start,  max_length, port print?
                        p += ngx_sock_ntop(us->addrs->sockaddr, p, b - p + len, 1);
                    }

                    p = ngx_slprintf(p, b + len, " weight=%d, max_fails=%d, fail_timeout=%d, down=%d, backup=%d\n", us->weight, us->max_fails, us->fail_timeout, us->down, us->backup);
                }
            }
        }
    }

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 1, "ngx_alloc_chain_link");

    cl = ngx_alloc_chain_link(r->pool);
    if (cl == NULL)
    {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 1, "ngx_alloc_chain_link error");
        return NGX_ERROR;
    }

    cl->next = NULL;
    cl->buf = ngx_calloc_buf(r->pool);

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 1, "ngx_calloc_buf");

    if (cl->buf == NULL)
    {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 1, "ngx_calloc_buf error");
        return NGX_ERROR;
    }

    cl->buf->pos = b;
    cl->buf->last = p;
    cl->buf->last_buf = 1;/* this is last , and there will be no more buffers in the request */
    cl->buf->memory = 1; /* content is in read-only memory */ /* (i.e., filters should copy it rather than rewrite in place) */

    r->headers_out.content_length_n = p - b;
    r->headers_out.status = NGX_HTTP_OK;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 1, "ngx_http_send_header(r)");

    if (ngx_http_send_header(r) != NGX_OK)
    {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 1, "ngx_http_send_header(r) error");
        return NGX_ERROR;
    }

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 1, "ngx_http_output_filter");

    return ngx_http_output_filter(r, cl);

}
ngx_int_t ngx_mrb_run(ngx_http_request_t *r, ngx_mrb_state_t *state, ngx_mrb_code_t *code, ngx_flag_t cached, ngx_str_t *result)
{
    int result_len;
    mrb_value mrb_result;
    ngx_http_mruby_ctx_t *ctx;
    ngx_mrb_rputs_chain_list_t *chain;

    if (state == NGX_CONF_UNSET_PTR || code == NGX_CONF_UNSET_PTR) {
        return NGX_DECLINED;
    }
    ctx = ngx_http_get_module_ctx(r, ngx_http_mruby_module);
    if (ctx == NULL && (ctx = ngx_pcalloc(r->pool, sizeof(*ctx))) == NULL) {
        ngx_log_error(NGX_LOG_ERR
            , r->connection->log
            , 0
            , "failed to allocate memory from r->pool %s:%d"
            , __FUNCTION__
            , __LINE__
        );
        return NGX_ERROR;
    }
    ngx_http_set_ctx(r, ctx, ngx_http_mruby_module);
    ngx_mrb_push_request(r);

    if (!cached) {
        state->ai = mrb_gc_arena_save(state->mrb);
    }

    ngx_log_error(NGX_LOG_INFO
        , r->connection->log
        , 0
        , "%s INFO %s:%d: mrb_run info: irep_n=%d arena_idx=%d"
        , MODULE_NAME
        , __func__
        , __LINE__
        , code->n
        , state->ai
    );
    mrb_result = mrb_run(state->mrb, mrb_proc_new(state->mrb, state->mrb->irep[code->n]), mrb_top_self(state->mrb));
    if (state->mrb->exc) {
        if (code->code_type == NGX_MRB_CODE_TYPE_FILE) {
            ngx_mrb_raise_file_error(state->mrb, mrb_obj_value(state->mrb->exc), r, code->code.file);
        } else {
            ngx_mrb_raise_error(state->mrb, mrb_obj_value(state->mrb->exc), r);
        }
    }
    if (result != NULL) {
        if (mrb_nil_p(mrb_result)) { 
            result->data = NULL;
            result->len = 0;
        } else {
            if (mrb_type(mrb_result) != MRB_TT_STRING) {
                mrb_result = mrb_funcall(state->mrb, mrb_result, "to_s", 0, NULL);
            }
            result_len = ngx_strlen((u_char *)RSTRING_PTR(mrb_result));
            result->data = ngx_palloc(r->pool, result_len);
            if (result->data == NULL) {
                return NGX_ERROR;
            }
            ngx_memcpy(result->data, (u_char *)RSTRING_PTR(mrb_result), result_len);
            result->len  = result_len;
            ngx_log_error(NGX_LOG_INFO
                , r->connection->log
                , 0
                , "%s INFO %s:%d: mrb_run info: irep_n=(%d) return value=(%s)"
                , MODULE_NAME
                , __func__
                , __LINE__
                , code->n
                , RSTRING_PTR(mrb_result)
            );
        }
    }

    mrb_gc_arena_restore(state->mrb, state->ai);

    if (!cached) {
        ngx_mrb_irep_clean(r, state, code);
        ngx_mrb_state_clean(r, state);
    }

    // TODO: Support rputs by multi directive
    if (ngx_http_get_module_ctx(r, ngx_http_mruby_module) != NULL) {
        chain = ctx->rputs_chain;
        if (chain == NULL) {
            ngx_log_error(NGX_LOG_INFO
                , r->connection->log
                , 0
                , "%s INFO %s:%d: mrb_run info: irep_n=(%d) rputs_chain is null and return NGX_OK"
                , MODULE_NAME
                , __func__
                , __LINE__
                , code->n
            );
            return NGX_OK;
        }
        if (r->headers_out.status == NGX_HTTP_OK || !(*chain->last)->buf->last_buf) {
            r->headers_out.status = NGX_HTTP_OK;
            (*chain->last)->buf->last_buf = 1;
            ngx_http_send_header(r);
            ngx_http_output_filter(r, chain->out);
            ngx_http_set_ctx(r, NULL, ngx_http_mruby_module);
            return NGX_OK;
        } else {
            return r->headers_out.status;
        }
    }
    return NGX_OK;
}
// like Nginx rewrite keywords
// used like this:
// => http code 3xx location in browser
// => internal redirection in nginx
static mrb_value ngx_mrb_redirect(mrb_state *mrb, mrb_value self)
{
    int                     argc;
    u_char                  *str;
    ngx_buf_t               *b;
    ngx_int_t               rc;
    mrb_value               uri, code;
    ngx_str_t               ns;
    ngx_http_mruby_ctx_t         *ctx;
    ngx_table_elt_t         *location;
    ngx_mrb_rputs_chain_list_t      *chain;

    ngx_http_request_t *r = ngx_mrb_get_request();
    argc = mrb_get_args(mrb, "o|oo", &uri, &code);

    // get status code from args
    if (argc == 2) {
        rc = mrb_fixnum(code);
    } else {
        rc = NGX_HTTP_MOVED_TEMPORARILY;
    }

    // get redirect uri from args
    if (mrb_type(uri) != MRB_TT_STRING) {
        uri = mrb_funcall(mrb, uri, "to_s", 0, NULL);
    }

    // save location uri to ns
    ns.data     = (u_char *)RSTRING_PTR(uri);
    ns.len      = ngx_strlen(ns.data);
    if (ns.len == 0) {
        return mrb_nil_value();
    }

    // if uri start with scheme prefix
    // return 3xx for redirect
    // else generate a internal redirection and response to raw request
    // request.path is not changed
    if (ngx_strncmp(ns.data, "http://", sizeof("http://") - 1) == 0 
        || ngx_strncmp(ns.data, "https://", sizeof("https://") - 1) == 0 
        || ngx_strncmp(ns.data, "$scheme", sizeof("$scheme") - 1) == 0) {    
        ctx = ngx_http_get_module_ctx(r, ngx_http_mruby_module);
        if (ctx == NULL) {
            ngx_log_error(NGX_LOG_ERR
                , r->connection->log
                , 0
                , "get mruby context failed."
            );
        }

        if (ctx->rputs_chain == NULL) {
            chain       = ngx_pcalloc(r->pool, sizeof(ngx_mrb_rputs_chain_list_t));
            chain->out  = ngx_alloc_chain_link(r->pool);
            chain->last = &chain->out;
        } else {
            chain = ctx->rputs_chain;
            (*chain->last)->next = ngx_alloc_chain_link(r->pool);
            chain->last = &(*chain->last)->next;
        }

        // allocate space for body
        b = ngx_calloc_buf(r->pool);
        (*chain->last)->buf = b;
        (*chain->last)->next = NULL;

        str         = ngx_pstrdup(r->pool, &ns);
        str[ns.len] = '\0';
        (*chain->last)->buf->pos    = str;
        (*chain->last)->buf->last   = str+ns.len;
        (*chain->last)->buf->memory = 1;
        ctx->rputs_chain = chain;
        ngx_http_set_ctx(r, ctx, ngx_http_mruby_module);

        if (r->headers_out.content_length_n == -1) {
            r->headers_out.content_length_n += ns.len + 1;
        } else {
            r->headers_out.content_length_n += ns.len;
        }

        // build redirect location
        location = ngx_list_push(&r->headers_out.headers);
        location->hash = 1;
        ngx_str_set(&location->key, "Location");
        location->value = ns;
        location->lowcase_key = ngx_pnalloc(r->pool, location->value.len);
        ngx_strlow(location->lowcase_key, location->value.data, location->value.len);

        // set location and response code for hreaders
        r->headers_out.location = location;
        r->headers_out.status = rc;

        ngx_http_send_header(r);
        ngx_http_output_filter(r, chain->out);
    } else {
        ngx_http_internal_redirect(r, &ns, &r->args);
    }

    return self;
}
Exemple #10
0
static ngx_int_t
ngx_http_push_stream_subscriber_handler(ngx_http_request_t *r)
{
    ngx_slab_pool_t                                *shpool = (ngx_slab_pool_t *)ngx_http_push_stream_shm_zone->shm.addr;
    ngx_http_push_stream_loc_conf_t                *cf = ngx_http_get_module_loc_conf(r, ngx_http_push_stream_module);
    ngx_http_push_stream_subscriber_t              *worker_subscriber;
    ngx_http_push_stream_requested_channel_t       *channels_ids, *cur;
    ngx_http_push_stream_subscriber_ctx_t          *ctx;
    time_t                                          if_modified_since;
    ngx_str_t                                      *last_event_id, vv_time = ngx_null_string;
    ngx_str_t                                      *push_mode;
    ngx_flag_t                                      polling, longpolling;
    ngx_int_t                                       rc;
    ngx_int_t                                       status_code;
    ngx_str_t                                      *explain_error_message;

    // add headers to support cross domain requests
    if (cf->allowed_origins.len > 0) {
        ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, &cf->allowed_origins);
        ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_METHODS, &NGX_HTTP_PUSH_STREAM_ALLOW_GET);
        ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_HEADERS, &NGX_HTTP_PUSH_STREAM_ALLOWED_HEADERS);
    }

    if (r->method & NGX_HTTP_OPTIONS) {
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_OK, NULL);
    }

    ngx_http_push_stream_set_expires(r, NGX_HTTP_PUSH_STREAM_EXPIRES_MAX, 0);

    // only accept GET method
    if (!(r->method & NGX_HTTP_GET)) {
        ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ALLOW, &NGX_HTTP_PUSH_STREAM_ALLOW_GET);
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_NOT_ALLOWED, NULL);
    }

    if ((ctx = ngx_http_push_stream_add_request_context(r)) == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: unable to create request context");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    //get channels ids and backtracks from path
    channels_ids = ngx_http_push_stream_parse_channels_ids_from_path(r, ctx->temp_pool);
    if ((channels_ids == NULL) || ngx_queue_empty(&channels_ids->queue)) {
        ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "push stream module: the $push_stream_channels_path variable is required but is not set");
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_BAD_REQUEST, &NGX_HTTP_PUSH_STREAM_NO_CHANNEL_ID_MESSAGE);
    }

    //validate channels: name, length and quantity. check if channel exists when authorized_channels_only is on. check if channel is full of subscribers
    if (ngx_http_push_stream_validate_channels(r, channels_ids, &status_code, &explain_error_message) == NGX_ERROR) {
        return ngx_http_push_stream_send_only_header_response(r, status_code, explain_error_message);
    }

    if (cf->last_received_message_time != NULL) {
        ngx_http_push_stream_complex_value(r, cf->last_received_message_time, &vv_time);
    } else if (r->headers_in.if_modified_since != NULL) {
        vv_time = r->headers_in.if_modified_since->value;
    }

    // get control headers
    if_modified_since = vv_time.len ? ngx_http_parse_time(vv_time.data, vv_time.len) : -1;
    last_event_id = ngx_http_push_stream_get_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_LAST_EVENT_ID);

    push_mode = ngx_http_push_stream_get_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_MODE);
    polling = ((cf->location_type == NGX_HTTP_PUSH_STREAM_SUBSCRIBER_MODE_POLLING) || ((push_mode != NULL) && (push_mode->len == NGX_HTTP_PUSH_STREAM_MODE_POLLING.len) && (ngx_strncasecmp(push_mode->data, NGX_HTTP_PUSH_STREAM_MODE_POLLING.data, NGX_HTTP_PUSH_STREAM_MODE_POLLING.len) == 0)));
    longpolling = ((cf->location_type == NGX_HTTP_PUSH_STREAM_SUBSCRIBER_MODE_LONGPOLLING) || ((push_mode != NULL) && (push_mode->len == NGX_HTTP_PUSH_STREAM_MODE_LONGPOLLING.len) && (ngx_strncasecmp(push_mode->data, NGX_HTTP_PUSH_STREAM_MODE_LONGPOLLING.data, NGX_HTTP_PUSH_STREAM_MODE_LONGPOLLING.len) == 0)));

    if (polling || longpolling) {
        ngx_int_t result = ngx_http_push_stream_subscriber_polling_handler(r, channels_ids, if_modified_since, last_event_id, longpolling, ctx->temp_pool);
        if (ctx->temp_pool != NULL) {
            ngx_destroy_pool(ctx->temp_pool);
            ctx->temp_pool = NULL;
        }
        return result;
    }

    ctx->padding = ngx_http_push_stream_get_padding_by_user_agent(r);

    // stream access
    if ((worker_subscriber = ngx_http_push_stream_subscriber_prepare_request_to_keep_connected(r)) == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_TRANSFER_ENCODING, &NGX_HTTP_PUSH_STREAM_HEADER_CHUNCKED);
    ngx_http_send_header(r);

    // sending response content header
    if (ngx_http_push_stream_send_response_content_header(r, cf) == NGX_ERROR) {
        ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0, "push stream module: could not send content header to subscriber");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ngx_shmtx_lock(&shpool->mutex);
    rc = ngx_http_push_stream_registry_subscriber_locked(r, worker_subscriber);
    ngx_shmtx_unlock(&shpool->mutex);

    if (rc == NGX_ERROR) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    // adding subscriber to channel(s) and send backtrack messages
    cur = channels_ids;
    while ((cur = (ngx_http_push_stream_requested_channel_t *) ngx_queue_next(&cur->queue)) != channels_ids) {
        if (ngx_http_push_stream_subscriber_assign_channel(shpool, cf, r, cur, if_modified_since, last_event_id, worker_subscriber, ctx->temp_pool) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
    }

    if (ctx->temp_pool != NULL) {
        ngx_destroy_pool(ctx->temp_pool);
        ctx->temp_pool = NULL;
    }
    return NGX_DONE;
}
Exemple #11
0
static ngx_int_t
ngx_http_push_stream_subscriber_polling_handler(ngx_http_request_t *r, ngx_http_push_stream_requested_channel_t *channels_ids, time_t if_modified_since, ngx_str_t *last_event_id, ngx_flag_t longpolling, ngx_pool_t *temp_pool)
{
    ngx_http_push_stream_loc_conf_t                *cf = ngx_http_get_module_loc_conf(r, ngx_http_push_stream_module);
    ngx_slab_pool_t                                *shpool = (ngx_slab_pool_t *)ngx_http_push_stream_shm_zone->shm.addr;
    ngx_http_push_stream_subscriber_ctx_t          *ctx = ngx_http_get_module_ctx(r, ngx_http_push_stream_module);
    ngx_http_push_stream_requested_channel_t       *cur;
    ngx_http_push_stream_subscriber_t              *worker_subscriber;
    ngx_http_push_stream_channel_t                 *channel;
    ngx_http_push_stream_subscription_t            *subscription;
    ngx_str_t                                      *etag = NULL, vv_etag = ngx_null_string;
    ngx_int_t                                       tag;
    time_t                                          greater_message_time;
    ngx_int_t                                       greater_message_tag;
    ngx_flag_t                                      has_message_to_send = 0;
    ngx_str_t                                       callback_function_name;
	ngx_flag_t										hit_old_message = 0;
	ngx_int_t										count_of_old_message = 0;

    if (cf->last_received_message_tag != NULL) {
        ngx_http_push_stream_complex_value(r, cf->last_received_message_tag, &vv_etag);
        etag = vv_etag.len ? &vv_etag : NULL;
    } else {
        etag = ngx_http_push_stream_get_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_IF_NONE_MATCH);
    }

    if (ngx_http_arg(r, NGX_HTTP_PUSH_STREAM_CALLBACK.data, NGX_HTTP_PUSH_STREAM_CALLBACK.len, &callback_function_name) == NGX_OK) {
        ngx_http_push_stream_unescape_uri(&callback_function_name);
        if ((ctx->callback = ngx_http_push_stream_get_formatted_chunk(callback_function_name.data, callback_function_name.len, r->pool)) == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: unable to allocate memory for callback function name");
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
    }

    tag = ((etag != NULL) && ((tag = ngx_atoi(etag->data, etag->len)) != NGX_ERROR)) ? ngx_abs(tag) : -1;
	
    greater_message_tag = tag;
    greater_message_time = if_modified_since = (if_modified_since < 0) ? 0 : if_modified_since;

    ngx_shmtx_lock(&shpool->mutex);

    // check if has any message to send
    cur = channels_ids;
    while ((cur = (ngx_http_push_stream_requested_channel_t *) ngx_queue_next(&cur->queue)) != channels_ids) {
		time_t next_greater_message_time = greater_message_time;//add by xinlu
		ngx_int_t next_greater_message_tag = greater_message_tag;//add by xinlu
		ngx_flag_t hitres = 0;

        channel = ngx_http_push_stream_find_channel(cur->id, r->connection->log);
        if (channel == NULL) {
            // channel not found
            ngx_shmtx_unlock(&shpool->mutex);
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: unable to allocate shared memory for channel %s", cur->id->data);
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

		count_of_old_message += channel->stored_messages;

		hitres = ngx_http_push_stream_has_old_messages_to_send(channel, cur->backtrack_messages, if_modified_since, tag, greater_message_time, greater_message_tag, last_event_id, &next_greater_message_time, &next_greater_message_tag);
		if(hitres == 1)
		{
			hit_old_message = 1;
		}
        if (hitres >= 2) 
		{
			/*
            if (channel->last_message_time > greater_message_time) 
			{
                greater_message_time = channel->last_message_time;
                greater_message_tag = channel->last_message_tag;
            } else {
                if ((channel->last_message_time == greater_message_time) && (channel->last_message_tag > greater_message_tag) ) {
                    greater_message_tag = channel->last_message_tag;
                }
            }
			*/
			if(!has_message_to_send)
			{
				greater_message_tag = next_greater_message_tag;
				greater_message_time = next_greater_message_time;
			}
			else
			{
				if(greater_message_time > next_greater_message_time)
				{
					greater_message_time = next_greater_message_time;
					greater_message_tag = next_greater_message_tag;
				}
				else if(greater_message_time == next_greater_message_time && greater_message_tag > next_greater_message_tag)
				{
					greater_message_tag = next_greater_message_tag;
				}
			}
			has_message_to_send++;
        }
    }

    if (longpolling && !has_message_to_send) {
        // long polling mode without messages
        if ((worker_subscriber = ngx_http_push_stream_subscriber_prepare_request_to_keep_connected(r)) == NULL) {
            ngx_shmtx_unlock(&shpool->mutex);
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
        worker_subscriber->longpolling = 1;

        if (ngx_http_push_stream_registry_subscriber_locked(r, worker_subscriber) == NGX_ERROR) {
            ngx_shmtx_unlock(&shpool->mutex);
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        // adding subscriber to channel(s)
        cur = channels_ids;
        while ((cur = (ngx_http_push_stream_requested_channel_t *) ngx_queue_next(&cur->queue)) != channels_ids) {
            if ((channel = ngx_http_push_stream_find_channel(cur->id, r->connection->log)) == NULL) {
                // channel not found
                ngx_shmtx_unlock(&shpool->mutex);
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: unable to allocate shared memory for channel %s", cur->id->data);
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            if ((subscription = ngx_http_push_stream_create_channel_subscription(r, channel, worker_subscriber)) == NULL) {
                ngx_shmtx_unlock(&shpool->mutex);
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            ngx_http_push_stream_assing_subscription_to_channel_locked(shpool, cur->id, subscription, &worker_subscriber->subscriptions_sentinel, r->connection->log);
        }

        ngx_shmtx_unlock(&shpool->mutex);
        return NGX_DONE;
    }

    ngx_shmtx_unlock(&shpool->mutex);

    // polling or long polling without messages to send

    ngx_http_push_stream_add_polling_headers(r, greater_message_time, greater_message_tag, temp_pool);

    if (!has_message_to_send) {
        // polling subscriber requests get a 304 with their entity tags preserved if don't have new messages.
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_NOT_MODIFIED, NULL);
    }

    // polling with messages or long polling without messages to send
    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = -1;

    ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_TRANSFER_ENCODING, &NGX_HTTP_PUSH_STREAM_HEADER_CHUNCKED);
    ngx_http_send_header(r);

    // sending response content header
    if (ngx_http_push_stream_send_response_content_header(r, cf) == NGX_ERROR) {
        ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0, "push stream module: could not send content header to subscriber");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (ctx->callback != NULL) {
        ngx_http_push_stream_send_response_text(r, ctx->callback->data, ctx->callback->len, 0);
        ngx_http_push_stream_send_response_text(r, NGX_HTTP_PUSH_STREAM_CALLBACK_INIT_CHUNK.data, NGX_HTTP_PUSH_STREAM_CALLBACK_INIT_CHUNK.len, 0);
    }

    cur = channels_ids;
    while ((cur = (ngx_http_push_stream_requested_channel_t *) ngx_queue_next(&cur->queue)) != channels_ids) {
		ngx_int_t message_count_had_send = 0;
        channel = ngx_http_push_stream_find_channel(cur->id, r->connection->log);
        if (channel == NULL) {
            // channel not found
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: unable to allocate shared memory for channel %s", cur->id->data);
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
        ngx_http_push_stream_send_old_messages(r, channel, cur->backtrack_messages, if_modified_since, tag, greater_message_time, greater_message_tag, last_event_id, &message_count_had_send);
		if(message_count_had_send > 0)
		{
			break;
		}
    }

    if (ctx->callback != NULL) {
        ngx_http_push_stream_send_response_text(r, NGX_HTTP_PUSH_STREAM_CALLBACK_END_CHUNK.data, NGX_HTTP_PUSH_STREAM_CALLBACK_END_CHUNK.len, 0);
    }

    if (cf->footer_template.len > 0) {
        ngx_http_push_stream_send_response_text(r, cf->footer_template.data, cf->footer_template.len, 0);
    }

    ngx_http_push_stream_send_response_text(r, NGX_HTTP_PUSH_STREAM_LAST_CHUNK.data, NGX_HTTP_PUSH_STREAM_LAST_CHUNK.len, 1);

    return NGX_OK;
}
ngx_int_t
ngx_http_rds_csv_process_header(ngx_http_request_t *r, ngx_chain_t *in,
    ngx_http_rds_csv_ctx_t *ctx)
{
    ngx_buf_t                       *b;
    ngx_http_rds_header_t            header;
    ngx_int_t                        rc;

    if (in == NULL) {
        return NGX_OK;
    }

    b = in->buf;

    if (!ngx_buf_in_memory(b)) {
        if (!ngx_buf_special(b)) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "rds_csv: process header: buf from "
                          "upstream not in memory");
            goto invalid;
        }

        in = in->next;

        if (in == NULL) {
            return NGX_OK;
        }

        b = in->buf;
    }

    rc = ngx_http_rds_parse_header(r, b, &header);

    if (rc != NGX_OK) {
        goto invalid;
    }

    dd("col count: %d", (int) header.col_count);

    if (header.col_count == 0) {
        /* for empty result set, just return the JSON
         * representation of the RDS header */

        dd("col count == 0");

        if (b->pos != b->last) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "rds_csv: header: there's unexpected remaining data "
                          "in the buf");

            goto invalid;
        }

        ctx->state = state_done;

        /* now we send the postponed response header */
        if (!ctx->header_sent) {
            ctx->header_sent = 1;

            rc = ngx_http_rds_csv_next_header_filter(r);

            if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
                return rc;
            }
        }

        rc = ngx_http_rds_csv_output_header(r, ctx, &header);

        if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
            return rc;
        }

        ngx_http_rds_csv_discard_bufs(r->pool, in);

        return rc;
    }

    ctx->cols = ngx_palloc(r->pool,
                           header.col_count * sizeof(ngx_http_rds_column_t));

    if (ctx->cols == NULL) {
        goto invalid;
    }

    ctx->state = state_expect_col;
    ctx->cur_col = 0;
    ctx->col_count = header.col_count;

    /* now we send the postponed response header */
    if (!ctx->header_sent) {
        ctx->header_sent = 1;

        rc = ngx_http_rds_csv_next_header_filter(r);
        if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
            return rc;
        }
    }

    return ngx_http_rds_csv_process_col(r, b->pos == b->last ? in->next : in,
                                        ctx);

invalid:

    dd("return 500");
    if (!ctx->header_sent) {
        ctx->header_sent = 1;

        r->headers_out.status = NGX_HTTP_INTERNAL_SERVER_ERROR;
        ngx_http_send_header(r);
        ngx_http_send_special(r, NGX_HTTP_LAST);

        return NGX_ERROR;
    }

    return NGX_ERROR;
}