/* Find the value of the URL parameter with the specified name */
static ngx_int_t
find_arg(ngx_pool_t *pool, ngx_str_t name, ngx_str_t args, ngx_str_t *value)
{
  u_char *start = args.data;
  u_char *end = start + args.len;
  size_t name_len = name.len;
  while (start < end) {
    if (start + name_len + 1 < end) { /* if enough room for "name=" */
      if ((ngx_strncmp(name.data, start, name_len) == 0) && (start[name_len] == (u_char)'=')) {
        u_char *arg_end;
        u_char *unescaped;
        start += (name_len + 1);  /* skip past the "name=" */
        arg_end = ngx_strlchr(start, end, (u_char)'&'); /* find terminating '&' */
        if (arg_end == NULL) {
          arg_end = end;
        }
        unescaped = (u_char *)ngx_palloc(pool, arg_end - start);
        value->data = unescaped;
        ngx_unescape_uri(&unescaped, &start, arg_end - start, NGX_UNESCAPE_URI);
        value->len = unescaped - value->data;
        return NGX_OK;
      }
    }
    start = ngx_strlchr(start, end, (u_char)'&');
    if (start == NULL) {
      break;
    }
    start++;
  }
  value->data = NULL;
  value->len = 0;
  return NGX_DECLINED;
}
static ngx_int_t
ngx_http_eval_parse_param(ngx_http_request_t *r, ngx_http_eval_ctx_t *ctx, ngx_str_t *param) {
    u_char                    *p, *src, *dst;

    ngx_str_t                  name;
    ngx_str_t                  value;

    p = (u_char *) ngx_strchr(param->data, '=');

    if(p == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "eval: invalid param \"%V\"", param);
        return NGX_ERROR;
    }

    name.data = param->data;
    name.len = p - param->data;

    value.data = p + 1;
    value.len = param->len - (p - param->data) - 1;

    src = dst = value.data;

    ngx_unescape_uri(&dst, &src, value.len, NGX_UNESCAPE_URI);

    value.len = dst - value.data;

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "eval param: \"%V\"=\"%V\"", &name, &value);

    return ngx_http_eval_set_variable_value(r, ctx, &name, &value);
}
static ngx_int_t
ngx_extra_var_original_uri(ngx_http_request_t *r,
    ngx_http_variable_value_t *v, uintptr_t data)
{
    ngx_str_t    uri, args;
    u_char      *src, *dst, *p;
    ngx_uint_t   flags;

    uri = r->unparsed_uri;
    ngx_str_null(&args);
    flags = 0;

    if (NGX_OK != ngx_http_parse_unsafe_uri(r, &uri, &args, &flags)) {
        v->not_found = 1;
        return NGX_OK;
    }

    p = ngx_pnalloc(r->pool, uri.len);
    if (p == NULL) {
        return NGX_ERROR;
    }

    src = uri.data;
    dst = p;

    ngx_unescape_uri(&dst, &src, uri.len, 0);

    v->len = dst - p;
    v->valid = 1;
    v->no_cacheable = 0;
    v->not_found = 0;
    v->data = p;

    return NGX_OK;
}
static ngx_int_t
ngx_captcha_get_request_parameter_value( ngx_http_request_t *r, u_char *buffer, ngx_str_t *name, ngx_str_t *value ) {
    
    u_char              *p      = NULL;
    u_char              *v      = NULL; 
    u_char              *last   = NULL;
 
    value->data = NULL;
    value->len = 0;

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

    ngx_log_debug( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "searching for %s (%d)", name->data, name->len );

    last = buffer + ngx_strlen( buffer ) ;
    
    for ( p = buffer; p < last; p++ ) {
        // we need '=' after name, so drop one char from last 
        p = ngx_strlcasestrn(p, last - 1, name->data, name->len - 1);
        if ( p == NULL ) {
            return NGX_ERROR;
        }

        if ((p == buffer || *(p - 1) == '&') && *(p + name->len) == '=') {
            size_t val_len = 0; 
            size_t dst_len = 0;

            v = p + name->len + 1;
            
            p = ngx_strlchr(p, last, '&');
            if (p == NULL) {
                p = last;
            }
            
            val_len = (p-v);
            
            /* Allocate buffer for request parameter value */
            value->data = ngx_pcalloc(r->pool, val_len + 1);
            if ( value->data == NULL ) {
                ngx_log_debug( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "--->> BOOOM" );
                return NGX_ERROR;
            }
            /* Unescape parameter value */
            dst_len = (size_t)value->data;
            ngx_unescape_uri(&value->data, &v, val_len, NGX_UNESCAPE_URI);
            dst_len = (size_t) value->data - dst_len;
            *(value->data) = '\0';
            value->data -= dst_len;            
            value->len = dst_len;

            return NGX_OK;
        }
    }

    return ( (value->data == NULL) ? NGX_ERROR: NGX_OK );
}
/* text will be modified */
static void
ngx_mail_zmauth_unescape(ngx_str_t *text) {
    u_char       *src, *dst;
    size_t        len;

    src = text->data;
    dst = text->data;

    ngx_unescape_uri(&dst, &src, text->len, NGX_UNESCAPE_URI);

    len = (text->data + text->len) - src;
    if (len) {
        dst = ngx_copy(dst, src, len);
    }

    text->len = dst - text->data;
}
ngx_int_t 
ngx_http_qrcode_set_content(ngx_http_request_t *r, ngx_str_t *val, ngx_array_t *compiled_args, ngx_int_t urlencode)
{
	ngx_str_t *arg;
	u_char *p;

	arg = compiled_args->elts;
	*val = arg[0];

	if (urlencode == 1) {
		p = ngx_pcalloc(r->pool, arg->len);
		val->data = p;

		ngx_unescape_uri(&p, &arg->data, arg->len, 0);
		val->len = p - val->data;
	}

	return NGX_OK;
}
//解析url中的参数,主要处理 http get 请求
inline ngx_str_t ngx_parser_http_request(ngx_http_request_t *r) {
	 ngx_str_t value;
	  // args is data=xxxxx
	 // 第二个参数是HTTP GET的key名,key名的长度,第四个参数是想存这个value的变量的指针
	 if (NGX_OK != ngx_http_arg(r, (u_char*)"data", 4, &value)) {
		 ngx_str_t res = ngx_null_string;
		 return res;
	 }
	 
	 ngx_str_t sentence;
	 u_char* dst, *src;
	 dst = (u_char*)ngx_pcalloc(r->pool, 1024);//解码后字词空间
	 src = value.data;
	 sentence.data = dst;
	 // 解析url 编码
	 ngx_unescape_uri(&dst, &src, value.len, 0);
	 sentence.len = dst - sentence.data;
	 //ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0, " data=%s", sentence.data);
	 return sentence; 
}
static ngx_int_t
ngx_http_xss_header_filter(ngx_http_request_t *r)
{
    ngx_http_xss_ctx_t          *ctx;
    ngx_http_xss_loc_conf_t     *xlcf;
    ngx_str_t                    callback;
    u_char                      *p, *src, *dst;

    if (r != r->main) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "xss skipped in subrequests");

        return ngx_http_next_header_filter(r);
    }

    xlcf = ngx_http_get_module_loc_conf(r, ngx_http_xss_filter_module);

    if (!xlcf->get_enabled) {
        return ngx_http_next_header_filter(r);
    }

    if (r->method != NGX_HTTP_GET) {
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "xss skipped due to the unmatched request method: %V",
                       &r->method_name);

        return ngx_http_next_header_filter(r);
    }

    if (xlcf->check_status) {

        if (r->headers_out.status != NGX_HTTP_OK
            && r->headers_out.status != NGX_HTTP_CREATED)
        {
            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "xss skipped due to unmatched response status "
                           "\"%ui\"", r->headers_out.status);

            return ngx_http_next_header_filter(r);
        }
    }

    if (xlcf->callback_arg.len == 0) {

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "xss: xss_get is enabled but no xss_callback_arg "
                      "specified");

        return ngx_http_next_header_filter(r);
    }

    if (ngx_http_test_content_type(r, &xlcf->input_types) == NULL) {

        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "xss skipped due to unmatched Content-Type response "
                       "header");

        return ngx_http_next_header_filter(r);
    }

    if (ngx_http_arg(r, xlcf->callback_arg.data, xlcf->callback_arg.len,
                     &callback)
        != NGX_OK)
    {
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "xss skipped: no GET argument \"%V\" specified in "
                       "the request", &xlcf->callback_arg);

        return ngx_http_next_header_filter(r);
    }

    p = ngx_palloc(r->pool, callback.len);
    if (p == NULL) {
        return NGX_ERROR;
    }

    src = callback.data; dst = p;

    ngx_unescape_uri(&dst, &src, callback.len, NGX_UNESCAPE_URI_COMPONENT);

    if (src != callback.data + callback.len) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "xss: unescape uri: input data not consumed completely");

        return NGX_ERROR;
    }

    callback.data = p;
    callback.len = dst - p;

    if (ngx_http_xss_test_callback(callback.data, callback.len) != NGX_OK) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "xss: bad callback argument: \"%V\"", &callback);

        return ngx_http_next_header_filter(r);
    }

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

    /*
     * set by ngx_pcalloc():
     *
     *     ctx->callback = { 0, NULL };
     *     ctx->before_body_sent = 0;
     */

    ctx->callback = callback;

    ngx_http_set_ctx(r, ctx, ngx_http_xss_filter_module);

    r->headers_out.content_type = xlcf->output_type;
    r->headers_out.content_type_len = xlcf->output_type.len;
    r->headers_out.content_type_lowcase = NULL;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "xss output Content-Type header \"%V\"",
                   &xlcf->output_type);

    ngx_http_clear_content_length(r);
    ngx_http_clear_accept_ranges(r);

    if (xlcf->override_status
        && r->headers_out.status >= NGX_HTTP_SPECIAL_RESPONSE)
    {
        r->headers_out.status = NGX_HTTP_OK;
    }

    return ngx_http_next_header_filter(r);
}
static ngx_int_t
ngx_http_xss_header_filter(ngx_http_request_t *r)
{
    ngx_http_xss_ctx_t          *ctx;
    ngx_http_xss_conf_t         *conf;
    ngx_str_t                    callback;
    u_char                      *p, *src, *dst;

    if (r->headers_out.status != NGX_HTTP_OK || r != r->main) {
        dd("skipped: status not 200 or in subrequest");
        return ngx_http_next_header_filter(r);
    }

    conf = ngx_http_get_module_loc_conf(r, ngx_http_xss_filter_module);

    if ( ! conf->get_enabled || r->method != NGX_HTTP_GET) {
        dd("skipped: get_enabled disabled or the current method is not GET");
        return ngx_http_next_header_filter(r);
    }

    if (conf->callback_arg.len == 0) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                "xss: xss_get is enabled but no xss_callback_arg specified");

        return ngx_http_next_header_filter(r);
    }

    if (ngx_http_test_content_type(r, &conf->input_types) == NULL) {
        dd("skipped: content type test not passed");
        return ngx_http_next_header_filter(r);
    }

    if (ngx_http_arg(r, conf->callback_arg.data, conf->callback_arg.len,
                &callback) != NGX_OK)
    {
        dd("skipped: no callback arg found in the current request: %.*s",
                conf->callback_arg.len, conf->callback_arg.data);

        return ngx_http_next_header_filter(r);
    }

    p = ngx_palloc(r->pool, callback.len);
    if (p == NULL) {
        return NGX_ERROR;
    }

    src = callback.data; dst = p;

    ngx_unescape_uri(&dst, &src, callback.len,
            NGX_UNESCAPE_URI_COMPONENT);

    if (src != callback.data + callback.len) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                "xss: unescape uri: input data not consumed completely");

        return NGX_ERROR;
    }

    callback.data = p;
    callback.len = dst - p;

    if (ngx_http_xss_test_callback((char *) callback.data, callback.len)
            != NGX_OK)
    {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                "xss: bad callback argument: \"%V\"", &callback);

        return ngx_http_next_header_filter(r);
    }

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

    /*
     * set by ngx_pcalloc():
     *
     *     ctx->callback = { 0, NULL };
     *     conf->before_body_sent = 0;
     */

    ctx->callback = callback;

    ngx_http_set_ctx(r, ctx, ngx_http_xss_filter_module);

    r->headers_out.content_type = conf->output_type;
    r->headers_out.content_type_len = conf->output_type.len;

    ngx_http_clear_content_length(r);
    ngx_http_clear_accept_ranges(r);

    return ngx_http_next_header_filter(r);
}
static const char *
ngx_rtmp_control_relay_handler(ngx_http_request_t *r, ngx_rtmp_session_t *s,
    ngx_rtmp_core_srv_conf_t *cscf,
    ngx_rtmp_core_app_conf_t **cacf)
{
    ngx_rtmp_control_ctx_t      *ctx;
    ngx_url_t                   *u;
    ngx_str_t                    name, decoded;
    ngx_rtmp_relay_target_t     *target, **t;
    u_char                      *dst;
    ngx_rtmp_relay_app_conf_t   *racf;
    u_char                       is_pull, is_static = 1, start;
    ngx_event_t                 *e;
    ngx_rtmp_relay_static_t     *rs;

    static ngx_rtmp_control_event_chain_t  *evt_chain = NULL, *evt_last;
    ngx_rtmp_control_event_chain_t  *evt_cur, *evt_prv;

    racf = (*cacf)->app_conf[ngx_rtmp_relay_module.ctx_index];

    target = ngx_pcalloc(cscf->pool, sizeof(*target));
    if (target == NULL) {
        return "unable to allocate memory";
    }

    ngx_memzero(target, sizeof(*target));

    target->tag = &ngx_rtmp_relay_module;
    target->data = target;

    ctx = ngx_http_get_module_ctx(r, ngx_rtmp_control_module);

    if (ctx->method.len == sizeof("start") - 1 &&
        ngx_strncmp(ctx->method.data, "start", ctx->method.len) == 0)
    {
        start = 1;

    } else if (ctx->method.len == sizeof("stop") - 1 &&
             ngx_strncmp(ctx->method.data, "stop", ctx->method.len) == 0)
    {
        start = 0;

    } else {
        return "Undefined method";
    }

    if (ngx_http_arg(r, (u_char *) "name", sizeof("name") - 1,
                     &name) == NGX_OK)
    {
        target->name.data = ngx_pnalloc(cscf->pool, name.len + 1);
        target->name.len = name.len;
        ngx_memcpy(target->name.data, name.data, name.len);
    }

    if (start == 0) {

        if (s) {
            ngx_rtmp_control_drop_handler(r, s, cscf, cacf);
        }

        for (evt_prv = NULL, evt_cur = evt_chain; evt_cur;) {
            e = &evt_cur->event;
            rs = e ? e->data : NULL;

            ngx_log_debug(NGX_LOG_DEBUG_RTMP, r->connection->log, 0,
                           "control: matching name='%*s' candidate='%*s'",
                           target->name.len, target->name.data,
                           rs && rs->target ? rs->target->name.len : 0,
                           rs && rs->target ? rs->target->name.data : NULL);

            if(!rs) {
                if(evt_prv) {
                    evt_prv->next = evt_cur->next;
                } else {
                    evt_chain = evt_cur->next;
                }

                if(!evt_cur->next) {
                    evt_last = evt_prv;
                }

                evt_prv = evt_cur->next;
                ngx_pfree(cscf->pool, evt_cur);
                evt_cur = evt_prv;

                continue;
            }

            if (rs->cctx.main_conf == (void **)cscf->ctx->main_conf &&
                rs->cctx.srv_conf  == (void **)cscf->ctx->srv_conf &&
                rs->cctx.app_conf  == (void **)cacf &&
                rs->target->name.len == target->name.len &&
                ngx_strncmp(rs->target->name.data, target->name.data,
                            target->name.len) == 0)
            {
                ngx_log_debug(NGX_LOG_DEBUG_RTMP, r->connection->log, 0,
                               "control: stopped url='%*s'",
                               rs->target->url.url.len,
                               rs->target->url.url.data);

                ngx_pfree(cscf->pool, e->data);
                e->data = NULL;

                if(evt_prv) {
                    evt_prv->next = evt_cur->next;
                } else {
                    evt_chain = evt_cur->next;
                }

                if(!evt_cur->next) {
                    evt_last = evt_prv;
                }

                evt_prv = evt_cur->next;
                ngx_pfree(cscf->pool, evt_cur);
                evt_cur = evt_prv;

                continue;
            }

            evt_prv = evt_cur;
            evt_cur = evt_cur->next;
        }

        return NGX_CONF_OK;
    }

    if (ngx_http_arg(r, (u_char *) "push", sizeof("push") - 1,
                     &name) == NGX_OK)
    {
        is_pull = 0;

    } else if (ngx_http_arg(r, (u_char *) "pull", sizeof("pull") - 1,
                     &name) == NGX_OK)
    {
        is_pull = 1;

    } else {
        return "unknown relay type";
    }

    dst = ngx_pnalloc(cscf->pool, name.len);
    if (dst == NULL) {
        return "unable to allocate memory";
    }

    decoded.data = dst;
    ngx_unescape_uri(&dst, &name.data, name.len, 0);
    decoded.len = dst - decoded.data;

    if (ngx_strncasecmp(decoded.data, (u_char *) "rtmp://", 7)) {
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                      "control: relay %s '%*s'",
                      (is_pull ? "from" : "to" ), decoded.len, decoded.data);
        return "invalid relay url";
    }

    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                  "control: %*s relay from '%*s'",
                  ctx->method.len, ctx->method.data, decoded.len, decoded.data);

    u = &target->url;
    u->url.data = decoded.data + 7;
    u->url.len = decoded.len - 7;
    u->default_port = 1935;
    u->uri_part = 1;

    if (ngx_parse_url(cscf->pool, u) != NGX_OK) {
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                      "control: %s failed '%*s'",
                      (is_pull ? "pull" : "push" ), decoded.len, decoded.data);
        return "invalid relay url";
    }

    if (u->uri.len > 0 &&
        ngx_rtmp_parse_relay_str(cscf->pool, target, &is_static) != NGX_OK)
    {
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                      "control: %s failed with args '%*s'",
                      (is_pull ? "pull" : "push" ), &u->uri.len, &u->uri.data);
        return "invalid relay args";
    }

    if (u->uri.len == 0)
    {
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                      "control: %s has no remote url '%*s'",
                      (is_pull ? "pull" : "push" ), decoded.len, decoded.data);
        return "no relay url";
    }

    if (is_static) {

        if (!is_pull) {
            ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
                               "static push is not allowed");
            return NGX_CONF_ERROR;
        }

        if (target->name.len == 0) {
            ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
                               "stream name missing in static pull "
                               "declaration");
            return NGX_CONF_ERROR;
        }

        if (evt_chain == NULL) {
            evt_chain = ngx_pcalloc(cscf->pool, sizeof(*evt_chain));
            if (evt_chain == NULL) {
                return "unable to allocate memory";
            }

            ngx_memzero(evt_chain, sizeof(*evt_chain));
            evt_last = evt_chain;
        }
        else {
            evt_last->next = ngx_pcalloc(cscf->pool, sizeof(*evt_chain));
            if (evt_last->next == NULL) {
                return "unable to allocate memory";
            }

            ngx_memzero(evt_last->next, sizeof(*evt_chain));
            evt_last = evt_last->next;
        }

        e = &evt_last->event;

        rs = ngx_pcalloc(cscf->pool, sizeof(ngx_rtmp_relay_static_t));
        if (rs == NULL) {
            return "unable to allocate memory";
        }

        rs->target = target;
        rs->cctx.main_conf = (void **)cscf->ctx->main_conf;
        rs->cctx.srv_conf  = (void **)cscf->ctx->srv_conf;
        rs->cctx.app_conf  = (void **)cacf;

        e->data = rs;
        e->log = r->connection->log;
        e->handler = ngx_rtmp_relay_static_pull_reconnect;

        ngx_rtmp_relay_static_pull_reconnect(e);

    } else if (is_pull) {
        t = ngx_array_push(&racf->pulls);

        if (t == NULL) {
            return NGX_CONF_ERROR;
        }

        *t = target;

    } else {
        t = ngx_array_push(&racf->pushes);

        if (t == NULL) {
            return NGX_CONF_ERROR;
        }

        *t = target;
    }

    return NGX_CONF_OK;
}
static ngx_int_t hexin_http_percn_post_handler(ngx_http_request_t *r)
{
	ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "进入 hexin_http_percn_post_handler 方法..");

	hexin_http_percn_loc_conf_t		*plcf;
	hexin_http_percn_ctx_t			*ctx;
	ngx_http_variable_value_t		*receivers, *common, *block_size;
	u_char							*buf, *unescapebuf;
	ngx_int_t						rc;

	plcf = ngx_http_get_module_loc_conf(r, hexin_http_percn_module);	
	ctx = ngx_http_get_module_ctx(r, hexin_http_percn_module);
	//获得分割所依据的字段值,并获得所以子请求通用的Form参数
	receivers = ngx_http_get_indexed_variable(r, plcf->receivers_index);	
	common =  ngx_http_get_indexed_variable(r, plcf->common_index);	
              
	ctx->common = common;
	ctx->receivers_complete_val_len = receivers->len;

	ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "接收者为: %v, ----- 通用体: %v", receivers, common);		
		
    buf = ngx_pnalloc(r->pool, receivers->len);
	if(buf == NULL) {
		ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "分配 buf 内存失败!");
		return NGX_ERROR;
	}

    ngx_memcpy(buf, receivers->data, receivers->len);
	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "URL 解码前: %s", buf);
	//进行URI 解码
	unescapebuf = ngx_pnalloc(r->pool, receivers->len);
	ngx_unescape_uri(&unescapebuf, &buf,  receivers->len, NGX_ESCAPE_ARGS);
	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "URL 解码后: %s", buf);
	//获取分割的尺寸大小	
	block_size = ngx_http_get_indexed_variable(r, plcf->block_size_index);	
	ngx_int_t block_size_int = ngx_atoi(block_size->data, block_size->len);

	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "推送块尺寸为: %d", block_size_int);
	//以','为分割符进行切割 并循环创建子请求
	char *p, *brkt;
	ngx_int_t count = 1;

	size_t len = 0;
	size_t fla_len = 0;
	u_char* next = receivers->data;
	for (p = strtok_r( (char *)buf, ",", &brkt); p;  p = strtok_r(NULL, ",", &brkt)) {
		len += ngx_strlen(p);
		fla_len++;
		if((count++) % (block_size_int) == 0) {	
			//获得块长度
			u_char* part ;
			size_t mem_len =  len + 3 * fla_len;
			//分配块内存 并拷贝内存赋值
			part = ngx_pnalloc(r->pool, mem_len - 3);
			ngx_memcpy(part, next, mem_len -3);	
			next = next + mem_len;
			ctx->receivers_part_val_len = mem_len - 3;
			ctx->receivers_part_val = part;			

			//=================
			hexin_http_percn_subrequest_t      *parsed_sr;
			ngx_http_request_t				   *sr; /* subrequest object */
			
			rc = hexin_http_percn_create_subrequest(r, &parsed_sr);
			if (rc != NGX_OK) {
				return rc;
			}
			
			ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "创建子查询.");
			rc = ngx_http_subrequest(r, parsed_sr->location, NULL, &sr, NULL, 0);
			if (rc != NGX_OK) {
				return NGX_ERROR;
			}	
			
			ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "创建子查询结束, 开始调整参数.");	
			rc = hexin_http_percn_adjust_subrequest(sr, parsed_sr);
			if (rc != NGX_OK) {
				return rc;
			}
			//=================
			len = 0;
			fla_len = 0;
		}
    }
	//剩余请求
	if(len != 0) {
		u_char* part ;
		size_t mem_len =  len + 3 * fla_len;
		part = ngx_pnalloc(r->pool, mem_len - 3);
		ngx_memcpy(part, next, mem_len -3);
		ctx->receivers_part_val_len = mem_len - 3;
		ctx->receivers_part_val = part;

		//=================
		hexin_http_percn_subrequest_t      *parsed_sr;
		ngx_http_request_t				   *sr; /* subrequest object */
			
		rc = hexin_http_percn_create_subrequest(r, &parsed_sr);
		if (rc != NGX_OK) {
			return rc;
		}

		rc = ngx_http_subrequest(r, parsed_sr->location, NULL, &sr, NULL, 0);
		if (rc != NGX_OK) {
			return NGX_ERROR;
		}	
						
		rc = hexin_http_percn_adjust_subrequest(sr, parsed_sr);
		if (rc != NGX_OK) {
			return rc;
		}
		//=================

		len = 0;
	}

	ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, " hexin_http_percn_post_handler 方法 结束..");

	return NGX_OK;
}
Beispiel #12
0
static CWX_KEY_VALUE* ngx_http_cwinux_parse_args(ngx_str_t* args, ngx_pool_t* pool)
{
    CWX_KEY_VALUE* head = NULL;
    CWX_KEY_VALUE* tail = NULL;
    char const *begin = NULL;
    char const *mid = NULL;
    char const *end =NULL;
    CWX_KEY_VALUE* key_value = NULL;
    unsigned int key_len = 0;
    unsigned int data_len = 0;
    u_char* src, *dst;
    size_t len = args->len;
    begin = (char*)args->data;
    mid = ngx_cwinux_strchr(begin, len, '=');
    while(mid){
        key_value = (CWX_KEY_VALUE*)ngx_pcalloc(pool, sizeof(CWX_KEY_VALUE));
        //get key
        while(*begin == '&') begin++;
        key_len = mid - begin;
        key_value->m_key = (char*)ngx_pcalloc(pool, key_len+1);
        key_value->m_lowerkey = (char*)ngx_pcalloc(pool, key_len+1);
        memcpy(key_value->m_key, begin, key_len);
        key_value->m_key[key_len] = 0x00;
        src = (u_char*)key_value->m_key;
        dst = (u_char*)key_value->m_key;
        ngx_unescape_uri(&dst, &src, key_len, 0);
        *dst = 0;
        ngx_cwinux_trim(key_value->m_key);
        ngx_strlow((u_char*)key_value->m_lowerkey, (u_char*)key_value->m_key, strlen(key_value->m_key));
        //get data
        mid++;
        end = strchr(mid, '&');
        if (0 == end)
            data_len = args->len - ((u_char*)mid - args->data);
        else
            data_len = end - mid;
        key_value->m_value = (char*)ngx_pcalloc(pool, data_len+1);
        memcpy(key_value->m_value, mid, data_len);
        key_value->m_value[data_len] = 0x00;
        src = (u_char*)key_value->m_value;
        dst = (u_char*)key_value->m_value;
        ngx_unescape_uri(&dst, &src, data_len, 0);
        *dst = 0;
        //add to the 
        key_value->m_next = NULL;
        if (!head){
            head = tail = key_value;
        }else{
            tail->m_next = key_value;
            tail = key_value;
        }
        if (end){
            len -= (end+1 - begin);
            begin = end+1;
            mid = ngx_cwinux_strchr(begin, len, '=');
        }else{
            break;
        }
    }
    return head;

}
/*
 *  Called when the full body has been received. Even if the body is sent in
 *  multiple chunks, this will be called only once when everything has
 *  been received.
 */
void ngx_http_rrd_body_received(ngx_http_request_t *r)
{
    ngx_log_t *log = r->connection->log;
    ngx_chain_t *body_chain = r->request_body->bufs;
    /* Use the content length as a max for our value. */
    u_char* copy_idx;
    /*  In theory I should check for the size of the body to avoid loading
     * too much stuff in memory. However this is already handled by nginx
     * client_max_body_size. If the admin thinks it's taking too much memory
     * he/she should use client_max_body_size.
     */
    u_char* rrd_value = copy_idx =
            ngx_palloc(r->pool, r->headers_in.content_length_n);
    if (NULL == rrd_value) {
        ngx_log_error(NGX_LOG_ALERT, log, 0,
                       "Alloc problem @ngx_http_rrd_body_received/1");
        return ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
    }
    u_char* p;
    /* TODO: rewrite this to first READ in mem, then look for = and urldecode*/
    ngx_int_t looking_for_eq = 1;
    /* Needed for pipelined requests in HTTP/1.1 which can all be in one buf. */
    ngx_int_t left_in_contentlength = r->headers_in.content_length_n;
    do {
        ngx_buf_t *temp_buf;
        if (body_chain->buf->in_file) {
            ngx_buf_t * file_buf = body_chain->buf;
            /* Read it first in mem. This is unfortunately blocking.
             * TODO : non-blocking. HttpUploadModule ?
             */
            temp_buf = ngx_create_temp_buf(r->pool, ngx_buf_size(file_buf));
            if (NULL == temp_buf) {
                ngx_log_error(NGX_LOG_ALERT, log, 0,
                               "Alloc problem @ngx_http_rrd_body_received/2");
                return ngx_http_finalize_request(r,
                                         NGX_HTTP_INTERNAL_SERVER_ERROR);
            }
            ssize_t read_n;
            read_n = ngx_read_file(file_buf->file, temp_buf->start,
                                   ngx_buf_size(file_buf), 0);
            if (read_n < 0) {
                /* Problem already logged by read_file. */
                return ngx_http_finalize_request(r,
                                         NGX_HTTP_INTERNAL_SERVER_ERROR);
            } else {
                temp_buf->last = temp_buf->start + read_n;
            }
        } else {
            temp_buf = body_chain->buf;
        }
        p = temp_buf->start;
        while (p!=temp_buf->last && looking_for_eq && left_in_contentlength>0) {
            if ('=' == *(p++)) {
                looking_for_eq = 0;
            }
            left_in_contentlength--;
        }
        if (!looking_for_eq) {
            u_char *dst = copy_idx;
            u_char *src = p;
            /*
             *   This won't work if buffer boundary is in the middle of a
             *  percent-encoded string (which is unlikely to happen I would
             *  say. Should try to unit test this situation.
             */
            /*  We'll copy only what's left in buffer or what's left in
             * content-length.
             */
            size_t size_to_copy;
            if (left_in_contentlength < temp_buf->last - p) {
                size_to_copy = left_in_contentlength;
            } else {
                size_to_copy = temp_buf->last - p;
            }
            ngx_unescape_uri(&dst, &src, size_to_copy, 0);
            left_in_contentlength -= size_to_copy;
            copy_idx = dst;
        }
        body_chain = body_chain->next;
    } while (NULL != body_chain);
    *copy_idx = '\x0';

    ngx_http_rrd_loc_conf_t *rrd_conf;
    rrd_conf = ngx_http_get_module_loc_conf(r, ngx_http_rrd_module);

    int rrd_rc;
    ngx_log_debug(NGX_LOG_DEBUG_HTTP, log, 0,
                  "rrd_update_r (%s, NULL, 1, %s)", rrd_conf->db_name_cstyle,
                  rrd_value);
    rrd_clear_error();
    rrd_rc = rrd_update_r(rrd_conf->db_name_cstyle, NULL,
                          1, (const char **)&rrd_value);
    ngx_log_debug(NGX_LOG_DEBUG_HTTP, log, 0,
                  "rrd_update_r returned: %d", rrd_rc);
    ngx_int_t rc;
    if (rrd_rc < 0) {
        char * rrd_err = rrd_get_error();
        ngx_log_error(NGX_LOG_ALERT, log, 0,
                       "Problem on rrd_update_r: %s", rrd_err);
        rc = ngx_http_rrd_outprintf(r, NGX_HTTP_INTERNAL_SERVER_ERROR,
                       "Problem (%s) updating %s with %s.",
                       rrd_err, rrd_conf->db_name_cstyle, &rrd_value);
    } else {
        rc = ngx_http_rrd_outprintf(r, NGX_HTTP_OK,
                       "Updated %s. You make the rock-n-roll go round, Robin.",
                       rrd_conf->db_name_cstyle);
    }
    ngx_http_finalize_request(r, rc);
}
static ngx_str_t*
ngx_http_graphicsmagick_get_command(ngx_http_request_t *r)
{
	u_char							*dst, *src;
	size_t							 len;
	u_char							*p, *start_p;
	ngx_uint_t						 i;
	ngx_list_part_t					*part;
	ngx_table_elt_t					*header;
	ngx_str_t						*ret;

	part = &r->headers_in.headers.part;
	header = part->elts;

	for (i = 0; /* void */ ; i++) {

		if (i >= part->nelts) {
			if (part->next == NULL) {
				break;
			}

			part = part->next;
			header = part->elts;
			i = 0;
		}

		if (header[i].key.len == ngx_http_graphicsmagick_command_header.len
			&& ngx_strncmp(header[i].key.data, ngx_http_graphicsmagick_command_header.data,
						   header[i].key.len) == 0) {
			ret = ngx_pcalloc(r->pool, sizeof(ngx_str_t));
			ret->data = header[i].value.data;
			ret->len = header[i].value.len;
			return ret;
		}
	}

	/* not found, check as a reaquest arg */
	if (r->args.len) {
		p = (u_char *) ngx_strstr(r->args.data, "X-ImageMagick-Convert");

		if (p) {
			start_p = p += 22;
			while (p < r->args.data + r->args.len) {
				if (*p++ != '&') {
					continue;
				}
			}

			ret = ngx_pcalloc(r->pool, sizeof(ngx_str_t));
			ret->data = start_p;
			ret->len = p - start_p;
			
			dst = ret->data;
			src = ret->data;

			ngx_unescape_uri(&dst, &src, ret->len, NGX_UNESCAPE_URI);
			
			len = (ret->data + ret->len) - src;
			if (len) {
				dst = ngx_copy(dst, src, len);
			}

			ret->len = dst - ret->data;
		
			return ret;
		}
	}

	return NULL;
}
static ngx_int_t
ngx_lua_http_btt_parse_args(ngx_http_request_t *r, ngx_btt_ctx_t *ctx)
{
    size_t   nlen, vlen;
    u_char  *p, *last, *name, *val, *dst, *src;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "lua http btt parse args");

    if (r->args.len == 0) {
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                      "invalid uri \"%V\"", &r->args);
        return NGX_ERROR;
    }

    p = r->args.data;
    last = p + r->args.len;

    for ( /* void */ ; p < last; p++) {

        name = p;

        p = ngx_strlchr(p, last, '&');

        if (p == NULL) {
            p = last;
        }

        val = ngx_strlchr(name, p, '=');

        if (val == NULL) {
            val = p;
        }

        nlen = val - name;
        vlen = (++val < p) ? p - val : 0;

        dst = ngx_pnalloc(r->pool, vlen);
        if (dst == NULL) {
            return NGX_ERROR;
        }

        src = val;
        val = dst;
        ngx_unescape_uri(&dst, &src, vlen, 0);
        vlen = dst - val;

        ngx_log_debug4(NGX_LOG_ALERT, r->connection->log, 0,
                       "%*s=%*s", nlen, name, vlen, val);

        /*
         * BT Client:
         *
         *   BitComet: localip, natmapped, port_type
         *   NetTransport: supportcrypto
         *   uTorrent: corrupt
         *   XunLei: ip
         */

        switch (nlen) {

        case 2:

            if (ngx_strncmp(name, "ip", nlen) == 0) {
                ctx->internal_ip = ngx_inet_addr(val, vlen);
                if (ctx->internal_ip == INADDR_NONE) {
                    goto invalid;
                }
                break;
            }

            break;

        case 3:

            if (ngx_strncmp(name, "key", nlen) == 0) {
                ngx_memcpy(ctx->key, val, vlen);
                break;
            }

            break;

        case 4:

            if (ngx_strncmp(name, "port", nlen) == 0) {
                ctx->internal_port = (in_port_t) ngx_atoi(val, vlen);
                if (ctx->internal_port == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            if (ngx_strncmp(name, "left", nlen) == 0) {
                ctx->left = ngx_atoof(val, vlen);
                if (ctx->left == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            break;

        case 5:

            if (ngx_strncmp(name, "event", nlen) == 0) {

                if (ngx_strncmp(val, "none", sizeof("none") - 1) == 0) {
                    ctx->event = NGX_BTT_EVENT_NONE;

                } else if (ngx_strncmp(val, "completed",
                                       sizeof("completed") - 1)
                           == 0)
                {
                    ctx->event = NGX_BTT_EVENT_COMPLETED;

                } else if (ngx_strncmp(val, "started", sizeof("started") - 1)
                           == 0)
                {
                    ctx->event = NGX_BTT_EVENT_STARTED;

                } else if (ngx_strncmp(val, "stopped", sizeof("stopped") - 1)
                           == 0)
                {
                    ctx->event = NGX_BTT_EVENT_STOPPED;

                } else {
                    goto invalid;
                }

                break;
            }

            break;

        case 7:

            if (ngx_strncmp(name, "peer_id", nlen) == 0) {
                ngx_memcpy(ctx->peer_id, val, vlen);
                break;
            }

            if (ngx_strncmp(name, "localip", nlen) == 0) {
                ctx->internal_ip = ngx_inet_addr(val, vlen);
                if (ctx->internal_ip == INADDR_NONE) {
                    goto invalid;
                }
                break;
            }

            if (ngx_strncmp(name, "numwant", nlen) == 0) {
                ctx->numwant = ngx_atoi(val, vlen);
                if (ctx->numwant == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            if (ngx_strncmp(name, "compact", nlen) == 0) {
                ctx->compact = ngx_atoi(val, vlen);
                if (ctx->compact == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            if (ngx_strncmp(name, "corrupt", nlen) == 0) {
                ctx->corrupt = ngx_atoi(val, vlen);
                if (ctx->corrupt == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            break;

        case 8:

            if (ngx_strncmp(name, "uploaded", nlen) == 0) {
                ctx->uploaded = ngx_atoof(val, vlen);
                if (ctx->uploaded == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            break;

        case 9:

            if (ngx_strncmp(name, "info_hash ", nlen) == 0) {
                ngx_memcpy(ctx->info_hash, val, vlen);
                break;
            }

            if (ngx_strncmp(name, "natmapped ", nlen) == 0) {
                ctx->natmapped = ngx_atoi(val, vlen);
                if (ctx->natmapped == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            if (ngx_strncmp(name, "port_type", nlen) == 0) {
                ngx_memcpy(ctx->port_type, val, vlen);
                break;
            }

            break;

        case 10:

            if (ngx_strncmp(name, "downloaded", nlen) == 0) {
                ctx->downloaded = ngx_atoof(val, vlen);
                if (ctx->downloaded == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            if (ngx_strncmp(name, "no_peer_id ", nlen) == 0) {
                ctx->no_peer_id = ngx_atoi(val, vlen);
                if (ctx->no_peer_id == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            break;

        case 13:

            if (ngx_strncmp(name, "supportcrypto", nlen) == 0) {
                ctx->supportcrypto = ngx_atoi(val, vlen);
                if (ctx->supportcrypto == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            break;

        default:
            break;
        }
    }

    return NGX_OK;

invalid:

    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                  "invalid value \"%*s\" of the key \"%*s\"",
                  nlen, name, vlen, val);

    return NGX_ERROR;
}
ngx_int_t
ngx_lcb_process(ngx_http_request_t *r)
{
    lcb_error_t err = LCB_NOT_SUPPORTED;
    ngx_http_variable_value_t *vv;
    ngx_str_t key, val;
    enum ngx_lcb_cmd opcode;
    ngx_http_core_loc_conf_t *clcf;
    ngx_lcb_connection_t *conn;
    lcb_cas_t cas = 0;
    lcb_uint32_t flags = 0, exptime = 0;
    ngx_int_t need_free_value = 0;

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
    conn = ngx_http_get_couchbase_connection(clcf->name);
    if (conn == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "couchbase: connection not found: \"%V\"", &clcf->name);
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /* setup command: use variable or fallback to HTTP method */
    vv = ngx_http_get_indexed_variable(r, ngx_lcb_cmd_idx);
    if (vv == NULL) {
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    if (vv->not_found || vv->len == 0) {
        if (r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD)) {
            opcode = ngx_lcb_cmd_get;
        } else if (r->method == NGX_HTTP_POST) {
            opcode = ngx_lcb_cmd_add;
        } else if (r->method == NGX_HTTP_PUT) {
            opcode = ngx_lcb_cmd_set;
        } else if (r->method == NGX_HTTP_DELETE) {
            opcode = ngx_lcb_cmd_delete;
        } else {
            ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                          "ngx_memc: $memc_cmd variable requires explicit "
                          "assignment for HTTP request method %V",
                          &r->method_name);
            ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
            return NGX_HTTP_BAD_REQUEST;
        }
    } else {
        if (ngx_strncmp(vv->data, "get", 3) == 0) {
            opcode = ngx_lcb_cmd_get;
        } else if (ngx_strncmp(vv->data, "add", 3) == 0) {
            opcode = ngx_lcb_cmd_add;
        } else if (ngx_strncmp(vv->data, "replace", 7) == 0) {
            opcode = ngx_lcb_cmd_replace;
        } else if (ngx_strncmp(vv->data, "set", 3) == 0) {
            opcode = ngx_lcb_cmd_set;
        } else if (ngx_strncmp(vv->data, "append", 6) == 0) {
            opcode = ngx_lcb_cmd_append;
        } else if (ngx_strncmp(vv->data, "prepend", 7) == 0) {
            opcode = ngx_lcb_cmd_prepend;
        } else if (ngx_strncmp(vv->data, "delete", 6) == 0) {
            opcode = ngx_lcb_cmd_delete;
        } else {
            ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                          "ngx_memc: unknown $couchbase_cmd \"%v\"", vv);
            ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
            return NGX_HTTP_BAD_REQUEST;
        }
    }

    /* setup key: use variable or fallback to URI */
    vv = ngx_http_get_indexed_variable(r, ngx_lcb_key_idx);
    if (vv == NULL) {
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    if (vv->not_found || vv->len == 0) {
        size_t loc_len;

        loc_len = r->valid_location ? clcf->name.len : 0;
        key.data = r->uri.data + loc_len;
        key.len = r->uri.len - loc_len;
    } else {
        u_char *dst, *src;
        key.data = ngx_palloc(r->pool, vv->len);
        if (key.data == NULL) {
            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
        dst = key.data;
        src = vv->data;
        ngx_unescape_uri(&dst, &src, vv->len, 0);
        *dst = 0;
        key.len = dst - key.data;
    }

    /* setup value: use variable or fallback to HTTP body */
    ngx_str_null(&val);
    if (opcode >= ngx_lcb_cmd_add && opcode <= ngx_lcb_cmd_prepend) {
        vv = ngx_http_get_indexed_variable(r, ngx_lcb_val_idx);
        if (vv == NULL) {
            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
        if (vv->not_found || vv->len == 0) {
            if (r->request_body == NULL || r->request_body->bufs == NULL) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "neither the \"$couchbase_value\" variable "
                              "nor the request body is available");
                ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
                return NGX_HTTP_BAD_REQUEST;
            } else {
                /* copy body to the buffer */
                ngx_chain_t *cl;
                u_char *p;

                val.len = 0;
                for (cl = r->request_body->bufs; cl; cl = cl->next) {
                    val.len += ngx_buf_size(cl->buf);
                }
                p = val.data = ngx_palloc(r->pool, val.len);
                if (p == NULL) {
                    ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }
                for (cl = r->request_body->bufs; cl; cl = cl->next) {
                    p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos);
                }
                vv = NULL;
            }
        } else {
            u_char *dst, *src;
            val.data = ngx_palloc(r->pool, vv->len);
            if (val.data == NULL) {
                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }
            need_free_value = 1;
            dst = val.data;
            src = vv->data;
            ngx_unescape_uri(&dst, &src, vv->len, 0);
            *dst = 0;
            val.len = dst - val.data;
        }
    }

    /* setup CAS value */
    vv = ngx_http_get_indexed_variable(r, ngx_lcb_cas_idx);
    if (vv == NULL) {
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    if (!vv->not_found && vv->len > 0) {
        if (ngx_lcb_atocas(vv->data, vv->len, &cas) != NGX_OK) {
            ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
            return NGX_HTTP_BAD_REQUEST;
        }
    }

    /* setup flags value */
    vv = ngx_http_get_indexed_variable(r, ngx_lcb_flags_idx);
    if (vv == NULL) {
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    if (!vv->not_found && vv->len > 0) {
        flags = ngx_atoi(vv->data, vv->len);
    }

    /* setup expiration value */
    vv = ngx_http_get_indexed_variable(r, ngx_lcb_exptime_idx);
    if (vv == NULL) {
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    if (!vv->not_found && vv->len > 0) {
        exptime = ngx_atoi(vv->data, vv->len);
    }

    switch (opcode) {
    case ngx_lcb_cmd_get: {
        lcb_get_cmd_t cmd;
        const lcb_get_cmd_t *commands[1];

        commands[0] = &cmd;
        memset(&cmd, 0, sizeof(cmd));
        cmd.v.v0.key = key.data;
        cmd.v.v0.nkey = key.len;
        cmd.v.v0.exptime = exptime;
        err = lcb_get(conn->lcb, r, 1, commands);
        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "couchbase(%p): get request \"%*s\"",
                       (void *)conn->lcb, cmd.v.v0.nkey, cmd.v.v0.key);
    }
    break;
    case ngx_lcb_cmd_add:
    case ngx_lcb_cmd_replace:
    case ngx_lcb_cmd_set:
    case ngx_lcb_cmd_append:
    case ngx_lcb_cmd_prepend: {
        lcb_store_cmd_t cmd;
        const lcb_store_cmd_t *commands[1];

        commands[0] = &cmd;
        memset(&cmd, 0, sizeof(cmd));

        cmd.v.v0.operation = opcode;
        cmd.v.v0.key = key.data;
        cmd.v.v0.nkey = key.len;
        cmd.v.v0.bytes = val.data;
        cmd.v.v0.nbytes = val.len;
        cmd.v.v0.cas = cas;
        cmd.v.v0.flags = flags;
        cmd.v.v0.exptime = exptime;
        err = lcb_store(conn->lcb, r, 1, commands);
        ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "couchbase(%p): store request \"%*s\", operation: 0x%02xd",
                       (void *)conn->lcb, cmd.v.v0.nkey, cmd.v.v0.key, cmd.v.v0.operation);
    }
    break;
    case ngx_lcb_cmd_delete: {
        lcb_remove_cmd_t cmd;
        const lcb_remove_cmd_t *commands[1];

        commands[0] = &cmd;
        memset(&cmd, 0, sizeof(cmd));
        cmd.v.v0.key = key.data;
        cmd.v.v0.nkey = key.len;
        err = lcb_remove(conn->lcb, r, 1, commands);
        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "couchbase(%p): remove request \"%*s\"",
                       (void *)conn->lcb, cmd.v.v0.nkey, cmd.v.v0.key);
    }
    break;
    }
    if (need_free_value) {
        ngx_pfree(r->pool, val.data);
    }
    if (err != LCB_SUCCESS) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "couchbase: failed to schedule couchbase request: %s",
                      lcb_strerror(conn->lcb, err));
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        return NGX_ERROR;
    }
    return NGX_OK;
}
static ngx_int_t
ngx_rtmp_authen_http_response_decode(ngx_rtmp_session_t *s,
        ngx_rtmp_authen_ctx_t *ctx)
{
    ngx_http_request_t    r;
    ngx_str_t             val;
    u_char                val_buf[NGX_RTMP_AUTHEN_MAX_RESPONSE];
    u_char                status;

    ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
            "connect (authen): response: %s", ctx->resp.data);

    val.len  = 0;
    val.data = val_buf;

    r.args.len  = ctx->resp.len;
    r.args.data = ctx->resp.data;

    ctx->conn_desc.len = 0;

    if (ngx_http_arg(&r, (u_char *)"desc", sizeof("desc") - 1, &val) == NGX_OK
            && val.len > 0) {

        ctx->conn_desc.len  = ngx_base64_decoded_length(val.len);
        ctx->conn_desc.data = ngx_pcalloc(s->connection->pool,
                ctx->conn_desc.len + 1);

        if (ctx->conn_desc.data != NULL &&
                ngx_decode_base64(&ctx->conn_desc, &val) == NGX_OK) {
            ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                    "connect (authen): description: %s", ctx->conn_desc.data);
        } else {
          ctx->conn_desc.len = 0;
        }
    }

    val.len = 0;
    if (ngx_http_arg(&r, (u_char *)"status", sizeof ("status") - 1,
            &val) != NGX_OK || val.len == 0) {
        return NGX_ERROR;
    } else {
        status = val.data[0];

        ctx->user.len = 0;
        val.len       = 0;

        if (ngx_http_arg(&r, (u_char *)"user", sizeof("user") - 1,
                &val) == NGX_OK && val.len > 0) {
            ctx->user.data = ngx_pcalloc(s->connection->pool, val.len + 1);

            if (ctx->user.data != NULL) {
                u_char *dst = ctx->user.data;

                ngx_unescape_uri(&dst, &val.data, val.len, 0);
                *dst = '\0';

                ctx->user.len = ngx_strlen(ctx->user.data);
            }
        }

        ctx->authmod.len = 0;
        val.len       = 0;

        if (ngx_http_arg(&r, (u_char *)"authmod", sizeof("authmod") - 1,
                &val) == NGX_OK && val.len > 0) {
            ctx->authmod.data = ngx_pcalloc(s->connection->pool, val.len + 1);

            if (ctx->authmod.data != NULL) {
                u_char *dst = ctx->authmod.data;

                ngx_unescape_uri(&dst, &val.data, val.len, 0);
                *dst = '\0';

                ctx->authmod.len = ngx_strlen(ctx->authmod.data);
            }
        }
    }

    switch (status) {
    /* Allow */
    case (u_char)'a':
    case (u_char)'A':
        if (ctx->user.len > 0) {
            ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
                    "connect (authen): Allow, user: %s", ctx->user.data);
        } else {
            ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
                    "connect (authen): Allow");
        }

        ctx->conn_status = NGX_RTMP_CONN_ALLOW;
        return NGX_OK;

    /* Reject */
    case (u_char)'r':
    case (u_char)'R':
        if (ctx->user.len > 0) {
            ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
                    "connect (authen): Reject, user: %s", ctx->user.data);
        } else {
            ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
                    "connect (authen): Reject");
        }

        if (ctx->conn_desc.len > 0) {
            ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
                    "connect (authen): Reject, reason: %s",
                    ctx->conn_desc.data);
        }

        ctx->conn_status = NGX_RTMP_CONN_REJECT;
        return NGX_OK;

    /* Deny */
    case (u_char)'d':
    case (u_char)'D':
    default:
        if (ctx->user.len > 0) {
            ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
                    "connect (authen): Deny, user: %s", ctx->user.data);
        } else {
            ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
                    "connect (authen): Deny");
        }

        ctx->conn_status = NGX_RTMP_CONN_DENY;
        return NGX_ERROR;
    }
}