Example #1
0
ngx_int_t ngx_lua_content_by_file_handler(ngx_http_request_t* r)
{
    ngx_lua_main_conf_t* pmainconf;
    ngx_lua_loc_conf_t*  plocconf;
    ngx_int_t rc;
    int top;
    ngx_str_t src_path;
    u_char new_path[PATH_MAX];
    dbg("ngx_lua_content_by_file_handler\n");

    pmainconf = ngx_http_get_module_main_conf(r, ngx_lua_module);
    plocconf  = ngx_http_get_module_loc_conf(r, ngx_lua_module);

    // complex path
    if (ngx_http_complex_value(r, &plocconf->lua_content_file, &src_path) != NGX_OK)
    {
        ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "ngx_lua_content_handler: ngx_http_complex_value error");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    // new path with\0
    memcpy(new_path, src_path.data, src_path.len);
    new_path[src_path.len] = 0;
    src_path.data = new_path;

    // register ngx.req.args
    top = lua_gettop(pmainconf->lua);
    ngx_lua_module_set_req_obj(pmainconf->lua, r);
    ngx_lua_module_parse_args(r->pool, r->args.data, r->args.len, pmainconf->lua);

    if (src_path.len)
    {
        code_cache_node_t* ptr;
        char path[PATH_MAX];
        ngx_str_t strPath;
        ngx_str_t code;

        ngx_str_null(&strPath);

        // file exists
        if (access((const char*)src_path.data, 0) == -1)
        {
            lua_pushfstring(pmainconf->lua, "%s doesn't exist", src_path.data);
            faild(NGX_HTTP_NOT_FOUND);
        }

        // get realpath
        if (realpath((const char*)src_path.data, path) == NULL)
        {
            lua_pushfstring(pmainconf->lua, "can't get realpath with %s", src_path.data);
            faild(NGX_HTTP_INTERNAL_SERVER_ERROR);
        }

        ngx_pfree(r->pool, src_path.data);

        // register ngx.scp.path
        ngx_lua_module_get_scp(pmainconf->lua);
        lua_pushstring(pmainconf->lua, "path");
        lua_pushstring(pmainconf->lua, path);
        lua_settable(pmainconf->lua, -3);
        lua_pop(pmainconf->lua, 2);

        // lookup cache
        strPath.data = (u_char*)path;
        strPath.len = strlen(path);
        ptr = ngx_lua_code_cache_key_exists(pmainconf->cache_table, strPath);
        ngx_lua_module_replace_global(pmainconf->lua);
        if (ptr == NULL) // doesn't exist
        {
            code = ngx_lua_code_cache_load(strPath);
            if (code.data == NULL)
            {
                lua_pushstring(pmainconf->lua, "out of memory");
                faild(NGX_HTTP_INTERNAL_SERVER_ERROR);
            }
            if (pmainconf->enable_code_cache)
            {
                ngx_str_t cache;
                dbg("code uncached\n");
                if (ngx_lua_module_code_to_chunk(pmainconf->lua, code.data, code.len, &cache))
                {
                    faild(NGX_HTTP_INTERNAL_SERVER_ERROR);
                }
                ptr = ngx_lua_code_cache_node_new(strPath, cache);
                if (ptr == NULL)
                {
                    lua_pushstring(pmainconf->lua, "out of memory");
                    faild(NGX_HTTP_INTERNAL_SERVER_ERROR);
                }
                ngx_pfree(ngx_cycle->pool, code.data);
                code = ptr->code;
                ngx_lua_core_hash_table_insert_notfind(pmainconf->cache_table, ptr);
                rc = ngx_lua_content_call_chunk(r, pmainconf->lua, &code);
            }
            else rc = ngx_lua_content_call_code(r, pmainconf->lua, code.data, code.len);
        }
        else
        {
            dbg("code cached\n");
            code = ptr->code;
            rc = ngx_lua_content_call_chunk(r, pmainconf->lua, &code);
        }

        ngx_pfree(ngx_cycle->pool, code.data);
        if (rc != NGX_OK) return rc;
        rc = ngx_lua_content_send(r, pmainconf->lua);
        if (rc != NGX_OK) return rc;
    }

    if (top != lua_gettop(pmainconf->lua))
    {
        ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "ngx_lua_content_by_file_handler: error lua stack");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    return NGX_OK;
}
//expires配置解析,会触发创建设置r->headers_out.expires r->headers_out.cache_control
static ngx_int_t //expires xx配置存储函数为ngx_http_headers_expires,真正组包生效函数为ngx_http_set_expires
ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf)
{
    char                *err;
    size_t               len;
    time_t               now, expires_time, max_age;
    ngx_str_t            value;
    ngx_int_t            rc;
    ngx_uint_t           i;
    ngx_table_elt_t     *e, *cc, **ccp;
    ngx_http_expires_t   expires;

    expires = conf->expires;
    expires_time = conf->expires_time;

    if (conf->expires_value != NULL) { //说明expires配置的是变量类型

        if (ngx_http_complex_value(r, conf->expires_value, &value) != NGX_OK) {
            return NGX_ERROR;
        }

        rc = ngx_http_parse_expires(&value, &expires, &expires_time, &err);

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

        if (expires == NGX_HTTP_EXPIRES_OFF) {
            return NGX_OK;
        }
    }

    e = r->headers_out.expires;

    if (e == NULL) {

        e = ngx_list_push(&r->headers_out.headers);
        if (e == NULL) {
            return NGX_ERROR;
        }

        r->headers_out.expires = e;

        e->hash = 1;
        ngx_str_set(&e->key, "Expires");
    }

    len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT");
    e->value.len = len - 1;

    ccp = r->headers_out.cache_control.elts;

    if (ccp == NULL) {

        if (ngx_array_init(&r->headers_out.cache_control, r->pool,
                           1, sizeof(ngx_table_elt_t *))
            != NGX_OK)
        {
            return NGX_ERROR;
        }

        ccp = ngx_array_push(&r->headers_out.cache_control);
        if (ccp == NULL) {
            return NGX_ERROR;
        }

        cc = ngx_list_push(&r->headers_out.headers);
        if (cc == NULL) {
            return NGX_ERROR;
        }

        cc->hash = 1;
        ngx_str_set(&cc->key, "Cache-Control");
        *ccp = cc;

    } else {
        for (i = 1; i < r->headers_out.cache_control.nelts; i++) {
            ccp[i]->hash = 0;
        }

        cc = ccp[0];
    }

    if (expires == NGX_HTTP_EXPIRES_EPOCH) {
        e->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT";
        ngx_str_set(&cc->value, "no-cache");//设置r->headers_out.cache_control
        return NGX_OK;
    }

    if (expires == NGX_HTTP_EXPIRES_MAX) {
        e->value.data = (u_char *) "Thu, 31 Dec 2037 23:55:55 GMT";
        /* 10 years */
        ngx_str_set(&cc->value, "max-age=315360000");//设置r->headers_out.cache_control
        return NGX_OK;
    }

    e->value.data = ngx_pnalloc(r->pool, len);
    if (e->value.data == NULL) {
        return NGX_ERROR;
    }

    if (expires_time == 0 && expires != NGX_HTTP_EXPIRES_DAILY) {
        ngx_memcpy(e->value.data, ngx_cached_http_time.data,
                   ngx_cached_http_time.len + 1);
        ngx_str_set(&cc->value, "max-age=0");//设置r->headers_out.cache_control
        return NGX_OK;
    }

    now = ngx_time();

    if (expires == NGX_HTTP_EXPIRES_DAILY) {
        expires_time = ngx_next_time(expires_time);
        max_age = expires_time - now;

    } else if (expires == NGX_HTTP_EXPIRES_ACCESS
               || r->headers_out.last_modified_time == -1)
    {
        max_age = expires_time;
        expires_time += now;

    } else {
        expires_time += r->headers_out.last_modified_time;
        max_age = expires_time - now;
    }

    ngx_http_time(e->value.data, expires_time);

    if (conf->expires_time < 0 || max_age < 0) {
        ngx_str_set(&cc->value, "no-cache");//设置r->headers_out.cache_control
        return NGX_OK;
    }

    //设置r->headers_out.cache_control
    cc->value.data = ngx_pnalloc(r->pool,
                                 sizeof("max-age=") + NGX_TIME_T_LEN + 1);
    if (cc->value.data == NULL) {
        return NGX_ERROR;
    }

    cc->value.len = ngx_sprintf(cc->value.data, "max-age=%T", max_age)
                    - cc->value.data;

    return NGX_OK;
}
static ngx_int_t 
ngx_http_vod_hls_handle_index_playlist(
	ngx_http_vod_submodule_context_t* submodule_context,
	ngx_str_t* response,
	ngx_str_t* content_type)
{
	ngx_http_vod_loc_conf_t* conf = submodule_context->conf;
	hls_encryption_params_t encryption_params;
	ngx_str_t segments_base_url = ngx_null_string;
	ngx_str_t base_url = ngx_null_string;
	vod_status_t rc;
	u_char iv[AES_BLOCK_SIZE];

	if (conf->hls.absolute_index_urls)
	{
		rc = ngx_http_vod_get_base_url(submodule_context->r, conf->base_url, &submodule_context->r->uri, &base_url);
		if (rc != NGX_OK)
		{
			return rc;
		}

		if (conf->segments_base_url != NULL)
		{
			rc = ngx_http_vod_get_base_url(
				submodule_context->r, 
				conf->segments_base_url,
				&submodule_context->r->uri, 
				&segments_base_url);
			if (rc != NGX_OK)
			{
				return rc;
			}
		}
		else
		{
			segments_base_url = base_url;
		}
	}

	ngx_http_vod_hls_init_encryption_params(&encryption_params, submodule_context, iv);

	if (encryption_params.type != HLS_ENC_NONE)
	{
		if (conf->hls.encryption_key_uri != NULL)
		{
			if (ngx_http_complex_value(
				submodule_context->r,
				conf->hls.encryption_key_uri,
				&encryption_params.key_uri) != NGX_OK)
			{
				ngx_log_debug0(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
					"ngx_http_vod_hls_handle_index_playlist: ngx_http_complex_value failed");
				return NGX_ERROR;
			}
		}
		else
		{
			encryption_params.key_uri.len = 0;
		}
	}

	rc = m3u8_builder_build_index_playlist(
		&submodule_context->request_context,
		&conf->hls.m3u8_config,
		&base_url,
		&segments_base_url,
		&submodule_context->request_params,
		&encryption_params,
		&submodule_context->media_set,
		response);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hls_handle_index_playlist: m3u8_builder_build_index_playlist failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	content_type->data = m3u8_content_type;
	content_type->len = sizeof(m3u8_content_type) - 1;
	
	return NGX_OK;
}
static ngx_int_t
ngx_http_auth_basic_handler(ngx_http_request_t *r)
{
    off_t                            offset;
    ssize_t                          n;
    ngx_fd_t                         fd;
    ngx_int_t                        rc;
    ngx_err_t                        err;
    ngx_str_t                        pwd, realm, user_file;
    ngx_uint_t                       i, level, login, left, passwd;
    ngx_file_t                       file;
    ngx_http_auth_basic_ctx_t       *ctx;
    ngx_http_auth_basic_loc_conf_t  *alcf;
    u_char                           buf[NGX_HTTP_AUTH_BUF_SIZE];
    enum {
        sw_login,
        sw_passwd,
        sw_skip
    } state;

    alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_basic_module);

    if (alcf->realm == NULL || alcf->user_file.value.data == NULL) {
        return NGX_DECLINED;
    }

    if (ngx_http_complex_value(r, alcf->realm, &realm) != NGX_OK) {
        return NGX_ERROR;
    }

    if (realm.len == 3 && ngx_strncmp(realm.data, "off", 3) == 0) {
        return NGX_DECLINED;
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_auth_basic_module);

    if (ctx) {
        return ngx_http_auth_basic_crypt_handler(r, ctx, &ctx->passwd,
                                                 &realm);
    }

    rc = ngx_http_auth_basic_user(r);

    if (rc == NGX_DECLINED) {

        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                      "no user/password was provided for basic authentication");

        return ngx_http_auth_basic_set_realm(r, &realm);
    }

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

    if (ngx_http_complex_value(r, &alcf->user_file, &user_file) != NGX_OK) {
        return NGX_ERROR;
    }

    fd = ngx_open_file(user_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);

    if (fd == NGX_INVALID_FILE) {
        err = ngx_errno;

        if (err == NGX_ENOENT) {
            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_file_n " \"%s\" failed", user_file.data);

        return rc;
    }

    ngx_memzero(&file, sizeof(ngx_file_t));

    file.fd = fd;
    file.name = user_file;
    file.log = r->connection->log;

    state = sw_login;
    passwd = 0;
    login = 0;
    left = 0;
    offset = 0;

    for ( ;; ) {
        i = left;

        n = ngx_read_file(&file, buf + left, NGX_HTTP_AUTH_BUF_SIZE - left,
                          offset);

        if (n == NGX_ERROR) {
            ngx_http_auth_basic_close(&file);
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        if (n == 0) {
            break;
        }

        for (i = left; i < left + n; i++) {
            switch (state) {

            case sw_login:
                if (login == 0) {

                    if (buf[i] == '#' || buf[i] == CR) {
                        state = sw_skip;
                        break;
                    }

                    if (buf[i] == LF) {
                        break;
                    }
                }

                if (buf[i] != r->headers_in.user.data[login]) {
                    state = sw_skip;
                    break;
                }

                if (login == r->headers_in.user.len) {
                    state = sw_passwd;
                    passwd = i + 1;
                }

                login++;

                break;

            case sw_passwd:
                if (buf[i] == LF || buf[i] == CR || buf[i] == ':') {
                    buf[i] = '\0';

                    ngx_http_auth_basic_close(&file);

                    pwd.len = i - passwd;
                    pwd.data = &buf[passwd];

                    return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd,
                                                             &realm);
                }

                break;

            case sw_skip:
                if (buf[i] == LF) {
                    state = sw_login;
                    login = 0;
                }

                break;
            }
        }

        if (state == sw_passwd) {
            left = left + n - passwd;
            ngx_memmove(buf, &buf[passwd], left);
            passwd = 0;

        } else {
            left = 0;
        }

        offset += n;
    }

    ngx_http_auth_basic_close(&file);

    if (state == sw_passwd) {
        pwd.len = i - passwd;
        pwd.data = ngx_pnalloc(r->pool, pwd.len + 1);
        if (pwd.data == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        ngx_cpystrn(pwd.data, &buf[passwd], pwd.len + 1);

        return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd, &realm);
    }

    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                  "user \"%V\" was not found in \"%V\"",
                  &r->headers_in.user, &user_file);

    return ngx_http_auth_basic_set_realm(r, &realm);
}
static ngx_int_t
ngx_http_srcache_fetch_subrequest(ngx_http_request_t *r,
    ngx_http_srcache_loc_conf_t *conf, ngx_http_srcache_ctx_t *ctx)
{
    ngx_http_srcache_ctx_t         *sr_ctx;
    ngx_http_post_subrequest_t     *psr;
    ngx_str_t                       args;
    ngx_uint_t                      flags = 0;
    ngx_http_request_t             *sr;
    ngx_int_t                       rc;

    ngx_http_srcache_parsed_request_t  *parsed_sr;

    dd_enter();

    parsed_sr = ngx_palloc(r->pool, sizeof(ngx_http_srcache_parsed_request_t));
    if (parsed_sr == NULL) {
        return NGX_ERROR;
    }

    if (conf->fetch == NULL) {
        return NGX_ERROR;
    }

    parsed_sr->method      = conf->fetch->method;
    parsed_sr->method_name = conf->fetch->method_name;

    parsed_sr->request_body = NULL;
    parsed_sr->content_length_n = -1;

    if (ngx_http_complex_value(r, &conf->fetch->location,
                               &parsed_sr->location) != NGX_OK)
    {
        return NGX_ERROR;
    }

    if (parsed_sr->location.len == 0) {
        return NGX_ERROR;
    }

    if (ngx_http_complex_value(r, &conf->fetch->args, &parsed_sr->args)
            != NGX_OK)
    {
        return NGX_ERROR;
    }

    args.data = NULL;
    args.len = 0;

    if (ngx_http_parse_unsafe_uri(r, &parsed_sr->location, &args, &flags)
        != NGX_OK)
    {
        return NGX_ERROR;
    }

    if (args.len > 0 && parsed_sr->args.len == 0) {
        parsed_sr->args = args;
    }

    sr_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_srcache_ctx_t));
    if (sr_ctx == NULL) {
        return NGX_ERROR;
    }

    sr_ctx->in_fetch_subrequest = 1;

    psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
    if (psr == NULL) {
        return NGX_ERROR;
    }

    psr->handler = ngx_http_srcache_fetch_post_subrequest;
    psr->data = sr_ctx;

    dd("firing the fetch subrequest");

    dd("fetch location: %.*s", (int) parsed_sr->location.len,
       parsed_sr->location.data);

    dd("fetch args: %.*s", (int) parsed_sr->args.len,
            parsed_sr->args.data);

    rc = ngx_http_subrequest(r, &parsed_sr->location, &parsed_sr->args,
                             &sr, psr, flags);

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

    rc = ngx_http_srcache_adjust_subrequest(sr, parsed_sr);

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

    ngx_http_set_ctx(sr, sr_ctx, ngx_http_srcache_filter_module);

    ctx->issued_fetch_subrequest = 1;

    return NGX_OK;
}
static ngx_int_t
ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page)
{
    ngx_int_t                  overwrite;
    ngx_str_t                  uri, args;
    ngx_table_elt_t           *location;
    ngx_http_core_loc_conf_t  *clcf;

    overwrite = err_page->overwrite;

    if (overwrite && overwrite != NGX_HTTP_OK) {
        r->expect_tested = 1;
    }

    if (overwrite >= 0) {
        r->err_status = overwrite;
    }

    if (ngx_http_complex_value(r, &err_page->value, &uri) != NGX_OK) {
        return NGX_ERROR;
    }

    if (uri.len && uri.data[0] == '/') {

        if (err_page->value.lengths) {
            ngx_http_split_args(r, &uri, &args);

        } else {
            args = err_page->args;
        }

        if (r->method != NGX_HTTP_HEAD) {
            r->method = NGX_HTTP_GET;
            r->method_name = ngx_http_get_name;
        }

        return ngx_http_internal_redirect(r, &uri, &args);
    }

    if (uri.len && uri.data[0] == '@') {
        return ngx_http_named_location(r, &uri);
    }

    location = ngx_list_push(&r->headers_out.headers);

    if (location == NULL) {
        return NGX_ERROR;
    }

    if (overwrite != NGX_HTTP_MOVED_PERMANENTLY
        && overwrite != NGX_HTTP_MOVED_TEMPORARILY
        && overwrite != NGX_HTTP_SEE_OTHER
        && overwrite != NGX_HTTP_TEMPORARY_REDIRECT)
    {
        r->err_status = NGX_HTTP_MOVED_TEMPORARILY;
    }

    location->hash = 1;
    ngx_str_set(&location->key, "Location");
    location->value = uri;

    ngx_http_clear_location(r);

    r->headers_out.location = location;

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    if (clcf->msie_refresh && r->headers_in.msie) {
        return ngx_http_send_refresh(r);
    }

    return ngx_http_send_special_response(r, clcf, r->err_status
                                                   - NGX_HTTP_MOVED_PERMANENTLY
                                                   + NGX_HTTP_OFF_3XX);
}
Example #7
0
static ngx_int_t websocket_publish(full_subscriber_t *fsub, ngx_buf_t *buf) {
  static ngx_str_t         nopublishing = ngx_string("Publishing not allowed.");
  static ngx_str_t         POST_REQUEST_STRING = {4, (u_char *)"POST "};
  
  if(!fsub->sub.cf->pub.websocket) {
    return websocket_send_close_frame(fsub, CLOSE_POLICY_VIOLATION, &nopublishing);
  }
  
#if (NGX_DEBUG_POOL)
  ERR("ws request pool size: %V", ngx_http_debug_pool_str(fsub->sub.request->pool));
#endif
  
  ngx_http_complex_value_t        *publisher_upstream_request_url_ccv;
  
  publisher_upstream_request_url_ccv = fsub->sub.cf->publisher_upstream_request_url;
  if(publisher_upstream_request_url_ccv == NULL) {
    websocket_publish_continue(fsub, buf);
  }
  else {
    nchan_pub_upstream_stuff_t    *psr_stuff;
    ngx_http_post_subrequest_t    *psr;
    nchan_pub_upstream_data_t     *psrd;
    ngx_http_request_t            *r = fsub->sub.request;
    ngx_http_request_t            *sr;
    ngx_http_request_body_t       *fakebody;
    ngx_chain_t                   *fakebody_chain;
    ngx_buf_t                     *fakebody_buf;
    size_t                         sz;
    
    if(!fsub->upstream_stuff) {
      
      if((psr_stuff = ngx_palloc(r->pool, sizeof(*psr_stuff))) == NULL) {
        ERR("can't allocate memory for publisher auth subrequest");
        websocket_respond_status(&fsub->sub, NGX_HTTP_INTERNAL_SERVER_ERROR, NULL);
        return NGX_ERROR;
      }
      
      fsub->upstream_stuff = psr_stuff;
      psr = &psr_stuff->psr;
      psr->data = &psr_stuff->psr_data;
      psr->handler = websocket_publisher_upstream_handler;
      psr_stuff->psr_data.fsub = fsub;
      
      psr_stuff->psr_data.tmp_pool = NULL;
      
      ngx_http_complex_value(r, publisher_upstream_request_url_ccv, &psr_stuff->psr_data.upstream_request_url); 
    }
    
    psrd = &fsub->upstream_stuff->psr_data;
    psr = &fsub->upstream_stuff->psr;
    
    if(psrd->tmp_pool) {
      //previous upstream request's pool
      ngx_destroy_pool(psrd->tmp_pool);
      psrd->tmp_pool = NULL;
    }
    
    psrd->buf = *buf;
    psrd->original_pool = r->pool;
    psrd->original_cleanup = r->cleanup;
    r->cleanup = NULL;
    
    psrd->tmp_pool = ngx_create_pool(NCHAN_WS_UPSTREAM_TMP_POOL_SIZE, r->connection->log);
    
    r->pool = psrd->tmp_pool;
    //ERR("request %p tmp pool %p", r, r->pool);
    
    fakebody = ngx_pcalloc(r->pool, sizeof(*fakebody));
    if(ngx_buf_size(buf) > 0) {
      fakebody_chain = ngx_palloc(r->pool, sizeof(*fakebody_chain));
      fakebody_buf = ngx_palloc(r->pool, sizeof(*fakebody_buf));
      fakebody->bufs = fakebody_chain;
      fakebody_chain->next = NULL;
      fakebody_chain->buf = fakebody_buf;
      init_msg_buf(fakebody_buf);
      
      //just copy the buffer contents. it's inefficient but I don't care at the moment.
      //this can and should be optimized later
      sz = ngx_buf_size(buf);
      fakebody_buf->start = ngx_palloc(r->pool, sz); //huuh?
      ngx_memcpy(fakebody_buf->start, buf->start, sz);
      fakebody_buf->end = fakebody_buf->start + sz;
      fakebody_buf->pos = fakebody_buf->start;
      fakebody_buf->last = fakebody_buf->end;
    }
    else {
      sz = 0;
    }
    
    ngx_http_subrequest(r, &psrd->upstream_request_url, NULL, &sr, psr, NGX_HTTP_SUBREQUEST_IN_MEMORY);
    nchan_adjust_subrequest(sr, NGX_HTTP_POST, &POST_REQUEST_STRING, fakebody, sz, NULL);
    
    /*
    //http request sudden close cleanup
    if((psrd->cln = ngx_http_cleanup_add(sr, 0)) == NULL) {
      ERR("Unable to add request cleanup for websocket upstream request");
      return NGX_ERROR;
    }
    psrd->cln->data = fsub;
    psrd->cln->handler = (ngx_http_cleanup_pt )sudden_upstream_request_abort_handler;
    */
  }
  
  return NGX_OK;
}
//获取secure_link配置的值,同时与secure_link_md5运算的值进行比较,相同则置$secure_link变量为1,不同则置0
static ngx_int_t
ngx_http_secure_link_variable(ngx_http_request_t *r,
    ngx_http_variable_value_t *v, uintptr_t data)
{
    u_char                       *p, *last;
    ngx_str_t                     val, hash;
    time_t                        expires;
    ngx_md5_t                     md5;
    ngx_http_secure_link_ctx_t   *ctx;
    ngx_http_secure_link_conf_t  *conf;
    u_char                        hash_buf[16], md5_buf[16];

    conf = ngx_http_get_module_loc_conf(r, ngx_http_secure_link_module);

    if (conf->secret.data) {
        return ngx_http_secure_link_old_variable(r, conf, v, data);
    }

    if (conf->variable == NULL || conf->md5 == NULL) {
        goto not_found;
    }

    if (ngx_http_complex_value(r, conf->variable, &val) != NGX_OK) {
        return NGX_ERROR;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secure link: \"%V\"", &val);

    last = val.data + val.len;

    p = ngx_strlchr(val.data, last, ','); ////secure_link md5_str, 120配置,
    expires = 0;

    if (p) {
        val.len = p++ - val.data; //这时候,val.len=md5_str的字符串长度了,不包括后面的,120字符串

        expires = ngx_atotm(p, last - p); //获取//secure_link md5_str, 120配置中的120
        if (expires <= 0) {
            goto not_found;
        }

        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_secure_link_ctx_t));
        if (ctx == NULL) {
            return NGX_ERROR;
        }

        ngx_http_set_ctx(r, ctx, ngx_http_secure_link_module);

        ctx->expires.len = last - p;
        ctx->expires.data = p;
    }

    //这时候,val.len=md5_str的字符串长度了,不包括后面的,120字符串
    if (val.len > 24) {//secure_link配置解析出的字符串不能超过24个字符 ?????? 为什么呢
        goto not_found;
    }

    hash.len = 16;
    hash.data = hash_buf;

    //把secure_link md5_str, 120配置中的md5_str字符串进行base64解密decode运算后的值存到这里面    
    if (ngx_decode_base64url(&hash, &val) != NGX_OK) {
        goto not_found;
    }

    if (hash.len != 16) {
        goto not_found;
    }

    //解析secure_link_md5 $the_uri_you_want_to_hashed_by_md5配置的字符串
    if (ngx_http_complex_value(r, conf->md5, &val) != NGX_OK) {
        return NGX_ERROR;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secure link md5: \"%V\"", &val);

    //echo -n 'ttlsa.com/download/nginx-1.9.2.rar1452130593' |     openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =
    ngx_md5_init(&md5);
    ngx_md5_update(&md5, val.data, val.len);
    ngx_md5_final(md5_buf, &md5);

    if (ngx_memcmp(hash_buf, md5_buf, 16) != 0) { //比较判断是否一致
        goto not_found;
    }

    //设置v变量对应的值为0或者1
    v->data = (u_char *) ((expires && expires < ngx_time()) ? "0" : "1");
    v->len = 1;
    v->valid = 1;
    v->no_cacheable = 0;
    v->not_found = 0;

    return NGX_OK;

not_found:

    v->not_found = 1;

    return NGX_OK;
}
static ngx_int_t
ngx_http_trailers_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    ngx_str_t                 value;
    ngx_uint_t                i, safe_status;
    ngx_chain_t              *cl;
    ngx_table_elt_t          *t;
    ngx_http_header_val_t    *h;
    ngx_http_headers_conf_t  *conf;

    conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module);

    if (in == NULL
        || conf->trailers == NULL
        || !r->expect_trailers
        || r->header_only)
    {
        return ngx_http_next_body_filter(r, in);
    }

    for (cl = in; cl; cl = cl->next) {
        if (cl->buf->last_buf) {
            break;
        }
    }

    if (cl == NULL) {
        return ngx_http_next_body_filter(r, in);
    }

    switch (r->headers_out.status) {

    case NGX_HTTP_OK:
    case NGX_HTTP_CREATED:
    case NGX_HTTP_NO_CONTENT:
    case NGX_HTTP_PARTIAL_CONTENT:
    case NGX_HTTP_MOVED_PERMANENTLY:
    case NGX_HTTP_MOVED_TEMPORARILY:
    case NGX_HTTP_SEE_OTHER:
    case NGX_HTTP_NOT_MODIFIED:
    case NGX_HTTP_TEMPORARY_REDIRECT:
    case NGX_HTTP_PERMANENT_REDIRECT:
        safe_status = 1;
        break;

    default:
        safe_status = 0;
        break;
    }

    h = conf->trailers->elts;
    for (i = 0; i < conf->trailers->nelts; i++) {

        if (!safe_status && !h[i].always) {
            continue;
        }

        if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) {
            return NGX_ERROR;
        }

        if (value.len) {
            t = ngx_list_push(&r->headers_out.trailers);
            if (t == NULL) {
                return NGX_ERROR;
            }

            t->key = h[i].key;
            t->value = value;
            t->hash = 1;
        }
    }

    return ngx_http_next_body_filter(r, in);
}
/**
 * Content handler.
 *
 * @param r
 *   Request structure pointer
 * @return
 *   Response status
 */
static ngx_int_t ngx_http_unzip_handler(ngx_http_request_t *r)
{
    ngx_buf_t   *b;
    ngx_chain_t out;
    ngx_str_t   unzip_filename;
    ngx_str_t   unzip_extract;
    struct      zip *zip_source;
    struct      zip_stat zip_st;
    struct      zip_file *file_in_zip;
    int         err = 0;
    char        *unzipfile_path;
    char        *unzipextract_path;
    unsigned char *zip_content;
    unsigned int  zip_read_bytes;

    ngx_http_unzip_loc_conf_t *unzip_config;
    unzip_config = ngx_http_get_module_loc_conf(r, ngx_http_unzip_module);

    /* let's try to get file_in_unzip_archivefile and file_in_unzip_extract from nginx configuration */
    if (ngx_http_complex_value(r, unzip_config->file_in_unzip_archivefile, &unzip_filename) != NGX_OK 
            || ngx_http_complex_value(r, unzip_config->file_in_unzip_extract, &unzip_extract) != NGX_OK) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to read unzip module configuration settings.");
        return NGX_ERROR;
    }

    /* we're supporting just GET and HEAD requests */
    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Only GET and HEAD requests are supported by the unzip module.");
        return NGX_HTTP_NOT_ALLOWED;
    }

    /* fill path variables with 0 as ngx_string_t doesn't terminate string with 0 */
    unzipfile_path = malloc(unzip_filename.len+1);
    if (unzipfile_path == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate buffer.");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    unzipextract_path = malloc(unzip_extract.len+1);
    if (unzipextract_path == NULL) {
        free(unzipfile_path);
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate buffer.");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    memset(unzipfile_path, 0, unzip_filename.len+1);
    memset(unzipextract_path, 0, unzip_extract.len+1);

    /* get path variables terminated with 0 */
    strncpy(unzipfile_path, (char *)unzip_filename.data, unzip_filename.len);
    strncpy(unzipextract_path, (char *)unzip_extract.data, unzip_extract.len);

    /* try to open archive (zip) file */
    if (!(zip_source = zip_open(unzipfile_path, 0, &err))) {
        free(unzipfile_path);
        free(unzipextract_path);
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s : no such archive file.", unzipfile_path);
        return NGX_HTTP_NOT_FOUND;
    }

    /* initialize structure */
    zip_stat_init(&zip_st);

    /* let's check what's the size of a file. return 404 if we can't stat file inside archive */
    if (0 != zip_stat(zip_source, unzipextract_path, 0, &zip_st)) {
        free(unzipfile_path);
        free(unzipextract_path);
        zip_close(zip_source);
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no file %s inside %s archive.", unzipextract_path, unzipfile_path);
        return NGX_HTTP_NOT_FOUND;
    }

    /* allocate buffer for the file content */
    if (!(zip_content = ngx_palloc(r->pool, zip_st.size))) {
        free(unzipfile_path);
        free(unzipextract_path);
        zip_close(zip_source);
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer memory.");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /* 
    *  try to open a file that we want - if not return 500 as we know that the file is there (making zip_stat before) 
    *  so let's return 500.
    */
    if (!(file_in_zip = zip_fopen(zip_source, unzipextract_path, 0))) {
        free(unzipfile_path);
        free(unzipextract_path);
        zip_close(zip_source);
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to open %s from %s archive (corrupted?).",
                unzipextract_path, unzipfile_path);
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /* 
    *  let's get file content and check if we got all
    *  we're expecting to get zip_st.size bytes so return 500 if we get something else.
    */
    if (!(zip_read_bytes = zip_fread(file_in_zip, zip_content, zip_st.size)) || zip_read_bytes != zip_st.size) {
        free(unzipfile_path);
        free(unzipextract_path);
        zip_fclose(file_in_zip);
        zip_close(zip_source);
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "couldn't get %d bytes of %s from %s archive (corrupted?).",
                zip_st.size, unzipextract_path, unzipfile_path);
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /* close both files */
    zip_fclose(file_in_zip);
    zip_close(zip_source);

    /* let's clean */
    free(unzipfile_path);
    free(unzipextract_path);

    /* set the content-type header. */
    if (ngx_http_set_content_type(r) != NGX_OK) {
        r->headers_out.content_type.len = sizeof("text/plain") - 1;
        r->headers_out.content_type.data = (u_char *) "text/plain";
    }

    /* allocate a new buffer for sending out the reply. */
    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));

    if (b == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /* insertion in the buffer chain. */
    out.buf = b;
    out.next = NULL; /* just one buffer */

    b->pos = zip_content;
    b->last = zip_content + zip_read_bytes;
    b->memory = 1;
    b->last_buf = 1;

    /* sending the headers for the reply. */
    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = zip_read_bytes;
    ngx_http_send_header(r);

    return ngx_http_output_filter(r, &out);
} /* ngx_http_unzip_handler */
ngx_int_t
ngx_http_lua_content_handler_file(ngx_http_request_t *r)
{
    lua_State                       *L;
    ngx_int_t                        rc;
    u_char                          *script_path;
    ngx_http_lua_main_conf_t        *lmcf;
    ngx_http_lua_loc_conf_t         *llcf;
    char                            *err;
    ngx_str_t                        eval_src;

    llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);

    if (ngx_http_complex_value(r, &llcf->content_src, &eval_src) != NGX_OK) {
        return NGX_ERROR;
    }

    script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data,
            eval_src.len);

    if (script_path == NULL) {
        return NGX_ERROR;
    }

    lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
    L = lmcf->lua;

    /*  load Lua script file (w/ cache)        sp = 1 */
    rc = ngx_http_lua_cache_loadfile(L, script_path, llcf->content_src_key,
            &err, llcf->enable_code_cache ? 1 : 0);

    if (rc != NGX_OK) {
        if (err == NULL) {
            err = "unknown error";
        }

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                "Failed to load Lua inlined code: %s", err);

        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /*  make sure we have a valid code chunk */
    assert(lua_isfunction(L, -1));

    rc = ngx_http_lua_content_by_chunk(L, r);

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

    if (rc == NGX_DONE) {
        return NGX_DONE;
    }

    if (rc == NGX_AGAIN) {
#if defined(nginx_version) && nginx_version >= 8011
        r->main->count++;
#endif
        return NGX_DONE;
    }

    return NGX_OK;
}
ngx_int_t
ngx_http_redis2_handler(ngx_http_request_t *r)
{
    ngx_int_t                        rc;
    ngx_http_upstream_t             *u;
    ngx_http_redis2_ctx_t           *ctx;
    ngx_http_redis2_loc_conf_t      *rlcf;
    ngx_str_t                        target;
    ngx_url_t                        url;

    rc = ngx_http_discard_request_body(r);

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

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

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

    u = r->upstream;

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis2_module);

    if (rlcf->complex_target) {
        /* variables used in the redis2_pass directive */

        if (ngx_http_complex_value(r, rlcf->complex_target, &target)
                != NGX_OK)
        {
            return NGX_ERROR;
        }

        if (target.len == 0) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                    "handler: empty \"redis2_pass\" target");
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        url.host = target;
        url.port = 0;
        url.no_resolve = 1;

        rlcf->upstream.upstream = ngx_http_redis2_upstream_add(r, &url);

        if (rlcf->upstream.upstream == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                   "redis2: upstream \"%V\" not found", &target);

            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
    }


    ngx_str_set(&u->schema, "redis2://");
    u->output.tag = (ngx_buf_tag_t) &ngx_http_redis2_module;

    u->conf = &rlcf->upstream;

    u->create_request = ngx_http_redis2_create_request;
    u->reinit_request = ngx_http_redis2_reinit_request;
    u->process_header = ngx_http_redis2_process_header;
    u->abort_request = ngx_http_redis2_abort_request;
    u->finalize_request = ngx_http_redis2_finalize_request;

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

    ctx->request = r;
    ctx->state = NGX_ERROR;

    ngx_http_set_ctx(r, ctx, ngx_http_redis2_module);

    u->input_filter_init = ngx_http_redis2_filter_init;
    u->input_filter = ngx_http_redis2_filter;
    u->input_filter_ctx = ctx;

    r->main->count++;

    ngx_http_upstream_init(r);

    return NGX_DONE;
}
static ngx_int_t
ngx_http_redis2_create_request(ngx_http_request_t *r)
{
    ngx_buf_t                       *b;
    ngx_chain_t                     *cl;
    ngx_http_redis2_loc_conf_t      *rlcf;
    ngx_str_t                        query;
    ngx_str_t                        query_count;
    ngx_int_t                        rc;
    ngx_http_redis2_ctx_t           *ctx;
    ngx_int_t                        n;

    ctx = ngx_http_get_module_ctx(r, ngx_http_redis2_module);

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis2_module);

    if (rlcf->queries) {
        ctx->query_count = rlcf->queries->nelts;

        rc = ngx_http_redis2_build_query(r, rlcf->queries, &b);
        if (rc != NGX_OK) {
            return rc;
        }

    } else if (rlcf->literal_query.len == 0) {
        if (rlcf->complex_query == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                    "no redis2 query specified or the query is empty");

            return NGX_ERROR;
        }

        if (ngx_http_complex_value(r, rlcf->complex_query, &query)
                != NGX_OK)
        {
            return NGX_ERROR;
        }

        if (query.len == 0) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                    "the redis query is empty");

            return NGX_ERROR;
        }

        if (rlcf->complex_query_count == NULL) {
            ctx->query_count = 1;

        } else {
            if (ngx_http_complex_value(r, rlcf->complex_query_count,
                    &query_count) != NGX_OK)
            {
                return NGX_ERROR;
            }

            if (query_count.len == 0) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                        "the N argument to redis2_raw_queries is empty");

                return NGX_ERROR;
            }

            n = ngx_atoi(query_count.data, query_count.len);
            if (n == NGX_ERROR || n == 0) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                        "the N argument to redis2_raw_queries is invalid");

                return NGX_ERROR;
            }

            ctx->query_count = n;
        }

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

        b->last = ngx_copy(b->pos, query.data, query.len);

    } else {
        ctx->query_count = 1;

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

        b->pos = rlcf->literal_query.data;
        b->last = b->pos + rlcf->literal_query.len;
        b->memory = 1;
    }

    cl = ngx_alloc_chain_link(r->pool);
    if (cl == NULL) {
        return NGX_ERROR;
    }

    cl->buf = b;
    cl->next = NULL;

    r->upstream->request_bufs = cl;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http redis2 request: \"%V\"", &rlcf->literal_query);

    return NGX_OK;
}
static ngx_int_t
ngx_http_poller_create_request(ngx_http_request_t *r)
{
  ngx_http_poller_t         *poller;
  ngx_http_poller_header_t  *header;
  ngx_str_t                 *value;
  ngx_buf_t                 *b;
  ngx_chain_t               *cl;
  ngx_uint_t                 i;
  size_t                     len;
  ngx_str_t                  uri;
  ngx_str_t                  body;
  ngx_array_t                headers;

  poller = ngx_http_get_module_ctx(r, ngx_http_poller_module);

  if (ngx_http_complex_value(r, &poller->uri, &uri) != NGX_OK) {
    return NGX_ERROR;
  }

  body.len = 0;
  body.data = NULL;
  if (poller->body_ok) {
    if (ngx_http_complex_value(r, &poller->body, &body) != NGX_OK) {
      return NGX_ERROR;
    }
  }

  len  = poller->method.len;
  len += sizeof(" ") - 1;
  len += uri.len;
  len += sizeof(" HTTP/1.0") - 1;
  len += sizeof(CRLF) - 1;

  if (poller->headers.nelts > 0) {
    if (ngx_array_init(&headers, r->pool, poller->headers.nelts,
		       sizeof(ngx_str_t)) != NGX_OK) {
      return NGX_ERROR;
    }

    header = poller->headers.elts;
    for (i = 0; i < poller->headers.nelts; ++i) {
      value = ngx_array_push(&headers);
      if (value == NULL) {
	return NGX_ERROR;
      }
      if (ngx_http_complex_value(r, &header[i].value, value) != NGX_OK) {
	return NGX_ERROR;
      }

      len += header[i].name.len;
      len += sizeof(": ") - 1;
      len += value->len;
      len += sizeof(CRLF) - 1;
    }    
  }

  if (poller->body_ok) {
    len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2;
  }

  len += sizeof(CRLF) - 1;

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

#define DO_CPYMEM(x, y) x = ngx_cpymem(x, y, sizeof(y) - 1)
#define DO_CPYSTR(x, y) x = ngx_cpymem(x, y.data, y.len)

  DO_CPYSTR(b->last, poller->method);
  DO_CPYMEM(b->last, " ");
  DO_CPYSTR(b->last, uri);
  DO_CPYMEM(b->last, " HTTP/1.0");
  DO_CPYMEM(b->last, CRLF);

  if (poller->headers.nelts > 0) {
    header = poller->headers.elts;
    value = headers.elts;
    for (i = 0; i < poller->headers.nelts; ++i) {
      DO_CPYSTR(b->last, header[i].name);
      DO_CPYMEM(b->last, ": ");
      DO_CPYSTR(b->last, value[i]);
      DO_CPYMEM(b->last, CRLF);
    }
  }

  if (poller->body_ok) {
    b->last = ngx_sprintf(b->last, "Content-Length: %O", (off_t)body.len);
    DO_CPYMEM(b->last, CRLF);
  }

  DO_CPYMEM(b->last, CRLF);

  if (poller->body_ok && body.len > 0) {
    DO_CPYSTR(b->last, body);
  }

#undef DO_CPYMEM
#undef DO_CPYSTR

  cl = ngx_alloc_chain_link(r->pool);
  if (cl == NULL) {
    return NGX_ERROR;
  }

  cl->buf = b;
  cl->next = NULL;

  r->upstream->request_bufs = cl;
  r->subrequest_in_memory = 1;
  b->last_buf = 1;

  return NGX_OK;
}
ngx_int_t
ngx_http_rds_json_output_props(ngx_http_request_t *r,
    ngx_http_rds_json_ctx_t *ctx, ngx_http_rds_json_loc_conf_t *conf)
{
    size_t                   size;
    u_char                  *pos, *last;
    ngx_uint_t               i;
    ngx_str_t               *values = NULL;
    uintptr_t               *escapes = NULL;

    ngx_http_rds_json_property_t        *prop = NULL;

    size = sizeof("{:") - 1 + conf->root.len;

    if (conf->success.len) {
        size += sizeof(",:true") - 1 + conf->success.len;
    }

    if (conf->user_props) {
        values = ngx_pnalloc(r->pool,
                             conf->user_props->nelts * (sizeof(ngx_str_t)
                             + sizeof(uintptr_t)));

        if (values == NULL) {
            return NGX_ERROR;
        }

        escapes = (uintptr_t *) ((u_char *) values
                  + conf->user_props->nelts * sizeof(ngx_str_t));

        prop = conf->user_props->elts;
        for (i = 0; i < conf->user_props->nelts; i++) {
            if (ngx_http_complex_value(r, &prop[i].value, &values[i])
                != NGX_OK)
            {
                return NGX_ERROR;
            }

            escapes[i] = ngx_http_rds_json_escape_json_str(NULL,
                                                           values[i].data,
                                                           values[i].len);

            size += sizeof(":\"\",") - 1 + prop[i].key.len + values[i].len
                    + escapes[i];
        }
    }

    pos = ngx_http_rds_json_request_mem(r, ctx, size);
    if (pos == NULL) {
        return NGX_ERROR;
    }

    last = pos;

    *last++ = '{';

    if (conf->success.len) {
        last = ngx_copy(last, conf->success.data, conf->success.len);
        last = ngx_copy_literal(last, ":true,");
    }

    if (conf->user_props) {
        for (i = 0; i < conf->user_props->nelts; i++) {
            last = ngx_copy(last, prop[i].key.data, prop[i].key.len);
            *last++ = ':';
            *last++ = '"';

            if (escapes[i] == 0) {
                last = ngx_copy(last, values[i].data, values[i].len);

            } else {
                last = (u_char *)
                        ngx_http_rds_json_escape_json_str(last,
                                                          values[i].data,
                                                          values[i].len);
            }

            *last++ = '"';
            *last++ = ',';
        }
    }

    last = ngx_copy(last, conf->root.data, conf->root.len);
    *last++ = ':';

    if (last - pos != (ssize_t) size) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "rds_json: output props begin: buffer error: %O != %uz",
                      (off_t) (last - pos), size);

        return NGX_ERROR;
    }

    return ngx_http_rds_json_submit_mem(r, ctx, size, 0);
}
Example #16
0
ngx_int_t nchan_maybe_send_channel_event_message(ngx_http_request_t *r, channel_event_type_t event_type) {
  static nchan_loc_conf_t            evcf_data;
  static nchan_loc_conf_t           *evcf = NULL;
  
  static ngx_str_t group =           ngx_string("meta");
  
  static ngx_str_t evt_sub_enqueue = ngx_string("subscriber_enqueue");
  static ngx_str_t evt_sub_dequeue = ngx_string("subscriber_dequeue");
  static ngx_str_t evt_sub_recvmsg = ngx_string("subscriber_receive_message");
  static ngx_str_t evt_sub_recvsts = ngx_string("subscriber_receive_status");
  static ngx_str_t evt_chan_publish= ngx_string("channel_publish");
  static ngx_str_t evt_chan_delete = ngx_string("channel_delete");

  nchan_loc_conf_t          *cf = ngx_http_get_module_loc_conf(r, ngx_nchan_module);
  ngx_http_complex_value_t  *cv = cf->channel_events_channel_id;
  if(cv==NULL) {
    //nothing to send
    return NGX_OK;
  }
  
  nchan_request_ctx_t       *ctx = ngx_http_get_module_ctx(r, ngx_nchan_module);
  ngx_str_t                  tmpid;
  size_t                     sz;
  ngx_str_t                 *id;
  u_char                    *cur;
  ngx_str_t                  evstr;
  nchan_msg_t                msg;
  
  switch(event_type) {
    case SUB_ENQUEUE:
      ctx->channel_event_name = &evt_sub_enqueue;
      break;
    case SUB_DEQUEUE:
      ctx->channel_event_name = &evt_sub_dequeue;
      break;
    case SUB_RECEIVE_MESSAGE:
      ctx->channel_event_name = &evt_sub_recvmsg;
      break;
    case SUB_RECEIVE_STATUS:
      ctx->channel_event_name = &evt_sub_recvsts;
      break;
    case CHAN_PUBLISH:
      ctx->channel_event_name = &evt_chan_publish;
      break;
    case CHAN_DELETE:
      ctx->channel_event_name = &evt_chan_delete;
      break;
  }
  
  //the id
  ngx_http_complex_value(r, cv, &tmpid); 
  sz = group.len + 1 + tmpid.len;
  if((id = ngx_palloc(r->pool, sizeof(*id) + sz)) == NULL) {
    nchan_log_request_error(r, "can't allocate space for legacy channel id");
    return NGX_ERROR;
  }
  id->len = sz;
  id->data = (u_char *)&id[1];
  cur = id->data;  
  ngx_memcpy(cur, group.data, group.len);
  cur += group.len;
  cur[0]='/';
  cur++;
  ngx_memcpy(cur, tmpid.data, tmpid.len);
  
  
  //the event message
  ngx_http_complex_value(r, cf->channel_event_string, &evstr);
  
  ngx_memzero(&msg, sizeof(msg));
  
  msg.buf.temporary = 1;
  msg.buf.memory = 1;
  msg.buf.last_buf = 1;
  msg.buf.pos = evstr.data;
  msg.buf.last = evstr.data + evstr.len;
  msg.buf.start = msg.buf.pos;
  msg.buf.end = msg.buf.last;
  
  msg.id.time = 0;
  msg.id.tag.fixed[0] = 0;
  msg.id.tagactive = 0;
  msg.id.tagcount = 1;
  
  if(evcf == NULL) {
    evcf = &evcf_data;
    ngx_memzero(evcf, sizeof(*evcf));

    evcf->message_timeout = NCHAN_META_CHANNEL_MESSAGE_TTL;
    evcf->max_messages = NCHAN_META_CHANNEL_MAX_MESSAGES;
    evcf->complex_max_messages = NULL;
    evcf->complex_message_timeout = NULL;
    evcf->subscriber_first_message = 0;
    evcf->channel_timeout = NCHAN_META_CHANNEL_TIMEOUT;
  }
  evcf->storage_engine = cf->storage_engine;
  evcf->redis = cf->redis;
  
  evcf->storage_engine->publish(id, &msg, evcf, NULL, NULL);
  
  return NGX_OK;
}
static ngx_int_t
ngx_http_replace_header_filter(ngx_http_request_t *r)
{
    size_t                         size;
    ngx_str_t                      skip;
    ngx_pool_cleanup_t            *cln;
    ngx_http_replace_ctx_t        *ctx;
    ngx_http_replace_loc_conf_t  *rlcf;

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_replace_filter_module);

    dd("replace header filter");

    if (rlcf->regexes.nelts == 0
        || r->headers_out.content_length_n == 0
        || (r->headers_out.content_encoding
            && r->headers_out.content_encoding->value.len)
        || ngx_http_test_content_type(r, &rlcf->types) == NULL)
    {
        return ngx_http_next_header_filter(r);
    }

    dd("skip: %p", rlcf->skip);

    if (rlcf->skip != NULL) {
        if (ngx_http_complex_value(r, rlcf->skip, &skip) != NGX_OK) {
            return NGX_ERROR;
        }

        if (skip.len && (skip.len != 1 || skip.data[0] != '0')) {
            return ngx_http_next_header_filter(r);
        }
    }

    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_replace_ctx_t));
    if (ctx == NULL) {
        return NGX_ERROR;
    }

    ctx->last_special = &ctx->special;
    ctx->last_pending = &ctx->pending;
    ctx->last_pending2 = &ctx->pending2;
    ctx->last_captured = &ctx->captured;

    ctx->sub = ngx_pcalloc(r->pool,
                           rlcf->multi_replace.nelts * sizeof(ngx_str_t));
    if (ctx->sub == NULL) {
        return NGX_ERROR;
    }

    ctx->ovector = ngx_palloc(r->pool, rlcf->ovecsize);
    if (ctx->ovector == NULL) {
        return NGX_ERROR;
    }

    size = ngx_align(rlcf->regexes.nelts, 8) / 8;
    ctx->disabled = ngx_pcalloc(r->pool, size);
    if (ctx->disabled == NULL) {
        return NGX_ERROR;
    }

    ctx->vm_pool = sre_create_pool(1024);
    if (ctx->vm_pool == NULL) {
        return NGX_ERROR;
    }

    dd("created vm pool %p", ctx->vm_pool);

    cln = ngx_pool_cleanup_add(r->pool, 0);
    if (cln == NULL) {
        sre_destroy_pool(ctx->vm_pool);
        return NGX_ERROR;
    }

    cln->data = ctx->vm_pool;
    cln->handler = ngx_http_replace_cleanup_pool;

    ctx->vm_ctx = sre_vm_pike_create_ctx(ctx->vm_pool, rlcf->program,
                                         ctx->ovector, rlcf->ovecsize);
    if (ctx->vm_ctx == NULL) {
        return NGX_ERROR;
    }

    ngx_http_set_ctx(r, ctx, ngx_http_replace_filter_module);

    ctx->last_out = &ctx->out;

    r->filter_need_in_memory = 1;

    if (r == r->main) {
        ngx_http_clear_content_length(r);

        if (rlcf->last_modified == NGX_HTTP_REPLACE_CLEAR_LAST_MODIFIED) {
            ngx_http_clear_last_modified(r);
        }
    }

    return ngx_http_next_header_filter(r);
}
Example #18
0
static void nchan_publisher_body_handler_continued(ngx_http_request_t *r, ngx_str_t *channel_id, nchan_loc_conf_t *cf) {
  ngx_http_complex_value_t       *publisher_upstream_request_url_ccv;
  static ngx_str_t                POST_REQUEST_STRING = {4, (u_char *)"POST "};
  safe_request_ptr_t             *pd;
  
  switch(r->method) {
    case NGX_HTTP_GET:
      if((pd = nchan_set_safe_request_ptr(r)) == NULL){
        return;
      }
      cf->storage_engine->find_channel(channel_id, cf, (callback_pt) &channel_info_callback, pd);
      break;
    
    case NGX_HTTP_PUT:
    case NGX_HTTP_POST:
      publisher_upstream_request_url_ccv = cf->publisher_upstream_request_url;
      if(publisher_upstream_request_url_ccv == NULL) {
        ngx_str_t    *content_type = (r->headers_in.content_type ? &r->headers_in.content_type->value : NULL);
        ngx_int_t     content_length = r->headers_in.content_length_n > 0 ? r->headers_in.content_length_n : 0;
        // no need to check for chunked transfer-encoding, nginx automatically sets the 
        // content-length either way.
        
        nchan_publisher_post_request(r, content_type, content_length, r->request_body->bufs, channel_id, cf);
      }
      else {
        nchan_pub_upstream_stuff_t    *psr_stuff;
        
        if((psr_stuff = ngx_palloc(r->pool, sizeof(*psr_stuff))) == NULL) {
          nchan_log_request_error(r, "can't allocate memory for publisher auth subrequest");
          nchan_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
          return;
        }
        
        ngx_http_post_subrequest_t    *psr = &psr_stuff->psr;
        nchan_pub_upstream_data_t     *psrd = &psr_stuff->psr_data;
        ngx_http_request_t            *sr;
        ngx_str_t                      publisher_upstream_request_url;
        
        ngx_http_complex_value(r, publisher_upstream_request_url_ccv, &publisher_upstream_request_url);
        
        psr->handler = nchan_publisher_upstream_handler;
        psr->data = psrd;
        
        psrd->ch_id = channel_id;
        
        ngx_http_subrequest(r, &publisher_upstream_request_url, NULL, &sr, psr, NGX_HTTP_SUBREQUEST_IN_MEMORY);
        nchan_adjust_subrequest(sr, NGX_HTTP_POST, &POST_REQUEST_STRING, r->request_body, r->headers_in.content_length_n, NULL);
        sr->args = r->args;
      }
      break;
      
    case NGX_HTTP_DELETE:
      if((pd = nchan_set_safe_request_ptr(r)) == NULL){
        return;
      }
      cf->storage_engine->delete_channel(channel_id, cf, (callback_pt) &channel_info_callback, pd);
      nchan_maybe_send_channel_event_message(r, CHAN_DELETE);
      break;
      
    default: 
      nchan_respond_status(r, NGX_HTTP_FORBIDDEN, NULL, 0);
  }
  
}
Example #19
0
ngx_int_t
ngx_http_redis2_build_query(ngx_http_request_t *r, ngx_array_t *queries,
    ngx_buf_t **b)
{
    ngx_uint_t                       i, j;
    ngx_uint_t                       n;
    ngx_str_t                       *arg;
    ngx_array_t                     *args;
    size_t                           len;
    ngx_array_t                    **query_args;
    ngx_http_complex_value_t       **complex_arg;
    u_char                          *p;
    ngx_http_redis2_loc_conf_t      *rlcf;

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis2_module);

    query_args = rlcf->queries->elts;

    n = 0;
    for (i = 0; i < rlcf->queries->nelts; i++) {
        for (j = 0; j < query_args[i]->nelts; j++) {
            n++;
        }
    }

    args = ngx_array_create(r->pool, n, sizeof(ngx_str_t));

    if (args == NULL) {
        return NGX_ERROR;
    }

    len = 0;
    n = 0;

    for (i = 0; i < rlcf->queries->nelts; i++) {
        complex_arg = query_args[i]->elts;

        len += sizeof("*") - 1
             + ngx_get_num_size(query_args[i]->nelts)
             + sizeof("\r\n") - 1
             ;

        for (j = 0; j < query_args[i]->nelts; j++) {
            n++;

            arg = ngx_array_push(args);
            if (arg == NULL) {
                return NGX_ERROR;
            }

            if (ngx_http_complex_value(r, complex_arg[j], arg) != NGX_OK) {
                return NGX_ERROR;
            }

            len += sizeof("$") - 1
                 + ngx_get_num_size(arg->len)
                 + sizeof("\r\n") - 1
                 + arg->len
                 + sizeof("\r\n") - 1
                 ;
        }
    }

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

    p = (*b)->last;

    arg = args->elts;

    n = 0;
    for (i = 0; i < rlcf->queries->nelts; i++) {
        *p++ = '*';
        p = ngx_sprintf(p, "%uz", query_args[i]->nelts);
        *p++ = '\r'; *p++ = '\n';

        for (j = 0; j < query_args[i]->nelts; j++) {
            *p++ = '$';
            p = ngx_sprintf(p, "%uz", arg[n].len);
            *p++ = '\r'; *p++ = '\n';
            p = ngx_copy(p, arg[n].data, arg[n].len);
            *p++ = '\r'; *p++ = '\n';

            n++;
        }
    }

    dd("query: %.*s", (int) (p - (*b)->pos), (*b)->pos);

    if (p - (*b)->pos != (ssize_t) len) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                "redis2: redis2_query buffer error %uz != %uz",
                (size_t) (p - (*b)->pos), len);

        return NGX_ERROR;
    }

    (*b)->last = p;

    return NGX_OK;
}
ngx_int_t
ngx_postgres_upstream_init_peer(ngx_http_request_t *r,
    ngx_http_upstream_srv_conf_t *uscf)
{
    ngx_postgres_upstream_peer_data_t  *pgdt;
    ngx_postgres_upstream_srv_conf_t   *pgscf;
    ngx_postgres_loc_conf_t            *pglcf;
    ngx_postgres_ctx_t                 *pgctx;
    ngx_http_core_loc_conf_t           *clcf;
    ngx_http_upstream_t                *u;
    ngx_postgres_mixed_t               *query;
    ngx_str_t                           sql;
    ngx_uint_t                          i;

    dd("entering");

    pgdt = ngx_pcalloc(r->pool, sizeof(ngx_postgres_upstream_peer_data_t));
    if (pgdt == NULL) {
        goto failed;
    }

    u = r->upstream;

    pgdt->upstream = u;
    pgdt->request = r;

    pgscf = ngx_http_conf_upstream_srv_conf(uscf, ngx_postgres_module);
    pglcf = ngx_http_get_module_loc_conf(r, ngx_postgres_module);
    pgctx = ngx_http_get_module_ctx(r, ngx_postgres_module);

    pgdt->srv_conf = pgscf;
    pgdt->loc_conf = pglcf;

    u->peer.data = pgdt;
    u->peer.get = ngx_postgres_upstream_get_peer;
    u->peer.free = ngx_postgres_upstream_free_peer;

    if (pglcf->query.methods_set & r->method) {
        /* method-specific query */
        dd("using method-specific query");

        query = pglcf->query.methods->elts;
        for (i = 0; i < pglcf->query.methods->nelts; i++) {
            if (query[i].key & r->method) {
                query = &query[i];
                break;
            }
        }

        if (i == pglcf->query.methods->nelts) {
            goto failed;
        }
    } else {
        /* default query */
        dd("using default query");

        query = pglcf->query.def;
    }

    if (query->cv) {
        /* complex value */
        dd("using complex value");

        if (ngx_http_complex_value(r, query->cv, &sql) != NGX_OK) {
            goto failed;
        }

        if (sql.len == 0) {
            clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "postgres: empty \"postgres_query\" (was: \"%V\")"
                          " in location \"%V\"", &query->cv->value,
                          &clcf->name);

            goto failed;
        }

        pgdt->query = sql;
    } else {
        /* simple value */
        dd("using simple value");

        pgdt->query = query->sv;
    }

    /* set $postgres_query */
    pgctx->var_query = pgdt->query;

    dd("returning NGX_OK");
    return NGX_OK;

failed:

#if defined(nginx_version) && (nginx_version >= 8017)
    dd("returning NGX_ERROR");
    return NGX_ERROR;
#else
    r->upstream->peer.data = NULL;

    dd("returning NGX_OK (NGX_ERROR)");
    return NGX_OK;
#endif
}
static ngx_int_t
ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    ngx_int_t                  rc;
    ngx_buf_t                 *b;
    ngx_chain_t               *cl;
    ngx_http_sub_ctx_t        *ctx;
    ngx_http_sub_loc_conf_t   *slcf;

    ctx = ngx_http_get_module_ctx(r, ngx_http_sub_filter_module);

    if (ctx == NULL) {
        return ngx_http_next_body_filter(r, in);
    }

    if ((in == NULL
         && ctx->buf == NULL
         && ctx->in == NULL
         && ctx->busy == NULL))
    {
        return ngx_http_next_body_filter(r, in);
    }

    if (ctx->once && (ctx->buf == NULL || ctx->in == NULL)) {

        if (ctx->busy) {
            if (ngx_http_sub_output(r, ctx) == NGX_ERROR) {
                return NGX_ERROR;
            }
        }

        return ngx_http_next_body_filter(r, in);
    }

    /* add the incoming chain to the chain ctx->in */

    if (in) {
        if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
            return NGX_ERROR;
        }
    }

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http sub filter \"%V\"", &r->uri);

    while (ctx->in || ctx->buf) {

        if (ctx->buf == NULL) {
            ctx->buf = ctx->in->buf;
            ctx->in = ctx->in->next;
            ctx->pos = ctx->buf->pos;
        }

        if (ctx->state == sub_start_state) {
            ctx->copy_start = ctx->pos;
            ctx->copy_end = ctx->pos;
        }

        b = NULL;

        while (ctx->pos < ctx->buf->last) {

            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "saved: \"%V\" state: %d", &ctx->saved, ctx->state);

            rc = ngx_http_sub_parse(r, ctx);

            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "parse: %d, looked: \"%V\" %p-%p",
                           rc, &ctx->looked, ctx->copy_start, ctx->copy_end);

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

            if (ctx->saved.len) {

                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                               "saved: \"%V\"", &ctx->saved);

                cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
                if (cl == NULL) {
                    return NGX_ERROR;
                }

                b = cl->buf;

                ngx_memzero(b, sizeof(ngx_buf_t));

                b->pos = ngx_pnalloc(r->pool, ctx->saved.len);
                if (b->pos == NULL) {
                    return NGX_ERROR;
                }

                ngx_memcpy(b->pos, ctx->saved.data, ctx->saved.len);
                b->last = b->pos + ctx->saved.len;
                b->memory = 1;

                *ctx->last_out = cl;
                ctx->last_out = &cl->next;

                ctx->saved.len = 0;
            }

            if (ctx->copy_start != ctx->copy_end) {

                cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
                if (cl == NULL) {
                    return NGX_ERROR;
                }

                b = cl->buf;

                ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t));

                b->pos = ctx->copy_start;
                b->last = ctx->copy_end;
                b->shadow = NULL;
                b->last_buf = 0;
                b->last_in_chain = 0;
                b->recycled = 0;

                if (b->in_file) {
                    b->file_last = b->file_pos + (b->last - ctx->buf->pos);
                    b->file_pos += b->pos - ctx->buf->pos;
                }

                *ctx->last_out = cl;
                ctx->last_out = &cl->next;
            }

            if (ctx->state == sub_start_state) {
                ctx->copy_start = ctx->pos;
                ctx->copy_end = ctx->pos;

            } else {
                ctx->copy_start = NULL;
                ctx->copy_end = NULL;
            }

            if (ctx->looked.len > (size_t) (ctx->pos - ctx->buf->pos)) {
                ctx->saved.len = ctx->looked.len - (ctx->pos - ctx->buf->pos);
                ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->saved.len);
            }

            if (rc == NGX_AGAIN) {
                continue;
            }


            /* rc == NGX_OK */

            cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
            if (cl == NULL) {
                return NGX_ERROR;
            }

            b = cl->buf;

            ngx_memzero(b, sizeof(ngx_buf_t));

            slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module);

            if (ctx->sub.data == NULL) {

                if (ngx_http_complex_value(r, &slcf->value, &ctx->sub)
                    != NGX_OK)
                {
                    return NGX_ERROR;
                }
            }

            if (ctx->sub.len) {
                b->memory = 1;
                b->pos = ctx->sub.data;
                b->last = ctx->sub.data + ctx->sub.len;

            } else {
                b->sync = 1;
            }

            *ctx->last_out = cl;
            ctx->last_out = &cl->next;

            ctx->once = slcf->once;

            continue;
        }

        if (ctx->looked.len
            && (ctx->buf->last_buf || ctx->buf->last_in_chain))
        {
            cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
            if (cl == NULL) {
                return NGX_ERROR;
            }

            b = cl->buf;

            ngx_memzero(b, sizeof(ngx_buf_t));

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

            *ctx->last_out = cl;
            ctx->last_out = &cl->next;

            ctx->looked.len = 0;
        }

        if (ctx->buf->last_buf || ctx->buf->flush || ctx->buf->sync
            || ngx_buf_in_memory(ctx->buf))
        {
            if (b == NULL) {
                cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
                if (cl == NULL) {
                    return NGX_ERROR;
                }

                b = cl->buf;

                ngx_memzero(b, sizeof(ngx_buf_t));

                b->sync = 1;

                *ctx->last_out = cl;
                ctx->last_out = &cl->next;
            }

            b->last_buf = ctx->buf->last_buf;
            b->last_in_chain = ctx->buf->last_in_chain;
            b->flush = ctx->buf->flush;
            b->shadow = ctx->buf;

            b->recycled = ctx->buf->recycled;
        }

        ctx->buf = NULL;

        ctx->saved.len = ctx->looked.len;
        ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->looked.len);
    }

    if (ctx->out == NULL && ctx->busy == NULL) {
        return NGX_OK;
    }

    return ngx_http_sub_output(r, ctx);
}
Example #22
0
ngx_http_request_t *subscriber_cv_subrequest(subscriber_t *sub, ngx_http_complex_value_t *url_ccv, ngx_buf_t *body, subrequest_callback_pt cb, void *cb_data) {
  ngx_str_t                     request_url;
  ngx_http_complex_value(sub->request, url_ccv, &request_url);
  return subscriber_subrequest(sub, &request_url, body, cb, cb_data);
}
ngx_int_t
ngx_http_srcache_access_handler(ngx_http_request_t *r)
{
    ngx_str_t                       skip;
    ngx_int_t                       rc;
    ngx_http_srcache_loc_conf_t    *conf;
    ngx_http_srcache_main_conf_t   *smcf;
    ngx_http_srcache_ctx_t         *ctx;
    ngx_chain_t                    *cl;
    size_t                          len;
    unsigned                        no_store;

    /* access phase handlers are skipped in subrequests,
     * so the current request must be a main request */

    conf = ngx_http_get_module_loc_conf(r, ngx_http_srcache_filter_module);

    if (conf->fetch == NULL && conf->store == NULL) {
        dd("bypass: %.*s", (int) r->uri.len, r->uri.data);
        return NGX_DECLINED;
    }

    dd("store defined? %p", conf->store);

    dd("req method: %lu", (unsigned long) r->method);
    dd("cache methods: %lu", (unsigned long) conf->cache_methods);

    if (!(r->method & conf->cache_methods)) {
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "srcache_fetch and srcache_store skipped due to request "
                       "method %V", &r->method_name);

        return NGX_DECLINED;
    }

    if (conf->req_cache_control
        && ngx_http_srcache_request_no_cache(r, &no_store) == NGX_OK)
    {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "srcache_fetch skipped due to request headers "
                       "\"Cache-Control: no-cache\" or \"Pragma: no-cache\"");

        if (!no_store) {
            /* register a ctx to give a chance to srcache_store to run */

            ctx = ngx_pcalloc(r->pool,
                              sizeof(ngx_http_srcache_filter_module));

            if (ctx == NULL) {
                return NGX_ERROR;
            }

            ngx_http_set_ctx(r, ctx, ngx_http_srcache_filter_module);

        } else {
            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "srcache_store skipped due to request header "
                           "\"Cache-Control: no-store\"");
        }

        return NGX_DECLINED;
    }

    if (conf->fetch_skip != NULL
        && ngx_http_complex_value(r, conf->fetch_skip, &skip) == NGX_OK
        && skip.len
        && (skip.len != 1 || skip.data[0] != '0'))
    {
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "srcache_fetch skipped due to the true value fed into "
                       "srcache_fetch_skip: \"%V\"", &skip);

        /* register a ctx to give a chance to srcache_store to run */

        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_srcache_filter_module));

        if (ctx == NULL) {
            return NGX_ERROR;
        }

        ngx_http_set_ctx(r, ctx, ngx_http_srcache_filter_module);

        return NGX_DECLINED;
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_srcache_filter_module);

    if (ctx != NULL) {
        /*
        if (ctx->fetch_error) {
            return NGX_DECLINED;
        }
        */

        if (ctx->waiting_subrequest) {
            dd("waiting subrequest");
            return NGX_AGAIN;
        }

        if (ctx->waiting_request_body) {
            return NGX_AGAIN;
        }

        if (ctx->request_body_done == 1) {
            ctx->request_body_done = 0;
            goto do_fetch_subrequest;
        }

        if (ctx->request_done) {
            dd("request done");

            if (ngx_http_post_request(r, NULL) != NGX_OK) {
                return NGX_ERROR;
            }

            if (!ctx->from_cache) {
                return NGX_DECLINED;
            }

            dd("sending header");

            if (ctx->body_from_cache) {
                len = 0;

                for (cl = ctx->body_from_cache; cl->next; cl = cl->next) {
                    len += ngx_buf_size(cl->buf);
                }

                len += ngx_buf_size(cl->buf);

                cl->buf->last_buf = 1;

                r->headers_out.content_length_n = len;

                rc = ngx_http_send_header(r);

                dd("srcache fetch header returned %d", (int) rc);

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

#if 1
                if (r->header_only) {
                    return NGX_HTTP_OK;
                }
#endif

                if (!r->filter_finalize) {
                    rc = ngx_http_output_filter(r, ctx->body_from_cache);
                    if (rc == NGX_ERROR || rc > NGX_OK) {
                        return rc;
                    }
                }

                dd("sent body from cache: %d", (int) rc);
                dd("finalize from here...");

                ngx_http_finalize_request(r, rc);

                /* dd("r->main->count (post): %d", (int) r->main->count); */
                return NGX_DONE;
            }

            return NGX_DECLINED;
        }

    } else {
        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_srcache_filter_module));

        if (ctx == NULL) {
            return NGX_ERROR;
        }

        ngx_http_set_ctx(r, ctx, ngx_http_srcache_filter_module);
    }

    smcf = ngx_http_get_module_main_conf(r, ngx_http_srcache_filter_module);

    if (!smcf->postponed_to_access_phase_end) {
        ngx_http_core_main_conf_t       *cmcf;
        ngx_http_phase_handler_t         tmp;
        ngx_http_phase_handler_t        *ph;
        ngx_http_phase_handler_t        *cur_ph;
        ngx_http_phase_handler_t        *last_ph;

        smcf->postponed_to_access_phase_end = 1;

        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

        ph = cmcf->phase_engine.handlers;
        cur_ph = &ph[r->phase_handler];

        /* we should skip the post_access phase handler here too */
        last_ph = &ph[cur_ph->next - 2];

        if (cur_ph < last_ph) {
            dd("swaping the contents of cur_ph and last_ph...");

            tmp = *cur_ph;

            memmove(cur_ph, cur_ph + 1,
                    (last_ph - cur_ph) * sizeof (ngx_http_phase_handler_t));

            *last_ph = tmp;

            r->phase_handler--; /* redo the current ph */

            return NGX_DECLINED;
        }
    }

    if (conf->fetch == NULL) {
        dd("fetch is not defined");
        return NGX_DECLINED;
    }

    dd("running phase handler...");

    if (!r->request_body) {
        dd("reading request body: ctx = %p", ctx);

        rc = ngx_http_read_client_request_body(r,
                                               ngx_http_srcache_post_read_body);
        if (rc == NGX_ERROR || rc > NGX_OK) {
#if (nginx_version < 1002006)                                               \
    || (nginx_version >= 1003000 && nginx_version < 1003009)
            r->main->count--;
#endif
            return rc;
        }

        if (rc == NGX_AGAIN) {
            ctx->waiting_request_body = 1;
            return NGX_AGAIN;
        }

        /* rc == NGX_OK */
    }

do_fetch_subrequest:
    /* issue a subrequest to fetch cached stuff (if any) */

    rc = ngx_http_srcache_fetch_subrequest(r, conf, ctx);

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

    ctx->waiting_subrequest = 1;

    dd("quit");

    return NGX_AGAIN;
}
static ngx_int_t
ngx_http_req_status_handler(ngx_http_request_t *r)
{
    size_t                              len;
    uint32_t                            hash;
    ngx_str_t                           key;
    ngx_uint_t                          i;
    ngx_shm_zone_t                    **pzone;
    ngx_pool_cleanup_t                 *cln;
    ngx_http_req_status_ctx_t          *r_ctx;
    ngx_http_req_status_zone_t         *ctx;
    ngx_http_req_status_node_t         *ssn;
    ngx_http_req_status_loc_conf_t     *rlcf;
    ngx_http_req_status_zone_node_t    *pzn;

    r_ctx = ngx_http_get_module_ctx(r, ngx_http_req_status_module);

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_req_status_module);

    do {
        pzone = rlcf->req_zones.elts;

        for (i = 0; i < rlcf->req_zones.nelts; i++) {
            ctx = pzone[i]->data;

            if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) {
                continue;
            }

            if (key.len == 0) {
                continue;
            }

            if (key.len > 65535) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                        "req-status, the value of the \"%V\" variable "
                        "is more than 65535 bytes: \"%v\"",
                        &ctx->key.value, &key);
                continue;
            }

            if (r_ctx == NULL) {

                r_ctx = ngx_palloc(r->pool, sizeof(ngx_http_req_status_ctx_t));
                if (r_ctx == NULL) {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                if (ngx_array_init(&r_ctx->req_zones, r->pool, 2,
                            sizeof(ngx_http_req_status_zone_node_t))
                        != NGX_OK)
                {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                cln = ngx_pool_cleanup_add(r->pool, 0);
                if (cln == NULL) {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                cln->handler = ngx_http_req_status_cleanup;
                cln->data = r_ctx;

                ngx_http_set_ctx(r, r_ctx, ngx_http_req_status_module);
            }

            hash = ngx_crc32_short(key.data, key.len);

            ngx_shmtx_lock(&ctx->shpool->mutex);

            ssn = ngx_http_req_status_lookup(ctx, hash, &key);

            if (ssn == NULL) {
                len  = sizeof(ngx_http_req_status_node_t) + key.len + 1;

                ssn = ngx_slab_alloc_locked(ctx->shpool, len);
                if (ssn == NULL) {
                    ngx_http_req_status_expire(ctx);

                    ssn = ngx_slab_alloc_locked(ctx->shpool, len);
                    if (ssn == NULL) {
                        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                                "req-status, slab alloc fail, zone = \"%V\", "
                                "key = \"%V\", size = %uz",
                                &ctx->shm_zone->shm.name, &key, len);

                        ngx_shmtx_unlock(&ctx->shpool->mutex);

                        continue;
                    }
                }

                ssn->node.key = hash;
                ssn->len = key.len;
                ssn->count = 1;

                ngx_memzero(&ssn->data, sizeof(ssn->data));
                ngx_memcpy(ssn->key, key.data, key.len);
                ssn->key[key.len] = '\0';
                ssn->last_traffic_update = 0;

                ngx_rbtree_insert(&ctx->sh->rbtree, &ssn->node);
            }

            ssn->data.requests ++;
            ssn->active ++;
            if (ssn->active > ssn->data.max_active) {
                ssn->data.max_active = ssn->active;
            }

            ngx_queue_insert_head(&ctx->sh->queue, &ssn->queue);

            ngx_shmtx_unlock(&ctx->shpool->mutex);

            pzn = ngx_array_push(&r_ctx->req_zones);
            if (pzn == NULL) {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            pzn->node = ssn;
            pzn->zone = ctx;
        }

        rlcf = rlcf->parent;
    } while (rlcf);

    return NGX_DECLINED;
}
static ngx_int_t
ngx_http_headers_filter(ngx_http_request_t *r)
{
    ngx_str_t                 value;
    ngx_uint_t                i, safe_status;
    ngx_http_header_val_t    *h;
    ngx_http_headers_conf_t  *conf;

    conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module);

    if ((conf->expires == NGX_HTTP_EXPIRES_OFF && conf->headers == NULL)
        || r != r->main) //expires off并且没有配置add_header,或者为子请求
    {
        return ngx_http_next_header_filter(r);
    }

    switch (r->headers_out.status) {

    case NGX_HTTP_OK:
    case NGX_HTTP_CREATED:
    case NGX_HTTP_NO_CONTENT:
    case NGX_HTTP_PARTIAL_CONTENT:
    case NGX_HTTP_MOVED_PERMANENTLY:
    case NGX_HTTP_MOVED_TEMPORARILY:
    case NGX_HTTP_SEE_OTHER:
    case NGX_HTTP_NOT_MODIFIED:
    case NGX_HTTP_TEMPORARY_REDIRECT:
        safe_status = 1;
        break;

    default:
        safe_status = 0;
        break;
    }

    if (conf->expires != NGX_HTTP_EXPIRES_OFF && safe_status) {
        if (ngx_http_set_expires(r, conf) != NGX_OK) {
            return NGX_ERROR;
        }
    }

    if (conf->headers) {
        h = conf->headers->elts;
        for (i = 0; i < conf->headers->nelts; i++) {

            if (!safe_status && !h[i].always) {
                continue;
            }

            if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) {
                return NGX_ERROR;
            }

            if (h[i].handler(r, &h[i], &value) != NGX_OK) {
                return NGX_ERROR;
            }
        }
    }

    return ngx_http_next_header_filter(r);
}
static ngx_http_reqstat_store_t *
ngx_http_reqstat_create_store(ngx_http_request_t *r,
    ngx_http_reqstat_conf_t *rlcf)
{
    ngx_str_t                     val;
    ngx_uint_t                    i;
    ngx_shm_zone_t              **shm_zone, *z;
    ngx_http_reqstat_ctx_t       *ctx;
    ngx_http_reqstat_store_t     *store;
    ngx_http_reqstat_rbnode_t    *fnode, **fnode_store;

    store = ngx_pcalloc(r->pool, sizeof(ngx_http_reqstat_store_t));
    if (store == NULL) {
        return NULL;
    }

    if (rlcf->monitor == NULL) {
        store->bypass = 1;
        return store;
    }

    store->conf = rlcf;

    switch (ngx_http_test_predicates(r, rlcf->bypass)) {

    case NGX_ERROR:
        return NULL;

    case NGX_DECLINED:
        store->bypass = 1;
        return store;

    default: /* NGX_OK */
        break;
    }

    if (ngx_array_init(&store->monitor_index, r->pool, rlcf->monitor->nelts,
                       sizeof(ngx_http_reqstat_rbnode_t *)) == NGX_ERROR)
    {
        return NULL;
    }

    shm_zone = rlcf->monitor->elts;
    for (i = 0; i < rlcf->monitor->nelts; i++) {
        z = shm_zone[i];
        ctx = z->data;

        if (ngx_http_complex_value(r, &ctx->value, &val) != NGX_OK) {
            ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
                          "failed to reap the key \"%V\"", ctx->val);
            continue;
        }

        fnode = ngx_http_reqstat_rbtree_lookup(shm_zone[i], &val);

        if (fnode == NULL) {
            ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
                          "failed to alloc node in zone \"%V\", "
                          "enlarge it please",
                          &z->shm.name);

        } else {
            fnode_store = ngx_array_push(&store->monitor_index);
            *fnode_store = fnode;
        }
    }

    return store;
}
Example #27
0
ngx_int_t nchan_maybe_send_channel_event_message(ngx_http_request_t *r, channel_event_type_t event_type) {
  static nchan_loc_conf_t            evcf_data;
  static nchan_loc_conf_t           *evcf = NULL;
  
  static ngx_str_t group =           ngx_string("meta");
  
  static ngx_str_t evt_sub_enqueue = ngx_string("subscriber_enqueue");
  static ngx_str_t evt_sub_dequeue = ngx_string("subscriber_dequeue");
  static ngx_str_t evt_sub_recvmsg = ngx_string("subscriber_receive_message");
  static ngx_str_t evt_sub_recvsts = ngx_string("subscriber_receive_status");
  static ngx_str_t evt_chan_publish= ngx_string("channel_publish");
  static ngx_str_t evt_chan_delete = ngx_string("channel_delete");

  struct timeval             tv;
  
  nchan_loc_conf_t          *cf = ngx_http_get_module_loc_conf(r, nchan_module);
  ngx_http_complex_value_t  *cv = cf->channel_events_channel_id;
  if(cv==NULL) {
    //nothing to send
    return NGX_OK;
  }
  
  nchan_request_ctx_t       *ctx = ngx_http_get_module_ctx(r, nchan_module);
  ngx_str_t                  tmpid;
  size_t                     sz;
  ngx_str_t                 *id;
  u_char                    *cur;
  ngx_str_t                  evstr;
  ngx_buf_t                  buf;
  nchan_msg_t                msg;
  
  switch(event_type) {
    case SUB_ENQUEUE:
      ctx->channel_event_name = &evt_sub_enqueue;
      break;
    case SUB_DEQUEUE:
      ctx->channel_event_name = &evt_sub_dequeue;
      break;
    case SUB_RECEIVE_MESSAGE:
      ctx->channel_event_name = &evt_sub_recvmsg;
      break;
    case SUB_RECEIVE_STATUS:
      ctx->channel_event_name = &evt_sub_recvsts;
      break;
    case CHAN_PUBLISH:
      ctx->channel_event_name = &evt_chan_publish;
      break;
    case CHAN_DELETE:
      ctx->channel_event_name = &evt_chan_delete;
      break;
  }
  
  //the id
  ngx_http_complex_value(r, cv, &tmpid); 
  sz = group.len + 1 + tmpid.len;
  if((id = ngx_palloc(r->pool, sizeof(*id) + sz)) == NULL) {
    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "nchan: can't allocate space for legacy channel id");
    return NGX_ERROR;
  }
  id->len = sz;
  id->data = (u_char *)&id[1];
  cur = id->data;  
  ngx_memcpy(cur, group.data, group.len);
  cur += group.len;
  cur[0]='/';
  cur++;
  ngx_memcpy(cur, tmpid.data, tmpid.len);
  
  
  //the event message
  ngx_http_complex_value(r, cf->channel_event_string, &evstr);
  ngx_memzero(&buf, sizeof(buf)); //do we really need this?...
  buf.temporary = 1;
  buf.memory = 1;
  buf.last_buf = 1;
  buf.pos = evstr.data;
  buf.last = evstr.data + evstr.len;
  buf.start = buf.pos;
  buf.end = buf.last;
  
  ngx_memzero(&msg, sizeof(msg));
  ngx_gettimeofday(&tv);
  msg.id.time = tv.tv_sec;
  msg.id.tagcount = 1;
  msg.buf = &buf;
  
  
  if(evcf == NULL) {
    evcf = &evcf_data;
    ngx_memzero(evcf, sizeof(*evcf));
    evcf->buffer_timeout = 10;
    evcf->max_messages = NGX_MAX_INT_T_VALUE;
    evcf->subscriber_start_at_oldest_message = 0;
    evcf->channel_timeout = 30;
  }
  evcf->storage_engine = cf->storage_engine;
  evcf->use_redis = cf->use_redis;
  
  evcf->storage_engine->publish(id, &msg, evcf, NULL, NULL);
  
  return NGX_OK;
}
ngx_int_t
ngx_http_rds_json_output_header(ngx_http_request_t *r,
    ngx_http_rds_json_ctx_t *ctx, ngx_http_rds_header_t *header)
{
    u_char                  *pos, *last;
    size_t                   size;
    uintptr_t                escape;
    unsigned                 last_buf = 0;
    ngx_uint_t               i;
    ngx_str_t               *values = NULL;
    uintptr_t               *escapes = NULL;

    ngx_http_rds_json_property_t        *prop = NULL;
    ngx_http_rds_json_loc_conf_t        *conf;

    conf = ngx_http_get_module_loc_conf(r, ngx_http_rds_json_filter_module);

    /* calculate the buffer size */

    size = sizeof("{") - 1
           + conf->errcode_key.len
           + sizeof(":") - 1
           + ngx_get_num_size(header->std_errcode)
           + sizeof("}") - 1;

    if (conf->success.len) {
        size += conf->success.len + sizeof(":,") - 1;
        if (header->std_errcode == 0) {
            size += sizeof("true") - 1;

        } else {
            size += sizeof("false") - 1;
        }
    }

    if (conf->user_props) {
        values = ngx_pnalloc(r->pool,
                             conf->user_props->nelts * (sizeof(ngx_str_t)
                             + sizeof(uintptr_t)));

        if (values == NULL) {
            return NGX_ERROR;
        }

        escapes = (uintptr_t *) ((u_char *) values
                  + conf->user_props->nelts * sizeof(ngx_str_t));

        prop = conf->user_props->elts;
        for (i = 0; i < conf->user_props->nelts; i++) {
            if (ngx_http_complex_value(r, &prop[i].value, &values[i])
                != NGX_OK)
            {
                return NGX_ERROR;
            }

            escapes[i] = ngx_http_rds_json_escape_json_str(NULL,
                                                           values[i].data,
                                                           values[i].len);

            size += sizeof(":\"\",") - 1 + prop[i].key.len + values[i].len
                    + escapes[i];
        }
    }


    if (header->errstr.len) {
        escape = ngx_http_rds_json_escape_json_str(NULL, header->errstr.data,
                                                   header->errstr.len);

        size += sizeof(",") - 1
                + conf->errstr_key.len
                + sizeof(":") - 1
                + sizeof("\"") - 1
                + header->errstr.len
                + escape
                + sizeof("\"") - 1;

    } else {
        escape = (uintptr_t) 0;
    }

    if (header->insert_id) {
        size += sizeof(",\"insert_id\":") - 1
                + ngx_get_num_size(header->insert_id);
    }

    if (header->affected_rows) {
        size += sizeof(",\"affected_rows\":") - 1
                + ngx_get_num_size(header->affected_rows);
    }

    /* create the buffer */

    pos = ngx_http_rds_json_request_mem(r, ctx, size);
    if (pos == NULL) {
        return NGX_ERROR;
    }

    last = pos;

    /* fill up the buffer */

    *last++ = '{';

    if (conf->success.len) {
        last = ngx_copy(last, conf->success.data, conf->success.len);

        if (header->std_errcode == 0) {
            last = ngx_copy_literal(last, ":true,");

        } else {
            last = ngx_copy_literal(last, ":false,");
        }
    }

    if (conf->user_props) {
        for (i = 0; i < conf->user_props->nelts; i++) {
            last = ngx_copy(last, prop[i].key.data, prop[i].key.len);
            *last++ = ':';
            *last++ = '"';

            if (escapes[i] == 0) {
                last = ngx_copy(last, values[i].data, values[i].len);

            } else {
                last = (u_char *)
                        ngx_http_rds_json_escape_json_str(last,
                                                          values[i].data,
                                                          values[i].len);
            }

            *last++ = '"';
            *last++ = ',';
        }
    }

    last = ngx_copy(last, conf->errcode_key.data, conf->errcode_key.len);
    *last++ = ':';

    last = ngx_snprintf(last, NGX_UINT16_LEN, "%uD",
                        (uint32_t) header->std_errcode);

    if (header->errstr.len) {
        *last++ = ',';
        last = ngx_copy(last, conf->errstr_key.data, conf->errstr_key.len);
        *last++ = ':';
        *last++ = '"';

        if (escape == 0) {
            last = ngx_copy(last, header->errstr.data, header->errstr.len);

        } else {
            last = (u_char *)
                    ngx_http_rds_json_escape_json_str(last,
                                                      header->errstr.data,
                                                      header->errstr.len);
        }

        *last++ = '"';
    }

    if (header->insert_id) {
        last = ngx_copy_literal(last, ",\"insert_id\":");
        last = ngx_snprintf(last, NGX_UINT64_LEN, "%uL", header->insert_id);
    }

    if (header->affected_rows) {
        last = ngx_copy_literal(last, ",\"affected_rows\":");
        last = ngx_snprintf(last, NGX_UINT64_LEN, "%uL",
                            header->affected_rows);
    }

    *last++ = '}';

    if ((size_t) (last - pos) != size) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "rds_json: output header buffer error: %O != %uz",
                      (off_t) (last - pos), size);

        return NGX_ERROR;
    }

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

    ctx->seen_stream_end = 1;

    return ngx_http_rds_json_submit_mem(r, ctx, size, (unsigned) last_buf);
}
static ngx_int_t
ngx_http_limit_req_handler(ngx_http_request_t *r)
{
    uint32_t                     hash;
    ngx_str_t                    key;
    ngx_int_t                    rc;
    ngx_uint_t                   n, excess;
    ngx_msec_t                   delay;
    ngx_http_limit_req_ctx_t    *ctx;
    ngx_http_limit_req_conf_t   *lrcf;
    ngx_http_limit_req_limit_t  *limit, *limits;

    if (r->main->limit_req_set) {
        return NGX_DECLINED;
    }

    lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req_module);
    limits = lrcf->limits.elts;

    excess = 0;

    rc = NGX_DECLINED;

#if (NGX_SUPPRESS_WARN)
    limit = NULL;
#endif

    for (n = 0; n < lrcf->limits.nelts; n++) {

        limit = &limits[n];

        ctx = limit->shm_zone->data;

        if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        if (key.len == 0) {
            continue;
        }

        if (key.len > 65535) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "the value of the \"%V\" key "
                          "is more than 65535 bytes: \"%V\"",
                          &ctx->key.value, &key);
            continue;
        }

        hash = ngx_crc32_short(key.data, key.len);

        ngx_shmtx_lock(&ctx->shpool->mutex);

        rc = ngx_http_limit_req_lookup(limit, hash, &key, &excess,
                                       (n == lrcf->limits.nelts - 1));

        ngx_shmtx_unlock(&ctx->shpool->mutex);

        ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "limit_req[%ui]: %i %ui.%03ui",
                       n, rc, excess / 1000, excess % 1000);

        if (rc != NGX_AGAIN) {
            break;
        }
    }

    if (rc == NGX_DECLINED) {
        return NGX_DECLINED;
    }

    r->main->limit_req_set = 1;

    if (rc == NGX_BUSY || rc == NGX_ERROR) {

        if (rc == NGX_BUSY) {
            ngx_log_error(lrcf->limit_log_level, r->connection->log, 0,
                          "limiting requests, excess: %ui.%03ui by zone \"%V\"",
                          excess / 1000, excess % 1000,
                          &limit->shm_zone->shm.name);
        }

        while (n--) {
            ctx = limits[n].shm_zone->data;

            if (ctx->node == NULL) {
                continue;
            }

            ngx_shmtx_lock(&ctx->shpool->mutex);

            ctx->node->count--;

            ngx_shmtx_unlock(&ctx->shpool->mutex);

            ctx->node = NULL;
        }

        return lrcf->status_code;
    }

    /* rc == NGX_AGAIN || rc == NGX_OK */

    if (rc == NGX_AGAIN) {
        excess = 0;
    }

    delay = ngx_http_limit_req_account(limits, n, &excess, &limit);

    if (!delay) {
        return NGX_DECLINED;
    }

    ngx_log_error(lrcf->delay_log_level, r->connection->log, 0,
                  "delaying request, excess: %ui.%03ui, by zone \"%V\"",
                  excess / 1000, excess % 1000, &limit->shm_zone->shm.name);

    if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    r->read_event_handler = ngx_http_test_reading;
    r->write_event_handler = ngx_http_limit_req_delay;

    r->connection->write->delayed = 1;
    ngx_add_timer(r->connection->write, delay);

    return NGX_AGAIN;
}
static ngx_int_t
ngx_http_srcache_store_subrequest(ngx_http_request_t *r,
        ngx_http_srcache_ctx_t *ctx)
{
    ngx_http_srcache_ctx_t         *sr_ctx;
    ngx_str_t                       args;
    ngx_uint_t                      flags = 0;
    ngx_http_request_t             *sr;
    ngx_int_t                       rc;
    ngx_http_request_body_t        *rb = NULL;
    ngx_http_srcache_loc_conf_t    *conf;
    ngx_http_post_subrequest_t     *psr;

    ngx_http_srcache_parsed_request_t  *parsed_sr;

    dd("store subrequest");

    conf = ngx_http_get_module_loc_conf(r, ngx_http_srcache_filter_module);

    if (conf->store == NULL) {
        dd("conf store is NULL");
        return NGX_ERROR;
    }

    parsed_sr = ngx_palloc(r->pool, sizeof(ngx_http_srcache_parsed_request_t));
    if (parsed_sr == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    parsed_sr->method      = conf->store->method;
    parsed_sr->method_name = conf->store->method_name;

    if (ctx->body_to_cache) {
        dd("found body to cache (len %d)", (int) ctx->response_length);

        rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));

        if (rb == NULL) {
            return NGX_ERROR;
        }

        rb->bufs = ctx->body_to_cache;
        rb->buf = ctx->body_to_cache->buf;

        parsed_sr->request_body = rb;

    } else {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "srcache_store: no request body for the subrequest");

        return NGX_ERROR;
    }

    parsed_sr->content_length_n = ctx->response_length;

    if (ngx_http_complex_value(r, &conf->store->location,
                &parsed_sr->location) != NGX_OK)
    {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (parsed_sr->location.len == 0) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (ngx_http_complex_value(r, &conf->store->args, &parsed_sr->args)
            != NGX_OK)
    {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    args.data = NULL;
    args.len = 0;

    if (ngx_http_parse_unsafe_uri(r, &parsed_sr->location, &args, &flags)
            != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (args.len > 0 && parsed_sr->args.len == 0) {
        parsed_sr->args = args;
    }

    dd("firing the store subrequest");

    dd("store location: %.*s", (int) parsed_sr->location.len,
            parsed_sr->location.data);

    dd("store args: %.*s", (int) parsed_sr->args.len,
            parsed_sr->args.data);

    sr_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_srcache_ctx_t));

    if (sr_ctx == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    sr_ctx->in_store_subrequest = 1;

    psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
    if (psr == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    psr->handler = ngx_http_srcache_store_post_subrequest;
    psr->data = sr_ctx;

    rc = ngx_http_subrequest(r, &parsed_sr->location, &parsed_sr->args,
            &sr, psr, flags);

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

    rc = ngx_http_srcache_adjust_subrequest(sr, parsed_sr);

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

    ngx_http_set_ctx(sr, sr_ctx, ngx_http_srcache_filter_module);

    return NGX_OK;
}