コード例 #1
0
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);
    }
}
コード例 #2
0
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;
}
コード例 #3
0
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;
}
コード例 #4
0
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;
}
コード例 #5
0
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--;
}
コード例 #6
0
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);
}
コード例 #7
0
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;
}
コード例 #8
0
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);
}
コード例 #9
0
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;
}
コード例 #10
0
/**
 * 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;
}
コード例 #11
0
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);
}
コード例 #12
0
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));
}
コード例 #13
0
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);
}
コード例 #14
0
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);
}
コード例 #15
0
/**
 * 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;
}
コード例 #16
0
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);
    }
}
コード例 #17
0
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;
}
コード例 #18
0
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;
}
コード例 #19
0
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);
}
コード例 #20
0
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);
}
コード例 #21
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;
}
コード例 #22
0
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;
}
コード例 #23
0
/*
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;
}
コード例 #24
0
/**
 * 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;
}
コード例 #25
0
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;
}
コード例 #26
0
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);
}
コード例 #27
0
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;
    }
}
コード例 #28
0
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;
}
コード例 #29
0
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;
    }
}
コード例 #30
0
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);
}