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