static void ngx_stream_lua_socket_udp_handle_success(ngx_stream_session_t *s, ngx_stream_lua_socket_udp_upstream_t *u) { ngx_stream_lua_ctx_t *ctx; u->read_event_handler = ngx_stream_lua_socket_dummy_handler; if (u->co_ctx) { u->co_ctx->cleanup = NULL; } if (u->waiting) { u->waiting = 0; ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return; } ctx->resume_handler = ngx_stream_lua_socket_udp_resume; ctx->cur_co_ctx = u->co_ctx; ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "stream lua udp socket waking up the current session"); ctx->write_event_handler(s, ctx); } }
int ngx_stream_lua_ffi_exit(ngx_stream_session_t *s, int status, u_char *err, size_t *errlen) { ngx_stream_lua_ctx_t *ctx; ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { *errlen = ngx_snprintf(err, *errlen, "no session ctx found") - err; return NGX_ERROR; } if (ngx_stream_lua_ffi_check_context(ctx, NGX_STREAM_LUA_CONTEXT_CONTENT | NGX_STREAM_LUA_CONTEXT_TIMER, err, errlen) != NGX_OK) { return NGX_ERROR; } ctx->exit_code = status; ctx->exited = 1; ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "stream lua exit with code %i", ctx->exit_code); return NGX_OK; }
static int ngx_stream_lua_socket_udp(lua_State *L) { ngx_stream_session_t *s; ngx_stream_lua_ctx_t *ctx; if (lua_gettop(L) != 0) { return luaL_error(L, "expecting zero arguments, but got %d", lua_gettop(L)); } s = ngx_stream_lua_get_session(L); if (s == NULL) { return luaL_error(L, "no session found"); } ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); } ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT | NGX_STREAM_LUA_CONTEXT_TIMER); lua_createtable(L, 3 /* narr */, 1 /* nrec */); lua_pushlightuserdata(L, &ngx_stream_lua_socket_udp_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); dd("top: %d", lua_gettop(L)); return 1; }
ngx_int_t ngx_stream_upm_send_request(ngx_stream_session_t *s) { ngx_int_t n; ngx_buf_t *buf; ngx_connection_t *pc; ngx_stream_upm_ctx_t *ctx; ngx_stream_upstream_t *u; u = s->upstream; pc = u->peer.connection; buf = &u->downstream_buf; ctx = ngx_stream_get_module_ctx(s, ngx_stream_upm_module); if (ctx->state == SEND_REQUEST) { n = pc->send(pc, buf->pos, buf->last - buf->pos); if (n == NGX_ERROR) { return NGX_ERROR; } //all nginx error; if (n == buf->last - buf->pos) { ctx->state = READ_AND_PARSE_HEADER; //FIXME: need fix the steps return ngx_stream_upm_process_resp_status_line(s); } else { buf->pos += n; } } return NGX_OK; }
static void ngx_stream_lua_flush_cleanup(void *data) { /* TODO */ ngx_stream_session_t *s; ngx_event_t *wev; ngx_stream_lua_ctx_t *ctx; ngx_stream_lua_co_ctx_t *coctx = data; coctx->flushing = 0; s = coctx->data; if (s == NULL) { return; } wev = s->connection->write; if (wev && wev->timer_set) { ngx_del_timer(wev); } ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return; } ctx->flushing_coros--; }
static void ngx_stream_upm_upstream_handler(ngx_event_t *ev) { ngx_connection_t *c; ngx_stream_session_t *s; ngx_stream_upm_ctx_t *ctx; //ngx_stream_upstream_t *u; c = ev->data; s = c->data; //u = s->upstream; ctx = ngx_stream_get_module_ctx(s, ngx_stream_upm_module); ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream upm upstream handler"); if (ev->write) { ctx->write_event_handler(s); } else { ctx->read_event_handler(s); } ngx_http_run_posted_requests(c); }
ngx_int_t ngx_stream_upm_read_and_parse_response(ngx_stream_session_t *s) { ngx_int_t n, rc; ngx_buf_t *b; ngx_connection_t *pc; ngx_stream_upm_ctx_t *ctx; ngx_stream_upstream_t *u; ngx_stream_upm_main_conf_t *ummcf; ctx = ngx_stream_get_module_ctx(s, ngx_stream_upm_module); ummcf = ngx_stream_get_module_srv_conf(s, ngx_stream_upm_module); u = s->upstream; pc = u->peer.connection; //Allocate big enough buffer //Must be assure the content_length_n big than 2 * ummcf->buffer_size; b = ctx->resp_body; if (b->start == NULL) { b->start = ngx_pcalloc(ctx->pool, 2 * ummcf->buffer_size); b->pos = b->start; b->last = b->start; b->end = b->start + 2 * ummcf->buffer_size; } for (;;) { n = pc->recv(pc, b->last, b->end - b->last); if (n == NGX_AGAIN) { if (ngx_handle_read_event(pc->read, 0) != NGX_OK) { return NGX_ERROR; } return NGX_AGAIN; } if (n == 0) { ngx_log_error(NGX_LOG_ERR, pc->log, 0, "upm upstream prematurely closed connection while read the body"); } if (n == NGX_ERROR || n == 0) { return NGX_ERROR; } b->last += n; if (b->last - b->pos == ctx->content_length_n) { rc = ngx_stream_upm_parse_resp_body(s); } else if (b->last - b->pos < ctx->content_length_n) { continue; } else { ngx_log_error(NGX_LOG_ERR, pc->log, 0, "upm upstream send a response body more than the content_length"); return NGX_ERROR; } } return rc; }
static int ngx_stream_lua_uthread_spawn(lua_State *L) { int n; ngx_stream_session_t *s; ngx_stream_lua_ctx_t *ctx; ngx_stream_lua_co_ctx_t *coctx = NULL; n = lua_gettop(L); s = ngx_stream_lua_get_session(L); if (s == NULL) { return luaL_error(L, "no session found"); } ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return luaL_error(L, "no session ctx found"); } ngx_stream_lua_coroutine_create_helper(L, s, ctx, &coctx); /* anchor the newly created coroutine into the Lua registry */ lua_pushlightuserdata(L, &ngx_stream_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); coctx->co_ref = luaL_ref(L, -2); lua_pop(L, 1); if (n > 1) { lua_replace(L, 1); lua_xmove(L, coctx->co, n - 1); } coctx->is_uthread = 1; ctx->uthreads++; coctx->co_status = NGX_STREAM_LUA_CO_RUNNING; ctx->co_op = NGX_STREAM_LUA_USER_THREAD_RESUME; ctx->cur_co_ctx->thread_spawn_yielded = 1; if (ngx_stream_lua_post_thread(s, ctx, ctx->cur_co_ctx) != NGX_OK) { return luaL_error(L, "no memory"); } coctx->parent_co_ctx = ctx->cur_co_ctx; ctx->cur_co_ctx = coctx; #if 0 /* TODO */ ngx_stream_lua_probe_user_thread_spawn(s, L, coctx->co); #endif dd("yielding with arg %s, top=%d, index-1:%s", luaL_typename(L, -1), (int) lua_gettop(L), luaL_typename(L, 1)); return lua_yield(L, 1); }
static int ngx_stream_lua_on_abort(lua_State *L) { ngx_stream_session_t *s; ngx_stream_lua_ctx_t *ctx; ngx_stream_lua_co_ctx_t *coctx = NULL; ngx_stream_lua_srv_conf_t *lscf; s = ngx_stream_lua_get_session(L); if (s == NULL) { return luaL_error(L, "no session found"); } ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return luaL_error(L, "no session ctx found"); } ngx_stream_lua_check_fake_session2(L, s, ctx); if (ctx->on_abort_co_ctx) { lua_pushnil(L); lua_pushliteral(L, "duplicate call"); return 2; } lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_lua_module); if (!lscf->check_client_abort) { lua_pushnil(L); lua_pushliteral(L, "lua_check_client_abort is off"); return 2; } ngx_stream_lua_coroutine_create_helper(L, s, ctx, &coctx); lua_pushlightuserdata(L, &ngx_stream_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); dd("on_wait thread 1: %p", lua_tothread(L, -1)); coctx->co_ref = luaL_ref(L, -2); lua_pop(L, 1); coctx->is_uthread = 1; ctx->on_abort_co_ctx = coctx; dd("on_wait thread 2: %p", coctx->co); coctx->co_status = NGX_STREAM_LUA_CO_SUSPENDED; coctx->parent_co_ctx = ctx->cur_co_ctx; lua_pushinteger(L, 1); return 1; }
/** * Send last_buf, terminate output stream * */ static int ngx_stream_lua_ngx_eof(lua_State *L) { #if 0 /* TODO */ ngx_stream_session_t *s; ngx_stream_lua_ctx_t *ctx; ngx_int_t rc; s = ngx_stream_lua_get_session(L); if (s == NULL) { return luaL_error(L, "no session object found"); } if (lua_gettop(L) != 0) { return luaL_error(L, "no argument is expected"); } ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); } if (ctx->acquired_raw_req_socket) { lua_pushnil(L); lua_pushliteral(L, "raw session socket acquired"); return 2; } if (ctx->eof) { lua_pushnil(L); lua_pushliteral(L, "seen eof"); return 2; } ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT); ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "stream lua send eof"); rc = ngx_stream_lua_send_chain_link(s, ctx, NULL /* indicate last_buf */); dd("send chain: %d", (int) rc); if (rc == NGX_ERROR || rc >= NGX_STREAM_SPECIAL_RESPONSE) { lua_pushnil(L); lua_pushliteral(L, "nginx output filter error"); return 2; } #endif lua_pushinteger(L, 1); return 1; }
static ngx_int_t ngx_stream_upm_process_resp_status_line(ngx_stream_session_t *s) { //size_t len; ngx_int_t rc; ngx_stream_upm_ctx_t *ctx; ngx_stream_upstream_t *u; ctx = ngx_stream_get_module_ctx(s, ngx_stream_upm_module); if (ctx == NULL) { return NGX_ERROR; } u = s->upstream; rc = ngx_stream_upm_parse_status_line(s, &u->downstream_buf, &ctx->resp_status); if (rc == NGX_AGAIN) { return rc; } if (rc == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "upstream sent no valid HTTP/1.0 header"); //u->resp_status.status.code = NGX_HTTP_OK; return NGX_ERROR; } //len = ctx->resp_status.status.end - ctx->resp_status.status.start; /* Without need to Copy the data; u->headers_in.status_line.data = ngx_pnalloc(r->pool, len); if (u->headers_in.status_line.data == NULL) { return NGX_ERROR; } ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len); */ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "stream upm status %ui", ctx->resp_status.status.code); if (ctx->resp_status.status.http_version < NGX_HTTP_VERSION_11) { ctx->connection_close = 1; } ctx->read_and_parse_header = ngx_stream_upm_process_resp_header; return ngx_stream_upm_process_resp_header(s); }
static int ngx_stream_lua_coroutine_yield(lua_State *L) { ngx_stream_session_t *s; ngx_stream_lua_ctx_t *ctx; ngx_stream_lua_co_ctx_t *coctx; s = ngx_stream_lua_get_session(L); if (s == NULL) { return luaL_error(L, "no session found"); } ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return luaL_error(L, "no session ctx found"); } ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT | NGX_STREAM_LUA_CONTEXT_TIMER); coctx = ctx->cur_co_ctx; coctx->co_status = NGX_STREAM_LUA_CO_SUSPENDED; ctx->co_op = NGX_STREAM_LUA_USER_CORO_YIELD; if (!coctx->is_uthread && coctx->parent_co_ctx) { dd("set coroutine to running"); coctx->parent_co_ctx->co_status = NGX_STREAM_LUA_CO_RUNNING; #if 0 /* TODO */ ngx_stream_lua_probe_user_coroutine_yield(s, coctx->parent_co_ctx->co, L); #endif } else { #if 0 /* TODO */ ngx_stream_lua_probe_user_coroutine_yield(s, NULL, L); #endif } /* yield and pass retvals to main thread, * and resume parent coroutine there */ return lua_yield(L, lua_gettop(L)); }
static void ngx_stream_return_write_handler(ngx_event_t *ev) { ssize_t n; ngx_buf_t *b; ngx_connection_t *c; ngx_stream_session_t *s; ngx_stream_return_ctx_t *ctx; c = ev->data; s = c->data; if (ev->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); ngx_stream_close_connection(c); return; } if (ev->ready) { ctx = ngx_stream_get_module_ctx(s, ngx_stream_return_module); b = &ctx->buf; n = c->send(c, b->pos, b->last - b->pos); if (n == NGX_ERROR) { ngx_stream_close_connection(c); return; } if (n > 0) { b->pos += n; if (b->pos == b->last) { ngx_stream_close_connection(c); return; } } } if (ngx_handle_write_event(ev, 0) != NGX_OK) { ngx_stream_close_connection(c); return; } ngx_add_timer(ev, 5000); }
static int ngx_stream_lua_coroutine_create(lua_State *L) { ngx_stream_session_t *s; ngx_stream_lua_ctx_t *ctx; s = ngx_stream_lua_get_session(L); if (s == NULL) { return luaL_error(L, "no session found"); } ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return luaL_error(L, "no session ctx found"); } return ngx_stream_lua_coroutine_create_helper(L, s, ctx, NULL); }
/** * Send last_buf, terminate output stream * */ static int ngx_stream_lua_ngx_eof(lua_State *L) { ngx_stream_session_t *s; ngx_stream_lua_ctx_t *ctx; s = ngx_stream_lua_get_session(L); if (s == NULL) { return luaL_error(L, "no session object found"); } if (lua_gettop(L) != 0) { return luaL_error(L, "no argument is expected"); } ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); } #if 0 if (ctx->acquired_raw_req_socket) { lua_pushnil(L); lua_pushliteral(L, "raw session socket acquired"); return 2; } #endif if (ctx->eof) { lua_pushnil(L); lua_pushliteral(L, "seen eof"); return 2; } ctx->eof = 1; ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT); ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "stream lua send eof"); lua_pushinteger(L, 1); return 1; }
static void ngx_stream_lua_socket_udp_handle_error(ngx_stream_session_t *s, ngx_stream_lua_socket_udp_upstream_t *u, ngx_uint_t ft_type) { ngx_stream_lua_ctx_t *ctx; ngx_stream_lua_co_ctx_t *coctx; ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "stream lua udp socket handle error"); u->ft_type |= ft_type; #if 0 ngx_stream_lua_socket_udp_finalize(s, u); #endif u->read_event_handler = ngx_stream_lua_socket_dummy_handler; coctx = u->co_ctx; if (coctx) { coctx->cleanup = NULL; } if (u->waiting) { u->waiting = 0; ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return; } ctx->resume_handler = ngx_stream_lua_socket_udp_resume; ctx->cur_co_ctx = coctx; ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "stream lua udp socket waking up the current session"); ctx->write_event_handler(s, ctx); } }
static int ngx_stream_lua_coroutine_status(lua_State *L) { lua_State *co; /* new coroutine to be created */ const ngx_str_t *names; ngx_stream_session_t *s; ngx_stream_lua_ctx_t *ctx; ngx_stream_lua_co_ctx_t *coctx; /* co ctx for the new coroutine */ co = lua_tothread(L, 1); luaL_argcheck(L, co, 1, "coroutine expected"); s = ngx_stream_lua_get_session(L); if (s == NULL) { return luaL_error(L, "no session found"); } ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return luaL_error(L, "no session ctx found"); } ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT | NGX_STREAM_LUA_CONTEXT_TIMER); names = ngx_stream_lua_co_status_names; coctx = ngx_stream_lua_get_co_ctx(co, ctx); if (coctx == NULL) { lua_pushlstring(L, (const char *) names[NGX_STREAM_LUA_CO_DEAD].data, names[NGX_STREAM_LUA_CO_DEAD].len); return 1; } dd("co status: %d", coctx->co_status); lua_pushlstring(L, (const char *) names[coctx->co_status].data, names[coctx->co_status].len); return 1; }
static ngx_int_t ngx_stream_ssl_preread_server_name_variable(ngx_stream_session_t *s, ngx_variable_value_t *v, uintptr_t data) { ngx_stream_ssl_preread_ctx_t *ctx; ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module); if (ctx == NULL) { v->not_found = 1; return NGX_OK; } v->valid = 1; v->no_cacheable = 0; v->not_found = 0; v->len = ctx->host.len; v->data = ctx->host.data; return NGX_OK; }
static void ngx_stream_return_write_handler(ngx_event_t *ev) { ngx_connection_t *c; ngx_stream_session_t *s; ngx_stream_return_ctx_t *ctx; c = ev->data; s = c->data; if (ev->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); ngx_stream_finalize_session(s, NGX_STREAM_OK); return; } ctx = ngx_stream_get_module_ctx(s, ngx_stream_return_module); if (ngx_stream_top_filter(s, ctx->out, 1) == NGX_ERROR) { ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } ctx->out = NULL; if (!c->buffered) { ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream return done sending"); ngx_stream_finalize_session(s, NGX_STREAM_OK); return; } if (ngx_handle_write_event(ev, 0) != NGX_OK) { ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } ngx_add_timer(ev, 5000); }
static int ngx_stream_lua_ngx_exit(lua_State *L) { ngx_int_t rc; ngx_stream_session_t *s; ngx_stream_lua_ctx_t *ctx; if (lua_gettop(L) != 1) { return luaL_error(L, "expecting one argument"); } s = ngx_stream_lua_get_session(L); if (s == NULL) { return luaL_error(L, "no session object found"); } ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return luaL_error(L, "no session ctx found"); } ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT | NGX_STREAM_LUA_CONTEXT_TIMER); rc = (ngx_int_t) luaL_checkinteger(L, 1); dd("setting exit code: %d", (int) rc); ctx->exit_code = rc; ctx->exited = 1; ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "stream lua exit with code %i", ctx->exit_code); dd("calling yield"); return lua_yield(L, 0); }
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; }
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; }
/* 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; }
/** * Force flush out response content * */ static int ngx_stream_lua_ngx_flush(lua_State *L) { #if 0 /* TODO */ ngx_stream_session_t *s; ngx_stream_lua_ctx_t *ctx; ngx_chain_t *cl; ngx_int_t rc; int n; unsigned wait = 0; ngx_event_t *wev; ngx_stream_core_loc_conf_t *clcf; ngx_stream_lua_co_ctx_t *coctx; n = lua_gettop(L); if (n > 1) { return luaL_error(L, "attempt to pass %d arguments, but accepted 0 " "or 1", n); } s = ngx_stream_lua_get_session(L); if (n == 1 && s == s->main) { luaL_checktype(L, 1, LUA_TBOOLEAN); wait = lua_toboolean(L, 1); } ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return luaL_error(L, "no session ctx found"); } ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_REWRITE | NGX_STREAM_LUA_CONTEXT_ACCESS | NGX_STREAM_LUA_CONTEXT_CONTENT); if (ctx->acquired_raw_req_socket) { lua_pushnil(L); lua_pushliteral(L, "raw session socket acquired"); return 2; } coctx = ctx->cur_co_ctx; if (coctx == NULL) { return luaL_error(L, "no co ctx found"); } if (ctx->eof) { lua_pushnil(L); lua_pushliteral(L, "seen eof"); return 2; } #if 1 if (!s->header_sent && !ctx->header_sent) { lua_pushnil(L); lua_pushliteral(L, "nothing to flush"); return 2; } #endif cl = ngx_stream_lua_get_flush_chain(s, ctx); if (cl == NULL) { return luaL_error(L, "no memory"); } rc = ngx_stream_lua_send_chain_link(s, ctx, cl); dd("send chain: %d", (int) rc); if (rc == NGX_ERROR || rc >= NGX_STREAM_SPECIAL_RESPONSE) { lua_pushnil(L); lua_pushliteral(L, "nginx output filter error"); return 2; } dd("wait:%d, rc:%d, buffered:0x%x", wait, (int) rc, s->connection->buffered); wev = s->connection->write; if (wait && (s->connection->buffered & NGX_STREAM_LOWLEVEL_BUFFERED || wev->delayed)) { ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "stream lua flush requires waiting: buffered 0x%uxd, " "delayed:%d", (unsigned) s->connection->buffered, wev->delayed); coctx->flushing = 1; ctx->flushing_coros++; if (ctx->entered_content_phase) { /* mimic ngx_stream_set_write_handler */ s->write_event_handler = ngx_stream_lua_content_wev_handler; } else { s->write_event_handler = ngx_stream_core_run_phases; } clcf = ngx_stream_get_module_loc_conf(s, ngx_stream_core_module); if (!wev->delayed) { ngx_add_timer(wev, clcf->send_timeout); } if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { if (wev->timer_set) { wev->delayed = 0; ngx_del_timer(wev); } lua_pushnil(L); lua_pushliteral(L, "connection broken"); return 2; } ngx_stream_lua_cleanup_pending_operation(ctx->cur_co_ctx); coctx->cleanup = ngx_stream_lua_flush_cleanup; coctx->data = s; return lua_yield(L, 0); } ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "stream lua flush asynchronously"); #endif lua_pushinteger(L, 1); return 1; }
static int ngx_stream_lua_ngx_echo(lua_State *L, unsigned newline) { ngx_stream_session_t *s; ngx_stream_lua_ctx_t *ctx; const char *p; size_t len; size_t size; ngx_buf_t *b; ngx_chain_t *cl; ngx_int_t rc; int i; int nargs; int type; const char *msg; s = ngx_stream_lua_get_session(L); if (s == NULL) { return luaL_error(L, "no session object found"); } ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return luaL_error(L, "no session ctx found"); } ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT); if (ctx->acquired_raw_req_socket) { lua_pushnil(L); lua_pushliteral(L, "raw session socket acquired"); return 2; } if (ctx->eof) { lua_pushnil(L); lua_pushliteral(L, "seen eof"); return 2; } nargs = lua_gettop(L); size = 0; for (i = 1; i <= nargs; i++) { type = lua_type(L, i); switch (type) { case LUA_TNUMBER: case LUA_TSTRING: lua_tolstring(L, i, &len); size += len; break; case LUA_TNIL: size += sizeof("nil") - 1; break; case LUA_TBOOLEAN: if (lua_toboolean(L, i)) { size += sizeof("true") - 1; } else { size += sizeof("false") - 1; } break; case LUA_TTABLE: size += ngx_stream_lua_calc_strlen_in_table(L, i, i, 0 /* strict */); break; case LUA_TLIGHTUSERDATA: dd("userdata: %p", lua_touserdata(L, i)); if (lua_touserdata(L, i) == NULL) { size += sizeof("null") - 1; break; } continue; default: msg = lua_pushfstring(L, "string, number, boolean, nil, " "ngx.null, or array table expected, " "but got %s", lua_typename(L, type)); return luaL_argerror(L, i, msg); } } if (newline) { size += sizeof("\n") - 1; } if (size == 0) { /* do nothing for empty strings */ lua_pushinteger(L, 1); return 1; } cl = ngx_stream_lua_chain_get_free_buf(s->connection->log, s->connection->pool, &ctx->free_bufs, size); if (cl == NULL) { return luaL_error(L, "no memory"); } b = cl->buf; for (i = 1; i <= nargs; i++) { type = lua_type(L, i); switch (type) { case LUA_TNUMBER: case LUA_TSTRING: p = lua_tolstring(L, i, &len); b->last = ngx_copy(b->last, (u_char *) p, len); break; case LUA_TNIL: *b->last++ = 'n'; *b->last++ = 'i'; *b->last++ = 'l'; break; case LUA_TBOOLEAN: if (lua_toboolean(L, i)) { *b->last++ = 't'; *b->last++ = 'r'; *b->last++ = 'u'; *b->last++ = 'e'; } else { *b->last++ = 'f'; *b->last++ = 'a'; *b->last++ = 'l'; *b->last++ = 's'; *b->last++ = 'e'; } break; case LUA_TTABLE: b->last = ngx_stream_lua_copy_str_in_table(L, i, b->last); break; case LUA_TLIGHTUSERDATA: *b->last++ = 'n'; *b->last++ = 'u'; *b->last++ = 'l'; *b->last++ = 'l'; break; default: return luaL_error(L, "impossible to reach here"); } } if (newline) { *b->last++ = '\n'; } #if 0 if (b->last != b->end) { return luaL_error(L, "buffer error: %p != %p", b->last, b->end); } #endif ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, newline ? "stream lua say response" : "stream lua print response"); rc = ngx_stream_lua_send_chain_link(s, ctx, cl); if (rc == NGX_ERROR) { lua_pushnil(L); lua_pushliteral(L, "nginx output filter error"); return 2; } dd("downstream write: %d, buf len: %d", (int) rc, (int) (b->last - b->pos)); lua_pushinteger(L, 1); return 1; }
static int ngx_stream_lua_coroutine_resume(lua_State *L) { lua_State *co; ngx_stream_session_t *s; ngx_stream_lua_ctx_t *ctx; ngx_stream_lua_co_ctx_t *coctx; ngx_stream_lua_co_ctx_t *p_coctx; /* parent co ctx */ co = lua_tothread(L, 1); luaL_argcheck(L, co, 1, "coroutine expected"); s = ngx_stream_lua_get_session(L); if (s == NULL) { return luaL_error(L, "no session found"); } ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return luaL_error(L, "no session ctx found"); } ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT | NGX_STREAM_LUA_CONTEXT_TIMER); p_coctx = ctx->cur_co_ctx; if (p_coctx == NULL) { return luaL_error(L, "no parent co ctx found"); } coctx = ngx_stream_lua_get_co_ctx(co, ctx); if (coctx == NULL) { return luaL_error(L, "no co ctx found"); } #if 0 /* TODO */ ngx_stream_lua_probe_user_coroutine_resume(s, L, co); #endif if (coctx->co_status != NGX_STREAM_LUA_CO_SUSPENDED) { dd("coroutine resume: %d", coctx->co_status); lua_pushboolean(L, 0); lua_pushfstring(L, "cannot resume %s coroutine", ngx_stream_lua_co_status_names[coctx->co_status].data); return 2; } p_coctx->co_status = NGX_STREAM_LUA_CO_NORMAL; coctx->parent_co_ctx = p_coctx; dd("set coroutine to running"); coctx->co_status = NGX_STREAM_LUA_CO_RUNNING; ctx->co_op = NGX_STREAM_LUA_USER_CORO_RESUME; ctx->cur_co_ctx = coctx; /* yield and pass args to main thread, and resume target coroutine from * there */ return lua_yield(L, lua_gettop(L) - 1); }
ngx_int_t ngx_stream_upm_read_and_parse_header(ngx_stream_session_t *s) { ngx_int_t n, rc; ngx_buf_t *b, tb; ngx_connection_t *pc; ngx_stream_upm_ctx_t *ctx; ngx_stream_upstream_t *u; ngx_stream_upm_main_conf_t *ummcf; ummcf = ngx_stream_get_module_srv_conf(s, ngx_stream_upm_module); u = s->upstream; pc = u->peer.connection; ctx = ngx_stream_get_module_ctx(s, ngx_stream_upm_module); if (u->upstream_buf.start == NULL) { tb.start = ngx_pcalloc(ctx->pool, ummcf->buffer_size * sizeof(char)); if (tb.start == NULL) { return NGX_ERROR; } tb.end = tb.start + ummcf->buffer_size; tb.pos = tb.start; tb.last = tb.pos; u->upstream_buf = tb; } b = &u->upstream_buf; for ( ;; ) { n = pc->recv(pc, b->last, b->end - b->last); if (n == NGX_AGAIN) { if (ngx_handle_read_event(pc->read, 0) != NGX_OK) { return NGX_ERROR; } return NGX_AGAIN; } if (n == 0) { ngx_log_error(NGX_LOG_ERR, pc->log, 0, "upm upstream prematurely closed connection"); } if (n == NGX_ERROR || n == 0) { return NGX_ERROR; } b->last += n; rc = ctx->read_and_parse_header(s); if (rc == NGX_AGAIN) { if (u->upstream_buf.last == u->upstream_buf.end) { ngx_log_error(NGX_LOG_ERR, pc->log, 0, "upm upstream sent too big header"); return NGX_HTTP_UPSTREAM_FT_INVALID_HEADER; } continue; } if(rc == NGX_DONE) { ctx->state = READ_AND_PARSE_RESPONSE; return ngx_stream_upm_read_and_parse_response(s); } return rc; } }
ngx_int_t ngx_stream_upm_parse_resp_body(ngx_stream_session_t *s) { int port, fail_timeout, max_fail, weight, ta[1024]; char *upname, *host, *t; cJSON *jsroot, *service, *jinsts, *jinst, *tags; ngx_buf_t *b; ngx_uint_t i, j, p, st, sfound, ifound; ngx_conf_t cf; //ngx_pool_t *pool; ngx_array_t *servs, *upstreams; ngx_connection_t *pc; ngx_stream_upstream_t *u; ngx_stream_upm_ctx_t *ctx; ngx_stream_upm_service_t *ums; ngx_stream_upm_main_conf_t *ummcf; ngx_stream_upm_service_inst_t *umsi; ngx_stream_upstream_init_pt init; ngx_stream_upstream_server_t *us; ngx_stream_upstream_srv_conf_t *uscf; ngx_stream_upstream_main_conf_t *umcf; ctx = ngx_stream_get_module_ctx(s, ngx_stream_upm_module); ummcf = ngx_stream_get_module_srv_conf(s, ngx_stream_upm_module); umcf = ngx_stream_get_module_main_conf(s, ngx_stream_upstream_module); upstreams = &umcf->upstreams; b = ctx->resp_body; u = s->upstream; pc = u->peer.connection; /* start to parse the JSON body; */ jsroot = cJSON_Parse((char *)b->start); if (jsroot == NULL) { ngx_log_error(NGX_LOG_ERR, pc->log, 0, "upm json parse failed"); return ERR_JSON; } /* start to parse the JSON; */ service = jsroot->child; if (service == NULL) { ngx_log_error(NGX_LOG_ERR, pc->log, 0, "upm json with empty service list"); return ERR_JSON; } /*service array */ servs = ngx_array_create(ctx->pool, 16, sizeof(ngx_stream_upm_service_t)); if (servs == NULL) { return NGX_ERROR; } while( service != NULL ) { //Got the service name; upname = service->string; //Got the service related instance; jinsts = service->child; if (jinsts == NULL || jinsts->child == NULL) { ngx_log_error(NGX_LOG_ERR, pc->log, 0, "upm service: %s without any instance", upname); } ums = ngx_array_push(servs); if (ums == NULL) { return NGX_ERROR; } ums->service_name.len = ngx_strlen(upname); ums->service_name.data = ngx_pcalloc(ctx->pool, ums->service_name.len); ngx_memcpy(ums->service_name.data, upname, ums->service_name.len); ums->insts = ngx_array_create(ctx->pool, 16, sizeof(ngx_stream_upm_service_inst_t)); if (ums->insts == NULL) { return NGX_ERROR; } //travers all the instance jinst = jinsts; while (jinst != NULL) { //FIXME need check the Item isn't exists; host = cJSON_GetObjectItem(jinst, "Host")->valuestring; port = cJSON_GetObjectItem(jinst, "Port")->valueint; tags = cJSON_GetObjectItem(jinst, "Tags"); fail_timeout = cJSON_GetObjectItem(tags, "fail_timeout")->valueint; max_fail = cJSON_GetObjectItem(tags, "max_fails")->valueint; weight = cJSON_GetObjectItem(tags, "weight")->valueint; umsi = ngx_array_push(ums->insts); if (umsi == NULL) { return NGX_ERROR; } i = ngx_strlen(host); //Here, ip:port, Max port is 65535 umsi->name.data = ngx_pcalloc(ctx->pool, (i + 5) * sizeof(char)); t = (char *)ngx_snprintf(umsi->name.data, i + 5, "%s:%d", (char *)host, port); umsi->name.len = t - (char *)umsi->name.data; umsi->host.data = (u_char *)host; umsi->host.len = i; umsi->port = port; umsi->fail_timeout = fail_timeout; umsi->max_fail = max_fail; umsi->weight = weight; jinst = jinst->next; } service = service->next; } //Process the upstream msg, check wether we need to update the server; cf.name = "ngx_stream_upm_module"; //Here, we create a memory pool, Only use to the upstream init peer; cf.pool = ngx_create_pool(8192, pc->log); cf.module_type = NGX_STREAM_MODULE; cf.cmd_type = NGX_STREAM_SRV_CONF; cf.log = pc->log; if (ummcf->pool == NULL) { ummcf->pool = cf.pool; } else { //pool = cf.pool; ummcf->pool = cf.pool; } for (i = 0; i < servs->nelts; i++) { ums = &((ngx_stream_upm_service_t *)(servs->elts))[i]; sfound = 0; /*First: find the upstream name */ uscf = NULL; for (j = 0; j < upstreams->nelts; j++) { uscf = &((ngx_stream_upstream_srv_conf_t *)upstreams->elts)[j]; if (uscf->host.len == ums->service_name.len && ngx_strncmp(uscf->host.data, ums->service_name.data, uscf->host.len) == 0) { sfound = 1; } } if (sfound == 1) { //reset the temporary array to zero; //the elt == 1, Means update; //the elt == 2, Means create; //the elt == 0, Means need set this server to down; memset(ta, 0, sizeof(ta)); us = NULL; for (p = 0; p < ums->insts->nelts; p++) { umsi = &((ngx_stream_upm_service_inst_t *)ums->insts->elts)[p]; ifound = 0; for (st = 0; st < uscf->servers->nelts; st++) { us = &((ngx_stream_upstream_server_t *)uscf->servers->elts)[st]; if(us->name.len == umsi->name.len && ngx_strncmp(us->name.data, umsi->name.data, us->name.len ) == 0) { ifound = 1; } } //Means server already exists; if (ifound == 1) { us->weight = umsi->weight; us->max_fails = umsi->max_fail; us->fail_timeout = umsi->fail_timeout; us->backup = umsi->backup; us->down = umsi->down; ta[st] = 1; //insert the server; } else { us = ngx_array_push(uscf->servers); us->weight = umsi->weight; us->max_fails = umsi->max_fail; us->fail_timeout = umsi->fail_timeout; us->backup = umsi->backup; us->down = umsi->down; ta[st] = 2; } } for (st = 0; st < uscf->servers->nelts; st++) { us = &((ngx_stream_upstream_server_t *)uscf->servers->elts)[st]; if (ta[st] == 0) { //FIXME: Only set this server to down, // If the backend change very quikly, there are too many down server list; us->down = 1; } } /*Reinit the upstream servers*/ init = uscf->peer.init_upstream ? uscf->peer.init_upstream: ngx_stream_upstream_init_round_robin; if (init(&cf, uscf) != NGX_OK) { return NGX_ERROR; } } else { //TODO: doesn't support auto discovery the service name? //Need alloc the memory from the global; ngx_log_error(NGX_LOG_ERR, pc->log, 0, "config server return uninitilized usptreams: %V", &ums->service_name); } } /*Update the upstream weight*/ return NGX_OK; }
ngx_int_t ngx_stream_upm_process_resp_header(ngx_stream_session_t *s) { ngx_int_t rc; ngx_array_t *resp_headers; ngx_table_elt_t *h; ngx_stream_upm_ctx_t *ctx; ngx_stream_upstream_t *u; //ngx_stream_upm_main_conf_t *ummcf; //ngx_http_upstream_header_t *hh; //ngx_stream_upstream_srv_conf_t *umcf; ngx_stream_upm_resp_header_ctx_t hctx; //ummcf = ngx_stream_get_module_srv_conf(s, ngx_stream_upm_module); ctx = ngx_stream_get_module_ctx(s, ngx_stream_upm_module); u = s->upstream; resp_headers = ctx->resp_headers; if (resp_headers == NULL) { resp_headers = ngx_array_create(ctx->pool, 4, sizeof(ngx_table_elt_t)); if (resp_headers == NULL) { return NGX_ERROR; } ctx->resp_headers = resp_headers; } ngx_memzero(&hctx, sizeof(ngx_stream_upm_resp_header_ctx_t)); for ( ;; ) { rc = ngx_stream_upm_parse_header_line(&hctx, &u->upstream_buf, 1); if (rc == NGX_OK) { /* a header line has been parsed successfully */ h = ngx_array_push(resp_headers); if (h == NULL) { return NGX_ERROR; } h->hash = hctx.header_hash; h->key.len = hctx.header_name_end - hctx.header_name_start; h->value.len = hctx.header_end - hctx.header_start; h->key.data = hctx.header_name_start; h->value.data = hctx.header_start; /*No need to care lowcase_key if (h->key.len == r->lowcase_index) { ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); } else { ngx_strlow(h->lowcase_key, h->key.data, h->key.len); }*/ ngx_log_debug2(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, "stream header: \"%V: %V\"", &h->key, &h->value); if (h->key.len == 14 && ngx_strncmp(h->key.data, "Content-Length", h->key.len) == 0) { ctx->content_length_n = ngx_atoof(h->value.data, h->value.len); } if (h->key.len == 17 && ngx_strncmp(h->key.data, "Transfer-Encoding", h->key.len) == 0) { if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len, (u_char *) "chunked", 7 - 1) != NULL) { ctx->chunked = 1; } } continue; } if (rc == NGX_HTTP_PARSE_HEADER_DONE) { /* a whole header has been parsed successfully */ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, "stream upm header done"); /* Get content length */ u = s->upstream; if (ctx->chunked) { ctx->content_length_n = -1; } /* * set u->keepalive if response has no body; this allows to keep * connections alive in case of r->header_only or X-Accel-Redirect */ return NGX_DONE; } if (rc == NGX_AGAIN) { return NGX_AGAIN; } /* there was error while a header line parsing */ ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "upm upstream sent invalid header"); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } }
ngx_int_t ngx_stream_upm_connect(ngx_stream_session_t *s) { ngx_int_t rc; ngx_connection_t *c, *pc; ngx_stream_upm_ctx_t *ctx; ngx_stream_upstream_t *u; //ngx_stream_upm_main_conf_t *ummcf; //ummcf = ngx_stream_get_module_srv_conf(s, ngx_stream_upm_module); c = s->connection; u = s->upstream; ctx = ngx_stream_get_module_ctx(s, ngx_stream_upm_module); ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "upm connect: %i", rc); rc = ngx_event_connect_peer(&u->peer); if (rc == NGX_ERROR) { return rc; } if (rc == NGX_BUSY) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "no live upstreams"); return NGX_ERROR; } if (rc == NGX_DECLINED) { //FIXME: just return NGX_ERROR; return NGX_ERROR; } /* rc == NGX_OK || rc == NGX_AGAIN || rc == NGX_DONE */ pc = u->peer.connection; pc->data = s; pc->log = c->log; pc->pool = c->pool; pc->read->log = c->log; pc->write->log = c->log; pc->recv = ngx_recv; pc->send = ngx_send; pc->recv_chain = ngx_recv_chain; pc->send_chain = ngx_send_chain; pc->sendfile = 1; pc->read->handler = ngx_stream_upm_upstream_handler; pc->write->handler = ngx_stream_upm_upstream_handler; //ngx_add_timer(pc->write, ummcf->connect_timeout); ctx->state = CREATE_REQUEST; rc = ngx_stream_upm_create_request(s); if (rc != NGX_OK) { //return ngx_stream_upm_finalize(s); return NGX_ERROR; } ctx->state = SEND_REQUEST; return ngx_stream_upm_send_request(s); }