From 291e82d35c797699828857f1df060881f637a367 Mon Sep 17 00:00:00 2001 From: Sergey Kharkhardin Date: Wed, 20 Feb 2019 23:56:59 +0300 Subject: [PATCH 1/2] feature: added new api function ngx.resolve which allows perform host name's resolution from Lua code using Nginx core's dynamic resolver. --- README.markdown | 57 +++++ src/ngx_http_lua_resolve.c | 483 +++++++++++++++++++++++++++++++++++++ src/ngx_http_lua_resolve.h | 18 ++ src/ngx_http_lua_util.c | 2 + t/161-resolve.t | 98 ++++++++ 5 files changed, 658 insertions(+) create mode 100644 src/ngx_http_lua_resolve.c create mode 100644 src/ngx_http_lua_resolve.h create mode 100644 t/161-resolve.t diff --git a/README.markdown b/README.markdown index 3df44953e0..56a526c608 100644 --- a/README.markdown +++ b/README.markdown @@ -7539,6 +7539,63 @@ This feature was first introduced in the `v0.5.0rc1` release. [Back to TOC](#nginx-api-for-lua) +ngx.resolve +------------------ +**syntax:** *addr, err = ngx.resolve(host, options?)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** + +Resolves the given host name into IP address by using Nginx core's dynamic resolver. + +An optional `options` table can be fed as the second argument, which supports the options: + +* `ipv4` + consider IPv4 addresses (A Record) - `true` by default +* `ipv6` + consider IPv6 addresses (AAAA Record) + +If multiple A/AAAA records were retrieved by Nginx core's dynamic resolver then this method will randomly choose and return only one address. + +It is required to configure the [resolver](http://nginx.org/en/docs/http/ngx_http_core_module.html#resolver) directive in the `nginx.conf`. + +```nginx + http { + resolver 8.8.8.8; + + upstream backend { + server 0.0.0.0; + + balancer_by_lua_block { + local balancer = require 'ngx.balancer' + + local ok, err = balancer.set_current_peer(ngx.ctx.peer_addr, ngx.ctx.peer_port) + if not ok then + ngx.log(ngx.ERR, "failed to set the peer: ", err) + ngx.exit(500) + end + } + } + + server { + listen 8080; + + access_by_lua_block { + local addr, err = ngx.resolve('google.com', { ipv4 = true }) + if addr then + ngx.ctx.peer_addr = addr + ngx.ctx.peer_port = 80 + end + } + + location / { + proxy_pass http://backend; + } + } + } +``` + +[Back to TOC](#nginx-api-for-lua) + ngx.get_phase ------------- **syntax:** *str = ngx.get_phase()* diff --git a/src/ngx_http_lua_resolve.c b/src/ngx_http_lua_resolve.c new file mode 100644 index 0000000000..1c596da4cb --- /dev/null +++ b/src/ngx_http_lua_resolve.c @@ -0,0 +1,483 @@ + +/* + * Copyright (C) Sergey Kharkhardin (slimboyfat) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_lua_util.h" +#include "ngx_http_lua_resolve.h" +#include "ngx_http_lua_contentby.h" + + +typedef struct ngx_http_lua_resolve_ctx_s + ngx_http_lua_resolve_ctx_t; + + +static int ngx_http_lua_ngx_resolve(lua_State *L); +static void ngx_http_lua_resolve_handler(ngx_resolver_ctx_t *ctx); +static void ngx_http_lua_resolve_cleanup(void *data); +static void ngx_http_lua_resolve_empty_handler(ngx_resolver_ctx_t *ctx); +static ngx_int_t ngx_http_lua_resolve_resume(ngx_http_request_t *r); +static int ngx_http_lua_resolve_select_retval(ngx_http_lua_resolve_ctx_t *u, + lua_State *L); +static int ngx_http_lua_resolve_get_retval(struct sockaddr *sockaddr, + socklen_t socklen, lua_State *L); +static int ngx_http_lua_resolve_set_query_option(const char *name, + unsigned *option, lua_State *L); + +struct ngx_http_lua_resolve_ctx_s { + ngx_http_request_t *request; + ngx_http_upstream_resolved_t *resolved; + ngx_http_lua_co_ctx_t *curr_co_ctx; + unsigned ipv4:1; + unsigned ipv6:1; +}; + + +static int ngx_http_lua_ngx_resolve(lua_State *L) +{ + int n, saved_top; + size_t len; + u_char *p; + ngx_int_t rc; + ngx_str_t host; + ngx_url_t url; + ngx_http_lua_ctx_t *ctx; + ngx_http_request_t *r; + ngx_resolver_ctx_t *rctx, temp; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_core_loc_conf_t *clcf; + ngx_http_lua_resolve_ctx_t *u; + + unsigned ipv4 = 1; + unsigned ipv6 = 0; + + n = lua_gettop(L); + if (n != 1 && n != 2) { + return luaL_error(L, "passed %d arguments, but accepted 1 or 2", n); + } + + if (lua_type(L, 1) != LUA_TSTRING) { + return luaL_error(L, "1st parameter must be a string"); + } + + if (n == 2) { + if (lua_type(L, 2) != LUA_TTABLE) { + return luaL_error(L, "2nd parameter must be a table"); + } + + rc = ngx_http_lua_resolve_set_query_option("ipv4", &ipv4, L); + if (rc != NGX_OK) { + return rc; + } + + rc = ngx_http_lua_resolve_set_query_option("ipv6", &ipv6, L); + if (rc != NGX_OK) { + return rc; + } + } + + 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"); + } + + ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_ACCESS + | NGX_HTTP_LUA_CONTEXT_CONTENT); + + p = (u_char *) luaL_checklstring(L, 1, &len); + + host.data = ngx_palloc(r->pool, len + 1); + if (host.data == NULL) { + return luaL_error(L, "no memory"); + } + + host.len = len; + + ngx_memcpy(host.data, p, len); + host.data[len] = '\0'; + + ngx_memzero(&url, sizeof(ngx_url_t)); + + url.url.len = host.len; + url.url.data = host.data; + url.default_port = (in_port_t) 0; + url.no_resolve = 1; + + if (ngx_parse_url(r->pool, &url) != NGX_OK) { + lua_pushnil(L); + + if (url.err) { + lua_pushfstring(L, "failed to parse host name \"%s\": %s", + host.data, url.err); + + } else { + lua_pushfstring(L, "failed to parse host name \"%s\"", host.data); + } + + return 2; + } + + if (url.addrs && url.addrs[0].sockaddr) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "the given host name is address"); + + return ngx_http_lua_resolve_get_retval(url.addrs[0].sockaddr, + url.addrs[0].socklen, L); + } + + u = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_resolve_ctx_t)); + if (u == NULL) { + return luaL_error(L, "no memory"); + } + + u->ipv4 = ipv4; + u->ipv6 = ipv6; + u->request = r; /* set the controlling request */ + + u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); + if (u->resolved == NULL) { + return luaL_error(L, "no memory"); + } + + u->resolved->host = host; + u->resolved->port = (in_port_t) 0; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + temp.name = host; + rctx = ngx_resolve_start(clcf->resolver, &temp); + if (rctx == NULL) { + lua_pushnil(L); + lua_pushliteral(L, "failed to start the resolver"); + return 2; + } + + if (rctx == NGX_NO_RESOLVER) { + lua_pushnil(L); + lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data); + return 2; + } + + rctx->name = host; + rctx->handler = ngx_http_lua_resolve_handler; + rctx->data = u; + rctx->timeout = clcf->resolver_timeout; + + u->resolved->ctx = rctx; + u->curr_co_ctx = ctx->cur_co_ctx; + coctx = ctx->cur_co_ctx; + + ngx_http_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_http_lua_resolve_cleanup; + coctx->data = u; + + saved_top = lua_gettop(L); + + if (ngx_resolve_name(rctx) != NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua ngx.resolve fail to run resolver immediately"); + + coctx->cleanup = NULL; + coctx->data = NULL; + + u->resolved->ctx = NULL; + lua_pushnil(L); + lua_pushfstring(L, "%s could not be resolved", host.data); + + return 2; + } + + if (rctx->async) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "DNS resolver is going to be queried asynchronously"); + + return lua_yield(L, 0); + } + + /* Resolver's response was retrieved synchronously (from cache) */ + n = lua_gettop(L) - saved_top; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "ngx.resolve has %i result(s) cached", n); + + return n; +} + + +static void +ngx_http_lua_resolve_handler(ngx_resolver_ctx_t *ctx) +{ + lua_State *L; + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_lua_ctx_t *lctx; + ngx_http_lua_resolve_ctx_t *u; + ngx_http_upstream_resolved_t *ur; + + u = ctx->data; + r = u->request; + c = r->connection; + ur = u->resolved; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua ngx.resolve handler"); + + lctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (lctx == NULL) { + return; + } + + lctx->cur_co_ctx = u->curr_co_ctx; + u->curr_co_ctx->cleanup = NULL; + L = lctx->cur_co_ctx->co; + + if (ctx->state) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "ngx.resolve error: %s " + "(async:%d)", ngx_resolver_strerror(ctx->state), + (int) ctx->async); + + lua_pushnil(L); + lua_pushlstring(L, (char *) ctx->name.data, ctx->name.len); + lua_pushfstring(L, " could not be resolved (%d: %s)", + (int) ctx->state, ngx_resolver_strerror(ctx->state)); + lua_concat(L, 2); + + ngx_resolve_name_done(ctx); + ur->ctx = NULL; + u->curr_co_ctx = NULL; + + if (ctx->async) { + goto resume; + } + + return; + } + + ur->naddrs = ctx->naddrs; + ur->addrs = ctx->addrs; + +#if (NGX_DEBUG) + { + u_char text[NGX_SOCKADDR_STRLEN]; + ngx_str_t addr; + ngx_uint_t i; + + addr.data = text; + + for (i = 0; i < ctx->naddrs; i++) { + addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen, + text, NGX_SOCKADDR_STRLEN, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "name was resolved to %V", &addr); + } + } +#endif + + ngx_resolve_name_done(ctx); + ur->ctx = NULL; + u->curr_co_ctx = NULL; + + if (!ctx->async) { + (void) ngx_http_lua_resolve_select_retval(u, L); + + return; + } + +resume: + if (lctx->entered_content_phase) { + (void) ngx_http_lua_resolve_resume(r); + + } else { + lctx->resume_handler = ngx_http_lua_resolve_resume; + ngx_http_core_run_phases(r); + } + + ngx_http_run_posted_requests(c); +} + + +static ngx_int_t +ngx_http_lua_resolve_resume(ngx_http_request_t *r) +{ + int nret; + lua_State *vm; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_resolve_ctx_t *u; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } + + ctx->resume_handler = ngx_http_lua_wev_handler; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua ngx.resolve operation is done, resuming lua thread"); + + coctx = ctx->cur_co_ctx; + + dd("coctx: %p", coctx); + + u = coctx->data; + + nret = ngx_http_lua_resolve_select_retval(u, ctx->cur_co_ctx->co); + + c = r->connection; + vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; + + rc = ngx_http_lua_run_thread(vm, r, ctx, nret); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); + } + + if (rc == NGX_DONE) { + ngx_http_lua_finalize_request(r, NGX_DONE); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); + } + + if (ctx->entered_content_phase) { + ngx_http_lua_finalize_request(r, rc); + return NGX_DONE; + } + + return rc; +} + + +static void +ngx_http_lua_resolve_cleanup(void *data) +{ + ngx_resolver_ctx_t *rctx; + ngx_http_lua_co_ctx_t *coctx = data; + ngx_http_upstream_resolved_t *resolved; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua ngx.resolve abort resolver"); + + resolved = coctx->data; + if (resolved == NULL) { + return; + } + + rctx = resolved->ctx; + if (rctx == NULL) { + return; + } + + /* just to be safer */ + rctx->handler = ngx_http_lua_resolve_empty_handler; + + ngx_resolve_name_done(rctx); +} + + +static void +ngx_http_lua_resolve_empty_handler(ngx_resolver_ctx_t *ctx) +{ + /* do nothing */ +} + + +static int +ngx_http_lua_resolve_select_retval(ngx_http_lua_resolve_ctx_t *u, lua_State *L) +{ + ngx_uint_t i; + ngx_resolver_addr_t *addr; + ngx_http_upstream_resolved_t *ur = u->resolved; + + for (i = 0; i < ur->naddrs; i++) { + addr = &ur->addrs[i]; + switch (addr->sockaddr->sa_family) { +#if (NGX_HAVE_INET6) + case AF_INET6: + if (u->ipv6) { + return ngx_http_lua_resolve_get_retval(addr->sockaddr, + addr->socklen, L); + } + break; +#endif + default: /* AF_INET */ + if (u->ipv4) { + return ngx_http_lua_resolve_get_retval(addr->sockaddr, + addr->socklen, L); + } + } + } + + lua_pushnil(L); + lua_pushliteral(L, "address not found"); + + return 2; +} + + +static int +ngx_http_lua_resolve_get_retval(struct sockaddr *sockaddr, socklen_t socklen, + lua_State *L) +{ + size_t len; + u_char text[NGX_SOCKADDR_STRLEN]; + + len = ngx_sock_ntop(sockaddr, socklen, text, NGX_SOCKADDR_STRLEN, 0); + lua_pushlstring(L, (const char *) text, len); + + return 1; +} + + +static int +ngx_http_lua_resolve_set_query_option(const char *name, unsigned *option, lua_State *L) +{ + lua_getfield(L, 2, name); + + switch (lua_type(L, -1)) { + case LUA_TNIL: + /* do nothing */ + break; + + case LUA_TBOOLEAN: + *option = lua_toboolean(L, -1); + break; + + default: + return luaL_error(L, "bad \"%s\" option value type: %s", + name, luaL_typename(L, -1)); + } + + lua_pop(L, 1); + + return NGX_OK; +} + + +void +ngx_http_lua_inject_resolve_api(lua_State *L) +{ + lua_pushcfunction(L, ngx_http_lua_ngx_resolve); + lua_setfield(L, -2, "resolve"); +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_resolve.h b/src/ngx_http_lua_resolve.h new file mode 100644 index 0000000000..c1ed695ed4 --- /dev/null +++ b/src/ngx_http_lua_resolve.h @@ -0,0 +1,18 @@ + +/* + * Copyright (C) Sergey Kharkhardin (slimboyfat) + */ + +#ifndef _NGX_HTTP_LUA_RESOLVE_H_INCLUDED_ +#define _NGX_HTTP_LUA_RESOLVE_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +void ngx_http_lua_inject_resolve_api(lua_State *L); + + +#endif /* _NGX_HTTP_LUA_RESOLVE_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 72558624fb..78ff849212 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -36,6 +36,7 @@ #include "ngx_http_lua_coroutine.h" #include "ngx_http_lua_socket_tcp.h" #include "ngx_http_lua_socket_udp.h" +#include "ngx_http_lua_resolve.h" #include "ngx_http_lua_sleep.h" #include "ngx_http_lua_setby.h" #include "ngx_http_lua_headerfilterby.h" @@ -768,6 +769,7 @@ ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf, ngx_http_lua_inject_shdict_api(lmcf, L); ngx_http_lua_inject_socket_tcp_api(log, L); ngx_http_lua_inject_socket_udp_api(log, L); + ngx_http_lua_inject_resolve_api(L); ngx_http_lua_inject_uthread_api(log, L); ngx_http_lua_inject_timer_api(L); ngx_http_lua_inject_config_api(L); diff --git a/t/161-resolve.t b/t/161-resolve.t new file mode 100644 index 0000000000..fa98e29b9d --- /dev/null +++ b/t/161-resolve.t @@ -0,0 +1,98 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua 'no_plan'; + +#worker_connections(1014); +#master_process_enabled(1); + +no_long_string(); +run_tests(); + +__DATA__ + + +=== TEST 1: use ngx.resolve in rewrite_by_lua_block +--- config + resolver 8.8.8.8; + rewrite_by_lua "ngx.ctx.addr = ngx.resolve('google.com')"; + location = /resolve { + content_by_lua "ngx.say(ngx.ctx.addr)"; + } +--- request +GET /resolve +--- response_body_like: ^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$ + + + +=== TEST 2: use ngx.resolve in access_by_lua_block +--- config + resolver 8.8.8.8; + access_by_lua "ngx.ctx.addr = ngx.resolve('google.com')"; + location = /resolve { + content_by_lua "ngx.say(ngx.ctx.addr)"; + } +--- request +GET /resolve +--- response_body_like: ^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$ + + + +=== TEST 3: use ngx.resolve in content_by_lua_block +--- config + resolver 8.8.8.8; + location = /resolve { + content_by_lua "ngx.say(ngx.resolve('google.com'))"; + } +--- request +GET /resolve +--- response_body_like: ^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$ + + + +=== TEST 4: query only IPv6 addresses +--- config + resolver 8.8.8.8; + location = /resolve { + content_by_lua "ngx.say(ngx.resolve('google.com', { ipv4 = false, ipv6 = true }))"; + } +--- request +GET /resolve +--- response_body_like: ^[a-fA-F0-9:]+$ + + + +=== TEST 5: pass IPv4 address to ngx.resolve +--- config + location = /resolve { + content_by_lua "ngx.say(ngx.resolve('192.168.0.1'))"; + } +--- request +GET /resolve +--- response_body +192.168.0.1 + + + +=== TEST 6: pass IPv6 address to ngx.resolve +--- config + location = /resolve { + content_by_lua "ngx.say(ngx.resolve('[2a00:1450:4010:c05::66]'))"; + } +--- request +GET /resolve +--- response_body +2a00:1450:4010:c05::66 + + + +=== TEST 7: pass non-existent domain name to ngx.resolve +--- config + resolver 8.8.8.8; + resolver_timeout 1s; + location = /resolve { + content_by_lua "ngx.say(ngx.resolve('non-existent-domain-name'))"; + } +--- request +GET /resolve +--- response_body +niladdress not found From 2c69f0a0b791773bbe4ae5bd4ec2f959181dc210 Mon Sep 17 00:00:00 2001 From: Sergey Kharkhardin Date: Wed, 6 Mar 2019 23:16:49 +0300 Subject: [PATCH 2/2] feature: added new Lua API for Nginx core's dynamic resolver. --- README.markdown | 57 ----- config | 1 + src/ngx_http_lua_resolve.c | 483 ------------------------------------ src/ngx_http_lua_resolve.h | 18 -- src/ngx_http_lua_resolver.c | 367 +++++++++++++++++++++++++++ src/ngx_http_lua_util.c | 2 - t/161-resolve.t | 98 -------- 7 files changed, 368 insertions(+), 658 deletions(-) delete mode 100644 src/ngx_http_lua_resolve.c delete mode 100644 src/ngx_http_lua_resolve.h create mode 100644 src/ngx_http_lua_resolver.c delete mode 100644 t/161-resolve.t diff --git a/README.markdown b/README.markdown index 56a526c608..3df44953e0 100644 --- a/README.markdown +++ b/README.markdown @@ -7539,63 +7539,6 @@ This feature was first introduced in the `v0.5.0rc1` release. [Back to TOC](#nginx-api-for-lua) -ngx.resolve ------------------- -**syntax:** *addr, err = ngx.resolve(host, options?)* - -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** - -Resolves the given host name into IP address by using Nginx core's dynamic resolver. - -An optional `options` table can be fed as the second argument, which supports the options: - -* `ipv4` - consider IPv4 addresses (A Record) - `true` by default -* `ipv6` - consider IPv6 addresses (AAAA Record) - -If multiple A/AAAA records were retrieved by Nginx core's dynamic resolver then this method will randomly choose and return only one address. - -It is required to configure the [resolver](http://nginx.org/en/docs/http/ngx_http_core_module.html#resolver) directive in the `nginx.conf`. - -```nginx - http { - resolver 8.8.8.8; - - upstream backend { - server 0.0.0.0; - - balancer_by_lua_block { - local balancer = require 'ngx.balancer' - - local ok, err = balancer.set_current_peer(ngx.ctx.peer_addr, ngx.ctx.peer_port) - if not ok then - ngx.log(ngx.ERR, "failed to set the peer: ", err) - ngx.exit(500) - end - } - } - - server { - listen 8080; - - access_by_lua_block { - local addr, err = ngx.resolve('google.com', { ipv4 = true }) - if addr then - ngx.ctx.peer_addr = addr - ngx.ctx.peer_port = 80 - end - } - - location / { - proxy_pass http://backend; - } - } - } -``` - -[Back to TOC](#nginx-api-for-lua) - ngx.get_phase ------------- **syntax:** *str = ngx.get_phase()* diff --git a/config b/config index e1d5e3543f..997e518310 100644 --- a/config +++ b/config @@ -363,6 +363,7 @@ HTTP_LUA_SRCS=" \ $ngx_addon_dir/src/ngx_http_lua_log_ringbuf.c \ $ngx_addon_dir/src/ngx_http_lua_input_filters.c \ $ngx_addon_dir/src/ngx_http_lua_pipe.c \ + $ngx_addon_dir/src/ngx_http_lua_resolver.c \ " HTTP_LUA_DEPS=" \ diff --git a/src/ngx_http_lua_resolve.c b/src/ngx_http_lua_resolve.c deleted file mode 100644 index 1c596da4cb..0000000000 --- a/src/ngx_http_lua_resolve.c +++ /dev/null @@ -1,483 +0,0 @@ - -/* - * Copyright (C) Sergey Kharkhardin (slimboyfat) - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include "ngx_http_lua_util.h" -#include "ngx_http_lua_resolve.h" -#include "ngx_http_lua_contentby.h" - - -typedef struct ngx_http_lua_resolve_ctx_s - ngx_http_lua_resolve_ctx_t; - - -static int ngx_http_lua_ngx_resolve(lua_State *L); -static void ngx_http_lua_resolve_handler(ngx_resolver_ctx_t *ctx); -static void ngx_http_lua_resolve_cleanup(void *data); -static void ngx_http_lua_resolve_empty_handler(ngx_resolver_ctx_t *ctx); -static ngx_int_t ngx_http_lua_resolve_resume(ngx_http_request_t *r); -static int ngx_http_lua_resolve_select_retval(ngx_http_lua_resolve_ctx_t *u, - lua_State *L); -static int ngx_http_lua_resolve_get_retval(struct sockaddr *sockaddr, - socklen_t socklen, lua_State *L); -static int ngx_http_lua_resolve_set_query_option(const char *name, - unsigned *option, lua_State *L); - -struct ngx_http_lua_resolve_ctx_s { - ngx_http_request_t *request; - ngx_http_upstream_resolved_t *resolved; - ngx_http_lua_co_ctx_t *curr_co_ctx; - unsigned ipv4:1; - unsigned ipv6:1; -}; - - -static int ngx_http_lua_ngx_resolve(lua_State *L) -{ - int n, saved_top; - size_t len; - u_char *p; - ngx_int_t rc; - ngx_str_t host; - ngx_url_t url; - ngx_http_lua_ctx_t *ctx; - ngx_http_request_t *r; - ngx_resolver_ctx_t *rctx, temp; - ngx_http_lua_co_ctx_t *coctx; - ngx_http_core_loc_conf_t *clcf; - ngx_http_lua_resolve_ctx_t *u; - - unsigned ipv4 = 1; - unsigned ipv6 = 0; - - n = lua_gettop(L); - if (n != 1 && n != 2) { - return luaL_error(L, "passed %d arguments, but accepted 1 or 2", n); - } - - if (lua_type(L, 1) != LUA_TSTRING) { - return luaL_error(L, "1st parameter must be a string"); - } - - if (n == 2) { - if (lua_type(L, 2) != LUA_TTABLE) { - return luaL_error(L, "2nd parameter must be a table"); - } - - rc = ngx_http_lua_resolve_set_query_option("ipv4", &ipv4, L); - if (rc != NGX_OK) { - return rc; - } - - rc = ngx_http_lua_resolve_set_query_option("ipv6", &ipv6, L); - if (rc != NGX_OK) { - return rc; - } - } - - 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"); - } - - ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE - | NGX_HTTP_LUA_CONTEXT_ACCESS - | NGX_HTTP_LUA_CONTEXT_CONTENT); - - p = (u_char *) luaL_checklstring(L, 1, &len); - - host.data = ngx_palloc(r->pool, len + 1); - if (host.data == NULL) { - return luaL_error(L, "no memory"); - } - - host.len = len; - - ngx_memcpy(host.data, p, len); - host.data[len] = '\0'; - - ngx_memzero(&url, sizeof(ngx_url_t)); - - url.url.len = host.len; - url.url.data = host.data; - url.default_port = (in_port_t) 0; - url.no_resolve = 1; - - if (ngx_parse_url(r->pool, &url) != NGX_OK) { - lua_pushnil(L); - - if (url.err) { - lua_pushfstring(L, "failed to parse host name \"%s\": %s", - host.data, url.err); - - } else { - lua_pushfstring(L, "failed to parse host name \"%s\"", host.data); - } - - return 2; - } - - if (url.addrs && url.addrs[0].sockaddr) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "the given host name is address"); - - return ngx_http_lua_resolve_get_retval(url.addrs[0].sockaddr, - url.addrs[0].socklen, L); - } - - u = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_resolve_ctx_t)); - if (u == NULL) { - return luaL_error(L, "no memory"); - } - - u->ipv4 = ipv4; - u->ipv6 = ipv6; - u->request = r; /* set the controlling request */ - - u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); - if (u->resolved == NULL) { - return luaL_error(L, "no memory"); - } - - u->resolved->host = host; - u->resolved->port = (in_port_t) 0; - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - temp.name = host; - rctx = ngx_resolve_start(clcf->resolver, &temp); - if (rctx == NULL) { - lua_pushnil(L); - lua_pushliteral(L, "failed to start the resolver"); - return 2; - } - - if (rctx == NGX_NO_RESOLVER) { - lua_pushnil(L); - lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data); - return 2; - } - - rctx->name = host; - rctx->handler = ngx_http_lua_resolve_handler; - rctx->data = u; - rctx->timeout = clcf->resolver_timeout; - - u->resolved->ctx = rctx; - u->curr_co_ctx = ctx->cur_co_ctx; - coctx = ctx->cur_co_ctx; - - ngx_http_lua_cleanup_pending_operation(coctx); - coctx->cleanup = ngx_http_lua_resolve_cleanup; - coctx->data = u; - - saved_top = lua_gettop(L); - - if (ngx_resolve_name(rctx) != NGX_OK) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua ngx.resolve fail to run resolver immediately"); - - coctx->cleanup = NULL; - coctx->data = NULL; - - u->resolved->ctx = NULL; - lua_pushnil(L); - lua_pushfstring(L, "%s could not be resolved", host.data); - - return 2; - } - - if (rctx->async) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "DNS resolver is going to be queried asynchronously"); - - return lua_yield(L, 0); - } - - /* Resolver's response was retrieved synchronously (from cache) */ - n = lua_gettop(L) - saved_top; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "ngx.resolve has %i result(s) cached", n); - - return n; -} - - -static void -ngx_http_lua_resolve_handler(ngx_resolver_ctx_t *ctx) -{ - lua_State *L; - ngx_connection_t *c; - ngx_http_request_t *r; - ngx_http_lua_ctx_t *lctx; - ngx_http_lua_resolve_ctx_t *u; - ngx_http_upstream_resolved_t *ur; - - u = ctx->data; - r = u->request; - c = r->connection; - ur = u->resolved; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua ngx.resolve handler"); - - lctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (lctx == NULL) { - return; - } - - lctx->cur_co_ctx = u->curr_co_ctx; - u->curr_co_ctx->cleanup = NULL; - L = lctx->cur_co_ctx->co; - - if (ctx->state) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "ngx.resolve error: %s " - "(async:%d)", ngx_resolver_strerror(ctx->state), - (int) ctx->async); - - lua_pushnil(L); - lua_pushlstring(L, (char *) ctx->name.data, ctx->name.len); - lua_pushfstring(L, " could not be resolved (%d: %s)", - (int) ctx->state, ngx_resolver_strerror(ctx->state)); - lua_concat(L, 2); - - ngx_resolve_name_done(ctx); - ur->ctx = NULL; - u->curr_co_ctx = NULL; - - if (ctx->async) { - goto resume; - } - - return; - } - - ur->naddrs = ctx->naddrs; - ur->addrs = ctx->addrs; - -#if (NGX_DEBUG) - { - u_char text[NGX_SOCKADDR_STRLEN]; - ngx_str_t addr; - ngx_uint_t i; - - addr.data = text; - - for (i = 0; i < ctx->naddrs; i++) { - addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen, - text, NGX_SOCKADDR_STRLEN, 0); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "name was resolved to %V", &addr); - } - } -#endif - - ngx_resolve_name_done(ctx); - ur->ctx = NULL; - u->curr_co_ctx = NULL; - - if (!ctx->async) { - (void) ngx_http_lua_resolve_select_retval(u, L); - - return; - } - -resume: - if (lctx->entered_content_phase) { - (void) ngx_http_lua_resolve_resume(r); - - } else { - lctx->resume_handler = ngx_http_lua_resolve_resume; - ngx_http_core_run_phases(r); - } - - ngx_http_run_posted_requests(c); -} - - -static ngx_int_t -ngx_http_lua_resolve_resume(ngx_http_request_t *r) -{ - int nret; - lua_State *vm; - ngx_int_t rc; - ngx_uint_t nreqs; - ngx_connection_t *c; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_co_ctx_t *coctx; - ngx_http_lua_resolve_ctx_t *u; - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { - return NGX_ERROR; - } - - ctx->resume_handler = ngx_http_lua_wev_handler; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua ngx.resolve operation is done, resuming lua thread"); - - coctx = ctx->cur_co_ctx; - - dd("coctx: %p", coctx); - - u = coctx->data; - - nret = ngx_http_lua_resolve_select_retval(u, ctx->cur_co_ctx->co); - - c = r->connection; - vm = ngx_http_lua_get_lua_vm(r, ctx); - nreqs = c->requests; - - rc = ngx_http_lua_run_thread(vm, r, ctx, nret); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua run thread returned %d", rc); - - if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); - } - - if (rc == NGX_DONE) { - ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); - } - - if (ctx->entered_content_phase) { - ngx_http_lua_finalize_request(r, rc); - return NGX_DONE; - } - - return rc; -} - - -static void -ngx_http_lua_resolve_cleanup(void *data) -{ - ngx_resolver_ctx_t *rctx; - ngx_http_lua_co_ctx_t *coctx = data; - ngx_http_upstream_resolved_t *resolved; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua ngx.resolve abort resolver"); - - resolved = coctx->data; - if (resolved == NULL) { - return; - } - - rctx = resolved->ctx; - if (rctx == NULL) { - return; - } - - /* just to be safer */ - rctx->handler = ngx_http_lua_resolve_empty_handler; - - ngx_resolve_name_done(rctx); -} - - -static void -ngx_http_lua_resolve_empty_handler(ngx_resolver_ctx_t *ctx) -{ - /* do nothing */ -} - - -static int -ngx_http_lua_resolve_select_retval(ngx_http_lua_resolve_ctx_t *u, lua_State *L) -{ - ngx_uint_t i; - ngx_resolver_addr_t *addr; - ngx_http_upstream_resolved_t *ur = u->resolved; - - for (i = 0; i < ur->naddrs; i++) { - addr = &ur->addrs[i]; - switch (addr->sockaddr->sa_family) { -#if (NGX_HAVE_INET6) - case AF_INET6: - if (u->ipv6) { - return ngx_http_lua_resolve_get_retval(addr->sockaddr, - addr->socklen, L); - } - break; -#endif - default: /* AF_INET */ - if (u->ipv4) { - return ngx_http_lua_resolve_get_retval(addr->sockaddr, - addr->socklen, L); - } - } - } - - lua_pushnil(L); - lua_pushliteral(L, "address not found"); - - return 2; -} - - -static int -ngx_http_lua_resolve_get_retval(struct sockaddr *sockaddr, socklen_t socklen, - lua_State *L) -{ - size_t len; - u_char text[NGX_SOCKADDR_STRLEN]; - - len = ngx_sock_ntop(sockaddr, socklen, text, NGX_SOCKADDR_STRLEN, 0); - lua_pushlstring(L, (const char *) text, len); - - return 1; -} - - -static int -ngx_http_lua_resolve_set_query_option(const char *name, unsigned *option, lua_State *L) -{ - lua_getfield(L, 2, name); - - switch (lua_type(L, -1)) { - case LUA_TNIL: - /* do nothing */ - break; - - case LUA_TBOOLEAN: - *option = lua_toboolean(L, -1); - break; - - default: - return luaL_error(L, "bad \"%s\" option value type: %s", - name, luaL_typename(L, -1)); - } - - lua_pop(L, 1); - - return NGX_OK; -} - - -void -ngx_http_lua_inject_resolve_api(lua_State *L) -{ - lua_pushcfunction(L, ngx_http_lua_ngx_resolve); - lua_setfield(L, -2, "resolve"); -} - -/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_resolve.h b/src/ngx_http_lua_resolve.h deleted file mode 100644 index c1ed695ed4..0000000000 --- a/src/ngx_http_lua_resolve.h +++ /dev/null @@ -1,18 +0,0 @@ - -/* - * Copyright (C) Sergey Kharkhardin (slimboyfat) - */ - -#ifndef _NGX_HTTP_LUA_RESOLVE_H_INCLUDED_ -#define _NGX_HTTP_LUA_RESOLVE_H_INCLUDED_ - - -#include "ngx_http_lua_common.h" - - -void ngx_http_lua_inject_resolve_api(lua_State *L); - - -#endif /* _NGX_HTTP_LUA_RESOLVE_H_INCLUDED_ */ - -/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_resolver.c b/src/ngx_http_lua_resolver.c new file mode 100644 index 0000000000..493f69bf28 --- /dev/null +++ b/src/ngx_http_lua_resolver.c @@ -0,0 +1,367 @@ + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_lua_util.h" +#include "ngx_http_lua_contentby.h" + + +typedef struct ngx_http_lua_resolver_ctx_s { + ngx_http_request_t *request; + u_char *buf; + size_t *buf_size; + ngx_http_lua_co_ctx_t *curr_co_ctx; + ngx_resolver_ctx_t *resolver_ctx; + ngx_int_t exit_code; + unsigned ipv4:1; + unsigned ipv6:1; +} ngx_http_lua_resolver_ctx_t; + + +static void ngx_http_lua_resolve_handler(ngx_resolver_ctx_t *rctx); +static void ngx_http_lua_resolve_cleanup(void *data); +static void ngx_http_lua_resolve_empty_handler(ngx_resolver_ctx_t *ctx); +static ngx_int_t ngx_http_lua_resolve_resume(ngx_http_request_t *r); +static int ngx_http_lua_resolve_retval(ngx_http_lua_resolver_ctx_t *ctx, + lua_State *L); + + +int +ngx_http_lua_ffi_resolve(ngx_http_lua_resolver_ctx_t *ctx, u_char *hostname) +{ + u_char *buf; + size_t *buf_size; + lua_State *L; + ngx_str_t host; + ngx_http_lua_ctx_t *lctx; + ngx_http_request_t *r; + ngx_resolver_ctx_t *rctx; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_core_loc_conf_t *clcf; + +#if (NGX_HAVE_INET6) + struct in6_addr inaddr6; +#endif + + buf = ctx->buf; + buf_size = ctx->buf_size; + + r = ctx->request; + if (r == NULL) { + *ctx->buf_size = ngx_snprintf(buf, *buf_size, "no request") - buf; + return NGX_ERROR; + } + + lctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (lctx == NULL) { + *buf_size = ngx_snprintf(buf, *buf_size, "no lua ctx") - buf; + return NGX_ERROR; + } + + L = ngx_http_lua_get_lua_vm(r, lctx); + + ngx_http_lua_check_context(L, lctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_ACCESS + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); + + host.data = hostname; + host.len = ngx_strlen(hostname); + + if (ngx_inet_addr(host.data, host.len) != INADDR_NONE +#if (NGX_HAVE_INET6) + || ngx_inet6_addr(host.data, host.len, inaddr6.s6_addr) == NGX_OK +#endif + ) + { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "given hostname contains a network address"); + + *buf_size = ngx_cpystrn(buf, host.data, host.len + 1) - buf; + return NGX_OK; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + rctx = ngx_resolve_start(clcf->resolver, NULL); + if (rctx == NULL) { + *buf_size = ngx_snprintf(buf, *buf_size, "failed to start the resolver") + - buf; + return NGX_ERROR; + } + + if (rctx == NGX_NO_RESOLVER) { + *buf_size = ngx_snprintf(buf, *buf_size, "no resolver defined " + "to resolve \"%s\"", host.data) + - buf; + return NGX_ERROR; + } + + rctx->name = host; + rctx->handler = ngx_http_lua_resolve_handler; + rctx->data = ctx; + rctx->timeout = clcf->resolver_timeout; + + ctx->resolver_ctx = rctx; + ctx->curr_co_ctx = lctx->cur_co_ctx; + coctx = lctx->cur_co_ctx; + ngx_http_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_http_lua_resolve_cleanup; + coctx->data = ctx; + + if (ngx_resolve_name(rctx) != NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua resolver fail to run resolver immediately"); + + coctx->cleanup = NULL; + coctx->data = NULL; + ctx->resolver_ctx = NULL; + + *buf_size = ngx_snprintf(buf, *buf_size, "%s could not be resolved", + host.data) + - buf; + return NGX_ERROR; + } + + if (rctx->async) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "resolution is going to be performed asynchronously"); + return NGX_DONE; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "resolution was finished with code %d", ctx->exit_code); + + return ctx->exit_code; +} + + +static void +ngx_http_lua_resolve_handler(ngx_resolver_ctx_t *rctx) +{ + u_char *buf; + size_t *buf_size; + unsigned async; + ngx_uint_t i; + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_lua_ctx_t *lctx; + ngx_resolver_addr_t *addr; + ngx_http_lua_resolver_ctx_t *ctx; + + ctx = rctx->data; + buf = ctx->buf; + buf_size = ctx->buf_size; + r = ctx->request; + c = r->connection; + async = rctx->async; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua ngx resolve handler"); + + lctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (lctx == NULL) { + return; + } + + lctx->cur_co_ctx = ctx->curr_co_ctx; + ctx->curr_co_ctx->cleanup = NULL; + + if (rctx->state) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "resolve error: %s " + "(async:%d)", ngx_resolver_strerror(rctx->state), async); + + *buf_size = ngx_snprintf(buf, *buf_size, "%s could not be resolved " + "(%d: %s)", rctx->name.data, (int) rctx->state, + ngx_resolver_strerror(rctx->state)) + - buf; + + goto failed; + } + +#if (NGX_DEBUG) + { + u_char text[NGX_SOCKADDR_STRLEN]; + ngx_str_t tmp; + + tmp.data = text; + + for (i = 0; i < rctx->naddrs; i++) { + tmp.len = ngx_sock_ntop(rctx->addrs[i].sockaddr, + rctx->addrs[i].socklen, + text, NGX_SOCKADDR_STRLEN, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "name was resolved to %V", &tmp); + } + } +#endif + + /* NG: On a cache hit, Nginx resolver performs random rotation of + * addrs list on every invocation, so, here we just looking for + * the first one that satisfies the requirements. + * See ngx_resolve_name_locked()/ngx_resolver_export() for details */ + for (i = 0; i < rctx->naddrs; i++) { + addr = &rctx->addrs[i]; + if ((addr->sockaddr->sa_family == AF_INET && ctx->ipv4) +#if (NGX_HAVE_INET6) + || (addr->sockaddr->sa_family == AF_INET6 && ctx->ipv6) +#endif + ) + { + *buf_size = ngx_sock_ntop(addr->sockaddr, addr->socklen, ctx->buf, + *buf_size, 0); + + goto done; + } + } + + *buf_size = ngx_snprintf(buf, *buf_size, "no suitable address found for " + "%s out of %d received", rctx->name.data, + rctx->naddrs) + - buf; + +failed: + + ctx->exit_code = NGX_ERROR; + +done: + + ngx_resolve_name_done(rctx); + ctx->resolver_ctx = NULL; + ctx->curr_co_ctx = NULL; + + if (async) { + if (lctx->entered_content_phase) { + (void) ngx_http_lua_resolve_resume(r); + + } else { + lctx->resume_handler = ngx_http_lua_resolve_resume; + ngx_http_core_run_phases(r); + } + + ngx_http_run_posted_requests(c); + } +} + + +static ngx_int_t +ngx_http_lua_resolve_resume(ngx_http_request_t *r) +{ + int nret; + lua_State *vm; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_connection_t *c; + ngx_http_lua_ctx_t *lctx; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_resolver_ctx_t *ctx; + + lctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (lctx == NULL) { + return NGX_ERROR; + } + + lctx->resume_handler = ngx_http_lua_wev_handler; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua resolve operation is done, resuming lua thread"); + + coctx = lctx->cur_co_ctx; + + dd("coctx: %p", coctx); + + ctx = coctx->data; + + nret = ngx_http_lua_resolve_retval(ctx, lctx->cur_co_ctx->co); + + c = r->connection; + vm = ngx_http_lua_get_lua_vm(r, lctx); + nreqs = c->requests; + + rc = ngx_http_lua_run_thread(vm, r, lctx, nret); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return ngx_http_lua_run_posted_threads(c, vm, r, lctx, nreqs); + } + + if (rc == NGX_DONE) { + ngx_http_lua_finalize_request(r, NGX_DONE); + return ngx_http_lua_run_posted_threads(c, vm, r, lctx, nreqs); + } + + if (lctx->entered_content_phase) { + ngx_http_lua_finalize_request(r, rc); + return NGX_DONE; + } + + return rc; +} + + +static void +ngx_http_lua_resolve_cleanup(void *data) +{ + ngx_resolver_ctx_t *rctx; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_resolver_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua ngx.resolve abort resolver"); + + coctx = data; + ctx = coctx->data; + rctx = ctx->resolver_ctx; + + if (rctx == NULL) { + return; + } + + /* just to be safer */ + rctx->handler = ngx_http_lua_resolve_empty_handler; + + ngx_resolve_name_done(rctx); +} + + +static void +ngx_http_lua_resolve_empty_handler(ngx_resolver_ctx_t *ctx) +{ + /* do nothing */ +} + + +static int +ngx_http_lua_resolve_retval(ngx_http_lua_resolver_ctx_t *ctx, lua_State *L) +{ + if (ctx->exit_code == NGX_OK) { + lua_pushlstring(L, (const char *) ctx->buf, *ctx->buf_size); + + return 1; + } + + lua_pushnil(L); + lua_pushlstring(L, (const char *) ctx->buf, *ctx->buf_size); + + return 2; +} + +void +ngx_http_lua_ffi_resolver_destroy(ngx_http_lua_resolver_ctx_t *ctx) +{ + if (ctx->resolver_ctx == NULL) { + return; + } + + ngx_resolve_name_done(ctx->resolver_ctx); + ctx->resolver_ctx = NULL; +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 78ff849212..72558624fb 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -36,7 +36,6 @@ #include "ngx_http_lua_coroutine.h" #include "ngx_http_lua_socket_tcp.h" #include "ngx_http_lua_socket_udp.h" -#include "ngx_http_lua_resolve.h" #include "ngx_http_lua_sleep.h" #include "ngx_http_lua_setby.h" #include "ngx_http_lua_headerfilterby.h" @@ -769,7 +768,6 @@ ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf, ngx_http_lua_inject_shdict_api(lmcf, L); ngx_http_lua_inject_socket_tcp_api(log, L); ngx_http_lua_inject_socket_udp_api(log, L); - ngx_http_lua_inject_resolve_api(L); ngx_http_lua_inject_uthread_api(log, L); ngx_http_lua_inject_timer_api(L); ngx_http_lua_inject_config_api(L); diff --git a/t/161-resolve.t b/t/161-resolve.t deleted file mode 100644 index fa98e29b9d..0000000000 --- a/t/161-resolve.t +++ /dev/null @@ -1,98 +0,0 @@ -# vim:set ft= ts=4 sw=4 et fdm=marker: - -use Test::Nginx::Socket::Lua 'no_plan'; - -#worker_connections(1014); -#master_process_enabled(1); - -no_long_string(); -run_tests(); - -__DATA__ - - -=== TEST 1: use ngx.resolve in rewrite_by_lua_block ---- config - resolver 8.8.8.8; - rewrite_by_lua "ngx.ctx.addr = ngx.resolve('google.com')"; - location = /resolve { - content_by_lua "ngx.say(ngx.ctx.addr)"; - } ---- request -GET /resolve ---- response_body_like: ^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$ - - - -=== TEST 2: use ngx.resolve in access_by_lua_block ---- config - resolver 8.8.8.8; - access_by_lua "ngx.ctx.addr = ngx.resolve('google.com')"; - location = /resolve { - content_by_lua "ngx.say(ngx.ctx.addr)"; - } ---- request -GET /resolve ---- response_body_like: ^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$ - - - -=== TEST 3: use ngx.resolve in content_by_lua_block ---- config - resolver 8.8.8.8; - location = /resolve { - content_by_lua "ngx.say(ngx.resolve('google.com'))"; - } ---- request -GET /resolve ---- response_body_like: ^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$ - - - -=== TEST 4: query only IPv6 addresses ---- config - resolver 8.8.8.8; - location = /resolve { - content_by_lua "ngx.say(ngx.resolve('google.com', { ipv4 = false, ipv6 = true }))"; - } ---- request -GET /resolve ---- response_body_like: ^[a-fA-F0-9:]+$ - - - -=== TEST 5: pass IPv4 address to ngx.resolve ---- config - location = /resolve { - content_by_lua "ngx.say(ngx.resolve('192.168.0.1'))"; - } ---- request -GET /resolve ---- response_body -192.168.0.1 - - - -=== TEST 6: pass IPv6 address to ngx.resolve ---- config - location = /resolve { - content_by_lua "ngx.say(ngx.resolve('[2a00:1450:4010:c05::66]'))"; - } ---- request -GET /resolve ---- response_body -2a00:1450:4010:c05::66 - - - -=== TEST 7: pass non-existent domain name to ngx.resolve ---- config - resolver 8.8.8.8; - resolver_timeout 1s; - location = /resolve { - content_by_lua "ngx.say(ngx.resolve('non-existent-domain-name'))"; - } ---- request -GET /resolve ---- response_body -niladdress not found