static void
ngx_tcp_websocket_init_protocol(ngx_event_t *ev) 
{
    ngx_connection_t             *c;
    ngx_tcp_session_t            *s;
    ngx_tcp_websocket_ctx_t      *wctx;

    c = ev->data;
    s = c->data;

    wctx = ngx_tcp_get_module_ctx(s, ngx_tcp_websocket_module);

    wctx->parser = ngx_pcalloc(s->connection->pool,
                               sizeof(http_request_parser));
    if (wctx->parser == NULL) {
        ngx_tcp_finalize_session(s);
        return;
    }

    websocket_http_request_parser_init(wctx->parser, s);

    c->read->handler = ngx_tcp_websocket_parse_protocol;

    ngx_tcp_websocket_parse_protocol(ev);
}
static void 
http_field(void *data, const signed char *field, 
    size_t flen, const signed char *value, size_t vlen)
{
    u_char                    *last;
    ngx_str_t                 *str;
    ngx_tcp_session_t         *s = data;
    ngx_tcp_websocket_ctx_t   *wctx;

    wctx = ngx_tcp_get_module_ctx(s, ngx_tcp_websocket_module);

#if (NGX_DEBUG)
    ngx_str_t             str_field, str_value;

    str_field.data = (u_char *) field;
    str_field.len = flen;

    str_value.data = (u_char *) value;
    str_value.len = vlen;

    ngx_log_debug2(NGX_LOG_DEBUG_TCP, s->connection->log, 0, 
                   "%V: %V", &str_field, &str_value);
#endif

    if ((flen == (sizeof("Host") - 1)) && 
            (ngx_strncasecmp((u_char *)"Host", (u_char *)field, flen) == 0)) {

        /*trim the port part from host string*/
        last = ngx_strlchr((u_char *)value,
                           (u_char *)value + vlen, (u_char)':');
        if (last) {
            vlen = last - (u_char *)value;
        }

        str = &wctx->host;

        str->len = vlen;
        str->data = ngx_palloc(s->connection->pool, vlen);
        if (str->data == NULL) {
            return;
        }

        ngx_memcpy(str->data, (u_char *)value, vlen);

        ngx_log_debug1(NGX_LOG_DEBUG_TCP, s->connection->log, 0, 
                       "true host: %V", str);
    }
}
static void 
request_path(void *data, const signed char *at, size_t length)
{
    u_char                    *p, *last;
    ngx_str_t                 *path;
    ngx_tcp_session_t         *s = data;
    ngx_tcp_websocket_ctx_t   *wctx;

    wctx = ngx_tcp_get_module_ctx(s, ngx_tcp_websocket_module);

#if (NGX_DEBUG)
    ngx_str_t          str;

    str.data = (u_char *) at;
    str.len = length;

    ngx_log_debug1(NGX_LOG_DEBUG_TCP, s->connection->log, 0, 
                   "PATH: \"%V\"", &str);
#endif
    if (length == 0) {
        return;
    }

    p = (u_char *)at;
    last = p + length;
    p++;

    while (p != last) {

        if (*p == '/' || *p == '?' || *p == '#') {
            break;
        }

        p++;
    }

    path = &wctx->path;
    path->len = p - (u_char *)at;
    path->data = ngx_palloc(s->connection->pool, path->len); 
    if (path->data == NULL) {
        return;
    }

    ngx_memcpy(path->data, (u_char *) at, path->len);
}
Exemplo n.º 4
0
static void
ngx_tcp_proxy_handler(ngx_event_t *ev) 
{
    char                     *action, *recv_action, *send_action;
    off_t                    *read_bytes, *write_bytes;
    size_t                    size;
    ssize_t                   n;
    ngx_buf_t                *b;
    ngx_err_t                 err;
    ngx_uint_t                do_write, first_read;
    ngx_connection_t         *c, *src, *dst;
    ngx_tcp_session_t        *s;
    ngx_tcp_proxy_conf_t     *pcf;
    ngx_tcp_proxy_ctx_t      *pctx;
    ngx_tcp_core_srv_conf_t  *cscf;

    c = ev->data;
    s = c->data;

    cscf = ngx_tcp_get_module_srv_conf(s, ngx_tcp_core_module);

    if (ev->timedout) {
        c->log->action = "proxying";

        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "proxy timed out");
        c->timedout = 1;

        ngx_tcp_finalize_session(s);
        return;
    }

    pctx = ngx_tcp_get_module_ctx(s, ngx_tcp_proxy_module);

    if (pctx == NULL) {
        ngx_tcp_finalize_session(s);
        return;
    }

    read_bytes = NULL;
    write_bytes = NULL;

    if (c == s->connection) {
        if (ev->write) {
            recv_action = "client write: proxying and reading from upstream";
            send_action = "client write: proxying and sending to client";
            src = pctx->upstream->connection;
            dst = c;
            b = pctx->buffer;
            write_bytes = &s->bytes_write;
        } else {
            recv_action = "client read: proxying and reading from client";
            send_action = "client read: proxying and sending to upstream";
            src = c;
            dst = pctx->upstream->connection;
            b = s->buffer;
            read_bytes = &s->bytes_read;
        }

    } else {
        if (ev->write) {
            recv_action = "upstream write: proxying and reading from client";
            send_action = "upstream write: proxying and sending to upstream";
            src = s->connection;
            dst = c;
            b = s->buffer;
            read_bytes = &s->bytes_read;
        } else {
            recv_action = "upstream read: proxying and reading from upstream";
            send_action = "upstream read: proxying and sending to client";
            src = c;
            dst = s->connection;
            b = pctx->buffer;
            write_bytes = &s->bytes_write;
        }
    }

    do_write = ev->write ? 1 : 0;

#if (NGX_TCP_SSL)
    /* SSL Need this */
    if (s->connection->ssl) {
        first_read = 1;
    }
#else
    first_read = 0;
#endif

    ngx_log_debug4(NGX_LOG_DEBUG_TCP, ev->log, 0,
                   "tcp proxy handler: %d, #%d > #%d, time:%ui",
                   do_write, src->fd, dst->fd, ngx_current_msec);

    for ( ;; ) {

        if (do_write) {

            size = b->last - b->pos;

            if (size && dst->write->ready) {
                c->log->action = send_action;

                n = dst->send(dst, b->pos, size);
                err = ngx_socket_errno;

                ngx_log_debug1(NGX_LOG_DEBUG_TCP, ev->log, 0,
                               "tcp proxy handler send:%d", n);

                if (n == NGX_ERROR) {
                    ngx_log_error(NGX_LOG_ERR, c->log, err, "proxy send error");

                    ngx_tcp_finalize_session(s);
                    return;
                }

                if (n > 0) {
                    b->pos += n;

                    if (write_bytes) {
                        *write_bytes += n;
                    }

                    if (b->pos == b->last) {
                        b->pos = b->start;
                        b->last = b->start;
                    }
                }
            }
        }

        size = b->end - b->last;

        if (size) {
            if (src->read->ready || first_read) { 

                first_read = 0;
                c->log->action = recv_action;

                n = src->recv(src, b->last, size);
                err = ngx_socket_errno;

                ngx_log_debug1(NGX_LOG_DEBUG_TCP, ev->log, 0,
                               "tcp proxy handler recv:%d", n);

                if (n == NGX_AGAIN || n == 0) {
                    break;
                }

                if (n > 0) {
                    do_write = 1;
                    b->last += n;

                    if (read_bytes) {
                        *read_bytes += n;
                    }

                    continue;
                }

                if (n == NGX_ERROR) {
                    src->read->eof = 1;
                }
            }
        }

        break;
    }

    c->log->action = "nginx tcp proxying";

    if ((s->connection->read->eof && s->buffer->pos == s->buffer->last)
            || (pctx->upstream->connection->read->eof
                && pctx->buffer->pos == pctx->buffer->last)
            || (s->connection->read->eof
                && pctx->upstream->connection->read->eof))
    {
        action = c->log->action;
        c->log->action = NULL;
        ngx_log_error(NGX_LOG_DEBUG, c->log, 0, "proxied session done");
        c->log->action = action;

        ngx_tcp_finalize_session(s);
        return;
    }

    if (ngx_handle_write_event(dst->write, 0) != NGX_OK) {
        ngx_tcp_finalize_session(s);
        return;
    }

    if (ngx_handle_read_event(dst->read, 0) != NGX_OK) {
        ngx_tcp_finalize_session(s);
        return;
    }

    if (ngx_handle_write_event(src->write, 0) != NGX_OK) {
        ngx_tcp_finalize_session(s);
        return;
    }

    if (ngx_handle_read_event(src->read, 0) != NGX_OK) {
        ngx_tcp_finalize_session(s);
        return;
    }

    pcf = ngx_tcp_get_module_srv_conf(s, ngx_tcp_proxy_module);

    if (c == s->connection) {
        ngx_add_timer(c->read, cscf->timeout);
    }

    if (c == pctx->upstream->connection) {
        if (ev->write) {
            ngx_add_timer(c->write, pcf->upstream.send_timeout);
        } else {
            ngx_add_timer(c->read, pcf->upstream.read_timeout);
        }
    }

    return;
}
Exemplo n.º 5
0
static void 
ngx_tcp_upstream_init_proxy_handler(ngx_tcp_session_t *s, ngx_tcp_upstream_t *u)
{
    ngx_connection_t         *c;
    ngx_tcp_proxy_ctx_t      *pctx;
    ngx_tcp_proxy_conf_t     *pcf;

    c = s->connection;
    c->log->action = "ngx_tcp_upstream_init_proxy_handler";

    ngx_log_debug0(NGX_LOG_DEBUG_TCP, s->connection->log, 0,
                   "tcp proxy upstream init proxy");

    pcf = ngx_tcp_get_module_srv_conf(s, ngx_tcp_proxy_module);

    pctx = ngx_tcp_get_module_ctx(s, ngx_tcp_proxy_module);

    if (pcf == NULL || pctx == NULL) {
        ngx_tcp_finalize_session(s);
        return;
    }

    pctx->upstream = &s->upstream->peer;

    c = pctx->upstream->connection;
    if (c->read->timedout || c->write->timedout) {
        ngx_tcp_upstream_next(s, u, NGX_TCP_UPSTREAM_FT_TIMEOUT);
        return;
    }

    if (ngx_tcp_upstream_check_broken_connection(s) != NGX_OK){
        ngx_tcp_upstream_next(s, u, NGX_TCP_UPSTREAM_FT_ERROR);
        return;
    }

    s->connection->read->handler = ngx_tcp_proxy_handler;
    s->connection->write->handler = ngx_tcp_proxy_handler;

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

    ngx_add_timer(c->read, pcf->upstream.read_timeout);
    ngx_add_timer(c->write, pcf->upstream.send_timeout);

    if (ngx_handle_read_event(s->connection->read, 0) != NGX_OK) {
        ngx_tcp_finalize_session(s);
        return;
    }

#if (NGX_TCP_SSL)

    /* 
     * The ssl connection with client may not trigger the read event again,
     * So I trigger it in this function.
     * */
    if (s->connection->ssl) {
        ngx_tcp_proxy_handler(s->connection->read); 
    }

#endif

    return;
}
ngx_int_t
ngx_tcp_lua_process_by_chunk(lua_State *L, ngx_tcp_session_t *s)
{
    int                      cc_ref;
    lua_State               *cc;
    ngx_tcp_lua_ctx_t      *ctx;
    ngx_tcp_cleanup_t      *cln;

    dd("content by chunk");

    ctx = ngx_tcp_get_module_ctx(s, ngx_tcp_lua_module);

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

        dd("setting new ctx, ctx = %p", ctx);

        ctx->cc_ref  = LUA_NOREF;
        ctx->ctx_ref = LUA_NOREF;
		ctx->exited  = 0;

        ngx_tcp_set_ctx(s, ctx, ngx_tcp_lua_module);

    } else {
        dd("reset ctx");
        ngx_tcp_lua_reset_ctx(s, L, ctx);
    }

    /*  {{{ new coroutine to handle request */
    cc = ngx_tcp_lua_new_thread(s, L, &cc_ref);

    if (cc == NULL) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                "(lua-content-by-chunk) failed to create new coroutine "
                "to handle request");

        return NGX_ERROR;
    }

    /*  move code closure to new coroutine */
    lua_xmove(L, cc, 1);

    /*  set closure's env table to new coroutine's globals table */
    lua_pushvalue(cc, LUA_GLOBALSINDEX);
    lua_setfenv(cc, -2);

    /*  save nginx request in coroutine globals table */
    lua_pushlightuserdata(cc, &ngx_tcp_lua_request_key);
    lua_pushlightuserdata(cc, s);
    lua_rawset(cc, LUA_GLOBALSINDEX);
    /*  }}} */

    ctx->co = cc;
    ctx->cc_ref = cc_ref;

    /*  {{{ register request cleanup hooks */
    if (ctx->cleanup == NULL) {
        cln = ngx_tcp_cleanup_add(s, 0);
        if (cln == NULL) {
            return NGX_ERROR;
        }

        cln->handler = ngx_tcp_lua_request_cleanup;
        cln->data = s;
        ctx->cleanup = &cln->handler;
    }
    /*  }}} */

    return ngx_tcp_lua_run_thread(L, s, ctx, 0);

}
static void 
ngx_tcp_upstream_websocket_proxy_init_handler(ngx_tcp_session_t *s,
    ngx_tcp_upstream_t *u)
{
    ngx_connection_t             *c;
    ngx_tcp_websocket_ctx_t      *wctx;
    ngx_tcp_websocket_conf_t     *wcf;

    c = s->connection;
    c->log->action = "ngx_tcp_upstream_websocket_proxy_init_handler";

    ngx_log_debug0(NGX_LOG_DEBUG_TCP, s->connection->log, 
                   0, "tcp upstream websocket proxy init handler");

    wcf = ngx_tcp_get_module_srv_conf(s, ngx_tcp_websocket_module);

    wctx = ngx_tcp_get_module_ctx(s, ngx_tcp_websocket_module);

    if (wcf == NULL || wctx == NULL) {
        ngx_tcp_finalize_session(s);
        return;
    }

    wctx->upstream = &s->upstream->peer;

    c = wctx->upstream->connection;
    if (c->read->timedout || c->write->timedout) {
        ngx_tcp_upstream_next(s, u, NGX_TCP_UPSTREAM_FT_TIMEOUT);
        return;
    }

    if (ngx_tcp_upstream_check_broken_connection(s) != NGX_OK){
        ngx_tcp_upstream_next(s, u, NGX_TCP_UPSTREAM_FT_ERROR);
        return;
    }

    s->connection->read->handler = ngx_tcp_websocket_proxy_handler;
    s->connection->write->handler = ngx_tcp_websocket_proxy_handler;

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

    ngx_add_timer(c->read, wcf->upstream.read_timeout);
    ngx_add_timer(c->write, wcf->upstream.send_timeout);

#if (NGX_TCP_SSL)

    if (s->connection->ssl) {
        ngx_tcp_websocket_proxy_handler(s->connection->read); 
        return;
    }

#endif

    if (ngx_handle_read_event(s->connection->read, 0) != NGX_OK) {
        ngx_tcp_finalize_session(s);
        return;
    }

    ngx_tcp_websocket_proxy_handler(s->connection->read);

    return;
}
static  void
ngx_tcp_websocket_init_upstream(ngx_connection_t *c, ngx_tcp_session_t *s) 
{
    ngx_tcp_upstream_t           *u;
    ngx_tcp_path_upstream_t      *pu;     
    ngx_tcp_upstream_conf_t      *ucf;
    ngx_tcp_websocket_ctx_t      *wctx;
    ngx_tcp_websocket_conf_t     *wcf;
    ngx_tcp_virtual_server_t     *vs;

    s->connection->log->action = "ngx_tcp_websocket_init_upstream";

    wctx = ngx_tcp_get_module_ctx(s, ngx_tcp_websocket_module);

    vs = ngx_tcp_websocket_find_virtual_server(s, wctx);

    if (vs) {
        s->main_conf = vs->ctx->main_conf;
        s->srv_conf = vs->ctx->srv_conf;
    }

    wcf = ngx_tcp_get_module_srv_conf(s, ngx_tcp_websocket_module);
    if (wcf->upstream.upstream == NULL) {
        ngx_tcp_finalize_session(s);
        return;
    }

    ngx_log_debug3(NGX_LOG_DEBUG_TCP, s->connection->log, 0, 
                   "tcp websocket init upstream, scheme: \"%V\" "
                   "path: \"%V\", host: \"%V\"",
                   &wcf->scheme, &wctx->path, &wctx->host);

    c->write->handler = ngx_tcp_websocket_dummy_write_handler;
    c->read->handler = ngx_tcp_websocket_dummy_read_handler;

    if (ngx_tcp_upstream_create(s) != NGX_OK) {
        ngx_tcp_finalize_session(s);
        return;
    }

    u = s->upstream;

    u->conf = &wcf->upstream;

    pu = ngx_tcp_websocket_find_path_upstream(s, wctx);

    if (pu) {
        ucf = ngx_palloc(s->pool, sizeof(ngx_tcp_upstream_conf_t));
        if (ucf == NULL) {
            ngx_tcp_finalize_session(s);
            return;
        }

        ngx_memcpy(ucf, &wcf->upstream, sizeof(ngx_tcp_upstream_conf_t));

        ucf->upstream = pu->upstream;

        u->conf = ucf;
    }

    u->write_event_handler = ngx_tcp_upstream_websocket_proxy_init_handler;
    u->read_event_handler = ngx_tcp_upstream_websocket_proxy_init_handler;

    wctx->upstream = &u->peer;

    wctx->buffer = ngx_create_temp_buf(s->connection->pool, 
                                       (s->buffer->end - s->buffer->start));
    if (wctx->buffer == NULL) {
        ngx_tcp_finalize_session(s);
        return;
    }

    /* move back to the start position, send the handshake 
     * packet to backend server */
    s->buffer->pos = s->buffer->start;
    s->connection->read->ready = 1;

    ngx_tcp_upstream_init(s);

    return;
}
static void 
ngx_tcp_websocket_parse_protocol(ngx_event_t *ev)
{
    u_char                       *new_buf;
    ssize_t                       size, n;
    ngx_int_t                     rc;
    ngx_connection_t             *c;
    ngx_tcp_session_t            *s;
    ngx_tcp_websocket_ctx_t      *wctx;
    ngx_tcp_websocket_conf_t     *wcf;

    c = ev->data;
    s = c->data;

    wcf = ngx_tcp_get_module_srv_conf(s, ngx_tcp_websocket_module);

    wctx = ngx_tcp_get_module_ctx(s, ngx_tcp_websocket_module);

    while (1) {
        n = s->buffer->end - s->buffer->last;
        /*Not enough buffer? Enlarge twice*/
        if (n == 0) {
            size = s->buffer->end - s->buffer->start;

            if ((size_t)size > wcf->buffer_size << 3) {

                ngx_log_error(NGX_LOG_ERR, ev->log, 0,
                              "too large websocket handshake packet "
                              "error with client: %V #%d",
                              &c->addr_text, c->fd);

                ngx_tcp_finalize_session(s);
                return;
            }

            new_buf = ngx_palloc(c->pool, size * 2);
            if (new_buf == NULL) {
                goto websocket_recv_fail;
            }

            ngx_memcpy(new_buf, s->buffer->start, size);
            
            n = s->buffer->pos - s->buffer->start;
            s->buffer->start = new_buf;
            s->buffer->pos = new_buf + n;
            s->buffer->last = new_buf + size;
            s->buffer->end = new_buf + size * 2;

            n = s->buffer->end - s->buffer->last;
        }

        size = c->recv(c, s->buffer->last, n);

#if (NGX_DEBUG)
        ngx_err_t                      err;

        if (size >= 0 || size == NGX_AGAIN) {
            err = 0;

        } else {
            err = ngx_socket_errno;

        }

        ngx_log_debug3(NGX_LOG_DEBUG_TCP, ev->log, err,
                       "tcp websocket recv size: %d, client: %V #%d",
                       size, &c->addr_text, c->fd);
#endif

        if (size > 0) {
            s->buffer->last += size;
            continue;

        } else if (size == 0 || size == NGX_AGAIN) {
            break;

        } else {
            c->error = 1;
            goto websocket_recv_fail;
        }
    }

    rc = websocket_http_request_parser_execute(wctx->parser);

    ngx_log_debug2(NGX_LOG_DEBUG_TCP, c->log, 0, 
                   "tcp websocket parse rc: %d, fd: %d", rc, c->fd);

    switch (rc) {

    case NGX_AGAIN:
        return;

    case NGX_ERROR:
        goto websocket_recv_fail;

    case NGX_OK:
        /* pass through */

    default:
        ngx_tcp_websocket_init_upstream(c, s);
    }

    return;

websocket_recv_fail:

    ngx_log_error(NGX_LOG_ERR, ev->log, 0,
                  "recv websocket handshake packet error with client: %V #%d",
                  &c->addr_text, c->fd);

    ngx_tcp_finalize_session(s);
}
static void
ngx_squ_tcp_request_read_handler(ngx_event_t *rev)
{
    char               *errstr;
    ssize_t             n;
    ngx_int_t           rc;
    ngx_buf_t          *b;
    ngx_connection_t   *c;
    ngx_squ_thread_t   *thr;
    ngx_squ_tcp_ctx_t  *ctx;
    ngx_tcp_session_t  *s;

    ngx_log_debug0(NGX_LOG_DEBUG_CORE, rev->log, 0,
                   "squ tcp request read handler");

    c = rev->data;
    s = c->data;

    thr = ngx_tcp_get_module_ctx(s, ngx_squ_tcp_module);

    ctx = thr->module_ctx;
    b = s->buffer;
    errstr = NULL;

    if (rev->timedout) {
        ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT,
                      "squ tcp request read %V timed out", &c->addr_text);
        errstr = "ngx_squ_tcp_request_read_handler() timed out";
        n = NGX_ERROR;
        goto done;
    }

    if (rev->timer_set) {
        ngx_del_timer(rev);
    }

    while (1) {

        n = ngx_recv(c, b->last, b->end - b->last);

        if (n > 0) {
            b->last += n;
            break;
        }

        if (n == NGX_AGAIN) {
            /* TODO */
            ngx_add_timer(rev, 60000);

            if (ngx_handle_read_event(rev, 0) != NGX_OK) {
                errstr = "ngx_handle_read_event() failed";
                n = NGX_ERROR;
                goto done;
            }

            ctx->rc = NGX_AGAIN;
            return;
        }

        /* n == NGX_ERROR || n == 0 */

        break;
    }

done:

    rev->handler = ngx_squ_tcp_request_dummy_handler;

    ctx->rc = 1;

    if (n > 0) {
        sq_pushstring(thr->v, (SQChar *) b->pos, n);

    } else {
        sq_pushbool(thr->v, SQFalse);

#if 0
        if (errstr != NULL) {
            sq_pushstring(thr->v, errstr, -1);

            ctx->rc++;
        }
#endif
    }

    if (ctx->not_event) {
        return;
    }

    rc = ngx_squ_thread_run(thr, ctx->rc);
    if (rc == NGX_AGAIN) {
        return;
    }

    ngx_squ_finalize(thr, rc);
}