diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index dbe9adfe46..cfe6953fd6 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -210,6 +210,15 @@ typedef struct { ngx_flag_t transform_underscores_in_resp_headers; ngx_flag_t log_socket_errors; ngx_flag_t check_client_abort; + +#if (NGX_HTTP_SSL) + ngx_ssl_t *ssl; + ngx_flag_t ssl_verify; + ngx_uint_t ssl_verify_depth; + ngx_str_t ssl_trusted_certificate; + ngx_str_t ssl_crl; +#endif + ngx_flag_t use_default_type; } ngx_http_lua_loc_conf_t; diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 4e348675ab..e551d0f67e 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -34,6 +34,8 @@ static char *ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf); static void *ngx_http_lua_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); +static ngx_int_t ngx_http_lua_set_ssl(ngx_conf_t *cf, + ngx_http_lua_loc_conf_t *plcf); static ngx_int_t ngx_http_lua_init(ngx_conf_t *cf); static char *ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data); @@ -343,6 +345,38 @@ static ngx_command_t ngx_http_lua_cmds[] = { offsetof(ngx_http_lua_loc_conf_t, check_client_abort), NULL }, +#if (NGX_HTTP_SSL) + + { ngx_string("lua_ssl_verify"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_lua_loc_conf_t, ssl_verify), + NULL }, + + { ngx_string("lua_ssl_verify_depth"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_lua_loc_conf_t, ssl_verify_depth), + NULL }, + + { ngx_string("lua_ssl_trusted_certificate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_lua_loc_conf_t, ssl_trusted_certificate), + NULL }, + + { ngx_string("lua_ssl_crl"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_lua_loc_conf_t, ssl_crl), + NULL }, + +#endif + { ngx_string("lua_use_default_type"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_FLAG, @@ -635,6 +669,8 @@ ngx_http_lua_create_loc_conf(ngx_conf_t *cf) * conf->body_filter_src = {{ 0, NULL }, NULL, NULL, NULL}; * conf->body_filter_src_key = NULL * conf->body_filter_handler = NULL; + * + * conf->ssl_trusted_certificate = NULL; */ conf->force_read_body = NGX_CONF_UNSET; @@ -654,7 +690,13 @@ ngx_http_lua_create_loc_conf(ngx_conf_t *cf) conf->transform_underscores_in_resp_headers = NGX_CONF_UNSET; conf->log_socket_errors = NGX_CONF_UNSET; - +#if (NGX_HTTP_SSL) + + conf->ssl_verify = NGX_CONF_UNSET; + conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; + +#endif + return conf; } @@ -733,7 +775,86 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->log_socket_errors, prev->log_socket_errors, 1); +#if (NGX_HTTP_SSL) + + if (ngx_http_lua_set_ssl(cf, conf) != NGX_OK) { + return NGX_CONF_ERROR; + } + + ngx_conf_merge_value(conf->ssl_verify, + prev->ssl_verify, 0); + ngx_conf_merge_uint_value(conf->ssl_verify_depth, + prev->ssl_verify_depth, 1); + ngx_conf_merge_str_value(conf->ssl_trusted_certificate, + prev->ssl_trusted_certificate, ""); + ngx_conf_merge_str_value(conf->ssl_crl, + prev->ssl_crl, ""); + + /* TODO: Maybe the verification should be an option for the + tcpsock:connect() method. */ + if (conf->ssl_verify) { + if (conf->ssl_trusted_certificate.len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "no \"lua_ssl_trusted_certificate\" is " + " defined for the \"lua_ssl_verify\" " + "directive"); + + return NGX_CONF_ERROR; + } + + if (ngx_ssl_trusted_certificate(cf, conf->ssl, + &conf->ssl_trusted_certificate, + conf->ssl_verify_depth) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + if (ngx_ssl_crl(cf, conf->ssl, &conf->ssl_crl) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + +#endif + return NGX_CONF_OK; } + +#if (NGX_HTTP_SSL) + +static ngx_int_t +ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *plcf) +{ + ngx_pool_cleanup_t *cln; + + plcf->ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); + if (plcf->ssl == NULL) { + return NGX_ERROR; + } + + plcf->ssl->log = cf->log; + + if (ngx_ssl_create(plcf->ssl, + NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1 + |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2, + NULL) + != NGX_OK) + { + return NGX_ERROR; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_ssl_cleanup_ctx; + cln->data = plcf->ssl; + + return NGX_OK; +} + +#endif + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 0dcd9e87e9..a3a1b60fcd 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -28,13 +28,14 @@ static int ngx_http_lua_socket_tcp_connect(lua_State *L); static int ngx_http_lua_socket_tcp_receive(lua_State *L); static int ngx_http_lua_socket_tcp_send(lua_State *L); static int ngx_http_lua_socket_tcp_close(lua_State *L); +static int ngx_http_lua_socket_tcp_fake_close(lua_State *L); static int ngx_http_lua_socket_tcp_setoption(lua_State *L); static int ngx_http_lua_socket_tcp_settimeout(lua_State *L); +static int ngx_http_lua_socket_tcp_set_receive_timeout(lua_State *L); +static int ngx_http_lua_socket_tcp_set_send_timeout(lua_State *L); static void ngx_http_lua_socket_tcp_handler(ngx_event_t *ev); static ngx_int_t ngx_http_lua_socket_tcp_get_peer(ngx_peer_connection_t *pc, void *data); -static void ngx_http_lua_socket_read_handler(ngx_http_request_t *r, - ngx_http_lua_socket_tcp_upstream_t *u); static void ngx_http_lua_socket_send_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); static void ngx_http_lua_socket_connected_handler(ngx_http_request_t *r, @@ -49,8 +50,16 @@ static ngx_int_t ngx_http_lua_socket_test_connect(ngx_http_request_t *r, ngx_connection_t *c); static void ngx_http_lua_socket_handle_error(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, ngx_uint_t ft_type); +static void ngx_http_lua_socket_handle_read_error(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, ngx_uint_t ft_type); +static void ngx_http_lua_socket_handle_write_error(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, ngx_uint_t ft_type); static void ngx_http_lua_socket_handle_success(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); +static void ngx_http_lua_socket_handle_read_success(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u); +static void ngx_http_lua_socket_handle_write_success(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u); static int ngx_http_lua_socket_tcp_send_retval_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); static int ngx_http_lua_socket_tcp_connect_retval_handler(ngx_http_request_t *r, @@ -72,6 +81,7 @@ static int ngx_http_lua_socket_error_retval_handler(ngx_http_request_t *r, static ngx_int_t ngx_http_lua_socket_read_all(void *data, ssize_t bytes); static ngx_int_t ngx_http_lua_socket_read_until(void *data, ssize_t bytes); static ngx_int_t ngx_http_lua_socket_read_chunk(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_socket_read_exact_chunk(void *data, ssize_t bytes); static int ngx_http_lua_socket_tcp_receiveuntil(lua_State *L); static int ngx_http_lua_socket_receiveuntil_iterator(lua_State *L); static ngx_int_t ngx_http_lua_socket_compile_pattern(u_char *data, size_t len, @@ -106,6 +116,23 @@ static void ngx_http_lua_tcp_resolve_cleanup(void *data); static void ngx_http_lua_tcp_socket_cleanup(void *data); +#if (NGX_HTTP_SSL) + +static int ngx_http_lua_socket_ssl_handshake_ended(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); +static void ngx_http_lua_socket_ssl_handshake(ngx_connection_t *c); +static ngx_int_t ngx_http_lua_socket_ssl_init_connection(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); + +/* TODO: When these functions are either built-in Nginx's OpenSSL module or + in the OpenSSL library itself, we should remove the following functions. + */ +static ngx_int_t ngx_http_lua_ssl_verify_name(X509 *cert, ngx_str_t *name); +static int ngx_http_lua_ssl_host_wildcard_match(ASN1_STRING *pattern, + ngx_str_t *hostname); + +#endif + enum { SOCKET_CTX_INDEX = 1, SOCKET_TIMEOUT_INDEX = 2, @@ -160,6 +187,12 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_http_lua_socket_tcp_settimeout); lua_setfield(L, -2, "settimeout"); /* ngx socket mt */ + lua_pushcfunction(L, ngx_http_lua_socket_tcp_set_receive_timeout); + lua_setfield(L, -2, "set_receive_timeout"); /* ngx socket mt */ + + lua_pushcfunction(L, ngx_http_lua_socket_tcp_fake_close); + lua_setfield(L, -2, "fake_close"); + lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); @@ -182,6 +215,15 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_http_lua_socket_tcp_settimeout); lua_setfield(L, -2, "settimeout"); /* ngx socket mt */ + lua_pushcfunction(L, ngx_http_lua_socket_tcp_set_receive_timeout); + lua_setfield(L, -2, "set_receive_timeout"); /* ngx socket mt */ + + lua_pushcfunction(L, ngx_http_lua_socket_tcp_set_send_timeout); + lua_setfield(L, -2, "set_send_timeout"); /* ngx socket mt */ + + lua_pushcfunction(L, ngx_http_lua_socket_tcp_fake_close); + lua_setfield(L, -2, "fake_close"); + lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); @@ -213,6 +255,12 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_http_lua_socket_tcp_settimeout); lua_setfield(L, -2, "settimeout"); /* ngx socket mt */ + lua_pushcfunction(L, ngx_http_lua_socket_tcp_set_receive_timeout); + lua_setfield(L, -2, "set_receive_timeout"); /* ngx socket mt */ + + lua_pushcfunction(L, ngx_http_lua_socket_tcp_set_send_timeout); + lua_setfield(L, -2, "set_send_timeout"); /* ngx socket mt */ + lua_pushcfunction(L, ngx_http_lua_socket_tcp_getreusedtimes); lua_setfield(L, -2, "getreusedtimes"); @@ -294,6 +342,11 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) const char *msg; ngx_http_lua_co_ctx_t *coctx; +#if (NGX_HTTP_SSL) + ngx_int_t ssl = 0; + ngx_str_t ssl_verify_name = {0, NULL}; +#endif + ngx_http_lua_socket_tcp_upstream_t *u; n = lua_gettop(L); @@ -355,7 +408,6 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) break; case LUA_TNIL: - lua_pop(L, 2); break; default: @@ -365,6 +417,46 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) break; } +#if (NGX_HTTP_SSL) + + lua_getfield(L, n, "ssl"); + + if (lua_type(L, -1) != LUA_TBOOLEAN) { + msg = lua_pushfstring(L, "bad \"ssl\" option type: %s", + luaL_typename(L, -1)); + return luaL_argerror(L, n, msg); + } + + ssl = lua_toboolean(L, -1); + lua_pop(L, 1); + + + /* TODO: Maybe if this is passed as true, used the host. + */ + lua_getfield(L, n, "ssl_verify_name"); + + p = (u_char *) lua_tolstring(L, -1, &len); + + if (p != NULL) { + ssl_verify_name.data = ngx_palloc(r->pool, len + 1); + + if (ssl_verify_name.data == NULL) { + return luaL_error(L, "out of memory"); + } + + ngx_memcpy(ssl_verify_name.data, p, len); + ssl_verify_name.data[len] = '\0'; + ssl_verify_name.len = len; + } + + lua_pop(L, 1); + +#endif + + if (!custom_pool) { + lua_pop(L, 2); + } + n--; } @@ -400,6 +492,8 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) u = lua_touserdata(L, -1); lua_pop(L, 1); + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + if (u) { if (u->waiting) { lua_pushnil(L); @@ -439,12 +533,23 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) ngx_memzero(u, sizeof(ngx_http_lua_socket_tcp_upstream_t)); +#if (NGX_HTTP_SSL) + + if (llcf->ssl) { + u->ssl = ssl; + + if (ssl && ssl_verify_name.data) { + u->ssl_verify_name.data = ssl_verify_name.data; + u->ssl_verify_name.len = ssl_verify_name.len; + } + } + +#endif + coctx = ctx->cur_co_ctx; u->request = r; /* set the controlling request */ - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - u->conf = llcf; pc = &u->peer; @@ -563,7 +668,8 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) rctx->timeout = clcf->resolver_timeout; u->resolved->ctx = rctx; - u->co_ctx = ctx->cur_co_ctx; + /* For connect and resolve, use co_ctx_read. */ + u->co_ctx_read = ctx->cur_co_ctx; coctx->data = u; @@ -647,9 +753,9 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) return; } - lctx->cur_co_ctx = u->co_ctx; + lctx->cur_co_ctx = u->co_ctx_read; - u->co_ctx->cleanup = NULL; + u->co_ctx_read->cleanup = NULL; L = lctx->cur_co_ctx->co; @@ -827,6 +933,245 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) } +#if (NGX_HTTP_SSL) +static ngx_int_t +ngx_http_lua_socket_ssl_init_connection(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) +{ + ngx_connection_t *c; + ngx_int_t rc; + + c = u->peer.connection; + + if (ngx_ssl_create_connection(u->conf->ssl, c, + NGX_SSL_BUFFER|NGX_SSL_CLIENT) + != NGX_OK) + { + return luaL_error(L, "error creating ssl session"); + } + /* TODO: Add SSL session reuse here. */ + + rc = ngx_ssl_handshake(c); + + if (rc == NGX_AGAIN) { + c->ssl->handler = ngx_http_lua_socket_ssl_handshake; + u->prepare_retvals = ngx_http_lua_socket_ssl_handshake_ended; + return NGX_AGAIN; + } + + return ngx_http_lua_socket_ssl_handshake_ended(r, u, L); +} + + +static void +ngx_http_lua_socket_ssl_handshake(ngx_connection_t *c) +{ + ngx_http_request_t *r; + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_ctx_t *ctx; + + u = c->data; + r = u->request; + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (ctx == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "ngx_lua ctx not found"); + return; + } + + c->write->handler = ngx_http_lua_socket_tcp_handler; + c->read->handler = ngx_http_lua_socket_tcp_handler; + + ctx->resume_handler = ngx_http_lua_socket_tcp_resume; + r->write_event_handler(r); + ngx_http_run_posted_requests(r->connection); +} + + +static int +ngx_http_lua_socket_ssl_handshake_ended(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) +{ + ngx_connection_t *c; + ngx_http_lua_loc_conf_t *llcf; + X509 *cert; + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + c = u->peer.connection; + + if (!c->ssl->handshaked) { + lua_pushnil(L); + if (c->read->timedout) { + lua_pushliteral(L, "SSL handshake timed out"); + } else { + lua_pushliteral(L, "SSL handshake failed"); + } + ngx_close_connection(u->peer.connection); + u->peer.connection = NULL; + return 2; + } + + if (llcf->ssl_verify) { + if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) { + lua_pushnil(L); + lua_pushliteral(L, "SSL certificate verification failed"); + return 2; + } + + cert = SSL_get_peer_certificate(c->ssl->connection); + if (cert == NULL) { + lua_pushnil(L); + lua_pushliteral(L, "SSL server did not return certificate"); + return 2; + } + + if (u->ssl_verify_name.data + && ngx_http_lua_ssl_verify_name(cert, &u->ssl_verify_name) != NGX_OK) + { + X509_free(cert); + lua_pushnil(L); + lua_pushliteral(L, "SSL certificate name validation error"); + return 2; + } + + X509_free(cert); + } + + c->log->action = "SSL connection transaction"; + lua_pushinteger(L, 1); + return 1; +} + +static int +ngx_http_lua_ssl_host_wildcard_match(ASN1_STRING *pattern, + ngx_str_t *hostname) +{ + int n; + u_char *p; + u_char *wp; + + /* sanity check */ + if (!pattern + || pattern->length <= 0 + || !hostname + || !hostname->len) + { + return 0; + } + + /* trivial case */ + if (ngx_strncasecmp((u_char *) pattern->data, + hostname->data, + hostname->len) + == 0) + { + return 1; + } + + /* simple wildcard matching - only in the beginning of the string. */ + if (pattern->length > 2 + && pattern->data[0] == '*' + && pattern->data[1] == '.') + { + + wp = (u_char *) (pattern->data + 1); + + p = ngx_strlchr(hostname->data, + hostname->data + hostname->len, + '.'); + + /* + * If the pattern begings with "*." and the hostname consists of + * a top level domain, compare the pattern to the top level domain. + */ + if (p != NULL) { + n = hostname->len - (int) (p - hostname->data); + + if (n == pattern->length - 1 + && ngx_strncasecmp(wp, + p, + pattern->length - 1) + == 0) + { + return 1; + } + } + } + + return 0; +} + + +static ngx_int_t +ngx_http_lua_ssl_verify_name(X509 *cert, ngx_str_t *name) +{ + X509_NAME_ENTRY *ne; + GENERAL_NAMES *gens; + GENERAL_NAME *gen; + ASN1_STRING *cstr; + X509_NAME *sn; + int rc; + int i; + + /* based on OpenSSL's do_x509_check */ + + gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); + + if (gens) { + + rc = 0; + + for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { + + gen = sk_GENERAL_NAME_value(gens, i); + + /* we only check for name */ + switch (gen->type) { + + case GEN_DNS: + cstr = gen->d.dNSName; + rc = ngx_http_lua_ssl_host_wildcard_match(cstr, + name); + break; + + default: + cstr = NULL; + rc = 0; + } + + if (rc) { + break; + } + + } + + GENERAL_NAMES_free(gens); + + if (rc) { + return NGX_OK; + } + } + + sn = X509_get_subject_name(cert); + i = X509_NAME_get_index_by_NID(sn, NID_commonName, -1); + while (i >= 0) { + ne = X509_NAME_get_entry(sn, i); + cstr = X509_NAME_ENTRY_get_data(ne); + + if (ngx_http_lua_ssl_host_wildcard_match(cstr, name)) { + return NGX_OK; + } + + i = X509_NAME_get_index_by_NID(sn, NID_commonName, i); + } + + return NGX_ERROR; +} +#endif + + static int ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) @@ -959,13 +1304,21 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, ngx_http_lua_socket_handle_error(r, u, NGX_HTTP_LUA_SOCKET_FT_ERROR); lua_pushnil(L); - lua_pushliteral(L, "failed to handle write event"); + lua_pushliteral(L, "failed to handle read event"); return 2; } u->read_event_handler = ngx_http_lua_socket_dummy_handler; u->write_event_handler = ngx_http_lua_socket_dummy_handler; +#if (NGX_HTTP_SSL) + + if (u->ssl) { + return ngx_http_lua_socket_ssl_init_connection(r, u, L); + } + +#endif + lua_pushinteger(L, 1); return 1; } @@ -983,7 +1336,8 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, r->write_event_handler = ngx_http_core_run_phases; } - u->co_ctx = ctx->cur_co_ctx; + /* For connect and resolve, use co_ctx_read. */ + u->co_ctx_read = ctx->cur_co_ctx; u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_tcp_connect_retval_handler; @@ -1011,8 +1365,12 @@ ngx_http_lua_socket_error_retval_handler(ngx_http_request_t *r, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket error retval handler"); - if (u->co_ctx) { - u->co_ctx->cleanup = NULL; + if (u->co_ctx_read) { + u->co_ctx_read->cleanup = NULL; + } + + if (u->co_ctx_write) { + u->co_ctx_write->cleanup = NULL; } ft_type = u->ft_type; @@ -1075,6 +1433,14 @@ ngx_http_lua_socket_tcp_connect_retval_handler(ngx_http_request_t *r, return ngx_http_lua_socket_error_retval_handler(r, u, L); } +#if (NGX_HTTP_SSL) + + if (u->ssl) { + return ngx_http_lua_socket_ssl_init_connection(r, u, L); + } + +#endif + lua_pushinteger(L, 1); return 1; } @@ -1094,10 +1460,11 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) int typ; ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_co_ctx_t *coctx; + int bsd_read; n = lua_gettop(L); - if (n != 1 && n != 2) { - return luaL_error(L, "expecting 1 or 2 arguments " + if (n != 1 && n != 2 && n != 3) { + return luaL_error(L, "expecting 1, 2 or 3 arguments " "(including the object), but got %d", n); } @@ -1131,9 +1498,9 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) return 2; } - if (u->waiting) { + if (u->waiting_read) { lua_pushnil(L); - lua_pushliteral(L, "socket busy"); + lua_pushliteral(L, "socket already busy reading"); return 2; } @@ -1190,7 +1557,37 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) } #endif - u->input_filter = ngx_http_lua_socket_read_chunk; + bsd_read = 0; + + /* Check if the options table is given. */ + if (n == 3) { + luaL_checktype(L, 3, LUA_TTABLE); + lua_getfield(L, 3, "bsd_read"); + + switch (lua_type(L, -1)) { + case LUA_TNIL: + /* use default value - false */ + break; + + case LUA_TBOOLEAN: + bsd_read = lua_toboolean(L, -1); + break; + + default: + return luaL_error(L, "bad \"bsd_read\" option value type: %s", + luaL_typename(L, -1)); + + } + + lua_pop(L, 1); + } + + if (bsd_read) { + u->input_filter = ngx_http_lua_socket_read_exact_chunk; + } else { + u->input_filter = ngx_http_lua_socket_read_chunk; + } + u->length = (size_t) bytes; u->rest = u->length; @@ -1233,7 +1630,7 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) r->read_event_handler = ngx_http_lua_req_socket_rev_handler; } - u->waiting = 0; + u->waiting_read = 0; rc = ngx_http_lua_socket_tcp_read(r, u); @@ -1255,7 +1652,6 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) /* rc == NGX_AGAIN */ u->read_event_handler = ngx_http_lua_socket_read_handler; - u->write_event_handler = ngx_http_lua_socket_dummy_handler; ctx->cur_co_ctx->cleanup = ngx_http_lua_tcp_socket_cleanup; @@ -1266,8 +1662,8 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) r->write_event_handler = ngx_http_core_run_phases; } - u->co_ctx = ctx->cur_co_ctx; - u->waiting = 1; + u->co_ctx_read = ctx->cur_co_ctx; + u->waiting_read = 1; u->prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; coctx = ctx->cur_co_ctx; @@ -1325,6 +1721,48 @@ ngx_http_lua_socket_read_chunk(void *data, ssize_t bytes) } +static ngx_int_t +ngx_http_lua_socket_read_exact_chunk(void *data, ssize_t bytes) +{ + ngx_http_lua_socket_tcp_upstream_t *u = data; + + ngx_buf_t *b; +#if (NGX_DEBUG) + ngx_http_request_t *r; + + r = u->request; +#endif + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket read max chunk %z", bytes); + + if (bytes == 0) { + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; + return NGX_ERROR; + } + + b = &u->buffer; + + if (bytes >= (ssize_t) u->rest) { + + u->buf_in->buf->last += u->rest; + b->pos += u->rest; + u->rest = 0; + + return NGX_OK; + } + + /* bytes < u->rest */ + + u->buf_in->buf->last += bytes; + b->pos += bytes; + + u->rest = 0; + + return NGX_OK; +} + + static ngx_int_t ngx_http_lua_socket_read_all(void *data, ssize_t bytes) { @@ -1445,7 +1883,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, rev = c->read; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua tcp socket read data: waiting: %d", (int) u->waiting); + "lua tcp socket read data: waiting: %d", (int) u->waiting_read); b = &u->buffer; read = 0; @@ -1462,7 +1900,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket receive done: wait:%d, eof:%d, " - "uri:\"%V?%V\"", (int) u->waiting, (int) u->eof, + "uri:\"%V?%V\"", (int) u->waiting_read, (int) u->eof, &r->uri, &r->args); if (u->body_downstream @@ -1480,12 +1918,12 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, } if (rc == NGX_HTTP_CLIENT_CLOSED_REQUEST) { - ngx_http_lua_socket_handle_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT); + ngx_http_lua_socket_handle_read_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT); } else { - ngx_http_lua_socket_handle_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); + ngx_http_lua_socket_handle_read_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_ERROR); } return NGX_ERROR; @@ -1494,23 +1932,23 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, #if 1 if (ngx_handle_read_event(rev, 0) != NGX_OK) { - ngx_http_lua_socket_handle_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); + ngx_http_lua_socket_handle_read_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_ERROR); return NGX_ERROR; } #endif success: - ngx_http_lua_socket_handle_success(r, u); + ngx_http_lua_socket_handle_read_success(r, u); return NGX_OK; } if (rc == NGX_ERROR) { dd("input filter error: ft_type:%d waiting:%d", - (int) u->ft_type, (int) u->waiting); + (int) u->ft_type, (int) u->waiting_read); - ngx_http_lua_socket_handle_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); + ngx_http_lua_socket_handle_read_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_ERROR); return NGX_ERROR; } @@ -1533,8 +1971,8 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, if (size == 0) { rc = ngx_http_lua_socket_add_input_buffer(r, u); if (rc == NGX_ERROR) { - ngx_http_lua_socket_handle_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_NOMEM); + ngx_http_lua_socket_handle_read_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_NOMEM); return NGX_ERROR; } @@ -1650,7 +2088,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, if (llcf->check_client_abort) { - ngx_http_lua_socket_handle_error(r, u, + ngx_http_lua_socket_handle_read_error(r, u, NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT); return NGX_ERROR; } @@ -1658,7 +2096,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, /* llcf->check_client_abort == 0 */ if (u->body_downstream && r->request_body->rest) { - ngx_http_lua_socket_handle_error(r, u, + ngx_http_lua_socket_handle_read_error(r, u, NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT); return NGX_ERROR; } @@ -1674,8 +2112,8 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, if (n == NGX_ERROR) { u->socket_errno = ngx_socket_errno; - ngx_http_lua_socket_handle_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); + ngx_http_lua_socket_handle_read_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_ERROR); return NGX_ERROR; } @@ -1689,8 +2127,8 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, #if 1 if (ngx_handle_read_event(rev, 0) != NGX_OK) { - ngx_http_lua_socket_handle_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); + ngx_http_lua_socket_handle_read_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_ERROR); return NGX_ERROR; } #endif @@ -1756,9 +2194,9 @@ ngx_http_lua_socket_tcp_send(lua_State *L) return 2; } - if (u->waiting) { + if (u->waiting_write) { lua_pushnil(L); - lua_pushliteral(L, "socket busy"); + lua_pushliteral(L, "socket already busy writing"); return 2; } @@ -1835,7 +2273,7 @@ ngx_http_lua_socket_tcp_send(lua_State *L) /* mimic ngx_http_upstream_init_request here */ #if 1 - u->waiting = 0; + u->waiting_write = 0; #endif ngx_http_lua_probe_socket_tcp_send_start(r, u, b->pos, len); @@ -1867,8 +2305,8 @@ ngx_http_lua_socket_tcp_send(lua_State *L) r->write_event_handler = ngx_http_core_run_phases; } - u->co_ctx = ctx->cur_co_ctx; - u->waiting = 1; + u->co_ctx_write = ctx->cur_co_ctx; + u->waiting_write = 1; u->prepare_retvals = ngx_http_lua_socket_tcp_send_retval_handler; dd("setting data to %p", u); @@ -2006,7 +2444,7 @@ ngx_http_lua_socket_tcp_close(lua_State *L) return 2; } - if (u->waiting) { + if ((u->waiting_read) || (u->waiting_write) || (u->waiting)) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); return 2; @@ -2024,6 +2462,42 @@ ngx_http_lua_socket_tcp_close(lua_State *L) return 1; } +static int +ngx_http_lua_socket_tcp_fake_close(lua_State *L) +{ + ngx_http_request_t *r; + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; + + if (lua_gettop(L) != 1) { + return luaL_error(L, "expecting 1 argument " + "(including the object) but seen %d", lua_gettop(L)); + } + + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no ctx found"); + } + + luaL_checktype(L, 1, LUA_TTABLE); + + lua_rawgeti(L, 1, SOCKET_CTX_INDEX); + u = lua_touserdata(L, -1); + lua_pop(L, 1); + + u->fake_eof = 1; + coctx = ctx->cur_co_ctx; + ngx_http_lua_socket_read_handler(r, u); + ctx->cur_co_ctx = coctx; + + return 0; +} static int ngx_http_lua_socket_tcp_setoption(lua_State *L) @@ -2073,6 +2547,76 @@ ngx_http_lua_socket_tcp_settimeout(lua_State *L) } +static int +ngx_http_lua_socket_tcp_set_receive_timeout(lua_State *L) +{ + int n; + ngx_int_t timeout; + + ngx_http_lua_socket_tcp_upstream_t *u; + + n = lua_gettop(L); + + if (n != 2) { + return luaL_error(L, "ngx.socket set_receive_timeout: expecting at least 2 " + "arguments (including the object) but seen %d", + lua_gettop(L)); + } + + timeout = (ngx_int_t) lua_tonumber(L, 2); + + lua_rawseti(L, 1, SOCKET_TIMEOUT_INDEX); + + lua_rawgeti(L, 1, SOCKET_CTX_INDEX); + u = lua_touserdata(L, -1); + + if (u) { + if (timeout > 0) { + u->read_timeout = (ngx_msec_t) timeout; + } else { + u->read_timeout = u->conf->read_timeout; + } + } + + return 0; +} + + +static int +ngx_http_lua_socket_tcp_set_send_timeout(lua_State *L) +{ + int n; + ngx_int_t timeout; + + ngx_http_lua_socket_tcp_upstream_t *u; + + n = lua_gettop(L); + + if (n != 2) { + return luaL_error(L, "ngx.socket set_send_timeout: expecting at least 2 " + "arguments (including the object) but seen %d", + lua_gettop(L)); + } + + timeout = (ngx_int_t) lua_tonumber(L, 2); + + lua_rawseti(L, 1, SOCKET_TIMEOUT_INDEX); + + lua_rawgeti(L, 1, SOCKET_CTX_INDEX); + u = lua_touserdata(L, -1); + + if (u) { + if (timeout > 0) { + u->send_timeout = (ngx_msec_t) timeout; + } else { + u->send_timeout = u->conf->send_timeout; + } + } + + return 0; +} + + static void ngx_http_lua_socket_tcp_handler(ngx_event_t *ev) { @@ -2125,6 +2669,11 @@ ngx_http_lua_socket_read_handler(ngx_http_request_t *r, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket read handler"); + if (u->fake_eof) { + ngx_http_lua_socket_handle_read_error(r, u, NGX_HTTP_LUA_SOCKET_FT_CLOSED); + return; + } + if (c->read->timedout) { c->read->timedout = 0; @@ -2135,7 +2684,7 @@ ngx_http_lua_socket_read_handler(ngx_http_request_t *r, "lua tcp socket read timed out"); } - ngx_http_lua_socket_handle_error(r, u, NGX_HTTP_LUA_SOCKET_FT_TIMEOUT); + ngx_http_lua_socket_handle_read_error(r, u, NGX_HTTP_LUA_SOCKET_FT_TIMEOUT); return; } @@ -2171,7 +2720,7 @@ ngx_http_lua_socket_send_handler(ngx_http_request_t *r, "lua tcp socket write timed out"); } - ngx_http_lua_socket_handle_error(r, u, NGX_HTTP_LUA_SOCKET_FT_TIMEOUT); + ngx_http_lua_socket_handle_write_error(r, u, NGX_HTTP_LUA_SOCKET_FT_TIMEOUT); return; } @@ -2199,8 +2748,8 @@ ngx_http_lua_socket_send(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { - ngx_http_lua_socket_handle_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); + ngx_http_lua_socket_handle_write_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_ERROR); return NGX_ERROR; } @@ -2233,12 +2782,12 @@ ngx_http_lua_socket_send(ngx_http_request_t *r, u->write_event_handler = ngx_http_lua_socket_dummy_handler; if (ngx_handle_write_event(c->write, 0) != NGX_OK) { - ngx_http_lua_socket_handle_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); + ngx_http_lua_socket_handle_write_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_ERROR); return NGX_ERROR; } - ngx_http_lua_socket_handle_success(r, u); + ngx_http_lua_socket_handle_write_success(r, u); return NGX_OK; } @@ -2252,7 +2801,7 @@ ngx_http_lua_socket_send(ngx_http_request_t *r, if (n == NGX_ERROR) { u->socket_errno = ngx_socket_errno; - ngx_http_lua_socket_handle_error(r, u, NGX_HTTP_LUA_SOCKET_FT_ERROR); + ngx_http_lua_socket_handle_write_error(r, u, NGX_HTTP_LUA_SOCKET_FT_ERROR); return NGX_ERROR; } @@ -2263,13 +2812,12 @@ ngx_http_lua_socket_send(ngx_http_request_t *r, } u->write_event_handler = ngx_http_lua_socket_send_handler; - u->read_event_handler = ngx_http_lua_socket_dummy_handler; ngx_add_timer(c->write, u->send_timeout); if (ngx_handle_write_event(c->write, u->conf->send_lowat) != NGX_OK) { - ngx_http_lua_socket_handle_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); + ngx_http_lua_socket_handle_write_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_ERROR); return NGX_ERROR; } @@ -2288,8 +2836,8 @@ ngx_http_lua_socket_handle_success(ngx_http_request_t *r, u->write_event_handler = ngx_http_lua_socket_dummy_handler; #endif - if (u->co_ctx) { - u->co_ctx->cleanup = NULL; + if (u->co_ctx_read) { + u->co_ctx_read->cleanup = NULL; } #if 0 @@ -2307,7 +2855,87 @@ ngx_http_lua_socket_handle_success(ngx_http_request_t *r, } ctx->resume_handler = ngx_http_lua_socket_tcp_resume; - ctx->cur_co_ctx = u->co_ctx; + ctx->cur_co_ctx = u->co_ctx_read; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket waking up the current request"); + + r->write_event_handler(r); + } +} + + +static void +ngx_http_lua_socket_handle_read_success(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u) +{ + ngx_http_lua_ctx_t *ctx; + +#if 1 + u->read_event_handler = ngx_http_lua_socket_dummy_handler; +#endif + + if (u->co_ctx_read) { + u->co_ctx_read->cleanup = NULL; + } + +#if 0 + if (u->eof) { + ngx_http_lua_socket_tcp_finalize(r, u); + } +#endif + + if (u->waiting_read) { + u->waiting_read = 0; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } + + ctx->resume_handler = ngx_http_lua_socket_tcp_resume; + ctx->cur_co_ctx = u->co_ctx_read; + u->prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket waking up the current request"); + + r->write_event_handler(r); + } +} + + +static void +ngx_http_lua_socket_handle_write_success(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u) +{ + ngx_http_lua_ctx_t *ctx; + +#if 1 + u->write_event_handler = ngx_http_lua_socket_dummy_handler; +#endif + + if (u->co_ctx_write) { + u->co_ctx_write->cleanup = NULL; + } + +#if 0 + if (u->eof) { + ngx_http_lua_socket_tcp_finalize(r, u); + } +#endif + + if (u->waiting_write) { + u->waiting_write = 0; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } + + ctx->resume_handler = ngx_http_lua_socket_tcp_resume; + ctx->cur_co_ctx = u->co_ctx_write; + u->prepare_retvals = ngx_http_lua_socket_tcp_send_retval_handler; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket waking up the current request"); @@ -2332,8 +2960,8 @@ ngx_http_lua_socket_handle_error(ngx_http_request_t *r, ngx_http_lua_socket_tcp_finalize(r, u); #endif - if (u->co_ctx) { - u->co_ctx->cleanup = NULL; + if (u->co_ctx_read) { + u->co_ctx_read->cleanup = NULL; } u->read_event_handler = ngx_http_lua_socket_dummy_handler; @@ -2348,7 +2976,89 @@ ngx_http_lua_socket_handle_error(ngx_http_request_t *r, } ctx->resume_handler = ngx_http_lua_socket_tcp_resume; - ctx->cur_co_ctx = u->co_ctx; + ctx->cur_co_ctx = u->co_ctx_read; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket waking up the current request"); + + r->write_event_handler(r); + } +} + + +static void +ngx_http_lua_socket_handle_read_error(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, ngx_uint_t ft_type) +{ + ngx_http_lua_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket handle error"); + + u->ft_type |= ft_type; + +#if 0 + ngx_http_lua_socket_tcp_finalize(r, u); +#endif + + if (u->co_ctx_read) { + u->co_ctx_read->cleanup = NULL; + } + + u->read_event_handler = ngx_http_lua_socket_dummy_handler; + + if (u->waiting_read) { + u->waiting_read = 0; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } + + ctx->resume_handler = ngx_http_lua_socket_tcp_resume; + ctx->cur_co_ctx = u->co_ctx_read; + u->prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket waking up the current request"); + + r->write_event_handler(r); + } +} + + +static void +ngx_http_lua_socket_handle_write_error(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, ngx_uint_t ft_type) +{ + ngx_http_lua_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket handle error"); + + u->ft_type |= ft_type; + +#if 0 + ngx_http_lua_socket_tcp_finalize(r, u); +#endif + + if (u->co_ctx_write) { + u->co_ctx_write->cleanup = NULL; + } + + u->write_event_handler = ngx_http_lua_socket_dummy_handler; + + if (u->waiting_write) { + u->waiting_write = 0; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } + + ctx->resume_handler = ngx_http_lua_socket_tcp_resume; + ctx->cur_co_ctx = u->co_ctx_write; + u->prepare_retvals = ngx_http_lua_socket_tcp_send_retval_handler; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket waking up the current request"); @@ -2476,6 +3186,7 @@ ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, } u->peer.connection = NULL; + ctx->writing_raw_req_socket = 0; return; } @@ -2492,6 +3203,15 @@ ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua close socket connection"); +#if (NGX_HTTP_SSL) + + if (u->peer.connection->ssl) { + u->peer.connection->ssl->no_wait_shutdown = 1; + (void) ngx_ssl_shutdown(u->peer.connection); + } + +#endif + ngx_close_connection(u->peer.connection); u->peer.connection = NULL; @@ -2719,7 +3439,7 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) return 2; } - if (u->waiting) { + if (u->waiting_read) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); return 2; @@ -2781,7 +3501,7 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) r->read_event_handler = ngx_http_lua_req_socket_rev_handler; } - u->waiting = 0; + u->waiting_read = 0; rc = ngx_http_lua_socket_tcp_read(r, u); @@ -2814,8 +3534,8 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) r->write_event_handler = ngx_http_core_run_phases; } - u->co_ctx = ctx->cur_co_ctx; - u->waiting = 1; + u->co_ctx_read = ctx->cur_co_ctx; + u->waiting_read = 1; u->prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; coctx = ctx->cur_co_ctx; @@ -3304,8 +4024,8 @@ ngx_http_lua_req_socket(lua_State *L) } dd("req content length: %d", (int) r->headers_in.content_length_n); - - if (r->headers_in.content_length_n <= 0) { + + if (r->headers_in.content_length_n == 0) { lua_pushnil(L); lua_pushliteral(L, "no body"); return 2; @@ -3433,7 +4153,7 @@ ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r) coctx = ctx->downstream_co_ctx; u = coctx->data; - if (u) { + if (u && u->peer.connection) { u->read_event_handler(r, u); } } @@ -3521,7 +4241,7 @@ static int ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } - if (u->waiting) { + if ((u->waiting_read) || (u->waiting_write) || (u->waiting)) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); return 2; diff --git a/src/ngx_http_lua_socket_tcp.h b/src/ngx_http_lua_socket_tcp.h index 087ac0aeca..92d9c654db 100644 --- a/src/ngx_http_lua_socket_tcp.h +++ b/src/ngx_http_lua_socket_tcp.h @@ -84,13 +84,24 @@ struct ngx_http_lua_socket_tcp_upstream_s { size_t request_len; ngx_chain_t *request_bufs; - ngx_http_lua_co_ctx_t *co_ctx; + ngx_http_lua_co_ctx_t *co_ctx_read; + ngx_http_lua_co_ctx_t *co_ctx_write; ngx_uint_t reused; +#if (NGX_HTTP_SSL) + ngx_str_t ssl_verify_name; +#endif + unsigned no_close:1; unsigned waiting:1; + unsigned waiting_read:1; + unsigned waiting_write:1; unsigned eof:1; + unsigned fake_eof:1; +#if (NGX_HTTP_SSL) + unsigned ssl:1; +#endif unsigned body_downstream:1; unsigned raw_downstream:1; };