static void
ngx_stream_return_handler(ngx_stream_session_t *s)
{
    ngx_str_t                      text;
    ngx_buf_t                     *b;
    ngx_connection_t              *c;
    ngx_stream_return_ctx_t       *ctx;
    ngx_stream_return_srv_conf_t  *rscf;

    c = s->connection;

    c->log->action = "returning text";

    rscf = ngx_stream_get_module_srv_conf(s, ngx_stream_return_module);

    if (ngx_stream_complex_value(s, &rscf->text, &text) != NGX_OK) {
        ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
        return;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
                   "stream return text: \"%V\"", &text);

    if (text.len == 0) {
        ngx_stream_finalize_session(s, NGX_STREAM_OK);
        return;
    }

    ctx = ngx_pcalloc(c->pool, sizeof(ngx_stream_return_ctx_t));
    if (ctx == NULL) {
        ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
        return;
    }

    ngx_stream_set_ctx(s, ctx, ngx_stream_return_module);

    b = ngx_calloc_buf(c->pool);
    if (b == NULL) {
        ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
        return;
    }

    b->memory = 1;
    b->pos = text.data;
    b->last = text.data + text.len;
    b->last_buf = 1;

    ctx->out = ngx_alloc_chain_link(c->pool);
    if (ctx->out == NULL) {
        ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
        return;
    }

    ctx->out->buf = b;
    ctx->out->next = NULL;

    c->write->handler = ngx_stream_return_write_handler;

    ngx_stream_return_write_handler(c->write);
}
static void
ngx_stream_return_handler(ngx_stream_session_t *s)
{
    ngx_str_t                      text;
    ngx_connection_t              *c;
    ngx_stream_return_ctx_t       *ctx;
    ngx_stream_return_srv_conf_t  *rscf;

    c = s->connection;

    c->log->action = "returning text";

    rscf = ngx_stream_get_module_srv_conf(s, ngx_stream_return_module);

    if (ngx_stream_complex_value(s, &rscf->text, &text) != NGX_OK) {
        ngx_stream_close_connection(c);
        return;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
                   "stream return text: \"%V\"", &text);

    if (text.len == 0) {
        ngx_stream_close_connection(c);
        return;
    }

    ctx = ngx_pcalloc(c->pool, sizeof(ngx_stream_return_ctx_t));
    if (ctx == NULL) {
        ngx_stream_close_connection(c);
        return;
    }

    ngx_stream_set_ctx(s, ctx, ngx_stream_return_module);

    ctx->buf.pos = text.data;
    ctx->buf.last = text.data + text.len;

    c->write->handler = ngx_stream_return_write_handler;

    ngx_stream_return_write_handler(c->write);
}
static ngx_int_t
ngx_stream_write_filter(ngx_stream_session_t *s, ngx_chain_t *in,
    ngx_uint_t from_upstream)
{
    off_t                           size;
    ngx_uint_t                      last, flush, sync;
    ngx_chain_t                    *cl, *ln, **ll, **out, *chain;
    ngx_connection_t               *c;
    ngx_stream_write_filter_ctx_t  *ctx;

    ctx = ngx_stream_get_module_ctx(s, ngx_stream_write_filter_module);

    if (ctx == NULL) {
        ctx = ngx_pcalloc(s->connection->pool,
                          sizeof(ngx_stream_write_filter_ctx_t));
        if (ctx == NULL) {
            return NGX_ERROR;
        }

        ngx_stream_set_ctx(s, ctx, ngx_stream_write_filter_module);
    }

    if (from_upstream) {
        c = s->connection;
        out = &ctx->from_upstream;

    } else {
        c = s->upstream->peer.connection;
        out = &ctx->from_downstream;
    }

    if (c->error) {
        return NGX_ERROR;
    }

    size = 0;
    flush = 0;
    sync = 0;
    last = 0;
    ll = out;

    /* find the size, the flush point and the last link of the saved chain */

    for (cl = *out; cl; cl = cl->next) {
        ll = &cl->next;

        ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0,
                       "write old buf t:%d f:%d %p, pos %p, size: %z "
                       "file: %O, size: %O",
                       cl->buf->temporary, cl->buf->in_file,
                       cl->buf->start, cl->buf->pos,
                       cl->buf->last - cl->buf->pos,
                       cl->buf->file_pos,
                       cl->buf->file_last - cl->buf->file_pos);

#if 1
        if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
            ngx_log_error(NGX_LOG_ALERT, c->log, 0,
                          "zero size buf in writer "
                          "t:%d r:%d f:%d %p %p-%p %p %O-%O",
                          cl->buf->temporary,
                          cl->buf->recycled,
                          cl->buf->in_file,
                          cl->buf->start,
                          cl->buf->pos,
                          cl->buf->last,
                          cl->buf->file,
                          cl->buf->file_pos,
                          cl->buf->file_last);

            ngx_debug_point();
            return NGX_ERROR;
        }
#endif

        size += ngx_buf_size(cl->buf);

        if (cl->buf->flush || cl->buf->recycled) {
            flush = 1;
        }

        if (cl->buf->sync) {
            sync = 1;
        }

        if (cl->buf->last_buf) {
            last = 1;
        }
    }

    /* add the new chain to the existent one */

    for (ln = in; ln; ln = ln->next) {
        cl = ngx_alloc_chain_link(c->pool);
        if (cl == NULL) {
            return NGX_ERROR;
        }

        cl->buf = ln->buf;
        *ll = cl;
        ll = &cl->next;

        ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0,
                       "write new buf t:%d f:%d %p, pos %p, size: %z "
                       "file: %O, size: %O",
                       cl->buf->temporary, cl->buf->in_file,
                       cl->buf->start, cl->buf->pos,
                       cl->buf->last - cl->buf->pos,
                       cl->buf->file_pos,
                       cl->buf->file_last - cl->buf->file_pos);

#if 1
        if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
            ngx_log_error(NGX_LOG_ALERT, c->log, 0,
                          "zero size buf in writer "
                          "t:%d r:%d f:%d %p %p-%p %p %O-%O",
                          cl->buf->temporary,
                          cl->buf->recycled,
                          cl->buf->in_file,
                          cl->buf->start,
                          cl->buf->pos,
                          cl->buf->last,
                          cl->buf->file,
                          cl->buf->file_pos,
                          cl->buf->file_last);

            ngx_debug_point();
            return NGX_ERROR;
        }
#endif

        size += ngx_buf_size(cl->buf);

        if (cl->buf->flush || cl->buf->recycled) {
            flush = 1;
        }

        if (cl->buf->sync) {
            sync = 1;
        }

        if (cl->buf->last_buf) {
            last = 1;
        }
    }

    *ll = NULL;

    ngx_log_debug3(NGX_LOG_DEBUG_STREAM, c->log, 0,
                   "stream write filter: l:%ui f:%ui s:%O", last, flush, size);

    if (size == 0
        && !(c->buffered & NGX_LOWLEVEL_BUFFERED)
        && !(last && c->need_last_buf))
    {
        if (last || flush || sync) {
            for (cl = *out; cl; /* void */) {
                ln = cl;
                cl = cl->next;
                ngx_free_chain(c->pool, ln);
            }

            *out = NULL;
            c->buffered &= ~NGX_STREAM_WRITE_BUFFERED;

            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ALERT, c->log, 0,
                      "the stream output chain is empty");

        ngx_debug_point();

        return NGX_ERROR;
    }

    chain = c->send_chain(c, *out, 0);

    ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
                   "stream write filter %p", chain);

    if (chain == NGX_CHAIN_ERROR) {
        c->error = 1;
        return NGX_ERROR;
    }

    for (cl = *out; cl && cl != chain; /* void */) {
        ln = cl;
        cl = cl->next;
        ngx_free_chain(c->pool, ln);
    }

    *out = chain;

    if (chain) {
        if (c->shared) {
            ngx_log_error(NGX_LOG_ALERT, c->log, 0,
                          "shared connection is busy");
            return NGX_ERROR;
        }

        c->buffered |= NGX_STREAM_WRITE_BUFFERED;
        return NGX_AGAIN;
    }

    c->buffered &= ~NGX_STREAM_WRITE_BUFFERED;

    if (c->buffered & NGX_LOWLEVEL_BUFFERED) {
        return NGX_AGAIN;
    }

    return NGX_OK;
}
ngx_int_t
ngx_stream_upm_init_worker(ngx_cycle_t * cycle)
{
    u_char                          *p;
    //ngx_int_t                        rc;
    ngx_connection_t                *c;
    //ngx_connection_t                *pc;
    ngx_stream_upm_ctx_t            *ctx;
    ngx_stream_session_t            *fake_session;
    ngx_stream_upstream_t           *u;
    //ngx_peer_connection_t           *peer;
    ngx_stream_upm_main_conf_t      *ummcf;
    ngx_stream_upstream_srv_conf_t  *uscf; 

    //Fake a client session
    ummcf = ngx_stream_cycle_get_module_main_conf(cycle, ngx_stream_upm_module);
    ummcf->fake_session = ngx_pcalloc(cycle->pool, sizeof(ngx_stream_session_t));
    if (ummcf->fake_session == NULL) {
        return NGX_ERROR;    
    }

    fake_session = ummcf->fake_session;
    //Fake the client fd as 254
    c = ngx_get_connection(254, cycle->log);
    if (c == NULL) {
        return NGX_ERROR;
    }
    //Set the fake conn's base items
    c->pool = cycle->pool;
    c->log = cycle->log;

    fake_session->signature = NGX_STREAM_MODULE;
    fake_session->main_conf = ((ngx_stream_conf_ctx_t *)cycle->conf_ctx)->main_conf;
    fake_session->srv_conf = ((ngx_stream_conf_ctx_t *)cycle->conf_ctx)->srv_conf;

    fake_session->connection = c;
    c->data = fake_session;

    u = ngx_pcalloc(c->pool, sizeof(ngx_stream_upstream_t));
    if (u == NULL) {
        return NGX_ERROR;
    }
    fake_session->upstream = u;
    
    //Init the upm ctx;
    fake_session->ctx = ngx_pcalloc(cycle->pool, sizeof(void *) * ngx_stream_max_module);
    if (fake_session->ctx == NULL) {
        return NGX_ERROR;
    }
    ctx = ngx_pcalloc(cycle->pool, sizeof(ngx_stream_upm_ctx_t));
    ngx_stream_set_ctx(fake_session, ctx, ngx_stream_upm_module);
    
    ctx->state = CONNECT;
    ctx->connect = ngx_stream_upm_connect;
    ctx->create_request = ngx_stream_upm_create_request;
    ctx->send_request = ngx_stream_upm_send_request;
    ctx->read_and_parse_response = ngx_stream_upm_read_and_parse_response;
    //ctx->process_response = ngx_stream_upm_process_response;

    u->peer.log = cycle->log;
    u->peer.log_error = NGX_ERROR_ERR;
    //whitout need set the local
    u->peer.local = NULL;

    uscf = ummcf->upstream;
    if (uscf->peer.init(fake_session, uscf) != NGX_OK) {
        return NGX_ERROR;
    }

    u->peer.start_time = ngx_current_msec;

    if (ummcf->next_upstream_tries
        && u->peer.tries > ummcf->next_upstream_tries)
    {
        u->peer.tries = ummcf->next_upstream_tries;
    }
    u->start_sec = ngx_time();

    //May without need alloc the downstream_buf
    p = ngx_pnalloc(c->pool, ummcf->buffer_size);
    if (p == NULL) {
        return NGX_ERROR;
    }
    
    //web use the downstream_buf to buffer the request;
    u->downstream_buf.start = p;
    u->downstream_buf.end = p + ummcf->buffer_size;
    u->downstream_buf.pos = p;
    u->downstream_buf.last = p;

    c->write->handler = ngx_stream_upm_empty_handler;
    c->read->handler = ngx_stream_upm_empty_handler;

    return ngx_stream_upm_connect(fake_session);
}
/*
static void ngx_app_empty_handler(ngx_event_t *wev)
{

}
*/
static void ngx_app_wait_request_handler(ngx_event_t *ev)
{
    ngx_connection_t      *c;
    ngx_stream_session_t  *s;
	ngx_stream_app_main_conf_t  *cscf;
	ngx_stream_app_srv_conf_t  *ascf;
	ngx_stream_app_ctx_t  *s_ctx;
	ngx_app_task_t		  *t;
	ngx_buf_t             *b;
	ngx_str_t			  log_buf;
	ssize_t                n;
	size_t                 size;
	u_char				   *tmp;
    c = ev->data;
    s = c->data;

    if (ev->timedout) {
        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
        ngx_stream_close_connection(c);
        return;
    }

    if (c->close) {
        ngx_stream_close_connection(c);
        return;
    }

	cscf = ngx_stream_get_module_main_conf(s, ngx_stream_app_module);

	ascf = ngx_stream_get_module_srv_conf(s, ngx_stream_app_module);
		
	s_ctx = ngx_stream_get_module_ctx(s,ngx_stream_app_module);
	if(s_ctx == NULL){
		s_ctx = ngx_palloc(c->pool, sizeof(ngx_stream_app_ctx_t));
		if(s_ctx == NULL)
			return;
		s_ctx->header = 0;
		ngx_stream_set_ctx(s,s_ctx,ngx_stream_app_module);
	}

	b = c->buffer;

	if (b == NULL) {
		size = ascf->header_len;
		b = ngx_create_temp_buf(c->pool, size);
		if (b == NULL) {
			ngx_stream_close_connection(c);
			return;
		}

		c->buffer = b;

	} else if (b->start == NULL) {

		size = s_ctx->header == 0?ascf->header_len:s_ctx->body_len;

		b->start = ngx_palloc(c->pool, size);
		if (b->start == NULL) {
			ngx_stream_close_connection(c);
			return;
		}

		b->pos = b->start;
		b->last = b->start;
		b->end = b->last + size;
	}
	else {

		size = ascf->header_len + s_ctx->body_len - s->received;
//		size = b->end - b->last;
	}

	n = c->recv(c, b->last, size);
	
    if (n == NGX_AGAIN) {

        if (!c->read->timer_set) {
            ngx_add_timer(c->read, ascf->client_timeout);
        }

        if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
            ngx_stream_close_connection(c);
            return;
        }

        return;
    }

	if (n == NGX_ERROR) {
        ngx_stream_close_connection(c);
        return;
    }
	
    if (n == 0) {
        ngx_log_error(NGX_LOG_INFO, c->log, 0,
                      "client closed connection");
        ngx_stream_close_connection(c);
        return;
    }

    b->last += n;
	s->received +=n;

	c->log->action = "reading client request line";
	
	log_buf.len = s->received;
	log_buf.data = b->start;
	ngx_log_error(NGX_LOG_ALERT, c->log, 0, "%d recved [%V],[%d:%d]",n,&log_buf,b->end,b->last);

	if(b->end != b->last){
        if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
            ngx_stream_close_connection(c);
            return;
        }
	}
	else {
		if(s_ctx->header == 0){
			s_ctx->body_len = ngx_atoi(b->start,ascf->header_len);
			s_ctx->header = 1;
			if(s_ctx->body_len > 0 ){
				
				tmp = ngx_pcalloc(c->pool, ascf->header_len + s_ctx->body_len);
				if (tmp == NULL) {
					ngx_stream_close_connection(c);
					return;
				}

				ngx_memcpy(tmp,b->start,ascf->header_len);
				ngx_pfree(c->pool, b->start);
				b->start = tmp;
				
				b->pos = b->start + ascf->header_len;
				b->last = b->pos;
				b->end = b->last + s_ctx->body_len;
				
				ngx_app_wait_request_handler(ev);
			}
			else{
				ngx_log_error(NGX_LOG_INFO, c->log, 0, "empty request body");
				ngx_stream_close_connection(c);
				return;
			}

			ngx_log_error(NGX_LOG_ALERT, c->log, 0, "recv header,len[%d]",s_ctx->body_len);

		}
		else{
//			c->read->handler = ngx_app_empty_handler;

			t = (ngx_app_task_t *)ngx_thread_task_alloc(c->pool,
				sizeof(ngx_app_task_t) - sizeof(ngx_thread_task_t));
			if(t == NULL){
				ngx_log_error(NGX_LOG_ERR, c->log, 0, "create thread task failed");
				ngx_stream_close_connection(c);
			}
			t->data = s;
			t->task.handler = ngx_stream_app_process;
			t->task.event.handler = ngx_stream_app_finalize;
			t->task.event.data= c;
			ngx_log_error(NGX_LOG_ALERT, c->log, 0, "t->data[%d]=[%d][%d]",t->data,t->task.ctx,t);
			if(ngx_thread_task_post(cscf->tp,(ngx_thread_task_t *)t) != NGX_OK){
				ngx_log_error(NGX_LOG_ERR, c->log, 0, "post task to thread pool failed");
				ngx_stream_close_connection(c);
				return;
			}
			ngx_log_error(NGX_LOG_ALERT, c->log, 0, "after post task");
		}
	}

	return;
}
static ngx_int_t
ngx_stream_ssl_preread_handler(ngx_stream_session_t *s)
{
    u_char                             *last, *p;
    size_t                              len;
    ngx_int_t                           rc;
    ngx_connection_t                   *c;
    ngx_stream_ssl_preread_ctx_t       *ctx;
    ngx_stream_ssl_preread_srv_conf_t  *sscf;

    c = s->connection;

    ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "ssl preread handler");

    sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_preread_module);

    if (!sscf->enabled) {
        return NGX_DECLINED;
    }

    if (c->type != SOCK_STREAM) {
        return NGX_DECLINED;
    }

    if (c->buffer == NULL) {
        return NGX_AGAIN;
    }

    ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module);
    if (ctx == NULL) {
        ctx = ngx_pcalloc(c->pool, sizeof(ngx_stream_ssl_preread_ctx_t));
        if (ctx == NULL) {
            return NGX_ERROR;
        }

        ngx_stream_set_ctx(s, ctx, ngx_stream_ssl_preread_module);

        ctx->pool = c->pool;
        ctx->log = c->log;
        ctx->pos = c->buffer->pos;
    }

    p = ctx->pos;
    last = c->buffer->last;

    while (last - p >= 5) {

        if (p[0] != 0x16) {
            ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
                           "ssl preread: not a handshake");
            return NGX_DECLINED;
        }

        if (p[1] != 3) {
            ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
                           "ssl preread: unsupported SSL version");
            return NGX_DECLINED;
        }

        len = (p[3] << 8) + p[4];

        /* read the whole record before parsing */
        if ((size_t) (last - p) < len + 5) {
            break;
        }

        p += 5;

        rc = ngx_stream_ssl_preread_parse_record(ctx, p, p + len);
        if (rc != NGX_AGAIN) {
            return rc;
        }

        p += len;
    }

    ctx->pos = p;

    return NGX_AGAIN;
}