static ngx_int_t
ngx_http_memcached_handler(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_http_upstream_t            *u;
    ngx_http_memcached_ctx_t       *ctx;
    ngx_http_memcached_loc_conf_t  *mlcf;

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

    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;

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

    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);

    u->conf = &mlcf->upstream;

    u->create_request = ngx_http_memcached_create_request;
    u->reinit_request = ngx_http_memcached_reinit_request;
    u->process_header = ngx_http_memcached_process_header;
    u->abort_request = ngx_http_memcached_abort_request;
    u->finalize_request = ngx_http_memcached_finalize_request;

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

    ctx->request = r;

    ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);

    u->input_filter_init = ngx_http_memcached_filter_init;
    u->input_filter = ngx_http_memcached_filter;
    u->input_filter_ctx = ctx;

    r->main->count++;

    ngx_http_upstream_init(r);

    return NGX_DONE;
}
static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)
{
	//首先建立http上下文结构体ngx_http_mytest_ctx_t
	ngx_http_mytest_ctx_t *myctx = ngx_http_get_module_ctx(r,ngx_http_mytest_module);
	if(myctx == NULL){
		myctx = ngx_palloc(r->pool,sizeof(ngx_http_mytest_ctx_t));
		if(myctx == NULL){
			return NGX_ERROR;
		}
		//将新建的上下文与请求关联起来
		ngx_http_set_ctx(r,myctx,ngx_http_mytest_module);
	}

	if(ngx_http_upstream_create(r) != NGX_OK){
		ngx_log_error(NGX_LOG_ERR,r->connection->log,0,"ngx_http_upstream_create() failed");
		return NGX_ERROR;
	}
	//得到配置结构体ngx_http_mytest_conf_t
	ngx_http_mytest_conf_t *mycf =
			(ngx_http_mytest_conf_t*)ngx_http_get_module_loc_conf(r,ngx_http_mytest_module);
	ngx_http_upstream_t *u = r->upstream;
	//这里用配置文件中的结构体来赋给r->upstream->conf成员
	u->conf = &mycf->upstream;
	u->buffering = mycf->upstream.buffering;
	//初始化resolved结构体,用来保存上游服务器的地址
	u->resolved = (ngx_http_upstream_resolved_t*)ngx_pcalloc(r->pool,sizeof(ngx_http_upstream_resolved_t));
	if(u->resolved == NULL){
		ngx_log_error(NGX_LOG_ERR,r->connection->log,0,"ngx_pcalloc resolved error. %s.",strerror(errno));
		return NGX_ERROR;
	}
	static struct sockaddr_in backendSockAddr;
	struct hostent *pHost = gethostbyname((char*)"www.mmkuaipai.com");
	if(pHost == NULL)
	{
		ngx_log_error(NGX_LOG_ERR,r->connection->log,0,"gethostbyname fail. %s",strerror(errno));
		return NGX_ERROR;
	}
	backendSockAddr.sin_family = AF_INET;
	backendSockAddr.sin_port = htons((in_port_t)80);
	char* pDmsIP = inet_ntoa(*(struct in_addr*)(pHost->h_addr_list[0]));
	backendSockAddr.sin_addr.s_addr = inet_addr(pDmsIP);
	//myctx->backendServer.data = (u_char*)pDmsIP;
	//myctx->backendServer.len = strlen(pDmsIP);

	u->resolved->sockaddr = (struct sockaddr*)&backendSockAddr;
	u->resolved->socklen = sizeof(struct sockaddr_in);
	u->resolved->naddrs = 1;

	u->create_request = mytest_upstream_create_request;
	u->process_header = mytest_process_status_line;
	u->finalize_request = mytest_upstream_finalize_request;

	r->main->count++;
	ngx_http_upstream_init(r);
	return NGX_DONE;
}
static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r) {
	//全局变量
	ngx_http_mytest_ctx_t* myctx = ngx_http_get_module_ctx(r,
			ngx_http_mytest_module);
	if (myctx == NULL) {
		myctx = ngx_palloc(r->pool, sizeof(ngx_http_mytest_ctx_t));
		if (myctx == NULL)
			return NGX_ERROR;
		ngx_http_set_ctx(r, myctx, ngx_http_mytest_module);
	}
	//创建upstream结构
	if (ngx_http_upstream_create(r) != NGX_OK) {
		ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
				"[jseanj] ngx_http_upstream_create() failed");
		return NGX_ERROR;
	}
	//获得conf
	ngx_http_mytest_conf_t *mycf =
			(ngx_http_mytest_conf_t *) ngx_http_get_module_loc_conf(r,
					ngx_http_mytest_module);
	ngx_http_upstream_t *u = r->upstream;

	u->conf = &mycf->upstream; //conf指定了upstream的运行方式,其中的配置都很重要,它们会影响访问上游服务器的方式
	u->buffering = mycf->upstream.buffering;
	u->resolved = (ngx_http_upstream_resolved_t*) ngx_pcalloc(r->pool,
			sizeof(ngx_http_upstream_resolved_t));
	if (u->resolved == NULL) {
		ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
				"[jseanj] ngx_pcalloc resolved error. %s.", strerror(errno));
		return NGX_ERROR;
	}
	static struct sockaddr_in backendSockAddr;
	//struct hostent *pHost = gethostbyname((char*)"www.google.com");
	struct hostent *pHost = gethostbyname((char*) "www.baidu.com");
	if (pHost == NULL) {
		ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
				"[jseanj] gethostbyname fail. %s.", strerror(errno));
		return NGX_ERROR;
	}
	backendSockAddr.sin_family = AF_INET;
	backendSockAddr.sin_port = htons((in_port_t) 80);
	char* pDmsIP = inet_ntoa(*(struct in_addr*) (pHost->h_addr_list[0]));
	backendSockAddr.sin_addr.s_addr = inet_addr(pDmsIP);
	//myctx->backendServer.data = (u_char*)pDmsIP;
	//myctx->backendServer.len = strlen(pDmsIP);
	u->resolved->sockaddr = (struct sockaddr *) &backendSockAddr;
	u->resolved->socklen = sizeof(struct sockaddr_in);
	u->resolved->naddrs = 1;
	u->create_request = mytest_upstream_create_request;
	u->process_header = mytest_process_status_line;
	u->finalize_request = mytest_upstream_finalize_request;
	r->main->count++;
	ngx_http_upstream_init(r);
	return NGX_DONE;
}
static ngx_int_t
ngx_http_mcset_module_init_cache_request( ngx_http_request_t *r ) {

    ngx_http_mcset_module_conf_t*     mscf;
    ngx_http_upstream_t             *u;
    ngx_mcset_module_ctx_t* ctx;

    mscf = ngx_http_get_module_loc_conf( r, ngx_http_mcset_module );
    ctx = ngx_http_get_module_ctx( r, ngx_http_mcset_module );

    if ( ctx == NULL ) {
        ctx = ngx_pcalloc( r->pool, sizeof( ngx_mcset_module_ctx_t ) );
        if ( ctx == NULL ) {
            return NGX_ERROR;
        }
        ctx->cache_id.len = 32;
        ctx->cache_id.data = ngx_pcalloc( r->pool, ctx->cache_id.len );
        ctx->r = r;
        ngx_http_set_ctx( r, ctx, ngx_http_mcset_module );
    }

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

    u = r->upstream;
    ngx_str_set( &u->schema, "memcached://" );
    u->conf = &mscf->upstream;
    u->create_request = ngx_http_mcset_cache_create_request;
    u->reinit_request = ngx_http_mcset_cache_reinit_request;
    u->process_header = ngx_http_mcset_cache_process_header;
    u->abort_request = ngx_http_mcset_cache_abort_request;
    u->finalize_request = ngx_http_mcset_cache_finalize_request;

    u->input_filter_init = ngx_http_mcset_module_filter_init;
    u->input_filter = ngx_http_mcset_module_filter;
    u->input_filter_ctx = ctx;

    r->subrequest_in_memory = 1;
    r->main->count++;
 
    ngx_http_upstream_init( r );
    return NGX_OK;
}
static void
ngx_http_poller_event(ngx_event_t *ev)
{
  ngx_http_poller_t   *poller = ev->data;
  ngx_http_request_t  *r;
  ngx_time_t          *tp;

  if (ngx_exiting) {
    return;
  }

  tp = ngx_timeofday();
  poller->poll_start = tp->sec * 1000 + tp->msec;

  r = ngx_http_poller_request(poller);
  if (r != NULL) {
    ngx_http_upstream_init(r);
  }
}
static ngx_int_t
ngx_http_proxy_connect_upstream(ngx_http_request_t *r)
{
    ngx_http_upstream_t                     *u;
    ngx_http_proxy_connect_ctx_t            *ctx;
    ngx_http_proxy_connect_loc_conf_t       *mlcf;

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

    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_connect_module);
    ctx = ngx_http_get_module_ctx(r,ngx_http_proxy_connect_module);
    if (ngx_http_proxy_connect_eval(r, ctx, mlcf) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

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

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

    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_connect_module);

    u->conf = &mlcf->upstream;

    u->create_request = ngx_http_proxy_connect_create_request;
    u->reinit_request = ngx_http_proxy_connect_reinit_request;
    u->process_header = ngx_http_proxy_connect_process_header;
    u->abort_request = ngx_http_proxy_connect_abort_request;
    u->finalize_request = ngx_http_proxy_connect_finalize_request;

    u->input_filter_init = NULL;
    u->input_filter = NULL;
    u->input_filter_ctx = ctx;
    ngx_http_upstream_init(r);
    return NGX_DONE;
}
static ngx_int_t
ngx_http_mogilefs_handler(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_http_upstream_t            *u;
    ngx_http_mogilefs_ctx_t        *ctx;
    ngx_http_mogilefs_loc_conf_t   *mgcf;

    mgcf = ngx_http_get_module_loc_conf(r, ngx_http_mogilefs_module);

    if (mgcf->location_type == NGX_MOGILEFS_MAIN) {
        if(!(r->method & mgcf->methods)) {
            return NGX_HTTP_NOT_ALLOWED;
        }

        if(r->method & NGX_HTTP_PUT) {
            return NGX_DECLINED;
        }
    }

    switch(r->method) {
        case NGX_HTTP_GET:
            if (ngx_http_set_content_type(r) != NGX_OK) {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            /* fall through */

        case NGX_HTTP_DELETE:
            rc = ngx_http_discard_request_body(r);

            if (rc != NGX_OK) {
                return rc;
            }
            break;
        default:
            break;
    }

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

    u->peer.log = r->connection->log;
    u->peer.log_error = NGX_ERROR_ERR;
#if (NGX_THREADS)
    u->peer.lock = &r->connection->lock;
#endif

    u->output.tag = (ngx_buf_tag_t) &ngx_http_mogilefs_module;

    u->conf = &mgcf->upstream;

    u->create_request = ngx_http_mogilefs_create_request;
    u->reinit_request = ngx_http_mogilefs_reinit_request;
    u->process_header = ngx_http_mogilefs_process_header;
    u->abort_request = ngx_http_mogilefs_abort_request;
    u->finalize_request = ngx_http_mogilefs_finalize_request;

    r->upstream = u;

    ctx = ngx_http_get_module_ctx(r, ngx_http_mogilefs_module);
    
    if(ctx == NULL) {
        ctx = ngx_palloc(r->pool, sizeof(ngx_http_mogilefs_ctx_t));
        if (ctx == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        ctx->peer_addr = NULL;
        ctx->peer_addr_len = 0;

        ctx->num_paths_returned = -1;
        ctx->aux_params = NULL;
        ctx->status = 0;

        ngx_array_init(&ctx->sources, r->pool, 1, sizeof(ngx_http_mogilefs_src_t));

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

        ngx_http_set_ctx(r, ctx, ngx_http_mogilefs_module);
    }

    u->input_filter_init = ngx_http_mogilefs_filter_init;
    u->input_filter = ngx_http_mogilefs_filter;
    u->input_filter_ctx = ctx;

    if (mgcf->tracker_lengths != 0) {
        if (ngx_http_mogilefs_eval_tracker(r, mgcf) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
    }

    if(ngx_http_mogilefs_set_cmd(r, ctx) != NGX_OK) {
        return NGX_ERROR;
    }

#if defined nginx_version && nginx_version >= 8011
    r->main->count++;
#endif

    ngx_http_upstream_init(r);

    return NGX_DONE;
}
/* 
    echo 处理handler
*/
static ngx_int_t 
ngx_http_echo_handler(ngx_http_request_t* r)
{
    ngx_http_echov4_loc_conf_t*     echo_conf;
    ngx_int_t                       rc;
    u_char*                         post_content = NULL;
    size_t                          post_content_len = 0;
    ngx_http_echov4_request_ctx_t*  echo_ctx;
    ngx_http_upstream_t*            u;

    echo_conf = ngx_http_get_module_loc_conf(r, ngx_http_echov4_module);
    // 我们模块运行时的上下文,如果没有的话,我们将进行初始化工作
    echo_ctx  = (ngx_http_echov4_request_ctx_t*) ngx_http_get_module_ctx(r, ngx_http_echov4_module);
    if (!echo_ctx){ //初始化
        echo_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_echov4_request_ctx_t)); 
        /*
            实际上calloc 已经把结构体里的数值设置为0 
        */
        echo_ctx->current_echo_times = 0;
        echo_ctx->post_content = ngx_pcalloc(r->pool, sizeof(ngx_str_t));

        ngx_http_set_ctx(r, echo_ctx, ngx_http_echov4_module);
    }
 
    rc = ngx_http_read_client_request_body(r, ngx_http_echov4_request_post_handler);
    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
        return rc;
    }

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

    ngx_http_dump_request_headers(r);
    // 将post_content的数值赋值给结构体
    post_content_len = ngx_http_dump_request_body(r, /* out */(void*) &post_content);
    echo_ctx->post_content->len = post_content_len;
    echo_ctx->post_content->data = post_content;     

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

    u->schema.len = sizeof("echo://") - 1;
    u->schema.data = (u_char *) "echo://";

    u->peer.log = r->connection->log;
    u->peer.log_error = NGX_ERROR_ERR;
#if (NGX_THREADS)
    u->peer.lock = &r->connection->lock;
#endif

    u->output.tag = (ngx_buf_tag_t) &ngx_http_echov4_module;

    u->conf = &echo_conf->upstream;

    u->create_request = ngx_http_echo_create_request;
    u->reinit_request = ngx_http_echo_reinit_request;
    u->process_header = ngx_http_echo_process_header;
    u->abort_request = ngx_http_echo_abort_request;
    u->finalize_request = ngx_http_echo_finalize_request;
    r->upstream = u;

    ngx_http_upstream_init(r);

    return NGX_DONE;
}
static ngx_int_t
ngx_http_upstreamTest_handler(ngx_http_request_t *r)
{

    static ngx_int_t visited_times = 0;
    ngx_http_upstreamTest_ctx_t *upstreamctx = ngx_http_get_module_ctx(r,ngx_http_upstreamTest_module);
    if(upstreamctx == NULL)
    {
        upstreamctx = ngx_pcalloc(r->pool,sizeof(ngx_http_upstreamTest_ctx_t));
        if(upstreamctx == NULL)
        {
            return NGX_ERROR;
        }
        ngx_http_set_ctx(r,upstreamctx,ngx_http_upstream_module);
    }

    if(ngx_http_upstream_create(r) != NGX_OK)
    {
        ngx_log_error(NGX_LOG_ERR,r->connection->log,0,"ngx_http_upstream_create() failed");
        return NGX_ERROR;
    }
    ngx_http_upstreamTest_conf_t *upstreamconf = (ngx_http_upstreamTest_conf_t *)ngx_http_get_module_loc_conf(r,ngx_http_upstreamTest_module);
    ngx_http_upstream_t *u = r->upstream;
    u->conf = &upstreamconf->upstream;
    u->buffering = upstreamconf->upstream.buffering;
    u->resolved = (ngx_http_upstream_resolved_t*)ngx_pcalloc(r->pool,sizeof(ngx_http_upstream_resolved_t));
    if(u->resolved == NULL)
    {
        ngx_log_error(NGX_LOG_ERR,r->connection->log,0,"ngx_pcalloc resolved error. %s",strerror(errno));
        return NGX_ERROR;
    }

//    static struct sockaddr_in  backendSockAddr;
//    backendSockAddr.sin_family = AF_INET;
//    backendSockAddr.sin_port = htons((in_port_t)7777);
//    backendSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

//    u->resolved->sockaddr = (struct sockaddr *)&backendSockAddr;
//    u->resolved->socklen = sizeof(struct sockaddr_in);
//    u->resolved->naddrs = 1;

    u->create_request = ngx_http_upstreamTest_create_request;
    u->process_header = ngx_http_upstreamTest_process_status_line;
    u->finalize_request = ngx_http_upstreamTest_finalize_request;
    
  //  r->main->count++;
 //   ngx_http_upstream_init(r);
    if(!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD)))
        return NGX_HTTP_NOT_ALLOWED;

    u_char ngx_upstream_string[1024];
    ngx_sprintf(ngx_upstream_string,"Visited times: %d",++visited_times);
    ngx_log_error(NGX_LOG_EMERG,r->connection->log,0,"ngx_upstream_string: %s",ngx_upstream_string); 
    ngx_uint_t content_length = ngx_strlen(ngx_upstream_string);
    ngx_int_t rc;
    
    if(!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD)))
        return NGX_HTTP_NOT_ALLOWED;

    rc = ngx_http_discard_request_body(r);
    if(rc != NGX_OK)
    {
        ngx_log_error(NGX_LOG_EMERG,r->connection->log,0,"discard requst_body failed!");
        return rc;
    }
    
    ngx_str_set(&r->headers_out.content_type,"text/html");

    if(r->method == NGX_HTTP_HEAD)
    {
        r->headers_out.status = NGX_HTTP_OK;
        r->headers_out.content_length_n = content_length;
        ngx_log_error(NGX_LOG_EMERG,r->connection->log,0,"send respond head!");
        return ngx_http_send_header(r);
    }

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

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

    b->pos = ngx_upstream_string;
    b->last = ngx_upstream_string + content_length;
    b->memory = 1;
    b->last_buf = 1;

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n  = content_length;

    rc = ngx_http_send_header(r);

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

    ngx_http_output_filter(r,&out);
    r->main->count++;
    ngx_http_upstream_init(r);
    return NGX_OK;
}
static ngx_int_t
ngx_http_token_handler(ngx_http_request_t *r)
{
	ngx_http_upstream_t        *u;
	ngx_http_token_ctx_t       *ctx;
	ngx_http_token_loc_conf_t  *tlcf;

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

	tlcf = ngx_http_get_module_loc_conf(r, ngx_http_token_module);

	ngx_str_t args = r->args;
	ngx_str_t key = tlcf->key;

	ngx_uint_t i = 0;

	if ( args.len > (tlcf->token_len + key.len)){
		for (; i < args.len; i++){
			if (args.data[i] == '=' 
				&& i >= key.len
				&& ngx_strncmp(args.data + i - key.len, key.data, key.len) == 0
				&& (args.data[i + tlcf->token_len + 1] == '&'
				|| (i + tlcf->token_len + 1) == args.len)){
					break;
			}
		}
	}

	if ( i < key.len || (args.len - i) < tlcf->token_len){
		ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "token:%V pos:%d args:%V.", &tlcf->key, i, &args);
		return NGX_HTTP_FORBIDDEN;
	}

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

	u->schema = tlcf->upstream.schema;

	u->peer.log = r->connection->log;
	u->peer.log_error = NGX_ERROR_ERR;
#if (NGX_THREADS)
	u->peer.lock = &r->connection->lock;
#endif

	u->output.tag = (ngx_buf_tag_t) &ngx_http_token_module;

	u->conf = &tlcf->upstream;

	u->create_request = ngx_http_token_create_request;
	u->process_header = ngx_http_token_process_header;
	u->abort_request = ngx_http_token_abort_request;
	u->finalize_request = ngx_http_token_finalize_request;

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

	r->upstream = u;

	ctx->rest = NGX_HTTP_MEMCACHED_END;
	ctx->request = r;
	ctx->index	= i;

	ngx_http_set_ctx(r, ctx, ngx_http_token_module);

	ngx_http_upstream_init(r);	
	
	return NGX_DONE;
}
//在ngx_http_mytest_handler方法中启动upstream
static ngx_int_t
ngx_http_mytest_handler(ngx_http_request_t *r)
{
	//首先建立HTTP上下文结构体
	ngx_http_mytest_ctx_t *myctx = ngx_http_get_module_ctx(r, ngx_http_mytest_module);
	if(myctx == NULL){
		myctx = ngx_palloc(r->pool, sizeof(ngx_http_mytest_ctx_t));
		if(myctx == NULL){
			return NGX_ERROR;
		}
		//将新建的上下文与请求联系起来
		ngx_http_set_ctx(r, myctx, ngx_http_mytest_module);
	}

	//对每一个要使用upstream的请求,必须调用且只能调用一次ngx_http_upstream_create方法,
	//它会初始化r->upstream成员
	if(ngx_http_upstream_create(r) != NGX_OK){
		ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
				"ngx_http_upstream_create() failed");
		return NGX_ERROR;
	}


	//得到配置结构体ngx_http_mytest_conf_t
	ngx_http_mytest_conf_t *mycf = (ngx_http_mytest_conf_t *)
		ngx_http_get_module_loc_conf(r, ngx_http_mytest_module);
	ngx_http_upstream_t *u = r->upstream;

	//这里用配置文件中的结构体来赋值给r->upstream->conf成员
	u->conf = &mycf->upstream;
	
	u->buffering = mycf->upstream.buffering;
	//以下代码开始初始化resolved结构体,用来保存上游服务器的地址

	u->resolved = (ngx_http_upstream_resolved_t *)ngx_pcalloc(r->pool, 
			sizeof(ngx_http_upstream_resolved_t));
	
	if(u->resolved == NULL){
		ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
				"ngx_pcalloc resolved error. %s.", strerror(errno));
		return NGX_ERROR;
	}

	//这里的上游服务器是www.bing.com
	static struct sockaddr_in backendSockAddr;
	struct hostent *pHost = gethostbyname((char*)"bing.com");
	if(pHost == NULL){
		ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
				"gethostbyname fail. %s.", strerror(errno));
		return NGX_ERROR;
	}

	//访问上游服务器的80端口
	backendSockAddr.sin_family = AF_INET;
	backendSockAddr.sin_port = htons((in_port_t)80);
	char *pDmsIP = inet_ntoa(*(struct in_addr*)(pHost->h_addr_list[0]));
	backendSockAddr.sin_addr.s_addr = inet_addr(pDmsIP);
	//myctx->backendServer.data = (u_char*)pDmsIP;
	//myctx->backendServer.len = strlen(pDmsIP);

	//将地址设置到resolved成员中
	u->resolved->sockaddr = (struct sockaddr *)&backendSockAddr;
	u->resolved->socklen = sizeof(struct sockaddr_in);
	u->resolved->naddrs = 1;

	//设置三个必须实现的回调方法
	u->create_request = mytest_upstream_create_request;
	u->process_header = mytest_process_status_line;
	u->finalize_request = mytest_upstream_finalize_request;

	//这里必须将count成员加1
	r->main->count++;
	//启动upstream
	ngx_http_upstream_init(r);
	//必须返回NGX_DONE
	return NGX_DONE;

}
示例#12
0
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_redis_handler(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_http_upstream_t            *u;
    ngx_http_redis_ctx_t           *ctx;
    ngx_http_redis_loc_conf_t      *rlcf;

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

    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 defined nginx_version && nginx_version >= 8011
    if (ngx_http_upstream_create(r) != NGX_OK) {
#else
    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module);

    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
    if (u == NULL) {
#endif
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

#if defined nginx_version && nginx_version >= 8011
    u = r->upstream;
#endif

#if defined nginx_version && nginx_version >= 8037
    ngx_str_set(&u->schema, "redis://");
#else
    u->schema.len = sizeof("redis://") - 1;
    u->schema.data = (u_char *) "redis://";
#endif

#if defined nginx_version && nginx_version >= 8011
    u->output.tag = (ngx_buf_tag_t) &ngx_http_redis_module;
#else
    u->peer.log = r->connection->log;
    u->peer.log_error = NGX_ERROR_ERR;
#endif

#if defined nginx_version && nginx_version >= 8011
    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module);
#else
    u->output.tag = (ngx_buf_tag_t) &ngx_http_redis_module;
#endif

    u->conf = &rlcf->upstream;

    u->create_request = ngx_http_redis_create_request;
    u->reinit_request = ngx_http_redis_reinit_request;
    u->process_header = ngx_http_redis_process_header;
    u->abort_request = ngx_http_redis_abort_request;
    u->finalize_request = ngx_http_redis_finalize_request;

#if defined nginx_version && nginx_version < 8011
    r->upstream = u;
#endif

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

    ctx->rest = NGX_HTTP_REDIS_END;
    ctx->request = r;

    ngx_http_set_ctx(r, ctx, ngx_http_redis_module);

    u->input_filter_init = ngx_http_redis_filter_init;
    u->input_filter = ngx_http_redis_filter;
    u->input_filter_ctx = ctx;

#if defined nginx_version && nginx_version >= 8011
    r->main->count++;
#endif

    ngx_http_upstream_init(r);

    return NGX_DONE;
}

static ngx_int_t
ngx_http_redis_create_request(ngx_http_request_t *r)
{
    size_t                          len, i;
    ngx_buf_t                      *b;
    ngx_chain_t                    *cl;
    ngx_http_redis_ctx_t           *ctx;
    ngx_http_variable_value_t      *vv[2];
    ngx_http_redis_loc_conf_t      *rlcf;

    //The start of the unified protocol GET request
    const char *get_request_start = "*2\r\n$3\r\nGET\r\n$";

    //Buffer to store the char version of the key - max size
    char key_len_buf[8];

    //Bad code
    //TODO: use ngx_get_num_size( to remove the need for this
    const char* key_len_ptr = &key_len_buf[0];
    int key_len;

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module);

    vv[0] = ngx_http_get_indexed_variable(r, ngx_http_redis_db_index);

    /*
     * If user do not select redis database in nginx.conf by redis_db
     * variable, just add size of "select 0" to request.  This is add
     * some overhead in talk with redis, but this way simplify parsing
     * the redis answer in ngx_http_redis_process_header().
     */
    if (vv[0] == NULL || vv[0]->not_found || vv[0]->len == 0) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select 0 redis database" );
        len = sizeof("select 0") - 1;
    } else {
        len = sizeof("select ") - 1 + vv[0]->len;
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select %s redis database", vv[0]->data);
    }
    len += sizeof(CRLF) - 1;

    vv[1] = ngx_http_get_indexed_variable(r, rlcf->index);

    /* If nginx.conf have no redis_key return error. */
    if (vv[1] == NULL || vv[1]->not_found || vv[1]->len == 0) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "the \"$redis_key\" variable is not set");
        return NGX_ERROR;
    }

    key_len = sprintf(key_len_buf,"%d",vv[1]->len);

    //Work out how long the request is going to be
    //14 = length of request_start
    len += 14 + key_len + sizeof(CRLF) - 1 + vv[1]->len + sizeof(CRLF) - 1;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "redis request length: %d", len);

    /* Create temporary buffer for request with size len. */
    b = ngx_create_temp_buf(r->pool, len);
    if (b == NULL) {
        return NGX_ERROR;
    }

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

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

    r->upstream->request_bufs = cl;

    /* Add "select " for request. */
    *b->last++ = 's'; *b->last++ = 'e'; *b->last++ = 'l'; *b->last++ = 'e';
    *b->last++ = 'c'; *b->last++ = 't'; *b->last++ = ' ';

    /* Get context redis_db from configuration file. */
    ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module);

    ctx->key.data = b->last;

    /*
     * Add "0" as redis number db to request if redis_db undefined,
     * othervise add real number from context.
     */
    if (vv[0] == NULL || vv[0]->not_found || vv[0]->len == 0) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select 0 redis database" );
        *b->last++ = '0';
    } else {
        b->last = ngx_copy(b->last, vv[0]->data, vv[0]->len);
        ctx->key.len = b->last - ctx->key.data;
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select %V redis database", &ctx->key);
    }

    /* Add "\r\n". */
    *b->last++ = CR; *b->last++ = LF;


    /* Add "get" command with space. */
    for(i=0;i<14;i++){
        *b->last++ = get_request_start[i];
    }

    /* Add length */
    while(key_len != 0){
        *b->last++ = *key_len_ptr;
        key_len--;
        key_len_ptr ++;
    }
    
    /* Add one more "\r\n". */
    *b->last++ = CR; *b->last++ = LF;

    /* Get context redis_key from nginx.conf. */
    ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module);

    ctx->key.data = b->last;

    /* Copy the key into the request buffer */
    b->last = ngx_copy(b->last, vv[1]->data, vv[1]->len);

    ctx->key.len = b->last - ctx->key.data;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http redis request: \"%V\"", &ctx->key);

    /* Add one more "\r\n". */
    *b->last++ = CR; *b->last++ = LF;

    /*
     * Summary, the request looks like this:
     * "select $redis_db\r\nget $redis_key\r\n", where
     * $redis_db and $redis_key are variable's values.
     */

    return NGX_OK;
}
static ngx_int_t
ngx_http_memcached_handler(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_http_upstream_t            *u;
    ngx_http_memcached_ctx_t       *ctx;
    ngx_http_memcached_loc_conf_t  *mlcf;

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

    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;
    }

    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);

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

    u->schema.len = sizeof("memcached://") - 1;
    u->schema.data = (u_char *) "memcached://";

    u->peer.log = r->connection->log;
    u->peer.log_error = NGX_ERROR_ERR;
#if (NGX_THREADS)
    u->peer.lock = &r->connection->lock;
#endif

    u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;

    u->conf = &mlcf->upstream;

    u->create_request = ngx_http_memcached_create_request;
    u->reinit_request = ngx_http_memcached_reinit_request;
    u->process_header = ngx_http_memcached_process_header;
    u->abort_request = ngx_http_memcached_abort_request;
    u->finalize_request = ngx_http_memcached_finalize_request;

    r->upstream = u;

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

    ctx->rest = NGX_HTTP_MEMCACHED_END;
    ctx->request = r;

    ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);

    u->input_filter_init = ngx_http_memcached_filter_init;
    u->input_filter = ngx_http_memcached_filter;
    u->input_filter_ctx = ctx;

    ngx_http_upstream_init(r);

    return NGX_DONE;
}
static ngx_int_t
ngx_http_memcached_handler(ngx_http_request_t *r) {
	ngx_int_t                        rc;
	ngx_http_upstream_t             *u;
	ngx_http_memcached_ctx_t        *ctx;
	ngx_http_memcached_loc_conf_t   *mlcf;
	u_char                          *cmd;
	ngx_int_t                        type;

	/* GET for get/delete */
	/* POST for set/add/replace */
	if (r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD)) {
		if (NGX_OK != (rc = ngx_http_discard_request_body(r)))
			return rc;
	} else if (!(r->method & NGX_HTTP_POST)) return NGX_HTTP_NOT_ALLOWED;

	/* last unit of uri is command of memcache */
	for (cmd = r->uri.data + r->uri.len; r->uri.data < cmd;)
		if (*--cmd == '/') break;
	if (cmd == r->uri.data) return NGX_HTTP_BAD_REQUEST;
	++cmd;
	if (!(ngx_memcmp(cmd, "get", sizeof("get") - 1)
		&& ngx_memcmp(cmd, "gets", sizeof("gets") - 1)))
		type = NGX_HTTP_MEMCACHED_GET;
	else if (!(ngx_memcmp(cmd, "set", sizeof("set") - 1)
		&& ngx_memcmp(cmd, "add", sizeof("add") - 1)
		&& ngx_memcmp(cmd, "replace", sizeof("replace") - 1)))
		type = NGX_HTTP_MEMCACHED_SET;
	else if (!ngx_memcmp(cmd, "delete", sizeof("delete") - 1))
		type = NGX_HTTP_MEMCACHED_DEL;
	else if (!ngx_memcmp(cmd, "cas", sizeof("cas") - 1))
		type = NGX_HTTP_MEMCACHED_CAS;
	else return NGX_HTTP_BAD_REQUEST;

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

	if (NGX_OK != ngx_http_upstream_create(r))
		return NGX_HTTP_INTERNAL_SERVER_ERROR;
	u = r->upstream;

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

	mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
	u->conf = &mlcf->upstream;

	u->create_request = ngx_http_memcached_create_request;
	u->reinit_request = ngx_http_memcached_reinit_request;
	u->process_header = ngx_http_memcached_process_header;
	u->abort_request = ngx_http_memcached_abort_request;
	u->finalize_request = ngx_http_memcached_finalize_request;

	/* context */
	if (!(ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t))))
		return NGX_HTTP_INTERNAL_SERVER_ERROR;
	ctx->request = r;
	ctx->cmd.data = cmd;
	ctx->cmd.len = r->uri.len - (ctx->cmd.data - r->uri.data);
	ctx->type = type;
	ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);

	u->input_filter_init = ngx_http_memcached_filter_init;
	u->input_filter = ngx_http_memcached_filter;
	u->input_filter_ctx = ctx;

	if (r->method & NGX_HTTP_POST) {
		/* POST */
		if (NGX_HTTP_SPECIAL_RESPONSE <= (rc =
			ngx_http_read_client_request_body(r, ngx_http_upstream_init)))
			return rc;
	} else {
		/* GET */
		++r->main->count;
		ngx_http_upstream_init(r);
	}
	return NGX_DONE;
}
static ngx_int_t
ngx_http_redis_handler(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_http_upstream_t            *u;
    ngx_http_redis_ctx_t           *ctx;
    ngx_http_redis_loc_conf_t      *rlcf;

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

    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 defined nginx_version && nginx_version >= 8011
    if (ngx_http_upstream_create(r) != NGX_OK) {
#else
    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module);

    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
    if (u == NULL) {
#endif
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

#if defined nginx_version && nginx_version >= 8011
    u = r->upstream;
#endif

#if defined nginx_version && nginx_version >= 8037
    ngx_str_set(&u->schema, "redis://");
#else
    u->schema.len = sizeof("redis://") - 1;
    u->schema.data = (u_char *) "redis://";
#endif

#if defined nginx_version && nginx_version >= 8011
    u->output.tag = (ngx_buf_tag_t) &ngx_http_redis_module;
#else
    u->peer.log = r->connection->log;
    u->peer.log_error = NGX_ERROR_ERR;
#endif

#if defined nginx_version && nginx_version >= 8011
    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module);
#else
    u->output.tag = (ngx_buf_tag_t) &ngx_http_redis_module;
#endif

    u->conf = &rlcf->upstream;

    u->create_request = ngx_http_redis_create_request;
    u->reinit_request = ngx_http_redis_reinit_request;
    u->process_header = ngx_http_redis_process_header;
    u->abort_request = ngx_http_redis_abort_request;
    u->finalize_request = ngx_http_redis_finalize_request;

#if defined nginx_version && nginx_version < 8011
    r->upstream = u;
#endif

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

    ctx->rest = NGX_HTTP_REDIS_END;
    ctx->request = r;

    ngx_http_set_ctx(r, ctx, ngx_http_redis_module);

    u->input_filter_init = ngx_http_redis_filter_init;
    u->input_filter = ngx_http_redis_filter;
    u->input_filter_ctx = ctx;

#if defined nginx_version && nginx_version >= 8011
    r->main->count++;
#endif

    ngx_http_upstream_init(r);

    return NGX_DONE;
}


static ngx_int_t
ngx_http_redis_create_request(ngx_http_request_t *r)
{
    size_t                          len;
    uintptr_t                       escape;
    ngx_buf_t                      *b;
    ngx_chain_t                    *cl;
    ngx_http_redis_ctx_t           *ctx;
    ngx_http_variable_value_t      *vv[2];
    ngx_http_redis_loc_conf_t      *rlcf;

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module);

    vv[0] = ngx_http_get_indexed_variable(r, ngx_http_redis_db_index);

    /*
     * If user do not select redis database in nginx.conf by redis_db
     * variable, just add size of "select 0" to request.  This is add
     * some overhead in talk with redis, but this way simplify parsing
     * the redis answer in ngx_http_redis_process_header().
     */
    if (vv[0] == NULL || vv[0]->not_found || vv[0]->len == 0) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select 0 redis database" );
        len = sizeof("select 0") - 1;
    } else {
        len = sizeof("select ") - 1 + vv[0]->len;
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select %s redis database", vv[0]->data);
    }
    len += sizeof(CRLF) - 1;

    vv[1] = ngx_http_get_indexed_variable(r, rlcf->index);

    /* If nginx.conf have no redis_key return error. */
    if (vv[1] == NULL || vv[1]->not_found || vv[1]->len == 0) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "the \"$redis_key\" variable is not set");
        return NGX_ERROR;
    }

    /* Count have space required escape symbols. */
    escape = 2 * ngx_escape_uri(NULL, vv[1]->data, vv[1]->len, NGX_ESCAPE_REDIS);

    len += sizeof("get ") - 1 + vv[1]->len + escape + sizeof(CRLF) - 1;

    /* Create temporary buffer for request with size len. */
    b = ngx_create_temp_buf(r->pool, len);
    if (b == NULL) {
        return NGX_ERROR;
    }

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

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

    r->upstream->request_bufs = cl;

    /* Add "select " for request. */
    *b->last++ = 's'; *b->last++ = 'e'; *b->last++ = 'l'; *b->last++ = 'e';
    *b->last++ = 'c'; *b->last++ = 't'; *b->last++ = ' ';

    /* Get context redis_db from configuration file. */
    ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module);

    ctx->key.data = b->last;

    /*
     * Add "0" as redis number db to request if redis_db undefined,
     * othervise add real number from context.
     */
    if (vv[0] == NULL || vv[0]->not_found || vv[0]->len == 0) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select 0 redis database" );
        *b->last++ = '0';
    } else {
        b->last = ngx_copy(b->last, vv[0]->data, vv[0]->len);
        ctx->key.len = b->last - ctx->key.data;
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select %V redis database", &ctx->key);
    }

    /* Add "\r\n". */
    *b->last++ = CR; *b->last++ = LF;


    /* Add "get" command with space. */
    *b->last++ = 'g'; *b->last++ = 'e'; *b->last++ = 't'; *b->last++ = ' ';

    /* Get context redis_key from nginx.conf. */
    ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module);

    ctx->key.data = b->last;

    /*
     * If no escape symbols then copy data as is, othervise use
     * escape-copy function.
     */

    if (escape == 0) {
        b->last = ngx_copy(b->last, vv[1]->data, vv[1]->len);

    } else {
        b->last = (u_char *) ngx_escape_uri(b->last, vv[1]->data, vv[1]->len,
                                            NGX_ESCAPE_REDIS);
    }

    ctx->key.len = b->last - ctx->key.data;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http redis request: \"%V\"", &ctx->key);

    /* Add one more "\r\n". */
    *b->last++ = CR; *b->last++ = LF;

    /*
     * Summary, the request looks like this:
     * "select $redis_db\r\nget $redis_key\r\n", where
     * $redis_db and $redis_key are variable's values.
     */

    return NGX_OK;
}
示例#17
0
static ngx_int_t ngx_http_cwinux_handler(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_http_upstream_t            *u;
    ngx_http_cwinux_ctx_t            *ctx;
    ngx_http_cwinux_loc_conf_t       *mlcf;

    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_POST))){
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
            "ngx_cwinux: method %V doesn't support ",
            &r->method_name);
        return NGX_HTTP_BAD_REQUEST;
    }
    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_cwinux_module);

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

#if defined(nginx_version) && \
    ((nginx_version >= 7063 && nginx_version < 8000) \
    || nginx_version >= 8007)

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

    u = r->upstream;

#else /* 0.7.x < 0.7.63, 0.8.x < 0.8.7 */

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

    u->peer.log = r->connection->log;
    u->peer.log_error = NGX_ERROR_ERR;
#  if (NGX_THREADS)
    u->peer.lock = &r->connection->lock;
#  endif

    r->upstream = u;

#endif

    u->schema.len = sizeof("cwinux://") - 1;
    u->schema.data = (u_char *) "cwinux://";

    u->output.tag = (ngx_buf_tag_t) &ngx_http_cwinux_module;

    u->conf = &mlcf->upstream;

    ctx = ngx_palloc(r->pool, sizeof(ngx_http_cwinux_ctx_t));
    if (ctx == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    ngx_gettimeofday(&ctx->start_time);
    ctx->header = false;
    ctx->finish = false;
    ctx->request = r;
    ngx_http_set_ctx(r, ctx, ngx_http_cwinux_module);

    u->create_request = ngx_http_cwinux_create_request;
    u->process_header = ngx_http_cwinux_process_header;

    u->input_filter_init = ngx_http_cwinux_empty_filter_init;
    u->input_filter = ngx_http_cwinux_empty_filter;

    u->reinit_request = ngx_http_cwinux_reinit_request;
    u->abort_request = ngx_http_cwinux_abort_request;
    u->finalize_request = ngx_http_cwinux_finalize_request;

    u->input_filter_ctx = ctx;

    if (NGX_HTTP_POST == r->method){
        rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);

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

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

#if defined(nginx_version) && nginx_version >= 8011
    r->main->count++;
#endif

    ngx_http_upstream_init(r);
    return NGX_DONE;
}
static ngx_int_t
ngx_http_redis_handler(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_http_upstream_t            *u;
    ngx_http_redis_ctx_t           *ctx;
    ngx_http_redis_loc_conf_t      *rlcf;

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

    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 defined nginx_version && nginx_version >= 8011
    if (ngx_http_upstream_create(r) != NGX_OK) {
#else
    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module);

    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
    if (u == NULL) {
#endif
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

#if defined nginx_version && nginx_version >= 8011
    u = r->upstream;
#endif

    u->schema.len = sizeof("redis://") - 1;
    u->schema.data = (u_char *) "redis://";

#if defined nginx_version && nginx_version >= 8011
    u->output.tag = (ngx_buf_tag_t) &ngx_http_redis_module;
#else
    u->peer.log = r->connection->log;
    u->peer.log_error = NGX_ERROR_ERR;
#endif

#if defined nginx_version && nginx_version >= 8011
    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module);
#else
    u->output.tag = (ngx_buf_tag_t) &ngx_http_redis_module;
#endif

    u->conf = &rlcf->upstream;

    u->create_request = ngx_http_redis_create_request;
    u->reinit_request = ngx_http_redis_reinit_request;
    u->process_header = ngx_http_redis_process_header;
    u->abort_request = ngx_http_redis_abort_request;
    u->finalize_request = ngx_http_redis_finalize_request;

#if defined nginx_version && nginx_version < 8011
    r->upstream = u;
#endif

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

    ctx->rest = NGX_HTTP_REDIS_END;
    ctx->request = r;

    ngx_http_set_ctx(r, ctx, ngx_http_redis_module);

    u->input_filter_init = ngx_http_redis_filter_init;
    u->input_filter = ngx_http_redis_filter;
    u->input_filter_ctx = ctx;

#if defined nginx_version && nginx_version >= 8011
    r->main->count++;
#endif

    ngx_http_upstream_init(r);

    return NGX_DONE;
}


static ngx_int_t
ngx_http_redis_create_request(ngx_http_request_t *r)
{
    size_t                          len;
    uintptr_t                       escape;
    ngx_buf_t                      *b;
    ngx_chain_t                    *cl;
    ngx_http_redis_ctx_t           *ctx;
    ngx_http_variable_value_t      *vv[2];
    ngx_http_redis_loc_conf_t      *rlcf;

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module);

    vv[0] = ngx_http_get_indexed_variable(r, rlcf->db);

    if (vv[0] == NULL || vv[0]->not_found || vv[0]->len == 0) {
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select 0 redis database" );
        len = sizeof("select 0") - 1;
    } else {
        len = sizeof("select ") - 1 + vv[0]->len;
    }
    len += sizeof(CRLF) - 1;

    vv[1] = ngx_http_get_indexed_variable(r, rlcf->index);

    if (vv[1] == NULL || vv[1]->not_found || vv[1]->len == 0) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "the \"$redis_key\" variable is not set");
        return NGX_ERROR;
    }

    escape = 2 * ngx_escape_uri(NULL, vv[1]->data, vv[1]->len, NGX_ESCAPE_REDIS);

    len += sizeof("get ") - 1 + vv[1]->len + escape + sizeof(CRLF) - 1;

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

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

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

    r->upstream->request_bufs = cl;

    *b->last++ = 's'; *b->last++ = 'e'; *b->last++ = 'l'; *b->last++ = 'e';
    *b->last++ = 'c'; *b->last++ = 't'; *b->last++ = ' ';

    ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module);

    ctx->key.data = b->last;

    if (vv[0] == NULL || vv[0]->not_found || vv[0]->len == 0) {
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select 0 redis database" );
        *b->last++ = '0';
    } else {
        b->last = ngx_copy(b->last, vv[0]->data, vv[0]->len);
        ctx->key.len = b->last - ctx->key.data;
    }

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


    *b->last++ = 'g'; *b->last++ = 'e'; *b->last++ = 't'; *b->last++ = ' ';

    ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module);

    ctx->key.data = b->last;

    if (escape == 0) {
        b->last = ngx_copy(b->last, vv[1]->data, vv[1]->len);

    } else {
        b->last = (u_char *) ngx_escape_uri(b->last, vv[1]->data, vv[1]->len,
                                            NGX_ESCAPE_REDIS);
    }

    ctx->key.len = b->last - ctx->key.data;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http redis request: \"%V\"", &ctx->key);

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

    return NGX_OK;
}
static ngx_int_t
ngx_http_mytest_upstream_handler(ngx_http_request_t *r)
{
    
    //首先建立http上下文结构体ngx_http_mytest_ctx_t
    ngx_http_mytest_upstream_ctx_t* myctx = ngx_http_get_module_ctx(r, ngx_http_mytest_upstream_module);
    if (myctx == NULL)
    {
        myctx = ngx_palloc(r->pool, sizeof(ngx_http_mytest_upstream_ctx_t));
        if (myctx == NULL)
        {
            return NGX_ERROR;
        }
        
        //将新建的上下文与请求关联起来
        ngx_http_set_ctx(r, myctx, ngx_http_mytest_upstream_module);
    }
    
    //对每1个要使用upstream的请求,必须调用且只能调用1次
    //ngx_http_upstream_create方法,它会初始化r->upstream成员
    if (ngx_http_upstream_create(r) != NGX_OK)
    {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_upstream_create() failed");
        return NGX_ERROR;
    }

    //得到配置结构体ngx_http_mytest_conf_t
    ngx_http_mytest_upstream_conf_t  *mycf = (ngx_http_mytest_upstream_conf_t  *) ngx_http_get_module_loc_conf(r, ngx_http_mytest_upstream_module);
    ngx_http_upstream_t *u = r->upstream;
    //这里用配置文件中的结构体来赋给r->upstream->conf成员
    u->conf = &mycf->upstream;//把我们设置好的upstream配置信息赋值给ngx_http_request_t->upstream->conf
    //决定转发包体时使用的缓冲区
    u->buffering = mycf->upstream.buffering;

    //以下代码开始初始化resolved结构体,用来保存上游服务器的地址
    u->resolved = (ngx_http_upstream_resolved_t*) ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
    if (u->resolved == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_pcalloc resolved error. %s.", strerror(errno));
        return NGX_ERROR;
    }

    //这里的上游服务器就是www.google.com
    static struct sockaddr_in backendSockAddr;
    struct hostent *pHost = gethostbyname((char*) "www.sina.com");
    if (pHost == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "gethostbyname fail. %s", strerror(errno));
        
        ngx_log_debugall(r->connection->log, 0, "yang test ############################MYTEST upstream gethostbyname error\n");
        return NGX_ERROR;
    }
    
    //访问上游服务器的80端口
    backendSockAddr.sin_family = AF_INET;
    backendSockAddr.sin_port = htons((in_port_t) 80);
    char* pDmsIP = inet_ntoa(*(struct in_addr*) (pHost->h_addr_list[0]));
    //char* pDmsIP = inet_ntoa(*(struct in_addr*) ("10.10.0.2"));
    backendSockAddr.sin_addr.s_addr = inet_addr(pDmsIP);
    myctx->backendServer.data = (u_char*)pDmsIP;
    myctx->backendServer.len = strlen(pDmsIP);
    ngx_log_debugall(r->connection->log, 0, "yang test ############################MYTEST upstream gethostbyname OK, addr:%s\n", pDmsIP);

    //将地址设置到resolved成员中
    u->resolved->sockaddr = (struct sockaddr *)&backendSockAddr;
    u->resolved->socklen = sizeof(struct sockaddr_in);
    u->resolved->naddrs = 1;

    //设置三个必须实现的回调方法,也就是5.3.3节至5.3.5节中实现的3个方法
    u->create_request = mytest_upstream_create_request; //构造http请求行和头部行
    u->process_header = mytest_process_status_line;
    u->finalize_request = mytest_upstream_finalize_request;

    //这里必须将count成员加1,理由见5.1.5节
/*
这里还需要执行r->main->count++,这是在告诉HTTP框架将当前请求的引用计数加1,即告诉ngx_http_mytest_handler方法暂时不要销
毁请求,因为HTTP框架只有在引用计数为0时才能真正地销毁请求。这样的话,upstream机制接下来才能接管请求的处理工作。
*/
    r->main->count++;
    //启动upstream
    ngx_http_upstream_init(r);
    //必须返回NGX_DONE
    return NGX_DONE; //这时要通过返回NGX DONE告诉HTTP框架暂停执行请求的下一个阶段
}