From ecbc5b67544769bddef08d122258333f3cf7561e Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Fri, 2 Mar 2018 14:48:13 -0500 Subject: [PATCH 01/34] enable setting upstreams dynamically via HTTP endpoint --- images/nginx/Dockerfile | 36 ++++- images/nginx/build.sh | 4 +- .../ingress/controller/template/template.go | 3 +- rootfs/etc/nginx/lua/balancer.lua | 8 ++ rootfs/etc/nginx/lua/dicts_handler.lua | 7 + rootfs/etc/nginx/lua/vendor/router.lua | 135 ++++++++++++++++++ rootfs/etc/nginx/template/nginx.tmpl | 20 +++ 7 files changed, 209 insertions(+), 4 deletions(-) create mode 100644 rootfs/etc/nginx/lua/balancer.lua create mode 100644 rootfs/etc/nginx/lua/dicts_handler.lua create mode 100644 rootfs/etc/nginx/lua/vendor/router.lua diff --git a/images/nginx/Dockerfile b/images/nginx/Dockerfile index 4144ae3a72..dcec3f2c5e 100644 --- a/images/nginx/Dockerfile +++ b/images/nginx/Dockerfile @@ -17,10 +17,42 @@ FROM BASEIMAGE CROSS_BUILD_COPY qemu-ARCH-static /usr/bin/ -COPY build.sh / - RUN clean-install bash +RUN mkdir -p /etc/nginx + +# install required packages to build +RUN apt-get update && apt-get dist-upgrade -y && \ + clean-install \ + bash \ + build-essential \ + curl ca-certificates \ + libgeoip1 \ + libgeoip-dev \ + patch \ + libpcre3 \ + libpcre3-dev \ + libssl-dev \ + zlib1g \ + zlib1g-dev \ + libaio1 \ + libaio-dev \ + openssl \ + libperl-dev \ + cmake \ + util-linux \ + lua5.1 liblua5.1-0 liblua5.1-dev lua5.1-cjson \ + lmdb-utils \ + libjemalloc1 libjemalloc-dev \ + wget \ + libcurl4-openssl-dev \ + procps \ + git g++ pkgconf flex bison doxygen libyajl-dev liblmdb-dev libtool dh-autoreconf libxml2 libpcre++-dev libxml2-dev \ + || exit 1 + +RUN ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so + +COPY build.sh / RUN /build.sh # Create symlinks to redirect nginx logs to stdout and stderr docker log collector diff --git a/images/nginx/build.sh b/images/nginx/build.sh index b0c09d3250..cef742bfca 100755 --- a/images/nginx/build.sh +++ b/images/nginx/build.sh @@ -342,7 +342,9 @@ WITH_MODULES="--add-module=$BUILD_PATH/ngx_devel_kit-$NDK_VERSION \ --add-dynamic-module=$BUILD_PATH/nginx-opentracing-$NGINX_OPENTRACING_VERSION/jaeger \ --add-dynamic-module=$BUILD_PATH/nginx-opentracing-$NGINX_OPENTRACING_VERSION/zipkin \ --add-dynamic-module=$BUILD_PATH/ModSecurity-nginx-$MODSECURITY_VERSION \ - --add-module=$BUILD_PATH/ngx_brotli" + --add-module=$BUILD_PATH/ngx_brotli \ + --add-module=$BUILD_PATH/lua-nginx-module-$LUA_VERSION \ + --add-module=$BUILD_PATH/lua-upstream-nginx-module-$LUA_UPSTREAM_VERSION" ./configure \ --prefix=/usr/share/nginx \ diff --git a/internal/ingress/controller/template/template.go b/internal/ingress/controller/template/template.go index e17f300ff4..ec366cb828 100644 --- a/internal/ingress/controller/template/template.go +++ b/internal/ingress/controller/template/template.go @@ -313,7 +313,8 @@ func buildProxyPass(host string, b interface{}, loc interface{}) string { } // defProxyPass returns the default proxy_pass, just the name of the upstream - defProxyPass := fmt.Sprintf("proxy_pass %s://%s;", proto, upstreamName) + //defProxyPass := fmt.Sprintf("proxy_pass %s://%s;", proto, upstreamName) + defProxyPass := fmt.Sprintf("proxy_pass %s://upstream_balancer;", proto) // if the path in the ingress rule is equals to the target: no special rewrite if path == location.Rewrite.Target { return defProxyPass diff --git a/rootfs/etc/nginx/lua/balancer.lua b/rootfs/etc/nginx/lua/balancer.lua new file mode 100644 index 0000000000..b1b7f15227 --- /dev/null +++ b/rootfs/etc/nginx/lua/balancer.lua @@ -0,0 +1,8 @@ +_M = {} + +-- curl localhost:18080/lua_dicts +function _M.call() + ngx.log(ngx.WARN, "I'm the balancer") +end + +return _M diff --git a/rootfs/etc/nginx/lua/dicts_handler.lua b/rootfs/etc/nginx/lua/dicts_handler.lua new file mode 100644 index 0000000000..8c2baf92b7 --- /dev/null +++ b/rootfs/etc/nginx/lua/dicts_handler.lua @@ -0,0 +1,7 @@ +_M = {} + +function _M.call() + ngx.log(ngx.WARN, "I'm the dicts handler") +end + +return _M diff --git a/rootfs/etc/nginx/lua/vendor/router.lua b/rootfs/etc/nginx/lua/vendor/router.lua new file mode 100644 index 0000000000..56eff96bc8 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/router.lua @@ -0,0 +1,135 @@ +local router = { + _VERSION = 'router.lua v2.1.0', + _DESCRIPTION = 'A simple router for Lua', + _LICENSE = [[ + MIT LICENSE + + * Copyright (c) 2013 Enrique GarcĂ­a Cota + * Copyright (c) 2013 Raimon Grau + * Copyright (c) 2015 Lloyd Zhou + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ]] +} + +local COLON_BYTE = string.byte(':', 1) + +local function match_one_path(node, path, f) + for token in path:gmatch("[^/.]+") do + node[token] = node[token] or {} + node = node[token] + end + node["LEAF"] = f +end + +local function resolve(path, node, params) + local _, _, current_token, path = path:find("([^/.]+)(.*)") + if not current_token then return node["LEAF"], params end + + for child_token, child_node in pairs(node) do + if child_token == current_token then + local f, bindings = resolve(path, child_node, params) + if f then return f, bindings end + end + end + + for child_token, child_node in pairs(node) do + if child_token:byte(1) == COLON_BYTE then -- token begins with ':' + local param_name = child_token:sub(2) + local param_value = params[param_name] + params[param_name] = current_token or param_value -- store the value in params, resolve tail path + + local f, bindings = resolve(path, child_node, params) + if f then return f, bindings end + + params[param_name] = param_value -- reset the params table. + end + end + + return false +end + +local function merge(destination, origin, visited) + if type(origin) ~= 'table' then return origin end + if visited[origin] then return visited[origin] end + if destination == nil then destination = {} end + + for k,v in pairs(origin) do + k = merge(nil, k, visited) -- makes a copy of k + if destination[k] == nil then + destination[k] = merge(nil, v, visited) + end + end + + return destination +end + +local function merge_params(...) + local params_list = {...} + local result, visited = {}, {} + + for i=1, #params_list do + merge(result, params_list[i], visited) + end + + return result +end + +------------------------------ INSTANCE METHODS ------------------------------------ +local Router = {} + +function Router:resolve(method, path, ...) + local node = self._tree[method] + if not node then return nil, ("Unknown method: %s"):format(method) end + return resolve(path, node, merge_params(...)) +end + +function Router:execute(method, path, ...) + local f,params = self:resolve(method, path, ...) + if not f then return nil, ('Could not resolve %s %s - %s'):format(method, path, params) end + return true, f(params) +end + +function Router:match(method, path, f) + if type(method) == 'string' then -- always make the method to table. + method = {[method] = {[path] = f}} + end + for m, routes in pairs(method) do + for path, f in pairs(routes) do + if not self._tree[m] then self._tree[m] = {} end + match_one_path(self._tree[m], path, f) + end + end +end + +for method in ("get post put delete trace connect options head"):gmatch("%S+") do + Router[method] = function(self, path, f) -- Router.get = function(self, path, f) + return self:match(method:upper(), path, f) -- return self:match('GET', path, f) + end -- end +end + +local router_mt = { __index = Router } + +------------------------------ PUBLIC INTERFACE ------------------------------------ +router.new = function() + return setmetatable({ _tree = {} }, router_mt) +end + +return router diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index 48ec311d85..40c7cd2c39 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -32,6 +32,8 @@ events { } http { + lua_package_path "/etc/nginx/lua/?.lua;/etc/nginx/lua/vendor/?.lua;;"; + {{/* we use the value of the header X-Forwarded-For to be able to use the geo_ip module */}} {{ if $cfg.UseProxyProtocol }} real_ip_header proxy_protocol; @@ -336,6 +338,17 @@ http { {{ end }} } + upstream upstream_balancer { + server 0.0.0.1; # placeholder + + balancer_by_lua_block { + local balancer = require("balancer") + balancer.call() + } + + keepalive 1000; + } + {{ end }} {{/* build the maps that will be use to validate the Whitelist */}} @@ -453,6 +466,13 @@ http { {{ end }} } + location /lua_dicts { + content_by_lua_block { + local dicts_handler = require("dicts_handler") + dicts_handler.call() + } + } + location / { {{ if .CustomErrors }} proxy_set_header X-Code 404; From d3f4c0830578a6ea6ec47dc613bda3d174b0d0f6 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Fri, 2 Mar 2018 15:39:15 -0500 Subject: [PATCH 02/34] added lua-resty-core as vendor --- rootfs/etc/nginx/lua/vendor/ngx/balancer.lua | 210 ++++ rootfs/etc/nginx/lua/vendor/ngx/balancer.md | 304 ++++++ rootfs/etc/nginx/lua/vendor/ngx/base64.lua | 89 ++ rootfs/etc/nginx/lua/vendor/ngx/base64.md | 137 +++ rootfs/etc/nginx/lua/vendor/ngx/errlog.lua | 133 +++ rootfs/etc/nginx/lua/vendor/ngx/errlog.md | 429 ++++++++ rootfs/etc/nginx/lua/vendor/ngx/ocsp.lua | 150 +++ rootfs/etc/nginx/lua/vendor/ngx/ocsp.md | 298 ++++++ rootfs/etc/nginx/lua/vendor/ngx/process.lua | 74 ++ rootfs/etc/nginx/lua/vendor/ngx/process.md | 230 +++++ rootfs/etc/nginx/lua/vendor/ngx/re.lua | 284 +++++ rootfs/etc/nginx/lua/vendor/ngx/re.md | 249 +++++ rootfs/etc/nginx/lua/vendor/ngx/semaphore.lua | 152 +++ rootfs/etc/nginx/lua/vendor/ngx/semaphore.md | 356 +++++++ rootfs/etc/nginx/lua/vendor/ngx/ssl.lua | 313 ++++++ rootfs/etc/nginx/lua/vendor/ngx/ssl.md | 513 +++++++++ .../etc/nginx/lua/vendor/ngx/ssl/session.lua | 109 ++ .../etc/nginx/lua/vendor/ngx/ssl/session.md | 277 +++++ rootfs/etc/nginx/lua/vendor/resty/core.lua | 29 + .../etc/nginx/lua/vendor/resty/core/base.lua | 236 +++++ .../nginx/lua/vendor/resty/core/base64.lua | 90 ++ .../etc/nginx/lua/vendor/resty/core/ctx.lua | 82 ++ .../etc/nginx/lua/vendor/resty/core/exit.lua | 48 + .../etc/nginx/lua/vendor/resty/core/hash.lua | 80 ++ .../etc/nginx/lua/vendor/resty/core/misc.lua | 155 +++ .../etc/nginx/lua/vendor/resty/core/phase.lua | 57 + .../etc/nginx/lua/vendor/resty/core/regex.lua | 971 ++++++++++++++++++ .../nginx/lua/vendor/resty/core/request.lua | 351 +++++++ .../nginx/lua/vendor/resty/core/response.lua | 165 +++ .../nginx/lua/vendor/resty/core/shdict.lua | 538 ++++++++++ .../etc/nginx/lua/vendor/resty/core/time.lua | 121 +++ .../etc/nginx/lua/vendor/resty/core/uri.lua | 64 ++ .../etc/nginx/lua/vendor/resty/core/var.lua | 130 +++ .../nginx/lua/vendor/resty/core/worker.lua | 46 + 34 files changed, 7470 insertions(+) create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/balancer.lua create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/balancer.md create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/base64.lua create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/base64.md create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/errlog.lua create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/errlog.md create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/ocsp.lua create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/ocsp.md create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/process.lua create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/process.md create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/re.lua create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/re.md create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/semaphore.lua create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/semaphore.md create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/ssl.lua create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/ssl.md create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/ssl/session.lua create mode 100644 rootfs/etc/nginx/lua/vendor/ngx/ssl/session.md create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/base.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/base64.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/ctx.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/exit.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/hash.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/misc.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/phase.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/regex.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/request.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/response.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/shdict.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/time.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/uri.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/var.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/worker.lua diff --git a/rootfs/etc/nginx/lua/vendor/ngx/balancer.lua b/rootfs/etc/nginx/lua/vendor/ngx/balancer.lua new file mode 100644 index 0000000000..b947043d73 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/balancer.lua @@ -0,0 +1,210 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local base = require "resty.core.base" +base.allows_subsystem('http', 'stream') + + +local ffi = require "ffi" +local C = ffi.C +local ffi_str = ffi.string +local errmsg = base.get_errmsg_ptr() +local FFI_OK = base.FFI_OK +local FFI_ERROR = base.FFI_ERROR +local int_out = ffi.new("int[1]") +local getfenv = getfenv +local error = error +local type = type +local tonumber = tonumber +local max = math.max +local subsystem = ngx.config.subsystem +local ngx_lua_ffi_balancer_set_current_peer +local ngx_lua_ffi_balancer_set_more_tries +local ngx_lua_ffi_balancer_get_last_failure +local ngx_lua_ffi_balancer_set_timeouts -- used by both stream and http + + +if subsystem == 'http' then + ffi.cdef[[ + int ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, + const unsigned char *addr, size_t addr_len, int port, char **err); + + int ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r, + int count, char **err); + + int ngx_http_lua_ffi_balancer_get_last_failure(ngx_http_request_t *r, + int *status, char **err); + + int ngx_http_lua_ffi_balancer_set_timeouts(ngx_http_request_t *r, + long connect_timeout, long send_timeout, + long read_timeout, char **err); + ]] + + ngx_lua_ffi_balancer_set_current_peer = + C.ngx_http_lua_ffi_balancer_set_current_peer + + ngx_lua_ffi_balancer_set_more_tries = + C.ngx_http_lua_ffi_balancer_set_more_tries + + ngx_lua_ffi_balancer_get_last_failure = + C.ngx_http_lua_ffi_balancer_get_last_failure + + ngx_lua_ffi_balancer_set_timeouts = + C.ngx_http_lua_ffi_balancer_set_timeouts + +elseif subsystem == 'stream' then + ffi.cdef[[ + int ngx_stream_lua_ffi_balancer_set_current_peer( + ngx_stream_lua_request_t *r, + const unsigned char *addr, size_t addr_len, int port, char **err); + + int ngx_stream_lua_ffi_balancer_set_more_tries(ngx_stream_lua_request_t *r, + int count, char **err); + + int ngx_stream_lua_ffi_balancer_get_last_failure( + ngx_stream_lua_request_t *r, int *status, char **err); + + int ngx_stream_lua_ffi_balancer_set_timeouts(ngx_stream_lua_request_t *r, + long connect_timeout, long timeout, char **err); + ]] + + ngx_lua_ffi_balancer_set_current_peer = + C.ngx_stream_lua_ffi_balancer_set_current_peer + + ngx_lua_ffi_balancer_set_more_tries = + C.ngx_stream_lua_ffi_balancer_set_more_tries + + ngx_lua_ffi_balancer_get_last_failure = + C.ngx_stream_lua_ffi_balancer_get_last_failure + + local ngx_stream_lua_ffi_balancer_set_timeouts = + C.ngx_stream_lua_ffi_balancer_set_timeouts + + ngx_lua_ffi_balancer_set_timeouts = + function(r, connect_timeout, send_timeout, read_timeout, err) + local timeout = max(send_timeout, read_timeout) + + return ngx_stream_lua_ffi_balancer_set_timeouts(r, connect_timeout, + timeout, err) + end + +else + error("unknown subsystem: " .. subsystem) +end + + +local peer_state_names = { + [1] = "keepalive", + [2] = "next", + [4] = "failed", +} + + +local _M = { version = base.version } + + +function _M.set_current_peer(addr, port) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + if not port then + port = 0 + elseif type(port) ~= "number" then + port = tonumber(port) + end + + local rc = ngx_lua_ffi_balancer_set_current_peer(r, addr, #addr, + port, errmsg) + if rc == FFI_OK then + return true + end + + return nil, ffi_str(errmsg[0]) +end + + +function _M.set_more_tries(count) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local rc = ngx_lua_ffi_balancer_set_more_tries(r, count, errmsg) + if rc == FFI_OK then + if errmsg[0] == nil then + return true + end + return true, ffi_str(errmsg[0]) -- return the warning + end + + return nil, ffi_str(errmsg[0]) +end + + +function _M.get_last_failure() + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local state = ngx_lua_ffi_balancer_get_last_failure(r, int_out, errmsg) + + if state == 0 then + return nil + end + + if state == FFI_ERROR then + return nil, nil, ffi_str(errmsg[0]) + end + + return peer_state_names[state] or "unknown", int_out[0] +end + + +function _M.set_timeouts(connect_timeout, send_timeout, read_timeout) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + if not connect_timeout then + connect_timeout = 0 + elseif type(connect_timeout) ~= "number" or connect_timeout <= 0 then + return error("bad connect timeout") + else + connect_timeout = connect_timeout * 1000 + end + + if not send_timeout then + send_timeout = 0 + elseif type(send_timeout) ~= "number" or send_timeout <= 0 then + return error("bad send timeout") + else + send_timeout = send_timeout * 1000 + end + + if not read_timeout then + read_timeout = 0 + elseif type(read_timeout) ~= "number" or read_timeout <= 0 then + return error("bad read timeout") + else + read_timeout = read_timeout * 1000 + end + + local rc + + rc = ngx_lua_ffi_balancer_set_timeouts(r, connect_timeout, + send_timeout, read_timeout, + errmsg) + + if rc == FFI_OK then + return true + end + + return false, ffi_str(errmsg[0]) +end + + +return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/balancer.md b/rootfs/etc/nginx/lua/vendor/ngx/balancer.md new file mode 100644 index 0000000000..b2f852be18 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/balancer.md @@ -0,0 +1,304 @@ +Name +==== + +ngx.balancer - Lua API for defining dynamic upstream balancers in Lua + +Table of Contents +================= + +* [Name](#name) +* [Status](#status) +* [Synopsis](#synopsis) +* [Description](#description) +* [Methods](#methods) + * [set_current_peer](#set_current_peer) + * [set_more_tries](#set_more_tries) + * [get_last_failure](#get_last_failure) + * [set_timeouts](#set_timeouts) +* [Community](#community) + * [English Mailing List](#english-mailing-list) + * [Chinese Mailing List](#chinese-mailing-list) +* [Bugs and Patches](#bugs-and-patches) +* [Author](#author) +* [Copyright and License](#copyright-and-license) +* [See Also](#see-also) + +Status +====== + +This Lua module is currently considered experimental. + +Synopsis +======== + +http subsystem +-------------- + +```nginx +http { + upstream backend { + server 0.0.0.1; # just an invalid address as a place holder + + balancer_by_lua_block { + local balancer = require "ngx.balancer" + + -- well, usually we calculate the peer's host and port + -- according to some balancing policies instead of using + -- hard-coded values like below + local host = "127.0.0.2" + local port = 8080 + + local ok, err = balancer.set_current_peer(host, port) + if not ok then + ngx.log(ngx.ERR, "failed to set the current peer: ", err) + return ngx.exit(500) + end + } + + keepalive 10; # connection pool + } + + server { + # this is the real entry point + listen 80; + + location / { + # make use of the upstream named "backend" defined above: + proxy_pass http://backend/fake; + } + } + + server { + # this server is just for mocking up a backend peer here... + listen 127.0.0.2:8080; + + location = /fake { + echo "this is the fake backend peer..."; + } + } +} +``` + +stream subsystem +---------------- + +```nginx +stream { + upstream backend { + server 0.0.0.1:1234; # just an invalid address as a place holder + + balancer_by_lua_block { + local balancer = require "ngx.balancer" + + -- well, usually we calculate the peer's host and port + -- according to some balancing policies instead of using + -- hard-coded values like below + local host = "127.0.0.2" + local port = 8080 + + local ok, err = balancer.set_current_peer(host, port) + if not ok then + ngx.log(ngx.ERR, "failed to set the current peer: ", err) + return ngx.exit(ngx.ERR) + end + } + } + + server { + # this is the real entry point + listen 10000; + + location / { + # make use of the upstream named "backend" defined above: + proxy_pass backend; + } + } + + server { + # this server is just for mocking up a backend peer here... + listen 127.0.0.2:8080; + + echo "this is the fake backend peer..."; + } +} +``` + +Description +=========== + +This Lua module provides API functions to allow defining highly dynamic NGINX load balancers for +any existing nginx upstream modules like [ngx_http_proxy_module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html), +[ngx_http_fastcgi_module](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html) and +[ngx_stream_proxy_module](https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html). + +It allows you to dynamically select a backend peer to connect to (or retry) on a per-request +basis from a list of backend peers which may also be dynamic. + +[Back to TOC](#table-of-contents) + +Methods +======= + +All the methods of this module are static (or module-level). That is, you do not need an object (or instance) +to call these methods. + +[Back to TOC](#table-of-contents) + +set_current_peer +---------------- +**syntax:** *ok, err = balancer.set_current_peer(host, port)* + +**context:** *balancer_by_lua** + +Sets the peer address (host and port) for the current backend query (which may be a retry). + +Domain names in `host` do not make sense. You need to use OpenResty libraries like +[lua-resty-dns](https://github.com/openresty/lua-resty-dns) to obtain IP address(es) from +all the domain names before entering the `balancer_by_lua*` handler (for example, +you can perform DNS lookups in an earlier phase like [access_by_lua*](https://github.com/openresty/lua-nginx-module#access_by_lua) +and pass the results to the `balancer_by_lua*` handler via [ngx.ctx](https://github.com/openresty/lua-nginx-module#ngxctx). + +[Back to TOC](#table-of-contents) + +set_more_tries +-------------- +**syntax:** *ok, err = balancer.set_more_tries(count)* + +**context:** *balancer_by_lua** + +Sets the tries performed when the current attempt (which may be a retry) fails (as determined +by directives like [proxy_next_upstream](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream), depending on what +particular nginx uptream module you are currently using). Note that the current attempt is *excluded* in the `count` number set here. + +Please note that, the total number of tries in a single downstream request cannot exceed the +hard limit configured by directives like [proxy_next_upstream_tries](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream_tries), +depending on what concrete nginx upstream module you are using. When exceeding this limit, +the `count` value will get reduced to meet the limit and the second return value will be +the string `"reduced tries due to limit"`, which is a warning, while the first return value +is still a `true` value. + +[Back to TOC](#table-of-contents) + +get_last_failure +---------------- +**syntax:** *state_name, status_code = balancer.get_last_failure()* + +**context:** *balancer_by_lua** + +Retrieves the failure details about the previous failed attempt (if any) when the `next_upstream` retrying +mechanism is in action. When there was indeed a failed previous attempt, it returned a string describing +that attempt's state name, as well as an integer describing the status code of that attempt. + +Possible state names are as follows: +* `"next"` + Failures due to bad status codes sent from the backend server. The origin's response is sane though, which means the backend connection +can still be reused for future requests. +* `"failed"` + Fatal errors while communicating to the backend server (like connection timeouts, connection resets, and etc). In this case, +the backend connection must be aborted and cannot get reused. + +Possible status codes are those HTTP error status codes like `502` and `504`. + +For stream module, `status_code` will always be 0 (ngx.OK) and is provided for compatibility reasons. + +When the current attempt is the first attempt for the current downstream request (which means +there is no previous attempts at all), this +method always returns a single `nil` value. + +[Back to TOC](#table-of-contents) + +set_timeouts +------------ +**syntax:** `ok, err = balancer.set_timeouts(connect_timeout, send_timeout, read_timeout)` + +**context:** *balancer_by_lua** + +Sets the upstream timeout (connect, send and read) in seconds for the current and any +subsequent backend requests (which might be a retry). + +If you want to inherit the timeout value of the global `nginx.conf` configuration (like `proxy_connect_timeout`), then +just specify the `nil` value for the corresponding argument (like the `connect_timeout` argument). + +Zero and negative timeout values are not allowed. + +You can specify millisecond precision in the timeout values by using floating point numbers like 0.001 (which means 1ms). + +**Note:** `send_timeout` and `read_timeout` are controlled by the same config +[`proxy_timeout`](https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_timeout) +for `ngx_stream_proxy_module`. To keep API compatibility, this function will use `max(send_timeout, read_timeout)` +as the value for setting `proxy_timeout`. + +Returns `true` when the operation is successful; returns `nil` and a string describing the error +otherwise. + +This only affects the current downstream request. It is not a global change. + +For the best performance, you should use the [OpenResty](https://openresty.org/) bundle. + +This function was first added in the `0.1.7` version of this library. + +[Back to TOC](#table-of-contents) + +Community +========= + +[Back to TOC](#table-of-contents) + +English Mailing List +-------------------- + +The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. + +[Back to TOC](#table-of-contents) + +Chinese Mailing List +-------------------- + +The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. + +[Back to TOC](#table-of-contents) + +Bugs and Patches +================ + +Please report bugs or submit patches by + +1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), +1. or posting to the [OpenResty community](#community). + +[Back to TOC](#table-of-contents) + +Author +====== + +Yichun Zhang <agentzh@gmail.com> (agentzh), OpenResty Inc. + +[Back to TOC](#table-of-contents) + +Copyright and License +===================== + +This module is licensed under the BSD license. + +Copyright (C) 2015-2017, by Yichun "agentzh" Zhang, OpenResty Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[Back to TOC](#table-of-contents) + +See Also +======== +* the ngx_lua module: https://github.com/openresty/lua-nginx-module +* the [balancer_by_lua*](https://github.com/openresty/lua-nginx-module#balancer_by_lua_block) directive. +* library [lua-resty-core](https://github.com/openresty/lua-resty-core) +* OpenResty: http://openresty.org + +[Back to TOC](#table-of-contents) diff --git a/rootfs/etc/nginx/lua/vendor/ngx/base64.lua b/rootfs/etc/nginx/lua/vendor/ngx/base64.lua new file mode 100644 index 0000000000..a8a6aaf447 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/base64.lua @@ -0,0 +1,89 @@ +-- Copyright (C) by Yichun Zhang (agentzh) +-- Copyright (C) by OpenResty Inc. + +local ffi = require("ffi") +local base = require("resty.core.base") + + +local ffi_str = ffi.string +local type = type +local C = ffi.C +local NGX_ERROR = ngx.ERROR + + +local _M = { version = base.version } + + +ffi.cdef[[ +typedef intptr_t ngx_int_t; + +void ngx_encode_base64url(ngx_str_t *dst, ngx_str_t *src); +ngx_int_t ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src); +]] + + +local get_string_buf = base.get_string_buf + + +local dst_str_t = ffi.new("ngx_str_t[1]") +local src_str_t = ffi.new("ngx_str_t[1]") + + +local function base64_encoded_length(len) + return ((len + 2) / 3) * 4 +end + + +local function base64_decoded_length(len) + return ((len + 3) / 4) * 3 +end + + +function _M.encode_base64url(s) + if type(s) ~= "string" then + return nil, "must provide a string" + end + + local len = #s + local trans_len = base64_encoded_length(len) + local src = src_str_t[0] + local dst = dst_str_t[0] + + src.data = s + src.len = len + + dst.data = get_string_buf(trans_len) + dst.len = trans_len + + C.ngx_encode_base64url(dst_str_t, src_str_t) + + return ffi_str(dst.data, dst.len) +end + + +function _M.decode_base64url(s) + if type(s) ~= "string" then + return nil, "must provide a string" + end + + local len = #s + local trans_len = base64_decoded_length(len) + local src = src_str_t[0] + local dst = dst_str_t[0] + + src.data = s + src.len = len + + dst.data = get_string_buf(trans_len) + dst.len = trans_len + + local ret = C.ngx_decode_base64url(dst_str_t, src_str_t) + if ret == NGX_ERROR then + return nil, "invalid input" + end + + return ffi_str(dst.data, dst.len) +end + + +return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/base64.md b/rootfs/etc/nginx/lua/vendor/ngx/base64.md new file mode 100644 index 0000000000..a410b21885 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/base64.md @@ -0,0 +1,137 @@ +Name +==== + +`ngx.base64` - urlsafe base64 encode/decode functions OpenResty/ngx\_lua. + +Table of Contents +================= + +* [Name](#name) +* [Status](#status) +* [Synopsis](#synopsis) +* [Methods](#methods) + * [encode\_base64url](#encode_base64url) + * [decode\_base64url](#decode_base64url) +* [Community](#community) + * [English Mailing List](#english-mailing-list) + * [Chinese Mailing List](#chinese-mailing-list) +* [Bugs and Patches](#bugs-and-patches) +* [Author](#author) +* [Copyright and License](#copyright-and-license) +* [See Also](#see-also) + +Status +====== + +This Lua module is production ready. + +Synopsis +======== + +```lua +local b64 = require("ngx.base64") +local res, err + +res = b64.encode_base64url("foo") + +res, err = b64.decode_base64url(res) +if not res then + -- invalid input + ngx.log(ngx.ERR, err) +end + +assert(res == "foo") +``` + +[Back to TOC](#table-of-contents) + +Methods +======= + +encode\_base64url +----------------- +**syntax:** *encoded = base64.encode_base64url(input)* + +**context:** *any* + +Encode `input` using base64url rules. Returns the encoded string. + +[Back to TOC](#table-of-contents) + +decode\_base64url +----------------- +**syntax:** *decoded, err = base64.decode_base64url(input)* + +**context:** *any* + +Decode `input` using base64url rules. Returns the decoded string. + +If the `input` is not a valid base64url encoded string, `decoded `will be `nil` +and `err` will be a string describing the error. + +[Back to TOC](#table-of-contents) + + +Community +========= + +[Back to TOC](#table-of-contents) + +English Mailing List +-------------------- + +The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. + +[Back to TOC](#table-of-contents) + +Chinese Mailing List +-------------------- + +The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. + +[Back to TOC](#table-of-contents) + +Bugs and Patches +================ + +Please report bugs or submit patches by + +1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), +1. or posting to the [OpenResty community](#community). + +[Back to TOC](#table-of-contents) + +Author +====== + +Datong Sun <datong@openresty.com> (dndx), OpenResty Inc. + +[Back to TOC](#table-of-contents) + +Copyright and License +===================== + +This module is licensed under the BSD license. + +Copyright (C) 2017, by Yichun "agentzh" Zhang, OpenResty Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[Back to TOC](#table-of-contents) + +See Also +======== +* library [lua-resty-core](https://github.com/openresty/lua-resty-core) +* the ngx_lua module: https://github.com/openresty/lua-nginx-module +* OpenResty: http://openresty.org + +[Back to TOC](#table-of-contents) + diff --git a/rootfs/etc/nginx/lua/vendor/ngx/errlog.lua b/rootfs/etc/nginx/lua/vendor/ngx/errlog.lua new file mode 100644 index 0000000000..94dc41d743 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/errlog.lua @@ -0,0 +1,133 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local base = require "resty.core.base" +base.allows_subsystem('http') + + +local ffi = require 'ffi' +local ffi_string = ffi.string +local get_string_buf = base.get_string_buf +local get_size_ptr = base.get_size_ptr +local C = ffi.C +local new_tab = base.new_tab +local ffi_new = ffi.new +local charpp = ffi_new("char *[1]") +local intp = ffi.new("int[1]") +local num_value = ffi_new("double[1]") +local getfenv = getfenv +local tonumber = tonumber +local type = type + + +local _M = { version = base.version } + + +ffi.cdef[[ +int ngx_http_lua_ffi_errlog_set_filter_level(int level, unsigned char *err, + size_t *errlen); +int ngx_http_lua_ffi_errlog_get_msg(char **log, int *loglevel, + unsigned char *err, size_t *errlen, double *log_time); + +int ngx_http_lua_ffi_errlog_get_sys_filter_level(ngx_http_request_t *r); + +int ngx_http_lua_ffi_raw_log(ngx_http_request_t *r, int level, + const unsigned char *s, size_t s_len); +]] + + +local ERR_BUF_SIZE = 128 +local FFI_ERROR = base.FFI_ERROR + + +function _M.set_filter_level(level) + if not level then + return nil, [[missing "level" argument]] + end + + local err = get_string_buf(ERR_BUF_SIZE) + local errlen = get_size_ptr() + errlen[0] = ERR_BUF_SIZE + local rc = C.ngx_http_lua_ffi_errlog_set_filter_level(level, err, errlen) + + if rc == FFI_ERROR then + return nil, ffi_string(err, errlen[0]) + end + + return true +end + + +function _M.get_logs(max, logs) + local err = get_string_buf(ERR_BUF_SIZE) + local errlen = get_size_ptr() + errlen[0] = ERR_BUF_SIZE + + local log = charpp + local loglevel = intp + local log_time = num_value + + max = max or 10 + + if not logs then + logs = new_tab(max * 3 + 1, 0) + end + + local count = 0 + + for i = 1, max do + local loglen = C.ngx_http_lua_ffi_errlog_get_msg(log, loglevel, err, + errlen, log_time) + if loglen == FFI_ERROR then + return nil, ffi_string(err, errlen[0]) + end + + if loglen > 0 then + logs[count + 1] = loglevel[0] + logs[count + 2] = log_time[0] + logs[count + 3] = ffi_string(log[0], loglen) + + count = count + 3 + end + + if loglen < 0 then -- no error log + logs[count + 1] = nil + break + end + + if i == max then -- last one + logs[count + 1] = nil + break + end + end + + return logs +end + + +function _M.get_sys_filter_level() + local r = getfenv(0).__ngx_req + return tonumber(C.ngx_http_lua_ffi_errlog_get_sys_filter_level(r)) +end + + +function _M.raw_log(level, msg) + if type(level) ~= "number" then + error("bad argument #1 to 'raw_log' (must be a number)", 2) + end + + if type(msg) ~= "string" then + error("bad argument #2 to 'raw_log' (must be a string)", 2) + end + + local r = getfenv(0).__ngx_req + + local rc = C.ngx_http_lua_ffi_raw_log(r, level, msg, #msg) + + if rc == FFI_ERROR then + error("bad log level") + end +end + + +return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/errlog.md b/rootfs/etc/nginx/lua/vendor/ngx/errlog.md new file mode 100644 index 0000000000..c51c86f335 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/errlog.md @@ -0,0 +1,429 @@ +Name +==== + +`ngx.errlog` - manage nginx error log data in Lua for OpenResty/ngx_lua. + +Table of Contents +================= + +* [Name](#name) +* [Status](#status) +* [Synopsis](#synopsis) + * [Capturing nginx error logs with specified log filtering level](#capturing-nginx-error-logs-with-specified-log-filtering-level) +* [Methods](#methods) + * [set_filter_level](#set_filter_level) + * [get_logs](#get_logs) + * [get_sys_filter_level](#get_sys_filter_level) + * [raw_log](#raw_log) +* [Community](#community) + * [English Mailing List](#english-mailing-list) + * [Chinese Mailing List](#chinese-mailing-list) +* [Bugs and Patches](#bugs-and-patches) +* [Author](#author) +* [Copyright and License](#copyright-and-license) +* [See Also](#see-also) + +Status +====== + +This Lua module is currently considered experimental. + +The API is still in flux and may change in the future without notice. + +Synopsis +======== + +Capturing nginx error logs with specified log filtering level +------------------------------------------------------------- + +```nginx +error logs/error.log info; + +http { + # enable capturing error logs + lua_capture_error_log 32m; + + init_by_lua_block { + local errlog = require "ngx.errlog" + local status, err = errlog.set_filter_level(ngx.WARN) + if not status then + ngx.log(ngx.ERR, err) + return + end + ngx.log(ngx.WARN, "set error filter level: WARN") + } + + server { + # ... + location = /t { + content_by_lua_block { + local errlog = require "ngx.errlog" + ngx.log(ngx.INFO, "test1") + ngx.log(ngx.WARN, "test2") + ngx.log(ngx.ERR, "test3") + + local logs, err = errlog.get_logs(10) + if not logs then + ngx.say("FAILED ", err) + return + end + + for i = 1, #logs, 3 do + ngx.say("level: ", logs[i], " time: ", logs[i + 1], + " data: ", logs[i + 2]) + end + } + } + } +} + +``` + +The example location above produces a response like this: + +``` +level: 5 time: 1498546995.304 data: 2017/06/27 15:03:15 [warn] 46877#0: + [lua] init_by_lua:8: set error filter level: WARN +level: 5 time: 1498546999.178 data: 2017/06/27 15:03:19 [warn] 46879#0: *1 + [lua] test.lua:5: test2, client: 127.0.0.1, server: localhost, ...... +level: 4 time: 1498546999.178 data: 2017/06/27 15:03:19 [error] 46879#0: *1 + [lua] test.lua:6: test3, client: 127.0.0.1, server: localhost, ...... +``` + +[Back to TOC](#table-of-contents) + +Methods +======= + +set_filter_level +----------------- +**syntax:** *status, err = log_module.set_filter_level(log_level)* + +**context:** *init_by_lua** + +Specifies the filter log level, only to capture and buffer the error logs with a log level +no lower than the specified level. + +If we don't call this API, all of the error logs will be captured by default. + +In case of error, `nil` will be returned as well as a string describing the +error. + +This API should always work with directive +[lua_capture_error_log](https://github.com/openresty/lua-nginx-module#lua_capture_error_log). + +See [Nginx log level constants](https://github.com/openresty/lua-nginx-module#nginx-log-level-constants) for all nginx log levels. + +For example, + +```lua + init_by_lua_block { + local errlog = require "ngx.errlog" + errlog.set_filter_level(ngx.WARN) + } +``` + +*NOTE:* The debugging logs since when OpenResty or NGINX is not built with `--with-debug`, all the debug level logs are suppressed regardless. + +[Back to TOC](#table-of-contents) + +get_logs +-------- +**syntax:** *res, err = log_module.get_logs(max?, res?)* + +**context:** *any* + +Fetches the captured nginx error log messages if any in the global data buffer +specified by `ngx_lua`'s +[lua_capture_error_log](https://github.com/openresty/lua-nginx-module#lua_capture_error_log) +directive. Upon return, this Lua function also *removes* those messages from +that global capturing buffer to make room for future new error log data. + +In case of error, `nil` will be returned as well as a string describing the +error. + +The optional `max` argument is a number that when specified, will prevent +`errlog.get_logs` from adding more than `max` messages to the `res` array. + +```lua +for i = 1, 20 do + ngx.log(ngx.ERR, "test") +end + +local errlog = require "ngx.errlog" +local res = errlog.get_logs(10) +-- the number of messages in the `res` table is 10 and the `res` table +-- has 30 elements. +``` + +The resulting table has the following structure: + +```lua +{ level1, time1, msg1, level2, time2, msg2, ... } +``` + +The `levelX` values are constants defined below: + +https://github.com/openresty/lua-nginx-module/#nginx-log-level-constants + +The `timeX` values are UNIX timestamps in seconds with millisecond precision. The sub-second part is presented as the decimal part. +The time format is exactly the same as the value returned by [ngx.now](https://github.com/openresty/lua-nginx-module/#ngxnow). It is +also subject to NGINX core's time caching. + +The `msgX` values are the error log message texts. + +So to traverse this array, the user can use a loop like this: + +```lua +for i = 1, #res, 3 do + local level = res[i] + if not level then + break + end + + local time = res[i + 1] + local msg = res[i + 2] + + -- handle the current message with log level in `level`, + -- log time in `time`, and log message body in `msg`. +end +``` + +Specifying `max <= 0` disables this behavior, meaning that the number of +results won't be limited. + +The optional 2th argument `res` can be a user-supplied Lua table +to hold the result instead of creating a brand new table. This can avoid +unnecessary table dynamic allocations on hot Lua code paths. It is used like this: + +```lua +local errlog = require "ngx.errlog" +local new_tab = require "table.new" + +local buffer = new_tab(100 * 3, 0) -- for 100 messages + +local errlog = require "ngx.errlog" +local res, err = errlog.get_logs(0, buffer) +if res then + -- res is the same table as `buffer` + for i = 1, #res, 3 do + local level = res[i] + if not level then + break + end + local time = res[i + 1] + local msg = res[i + 2] + ... + end +end +``` + +When provided with a `res` table, `errlog.get_logs` won't clear the table +for performance reasons, but will rather insert a trailing `nil` value +after the last table element. + +When the trailing `nil` is not enough for your purpose, you should +clear the table yourself before feeding it into the `errlog.get_logs` function. + +[Back to TOC](#table-of-contents) + +get_sys_filter_level +-------------------- +**syntax:** *log_level = log_module.get_sys_filter_level()* + +**context:** *any* + +Return the nginx core's error log filter level (defined via the [error_log](http://nginx.org/r/error_log) +configuration directive in `nginx.conf`) as an integer value matching the nginx error log level +constants documented below: + +https://github.com/openresty/lua-nginx-module/#nginx-log-level-constants + +For example: + +```lua +local errlog = require "ngx.errlog" +local log_level = errlog.get_sys_filter_level() +-- Now the filter level is always one level higher than system default log level on priority +local status, err = errlog.set_filter_level(log_level - 1) +if not status then + ngx.log(ngx.ERR, err) + return +end +``` + +[Back to TOC](#table-of-contents) + +raw_log +------- +**syntax:** *log_module.raw_log(log_level, msg)* + +**context:** *any* + +Log `msg` to the error logs with the given logging level. + +Just like the [ngx.log](https://github.com/openresty/lua-nginx-module#ngxlog) +API, the `log_level` argument can take constants like `ngx.ERR` and `ngx.WARN`. +Check out [Nginx log level constants for +details.](https://github.com/openresty/lua-nginx-module#nginx-log-level-constants) + +However, unlike the `ngx.log` API which accepts variadic arguments, this +function only accepts a single string as its second argument `msg`. + +This function differs from `ngx.log` in the way that it will not prefix the +written logs with any sort of debug information (such as the caller's file +and line number). + +For example, while `ngx.log` would produce + +``` +2017/07/09 19:36:25 [notice] 25932#0: *1 [lua] content_by_lua(nginx.conf:51):5: hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" +``` + +from + +```lua +ngx.log(ngx.NOTICE, "hello world") +``` + +the `errlog.raw_log()` call produces + +``` +2017/07/09 19:36:25 [notice] 25932#0: *1 hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" +``` + +from + +```lua +local errlog = require "ngx.errlog" +errlog.raw_log(ngx.NOTICE, "hello world") +``` + +This function is best suited when the format and/or stack level of the debug +information proposed by `ngx.log` is not desired. A good example of this would +be a custom logging function which prefixes each log with a namespace in +an application: + +``` +1. local function my_log(lvl, ...) +2. ngx.log(lvl, "[prefix] ", ...) +3. end +4. +5. my_log(ngx.ERR, "error") +``` + +Here, the produced log would indicate that this error was logged at line `2.`, +when in reality, we wish the investigator of that log to realize it was logged +at line `5.` right away. + +For such use cases (or other formatting reasons), one may use `raw_log` to +create a logging utility that supports such requirements. Here is a suggested +implementation: + +```lua +local errlog = require "ngx.errlog" + +local function my_log(lvl, ...) + -- log to error logs with our custom prefix, stack level + -- and separator + local n = select("#", ...) + local t = { ... } + local info = debug.getinfo(2, "Sl") + + local prefix = string.format("(%s):%d:", info.short_src, info.currentline) + local buf = { prefix } + + for i = 1, n do + buf[i + 1] = tostring(t[i]) + end + + local msg = table.concat(buf, " ") + + errlog.raw_log(lvl, msg) -- line 19. +end + +local function my_function() + -- do something and log + + my_log(ngx.ERR, "hello from", "raw_log:", true) -- line 25. +end + +my_function() +``` + +This utility function will produce the following log, explicitly stating that +the error was logged on line `25.`: + +``` +2017/07/09 20:03:07 [error] 26795#0: *2 (/path/to/file.lua):25: hello from raw_log: true, context: ngx.timer +``` + +As a reminder to the reader, one must be wary of the cost of string +concatenation on the Lua land, and should prefer the combined use of a buffer +table and `table.concat` to avoid unnecessary GC pressure. + +[Back to TOC](#table-of-contents) + +Community +========= + +[Back to TOC](#table-of-contents) + +English Mailing List +-------------------- + +The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. + +[Back to TOC](#table-of-contents) + +Chinese Mailing List +-------------------- + +The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. + +[Back to TOC](#table-of-contents) + +Bugs and Patches +================ + +Please report bugs or submit patches by + +1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), +1. or posting to the [OpenResty community](#community). + +[Back to TOC](#table-of-contents) + +Author +====== + +Yuansheng Wang <membphis@gmail.com> (membphis), OpenResty Inc. + +[Back to TOC](#table-of-contents) + +Copyright and License +===================== + +This module is licensed under the BSD license. + +Copyright (C) 2017, by Yichun "agentzh" Zhang, OpenResty Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[Back to TOC](#table-of-contents) + +See Also +======== +* library [lua-resty-core](https://github.com/openresty/lua-resty-core) +* the ngx_lua module: https://github.com/openresty/lua-nginx-module +* OpenResty: http://openresty.org + +[Back to TOC](#table-of-contents) + diff --git a/rootfs/etc/nginx/lua/vendor/ngx/ocsp.lua b/rootfs/etc/nginx/lua/vendor/ngx/ocsp.lua new file mode 100644 index 0000000000..53c1acc957 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/ocsp.lua @@ -0,0 +1,150 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local base = require "resty.core.base" +base.allows_subsystem('http') + + +local ffi = require "ffi" +local C = ffi.C +local ffi_str = ffi.string +local getfenv = getfenv +local error = error +local tonumber = tonumber +local errmsg = base.get_errmsg_ptr() +local get_string_buf = base.get_string_buf +local get_string_buf_size = base.get_string_buf_size +local get_size_ptr = base.get_size_ptr +local FFI_DECLINED = base.FFI_DECLINED +local FFI_OK = base.FFI_OK +local FFI_BUSY = base.FFI_BUSY + + +ffi.cdef[[ +int ngx_http_lua_ffi_ssl_get_ocsp_responder_from_der_chain( + const char *chain_data, size_t chain_len, char *out, size_t *out_size, + char **err); + +int ngx_http_lua_ffi_ssl_create_ocsp_request(const char *chain_data, + size_t chain_len, unsigned char *out, size_t *out_size, char **err); + +int ngx_http_lua_ffi_ssl_validate_ocsp_response(const unsigned char *resp, + size_t resp_len, const char *chain_data, size_t chain_len, + unsigned char *errbuf, size_t *errbuf_size); + +int ngx_http_lua_ffi_ssl_set_ocsp_status_resp(ngx_http_request_t *r, + const unsigned char *resp, size_t resp_len, char **err); +]] + + +local _M = { version = base.version } + + +function _M.get_ocsp_responder_from_der_chain(certs, maxlen) + + local buf_size = maxlen + if not buf_size then + buf_size = get_string_buf_size() + end + local buf = get_string_buf(buf_size) + + local sizep = get_size_ptr() + sizep[0] = buf_size + + local rc = C.ngx_http_lua_ffi_ssl_get_ocsp_responder_from_der_chain(certs, + #certs, buf, sizep, errmsg) + + if rc == FFI_DECLINED then + return nil + end + + if rc == FFI_OK then + return ffi_str(buf, sizep[0]) + end + + if rc == FFI_BUSY then + return ffi_str(buf, sizep[0]), "truncated" + end + + return nil, ffi_str(errmsg[0]) +end + + +function _M.create_ocsp_request(certs, maxlen) + + local buf_size = maxlen + if not buf_size then + buf_size = get_string_buf_size() + end + local buf = get_string_buf(buf_size) + + local sizep = get_size_ptr() + sizep[0] = buf_size + + local rc = C.ngx_http_lua_ffi_ssl_create_ocsp_request(certs, + #certs, buf, sizep, + errmsg) + + if rc == FFI_OK then + return ffi_str(buf, sizep[0]) + end + + if rc == FFI_BUSY then + return nil, ffi_str(errmsg[0]) .. ": " .. tonumber(sizep[0]) + .. " > " .. buf_size + end + + return nil, ffi_str(errmsg[0]) +end + + +function _M.validate_ocsp_response(resp, chain, max_errmsg_len) + + local errbuf_size = max_errmsg_len + if not errbuf_size then + errbuf_size = get_string_buf_size() + end + local errbuf = get_string_buf(errbuf_size) + + local sizep = get_size_ptr() + sizep[0] = errbuf_size + + local rc = C.ngx_http_lua_ffi_ssl_validate_ocsp_response( + resp, #resp, chain, #chain, errbuf, sizep) + + if rc == FFI_OK then + return true + end + + -- rc == FFI_ERROR + + return nil, ffi_str(errbuf, sizep[0]) +end + + +function _M.set_ocsp_status_resp(ocsp_resp) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local rc = C.ngx_http_lua_ffi_ssl_set_ocsp_status_resp(r, ocsp_resp, + #ocsp_resp, + errmsg) + + if rc == FFI_DECLINED then + -- no client status req + return true, "no status req" + end + + if rc == FFI_OK then + return true + end + + -- rc == FFI_ERROR + + return nil, ffi_str(errmsg[0]) +end + + +return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/ocsp.md b/rootfs/etc/nginx/lua/vendor/ngx/ocsp.md new file mode 100644 index 0000000000..62c230810c --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/ocsp.md @@ -0,0 +1,298 @@ +Name +==== + +ngx.ocsp - Lua API for implementing OCSP stapling in ssl_certificate_by_lua* + +Table of Contents +================= + +* [Name](#name) +* [Status](#status) +* [Synopsis](#synopsis) +* [Description](#description) +* [Methods](#methods) + * [get_ocsp_responder_from_der_chain](#get_ocsp_responder_from_der_chain) + * [create_ocsp_request](#create_ocsp_request) + * [validate_ocsp_response](#validate_ocsp_response) + * [set_ocsp_status_resp](#set_ocsp_status_resp) +* [Community](#community) + * [English Mailing List](#english-mailing-list) + * [Chinese Mailing List](#chinese-mailing-list) +* [Bugs and Patches](#bugs-and-patches) +* [Author](#author) +* [Copyright and License](#copyright-and-license) +* [See Also](#see-also) + +Status +====== + +This Lua module is currently considered experimental. + +Synopsis +======== + +```nginx +# Note: you do not need the following line if you are using +# OpenResty 1.9.7.2+. +lua_package_path "/path/to/lua-resty-core/lib/?.lua;;"; + +server { + listen 443 ssl; + server_name test.com; + + # useless placeholders: just to shut up NGINX configuration + # loader errors: + ssl_certificate /path/to/fallback.crt; + ssl_certificate_key /path/to/fallback.key; + + ssl_certificate_by_lua_block { + local ssl = require "ngx.ssl" + local ocsp = require "ngx.ocsp" + local http = require "resty.http.simple" + + -- assuming the user already defines the my_load_certificate_chain() + -- herself. + local pem_cert_chain = assert(my_load_certificate_chain()) + + local der_cert_chain, err = ssl.cert_pem_to_der(pem_cert_chain) + if not der_cert_chain then + ngx.log(ngx.ERR, "failed to convert certificate chain ", + "from PEM to DER: ", err) + return ngx.exit(ngx.ERROR) + end + + local ocsp_url, err = ocsp.get_ocsp_responder_from_der_chain(der_cert_chain) + if not ocsp_url then + ngx.log(ngx.ERR, "failed to get OCSP responder: ", err) + return ngx.exit(ngx.ERROR) + end + + print("ocsp_url: ", ocsp_url) + + -- use cosocket-based HTTP client libraries like lua-resty-http-simple + -- to send the request (url + ocsp_req as POST params or URL args) to + -- CA's OCSP server. assuming the server returns the OCSP response + -- in the Lua variable, resp. + + local schema, host, port, ocsp_uri, err = parse_url(ocsp_url) + + local ocsp_req, err = ocsp.create_ocsp_request(der_cert_chain) + if not ocsp_req then + ngx.log(ngx.ERR, "failed to create OCSP request: ", err) + return ngx.exit(ngx.ERROR) + end + + local res, err = http.request(host, port, { + path = ocsp_uri, + headers = { Host = host, + ["Content-Type"] = "application/ocsp-request" }, + timeout = 10000, -- 10 sec + method = "POST", + body = ocsp_req, + maxsize = 102400, -- 100KB + }) + + if not res then + ngx.log(ngx.ERR, "OCSP responder query failed: ", err) + return ngx.exit(ngx.ERROR) + end + + local http_status = res.status + + if http_status ~= 200 then + ngx.log(ngx.ERR, "OCSP responder returns bad HTTP status code ", + http_status) + return ngx.exit(ngx.ERROR) + end + + local ocsp_resp = res.body + + if ocsp_resp and #ocsp_resp > 0 then + local ok, err = ocsp.validate_ocsp_response(ocsp_resp, der_cert_chain) + if not ok then + ngx.log(ngx.ERR, "failed to validate OCSP response: ", err) + return ngx.exit(ngx.ERROR) + end + + -- set the OCSP stapling + ok, err = ocsp.set_ocsp_status_resp(ocsp_resp) + if not ok then + ngx.log(ngx.ERR, "failed to set ocsp status resp: ", err) + return ngx.exit(ngx.ERROR) + end + end + } + + location / { + root html; + } +} + +``` + +Description +=========== + +This Lua module provides API to perform OCSP queries, OCSP response validations, and +OCSP stapling planting. + +Usually, this module is used together with the [ngx.ssl](ssl.md) module in the +context of [ssl_certificate_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_certificate_by_lua_block) +(of the [ngx_lua](https://github.com/openresty/lua-nginx-module#readme) module). + +To load the `ngx.ocsp` module in Lua, just write + +```lua +local ocsp = require "ngx.ocsp" +``` + +[Back to TOC](#table-of-contents) + +Methods +======= + +get_ocsp_responder_from_der_chain +--------------------------------- +**syntax:** *ocsp_url, err = ocsp.get_ocsp_responder_from_der_chain(der_cert_chain, max_len)* + +**context:** *any* + +Extracts the OCSP responder URL (like `"http://test.com/ocsp/"`) from the SSL server certificate chain in the DER format. + +Usually the SSL server certificate chain is originally formatted in PEM. You can use the Lua API +provided by the [ngx.ssl](ssl.md) module to do the PEM to DER conversion. + +The optional `max_len` argument specifies the maximum length of OCSP URL allowed. This determines +the buffer size; so do not specify an unnecessarily large value here. It defaults to the internal +string buffer size used throughout this `lua-resty-core` library (usually default to 4KB). + +In case of failures, returns `nil` and a string describing the error. + +[Back to TOC](#table-of-contents) + +create_ocsp_request +------------------- +**syntax:** *ocsp_req, err = ocsp.create_ocsp_request(der_cert_chain, max_len)* + +**context:** *any* + +Builds an OCSP request from the SSL server certificate chain in the DER format, which +can be used to send to the OCSP server for validation. + +The optional `max_len` argument specifies the maximum length of the OCSP request allowed. +This value determines the size of the internal buffer allocated, so do not specify an +unnecessarily large value here. It defaults to the internal string buffer size used +throughout this `lua-resty-core` library (usually defaults to 4KB). + +In case of failures, returns `nil` and a string describing the error. + +The raw OCSP response data can be used as the request body directly if the POST method +is used for the OCSP request. But for GET requests, you need to do base64 encoding and +then URL encoding on the data yourself before appending it to the OCSP URL obtained +by the [get_ocsp_responder_from_der_chain](#get_ocsp_responder_from_der_chain) function. + +[Back to TOC](#table-of-contents) + +validate_ocsp_response +---------------------- +**syntax:** *ok, err = ocsp.validate_ocsp_response(ocsp_resp, der_cert_chain, max_err_msg_len)* + +**context:** *any* + +Validates the raw OCSP response data specified by the `ocsp_resp` argument using the SSL +server certificate chain in DER format as specified in the `der_cert_chain` argument. + +Returns true when the validation is successful. + +In case of failures, returns `nil` and a string +describing the failure. The maximum +length of the error string is controlled by the optional `max_err_msg` argument (which defaults +to the default internal string buffer size used throughout this `lua-resty-core` library, usually +being 4KB). + +[Back to TOC](#table-of-contents) + +set_ocsp_status_resp +-------------------- +**syntax:** *ok, err = ocsp.set_ocsp_status_resp(ocsp_resp)* + +**context:** *ssl_certificate_by_lua** + +Sets the OCSP response as the OCSP stapling for the current SSL connection. + +Returns `true` in case of successes. If the SSL client does not send a "status request" +at all, then this method still returns `true` but also with a string as the warning +`"no status req"`. + +In case of failures, returns `nil` and a string describing the error. + +The OCSP response is returned from CA's OCSP server. See the [create_ocsp_request](#create_ocsp_request) +function for how to create an OCSP request and also [validate_ocsp_response](#validate_ocsp_response) +for how to validate the OCSP response. + +[Back to TOC](#table-of-contents) + +Community +========= + +[Back to TOC](#table-of-contents) + +English Mailing List +-------------------- + +The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. + +[Back to TOC](#table-of-contents) + +Chinese Mailing List +-------------------- + +The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. + +[Back to TOC](#table-of-contents) + +Bugs and Patches +================ + +Please report bugs or submit patches by + +1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), +1. or posting to the [OpenResty community](#community). + +[Back to TOC](#table-of-contents) + +Author +====== + +Yichun Zhang <agentzh@gmail.com> (agentzh), OpenResty Inc. + +[Back to TOC](#table-of-contents) + +Copyright and License +===================== + +This module is licensed under the BSD license. + +Copyright (C) 2015-2017, by Yichun "agentzh" Zhang, OpenResty Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[Back to TOC](#table-of-contents) + +See Also +======== +* the ngx_lua module: https://github.com/openresty/lua-nginx-module +* the [ngx.ssl](ssl.md) module. +* the [ssl_certificate_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_certificate_by_lua_block) directive. +* library [lua-resty-core](https://github.com/openresty/lua-resty-core) +* OpenResty: http://openresty.org + +[Back to TOC](#table-of-contents) diff --git a/rootfs/etc/nginx/lua/vendor/ngx/process.lua b/rootfs/etc/nginx/lua/vendor/ngx/process.lua new file mode 100644 index 0000000000..80fa2b19a4 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/process.lua @@ -0,0 +1,74 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local base = require "resty.core.base" +base.allows_subsystem('http') + + +local ffi = require 'ffi' +local errmsg = base.get_errmsg_ptr() +local FFI_ERROR = base.FFI_ERROR +local ffi_str = ffi.string +local ngx_phase = ngx.get_phase +local tonumber = tonumber + + +local process_type_names = { + [0 ] = "single", + [1 ] = "master", + [2 ] = "signaller", + [3 ] = "worker", + [4 ] = "helper", + [99] = "privileged agent", +} + + +local C = ffi.C +local _M = { version = base.version } + + +ffi.cdef[[ +int ngx_http_lua_ffi_enable_privileged_agent(char **err); +int ngx_http_lua_ffi_get_process_type(void); +void ngx_http_lua_ffi_process_signal_graceful_exit(void); +int ngx_http_lua_ffi_master_pid(void); +]] + + +function _M.type() + local typ = C.ngx_http_lua_ffi_get_process_type() + return process_type_names[tonumber(typ)] +end + + +function _M.enable_privileged_agent() + if ngx_phase() ~= "init" then + return nil, "API disabled in the current context" + end + + local rc = C.ngx_http_lua_ffi_enable_privileged_agent(errmsg) + + if rc == FFI_ERROR then + return nil, ffi_str(errmsg[0]) + end + + return true +end + + +function _M.signal_graceful_exit() + C.ngx_http_lua_ffi_process_signal_graceful_exit() +end + + +function _M.get_master_pid() + local pid = C.ngx_http_lua_ffi_master_pid() + if pid == FFI_ERROR then + return nil + end + + return tonumber(pid) +end + + +return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/process.md b/rootfs/etc/nginx/lua/vendor/ngx/process.md new file mode 100644 index 0000000000..30b6630dd3 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/process.md @@ -0,0 +1,230 @@ +Name +==== + +`ngx.process` - manage the nginx processes for OpenResty/ngx_lua. + +Table of Contents +================= + +* [Name](#name) +* [Status](#status) +* [Synopsis](#synopsis) +* [Functions](#functions) + * [type](#type) + * [enable_privileged_agent](#enable_privileged_agent) + * [signal_graceful_exit](#signal_graceful_exit) + * [get_master_pid](#get_master_pid) +* [Community](#community) + * [English Mailing List](#english-mailing-list) + * [Chinese Mailing List](#chinese-mailing-list) +* [Bugs and Patches](#bugs-and-patches) +* [Author](#author) +* [Copyright and License](#copyright-and-license) +* [See Also](#see-also) + +Status +====== + +This Lua module is currently considered experimental. +The API is still in flux and may change in the future without notice. + +Synopsis +======== + +Enables privileged agent process, gets process type, and then gets the master process PID: + +```nginx +# http config +init_by_lua_block { + local process = require "ngx.process" + + -- enables privileged agent process + local ok, err = process.enable_privileged_agent() + if not ok then + ngx.log(ngx.ERR, "enables privileged agent failed error:", err) + end + + -- output process type + ngx.log(ngx.INFO, "process type: ", process.type()) +} + +init_worker_by_lua_block { + local process = require "ngx.process" + ngx.log(ngx.INFO, "process type: ", process.type()) +} + +server { + # ... + location = /t { + content_by_lua_block { + local process = require "ngx.process" + ngx.say("process type: ", process.type()) + ngx.say("master process pid: ", process.get_master_pid() or "-") + } + } +} + +``` + +The example config above produces an output to `error.log` when +server starts: + +``` +[lua] init_by_lua:11: process type: master +[lua] init_worker_by_lua:3: process type: privileged agent +[lua] init_worker_by_lua:3: process type: worker +``` + +The example location above produces the following response body: + +``` +process type: worker +master process pid: 8261 +``` + +[Back to TOC](#table-of-contents) + +Functions +========= + +type +---- +**syntax:** *type_name = process_module.type()* + +**context:** *any* + +Returns the current process's type name. Here are all of the names: + +``` +single +master +signaller +worker +helper +privileged agent +``` + +For example, + +```lua + local process = require "ngx.process" + ngx.say("process type:", process.type()) -- RESPONSE: worker +``` + +[Back to TOC](#table-of-contents) + +enable_privileged_agent +----------------------- +**syntax:** *ok, err = process_module.enable_privileged_agent()* + +**context:** *init_by_lua** + +Enables the privileged agent process in Nginx. + +The priviledged agent process does not listen on any virtual server ports like those worker processes. +And it uses the same system account as the nginx master process, which is usually a privileged account +like `root`. + +The `init_worker_by_lua*` directive handler still runs in the privileged agent process. And one can +use the [type](#type) function provided by this module to check if the current process is a privileged +agent. + +In case of failures, returns `nil` and a string describing the error. + +[Back to TOC](#table-of-contents) + +signal_graceful_exit +-------------------- +**syntax:** *process_module.signal_graceful_exit()* + +**context:** *any* + +Signals the *current* nginx (worker) process to quit gracefully, i.e., after all the timers have expired (in time or expired prematurely). + +Note that this API function simply sets the nginx global C variable `ngx_quit` to signal the nginx event +loop directly. No UNIX signals or IPC are involved here. + +WARNING: the official NGINX core does not perform the graceful exiting procedure when the [master_process](http://nginx.org/r/master_process) +directive is turned `off`. The OpenResty's NGINX core has a +[custom patch](https://github.com/openresty/openresty/blob/master/patches/nginx-1.11.2-single_process_graceful_exit.patch) +applied, which fixes this issue. + +[Back to TOC](#table-of-contents) + +get_master_pid +-------------- +**syntax:** *pid = process_module.get_master_pid()* + +**context:** *any* + +Returns a number value for the nginx master process's process ID (or PID). + +This function requires NGINX 1.13.8+ cores to work properly. Otherwise it returns `nil`. + +This feature first appeared in lua-resty-core v0.1.14. + +[Back to TOC](#table-of-contents) + +Community +========= + +[Back to TOC](#table-of-contents) + +English Mailing List +-------------------- + +The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. + +[Back to TOC](#table-of-contents) + +Chinese Mailing List +-------------------- + +The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. + +[Back to TOC](#table-of-contents) + +Bugs and Patches +================ + +Please report bugs or submit patches by + +1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), +1. or posting to the [OpenResty community](#community). + +[Back to TOC](#table-of-contents) + +Author +====== + +Yuansheng Wang <membphis@gmail.com> (membphis), OpenResty Inc. + +[Back to TOC](#table-of-contents) + +Copyright and License +===================== + +This module is licensed under the BSD license. + +Copyright (C) 2017, by Yichun "agentzh" Zhang, OpenResty Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[Back to TOC](#table-of-contents) + +See Also +======== +* library [lua-resty-core](https://github.com/openresty/lua-resty-core) +* the ngx_lua module: https://github.com/openresty/lua-nginx-module +* OpenResty: http://openresty.org + +[Back to TOC](#table-of-contents) + diff --git a/rootfs/etc/nginx/lua/vendor/ngx/re.lua b/rootfs/etc/nginx/lua/vendor/ngx/re.lua new file mode 100644 index 0000000000..09dd2ea560 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/re.lua @@ -0,0 +1,284 @@ +-- I hereby assign copyright in this code to the lua-resty-core project, +-- to be licensed under the same terms as the rest of the code. + + +local base = require "resty.core.base" +base.allows_subsystem('http') + + +local ffi = require 'ffi' +local bit = require "bit" +local core_regex = require "resty.core.regex" + + +local C = ffi.C +local ffi_str = ffi.string +local sub = string.sub +local error = error +local type = type +local band = bit.band +local new_tab = base.new_tab +local tostring = tostring +local math_max = math.max +local math_min = math.min +local is_regex_cache_empty = core_regex.is_regex_cache_empty +local re_match_compile = core_regex.re_match_compile +local destroy_compiled_regex = core_regex.destroy_compiled_regex +local get_string_buf = base.get_string_buf +local get_size_ptr = base.get_size_ptr +local FFI_OK = base.FFI_OK + + +local MAX_ERR_MSG_LEN = 128 +local FLAG_DFA = 0x02 +local PCRE_ERROR_NOMATCH = -1 +local DEFAULT_SPLIT_RES_SIZE = 4 + + +local split_ctx = new_tab(0, 1) + + +ffi.cdef[[ +int ngx_http_lua_ffi_set_jit_stack_size(int size, unsigned char *errstr, + size_t *errstr_size); +]] + + +local _M = { version = base.version } + + +local function re_split_helper(subj, compiled, compile_once, flags, ctx) + local rc + do + local pos = math_max(ctx.pos, 0) + + rc = C.ngx_http_lua_ffi_exec_regex(compiled, flags, subj, #subj, pos) + end + + if rc == PCRE_ERROR_NOMATCH then + return nil, nil, nil + end + + if rc < 0 then + if not compile_once then + destroy_compiled_regex(compiled) + end + return nil, nil, nil, "pcre_exec() failed: " .. rc + end + + if rc == 0 then + if band(flags, FLAG_DFA) == 0 then + if not compile_once then + destroy_compiled_regex(compiled) + end + return nil, nil, nil, "capture size too small" + end + + rc = 1 + end + + local caps = compiled.captures + local ncaps = compiled.ncaptures + + local from = caps[0] + local to = caps[1] + + if from < 0 or to < 0 then + return nil, nil, nil + end + + if from == to then + -- empty match, skip to next char + ctx.pos = to + 1 + + else + ctx.pos = to + end + + -- convert to Lua string indexes + + from = from + 1 + to = to + 1 + + -- retrieve the first sub-match capture if any + + if ncaps > 0 and rc > 1 then + return from, to, sub(subj, caps[2] + 1, caps[3]) + end + + return from, to +end + + +function _M.split(subj, regex, opts, ctx, max, res) + -- we need to cast this to strings to avoid exceptions when they are + -- something else. + -- needed because of further calls to string.sub in this function. + subj = tostring(subj) + + if not ctx then + ctx = split_ctx + ctx.pos = 1 -- set or reset upvalue field + + elseif not ctx.pos then + -- ctx provided by user but missing pos field + ctx.pos = 1 + end + + max = max or 0 + + if not res then + -- limit the initial arr_n size of res to a reasonable value + -- 0 < narr <= DEFAULT_SPLIT_RES_SIZE + local narr = DEFAULT_SPLIT_RES_SIZE + if max > 0 then + -- the user specified a valid max limiter if max > 0 + narr = math_min(narr, max) + end + + res = new_tab(narr, 0) + + elseif type(res) ~= "table" then + error("res is not a table", 2) + end + + local len = #subj + if ctx.pos > len then + res[1] = nil + return res + end + + -- compile regex + + local compiled, compile_once, flags = re_match_compile(regex, opts) + if compiled == nil then + -- compiled_once holds the error string + return nil, compile_once + end + + local sub_idx = ctx.pos + local res_idx = 0 + local last_empty_match + + -- update to split_helper PCRE indexes + ctx.pos = sub_idx - 1 + + -- splitting: with and without a max limiter + + if max > 0 then + local count = 1 + + while count < max do + local from, to, capture, err = re_split_helper(subj, compiled, + compile_once, flags, ctx) + if err then + return nil, err + end + + if not from then + break + end + + if last_empty_match then + sub_idx = last_empty_match + end + + if from == to then + last_empty_match = from + end + + if from > sub_idx or not last_empty_match then + count = count + 1 + res_idx = res_idx + 1 + res[res_idx] = sub(subj, sub_idx, from - 1) + + if capture then + res_idx = res_idx + 1 + res[res_idx] = capture + end + + sub_idx = to + + if sub_idx >= len then + break + end + end + end + + else + while true do + local from, to, capture, err = re_split_helper(subj, compiled, + compile_once, flags, ctx) + if err then + return nil, err + end + + if not from then + break + end + + if last_empty_match then + sub_idx = last_empty_match + end + + if from == to then + last_empty_match = from + end + + if from > sub_idx or not last_empty_match then + res_idx = res_idx + 1 + res[res_idx] = sub(subj, sub_idx, from - 1) + + if capture then + res_idx = res_idx + 1 + res[res_idx] = capture + end + + sub_idx = to + + if sub_idx >= len then + break + end + end + end + + end + + if not compile_once then + destroy_compiled_regex(compiled) + end + + -- trailing nil for non-cleared res tables + + res[res_idx + 1] = sub(subj, sub_idx) + res[res_idx + 2] = nil + + return res +end + + +function _M.opt(option, value) + if option == "jit_stack_size" then + if not is_regex_cache_empty() then + error("changing jit stack size is not allowed when some " .. + "regexs have already been compiled and cached") + end + + local errbuf = get_string_buf(MAX_ERR_MSG_LEN) + local sizep = get_size_ptr() + sizep[0] = MAX_ERR_MSG_LEN + + local rc = C.ngx_http_lua_ffi_set_jit_stack_size(value, errbuf, sizep) + + if rc == FFI_OK then + return + end + + error(ffi_str(errbuf, sizep[0])) + end + + error("unrecognized option name") +end + + +return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/re.md b/rootfs/etc/nginx/lua/vendor/ngx/re.md new file mode 100644 index 0000000000..1c97ff6680 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/re.md @@ -0,0 +1,249 @@ +Name +==== + +ngx.re - Lua API for convenience utilities for `ngx.re`. + +Table of Contents +================= + +* [Name](#name) +* [Status](#status) +* [Synopsis](#synopsis) +* [Description](#description) +* [Methods](#methods) + * [split](#split) + * [opt](#opt) +* [Community](#community) + * [English Mailing List](#english-mailing-list) + * [Chinese Mailing List](#chinese-mailing-list) +* [Bugs and Patches](#bugs-and-patches) +* [Author](#author) +* [Copyright and License](#copyright-and-license) +* [See Also](#see-also) + +Status +====== + +This Lua module is currently considered experimental. + +Synopsis +======== + +```lua +local ngx_re = require "ngx.re" + +-- split +local res, err = ngx_re.split("a,b,c,d", ",") +--> res is now {"a", "b", "c", "d"} + +-- opt +ngx_re.opt("jit_stack_size", 128 * 1024) +--> the PCRE jit stack can now handle more complex regular expressions +``` + +[Back to TOC](#table-of-contents) + +Description +=========== + +This Lua module provides a Lua API which implements convenience utilities for +the `ngx.re` API. + +[Back to TOC](#table-of-contents) + +Methods +======= + +All the methods of this module are static (or module-level). That is, you do +not need an object (or instance) to call these methods. + +[Back to TOC](#table-of-contents) + +split +----- +**syntax:** *res, err = ngx_re.split(subject, regex, options?, ctx?, max?, res?)* + +Splits the `subject` string using the Perl compatible regular expression +`regex` with the optional `options`. + +This function returns a Lua (array) table (with integer keys) containing the +splitted values. + +In case of error, `nil` will be returned as well as a string describing the +error. + +When `regex` contains a sub-match capturing group, and when such a match is +found, the first submatch capture will be inserted in between each splitted +value, like so: + +```lua +local ngx_re = require "ngx.re" + +local res, err = ngx_re.split("a,b,c,d", "(,)") +-- res is now {"a", ",", "b", ",", "c", ",", "d"} +``` + +When `regex` is empty string `""`, the `subject` will be split into chars, +like so: + +```lua +local ngx_re = require "ngx.re" + +local res, err = ngx_re.split("abcd", "") +-- res is now {"a", "b", "c", "d"} +``` + +The optional `ctx` table argument can be a Lua table holding an optional `pos` +field. When the `pos` field in the `ctx` table argument is specified, +`ngx_re.split` will start splitting the `subject` from that index: + +```lua +local ngx_re = require "ngx.re" + +local res, err = ngx_re.split("a,b,c,d", ",", nil, {pos = 5}) +-- res is now {"c", "d"} +``` + +The optional `max` argument is a number that when specified, will prevent +`ngx_re.split` from adding more than `max` matches to the `res` array: + +```lua +local ngx_re = require "ngx.re" + +local res, err = ngx_re.split("a,b,c,d", ",", nil, nil, 3) +-- res is now {"a", "b", "c,d"} +``` + +Specifying `max <= 0` disables this behavior, meaning that the number of +results won't be limited. + +The optional 6th argument `res` can be a table that `ngx_re.split` will re-use +to hold the results instead of creating a new one, which can improve +performance in hot code paths. It is used like so: + +```lua +local ngx_re = require "ngx.re" + +local my_table = {"hello world"} + +local res, err = ngx_re.split("a,b,c,d", ",", nil, nil, nil, my_table) +-- res/my_table is now {"a", "b", "c", "d"} +``` + +When provided with a `res` table, `ngx_re.split` won't clear the table +for performance reasons, but will rather insert a trailing `nil` value +when the split is completed: + +```lua +local ngx_re = require "ngx.re" + +local my_table = {"W", "X", "Y", "Z"} + +local res, err = ngx_re.split("a,b", ",", nil, nil, nil, my_table) +-- res/my_table is now {"a", "b", nil, "Z"} +``` + +When the trailing `nil` is not enough for your purpose, you should +clear the table yourself before feeding it into the `split` function. + +[Back to TOC](#table-of-contents) + +opt +----- +**syntax:** *ngx_re.opt(option, value)* + +Allows changing of regex settings. Currently, it can only change the +`jit_stack_size` of the PCRE engine, like so: + +```nginx + + init_by_lua_block { require "ngx.re".opt("jit_stack_size", 200 * 1024) } + + server { + location /re { + content_by_lua_block { + -- full regex and string are taken from https://github.com/JuliaLang/julia/issues/8278 + local very_long_string = [[71.163.72.113 - - [30/Jul/2014:16:40:55 -0700] ...]] + local very_complicated_regex = [[([\d\.]+) ([\w.-]+) ([\w.-]+) (\[.+\]) ...]] + local from, to, err = ngx.re.find(very_long_string, very_complicated_regex, "jo") + + -- with the regular jit_stack_size, we would get the error 'pcre_exec() failed: -27' + -- instead, we get a match + ngx.print(from .. "-" .. to) -- prints '1-1563' + } + } + } +``` + +The `jit_stack_size` cannot be set to a value lower than PCRE's default of 32K. + +This method requires the PCRE library enabled in Nginx. + +This feature was first introduced in the `v0.1.12` release. + +[Back to TOC](#table-of-contents) + +Community +========= + +[Back to TOC](#table-of-contents) + +English Mailing List +-------------------- + +The [openresty-en](https://groups.google.com/group/openresty-en) mailing list +is for English speakers. + +[Back to TOC](#table-of-contents) + +Chinese Mailing List +-------------------- + +The [openresty](https://groups.google.com/group/openresty) mailing list is for +Chinese speakers. + +[Back to TOC](#table-of-contents) + +Bugs and Patches +================ + +Please report bugs or submit patches by + +1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), +1. or posting to the [OpenResty community](#community). + +[Back to TOC](#table-of-contents) + +Author +====== + +Thibault Charbonnier - ([@thibaultcha](https://github.com/thibaultcha)) + +[Back to TOC](#table-of-contents) + +Copyright and License +===================== + +This module is licensed under the BSD license. + +Copyright (C) 2016-2017, by Yichun "agentzh" Zhang, OpenResty Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[Back to TOC](#table-of-contents) + +See Also +======== +* library [lua-resty-core](https://github.com/openresty/lua-resty-core) +* the ngx_lua module: https://github.com/openresty/lua-nginx-module +* OpenResty: http://openresty.org + +[Back to TOC](#table-of-contents) diff --git a/rootfs/etc/nginx/lua/vendor/ngx/semaphore.lua b/rootfs/etc/nginx/lua/vendor/ngx/semaphore.lua new file mode 100644 index 0000000000..cd5101bb12 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/semaphore.lua @@ -0,0 +1,152 @@ +-- Copyright (C) Yichun Zhang (agentzh) +-- Copyright (C) cuiweixie +-- I hereby assign copyright in this code to the lua-resty-core project, +-- to be licensed under the same terms as the rest of the code. + + +local base = require "resty.core.base" +base.allows_subsystem('http') + + +local ffi = require 'ffi' +local FFI_OK = base.FFI_OK +local FFI_ERROR = base.FFI_ERROR +local FFI_DECLINED = base.FFI_DECLINED +local ffi_new = ffi.new +local ffi_str = ffi.string +local ffi_gc = ffi.gc +local C = ffi.C +local type = type +local error = error +local tonumber = tonumber +local getfenv = getfenv +local get_string_buf = base.get_string_buf +local get_size_ptr = base.get_size_ptr +local setmetatable = setmetatable +local co_yield = coroutine._yield +local ERR_BUF_SIZE = 128 + + +local errmsg = base.get_errmsg_ptr() + + +ffi.cdef[[ + struct ngx_http_lua_sema_s; + typedef struct ngx_http_lua_sema_s ngx_http_lua_sema_t; + + int ngx_http_lua_ffi_sema_new(ngx_http_lua_sema_t **psem, + int n, char **errmsg); + + int ngx_http_lua_ffi_sema_post(ngx_http_lua_sema_t *sem, int n); + + int ngx_http_lua_ffi_sema_count(ngx_http_lua_sema_t *sem); + + int ngx_http_lua_ffi_sema_wait(ngx_http_request_t *r, + ngx_http_lua_sema_t *sem, int wait_ms, + unsigned char *errstr, size_t *errlen); + + void ngx_http_lua_ffi_sema_gc(ngx_http_lua_sema_t *sem); +]] + + +local psem = ffi_new("ngx_http_lua_sema_t *[1]") + + +local _M = { version = base.version } +local mt = { __index = _M } + + +function _M.new(n) + n = tonumber(n) or 0 + if n < 0 then + return error("no negative number") + end + + local ret = C.ngx_http_lua_ffi_sema_new(psem, n, errmsg) + if ret == FFI_ERROR then + return nil, ffi_str(errmsg[0]) + end + + local sem = psem[0] + + ffi_gc(sem, C.ngx_http_lua_ffi_sema_gc) + + return setmetatable({ sem = sem }, mt) +end + + +function _M.wait(self, seconds) + if type(self) ~= "table" or type(self.sem) ~= "cdata" then + return error("not a semaphore instance") + end + + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local milliseconds = tonumber(seconds) * 1000 + if milliseconds < 0 then + return error("no negative number") + end + + local cdata_sem = self.sem + + local err = get_string_buf(ERR_BUF_SIZE) + local errlen = get_size_ptr() + errlen[0] = ERR_BUF_SIZE + + local ret = C.ngx_http_lua_ffi_sema_wait(r, cdata_sem, + milliseconds, err, errlen) + + if ret == FFI_ERROR then + return nil, ffi_str(err, errlen[0]) + end + + if ret == FFI_OK then + return true + end + + if ret == FFI_DECLINED then + return nil, "timeout" + end + + -- Note: we cannot use the tail-call form here since we + -- might need the current function call's activation + -- record to hold the reference to our semaphore object + -- to prevent it from getting GC'd prematurely. + local ok + ok, err = co_yield() + return ok, err +end + + +function _M.post(self, n) + if type(self) ~= "table" or type(self.sem) ~= "cdata" then + return error("not a semaphore instance") + end + + local cdata_sem = self.sem + + local num = n and tonumber(n) or 1 + if num < 1 then + return error("no negative number") + end + + -- always return NGX_OK + C.ngx_http_lua_ffi_sema_post(cdata_sem, num) + + return true +end + + +function _M.count(self) + if type(self) ~= "table" or type(self.sem) ~= "cdata" then + return error("not a semaphore instance") + end + + return C.ngx_http_lua_ffi_sema_count(self.sem) +end + + +return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/semaphore.md b/rootfs/etc/nginx/lua/vendor/ngx/semaphore.md new file mode 100644 index 0000000000..8c9314fa6d --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/semaphore.md @@ -0,0 +1,356 @@ +Name +==== + +ngx.semaphore - light thread semaphore for OpenResty/ngx_lua. + +Table of Contents +================= + +* [Name](#name) +* [Status](#status) +* [Synopsis](#synopsis) + * [Synchronizing threads in the same context](#synchronizing-threads-in-the-same-context) + * [Synchronizing threads in different contexts](#synchronizing-threads-in-different-contexts) +* [Description](#description) +* [Methods](#methods) + * [new](#new) + * [post](#post) + * [wait](#wait) + * [count](#count) +* [Community](#community) + * [English Mailing List](#english-mailing-list) + * [Chinese Mailing List](#chinese-mailing-list) +* [Bugs and Patches](#bugs-and-patches) +* [Author](#author) +* [Copyright and License](#copyright-and-license) +* [See Also](#see-also) + +Status +====== + +This Lua module is currently considered experimental. + +Synopsis +======== + +Synchronizing threads in the same context +----------------------------------------- + +```nginx +location = /t { + content_by_lua_block { + local semaphore = require "ngx.semaphore" + local sema = semaphore.new() + + local function handler() + ngx.say("sub thread: waiting on sema...") + + local ok, err = sema:wait(1) -- wait for a second at most + if not ok then + ngx.say("sub thread: failed to wait on sema: ", err) + else + ngx.say("sub thread: waited successfully.") + end + end + + local co = ngx.thread.spawn(handler) + + ngx.say("main thread: sleeping for a little while...") + + ngx.sleep(0.1) -- wait a bit + + ngx.say("main thread: posting to sema...") + + sema:post(1) + + ngx.say("main thread: end.") + } +} +``` + +The example location above produces a response output like this: + +``` +sub thread: waiting on sema... +main thread: sleeping for a little while... +main thread: posting to sema... +main thread: end. +sub thread: waited successfully. +``` + +[Back to TOC](#table-of-contents) + +Synchronizing threads in different contexts +------------------------------------------- + +```nginx +location = /t { + content_by_lua_block { + local semaphore = require "ngx.semaphore" + local sema = semaphore.new() + + local outputs = {} + local i = 1 + + local function out(s) + outputs[i] = s + i = i + 1 + end + + local function handler() + out("timer thread: sleeping for a little while...") + + ngx.sleep(0.1) -- wait a bit + + out("timer thread: posting on sema...") + + sema:post(1) + end + + assert(ngx.timer.at(0, handler)) + + out("main thread: waiting on sema...") + + local ok, err = sema:wait(1) -- wait for a second at most + if not ok then + out("main thread: failed to wait on sema: ", err) + else + out("main thread: waited successfully.") + end + + out("main thread: end.") + + ngx.say(table.concat(outputs, "\n")) + } +} +``` + +The example location above produces a response body like this + +``` +main thread: waiting on sema... +timer thread: sleeping for a little while... +timer thread: posting on sema... +main thread: waited successfully. +main thread: end. +``` + +The same applies to different request contexts as long as these requests are served +by the same nginx worker process. + +[Back to TOC](#table-of-contents) + +Description +=========== + +This module provides an efficient semaphore API for the OpenResty/ngx_lua module. With +semaphores, "light threads" (created by [ngx.thread.spawn](https://github.com/openresty/lua-nginx-module#ngxthreadspawn), +[ngx.timer.at](https://github.com/openresty/lua-nginx-module#ngxtimerat), and etc.) can +synchronize among each other very efficiently without constant polling and sleeping. + +"Light threads" in different contexts (like in different requests) can share the same +semaphore instance as long as these "light threads" reside in the same NGINX worker +process and the [lua_code_cache](https://github.com/openresty/lua-nginx-module#lua_code_cache) +directive is turned on (which is the default). For inter-process "light thread" synchronization, +it is recommended to use the [lua-resty-lock](https://github.com/openresty/lua-resty-lock) library instead +(which is a bit less efficient than this semaphore API though). + +This semaphore API has a pure userland implementation which does not involve any system calls nor +block any operating system threads. It works closely with the event model of NGINX without +introducing any extra delay. + +Like other APIs provided by this `lua-resty-core` library, the LuaJIT FFI feature is required. + +[Back to TOC](#table-of-contents) + +Methods +======= + +[Back to TOC](#table-of-contents) + +new +--- +**syntax:** *sema, err = semaphore_module.new(n?)* + +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** + +Creates and returns a new semaphore instance that has `n` (default to `0`) resources. + +For example, + +```lua + local semaphore = require "ngx.semaphore" + local sema, err = semaphore.new() + if not sema then + ngx.say("create semaphore failed: ", err) + end +``` + +Often the semaphore object created is shared on the NGINX worker process by mounting in a custom Lua module, as +documented below: + +https://github.com/openresty/lua-nginx-module#data-sharing-within-an-nginx-worker + +[Back to TOC](#table-of-contents) + +post +-------- +**syntax:** *sema:post(n?)* + +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** + +Releases `n` (default to `1`) "resources" to the semaphore instance. + +This will not yield the current running "light thread". + +At most `n` "light threads" will be waken up when the current running "light thread" later yields (or terminates). + +```lua +-- typically, we get the semaphore instance from upvalue or globally shared data +-- See https://github.com/openresty/lua-nginx-module#data-sharing-within-an-nginx-worker + +local semaphore = require "ngx.semaphore" +local sema = semaphore.new() + +sema:post(2) -- releases 2 resources +``` + +[Back to TOC](#table-of-contents) + +wait +---- +**syntax:** *ok, err = sema:wait(timeout)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** + +Requests a resource from the semaphore instance. + +Returns `true` immediately when there is resources available for the current running "light thread". +Otherwise the current "light thread" will enter the waiting queue and yield execution. +The current "light thread" will be automatically waken up and the `wait` function call +will return `true` when there is resources available for it, or return `nil` and a string describing +the error in case of failure (like `"timeout"`). + +The `timeout` argument specifies the maximum time this function call should wait for (in seconds). + +When the `timeout` argument is 0, it means "no wait", that is, when there is no readily available +"resources" for the current running "light thread", this `wait` function call returns immediately +`nil` and the error string `"timeout"`. + +You can specify millisecond precision in the timeout value by using floating point numbers like 0.001 (which means 1ms). + +"Light threads" created by different contexts (like request handlers) can wait on the +same semaphore instance without problem. + +See [Synopsis](#synopsis) for code examples. + +[Back to TOC](#table-of-contents) + +count +-------- +**syntax:** *count = sema:count()* + +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, +content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** + +Returns the number of resources readily available in the `sema` semaphore instance (if any). + +When the returned number is negative, it means the number of "light threads" waiting on +this semaphore. + +Consider the following example, + +```lua +local semaphore = require "ngx.semaphore" +local sema = semaphore.new(0) + +ngx.say("count: ", sema:count()) -- count: 0 + +local function handler(id) + local ok, err = sema:wait(1) + if not ok then + ngx.say("err: ", err) + else + ngx.say("wait success") + end +end + +local co1 = ngx.thread.spawn(handler) +local co2 = ngx.thread.spawn(handler) + +ngx.say("count: ", sema:count()) -- count: -2 + +sema:post(1) + +ngx.say("count: ", sema:count()) -- count: -1 + +sema:post(2) + +ngx.say("count: ", sema:count()) -- count: 1 +``` + +[Back to TOC](#table-of-contents) + +Community +========= + +[Back to TOC](#table-of-contents) + +English Mailing List +-------------------- + +The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. + +[Back to TOC](#table-of-contents) + +Chinese Mailing List +-------------------- + +The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. + +[Back to TOC](#table-of-contents) + +Bugs and Patches +================ + +Please report bugs or submit patches by + +1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), +1. or posting to the [OpenResty community](#community). + +[Back to TOC](#table-of-contents) + +Author +====== + +Weixie Cui, Kugou Inc. + +[Back to TOC](#table-of-contents) + +Copyright and License +===================== + +This module is licensed under the BSD license. + +Copyright (C) 2015-2017, by Yichun "agentzh" Zhang, OpenResty Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[Back to TOC](#table-of-contents) + +See Also +======== +* library [lua-resty-core](https://github.com/openresty/lua-resty-core) +* the ngx_lua module: https://github.com/openresty/lua-nginx-module +* OpenResty: http://openresty.org + +[Back to TOC](#table-of-contents) + diff --git a/rootfs/etc/nginx/lua/vendor/ngx/ssl.lua b/rootfs/etc/nginx/lua/vendor/ngx/ssl.lua new file mode 100644 index 0000000000..ecedb61d14 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/ssl.lua @@ -0,0 +1,313 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local base = require "resty.core.base" +base.allows_subsystem('http') + + +local ffi = require "ffi" +local C = ffi.C +local ffi_str = ffi.string +local ffi_gc = ffi.gc +local getfenv = getfenv +local error = error +local tonumber = tonumber +local errmsg = base.get_errmsg_ptr() +local get_string_buf = base.get_string_buf +local get_size_ptr = base.get_size_ptr +local FFI_DECLINED = base.FFI_DECLINED +local FFI_OK = base.FFI_OK + + +ffi.cdef[[ + +struct ngx_ssl_conn_s; +typedef struct ngx_ssl_conn_s ngx_ssl_conn_t; + +int ngx_http_lua_ffi_ssl_set_der_certificate(ngx_http_request_t *r, + const char *data, size_t len, char **err); + +int ngx_http_lua_ffi_ssl_clear_certs(ngx_http_request_t *r, char **err); + +int ngx_http_lua_ffi_ssl_set_der_private_key(ngx_http_request_t *r, + const char *data, size_t len, char **err); + +int ngx_http_lua_ffi_ssl_raw_server_addr(ngx_http_request_t *r, char **addr, + size_t *addrlen, int *addrtype, char **err); + +int ngx_http_lua_ffi_ssl_server_name(ngx_http_request_t *r, char **name, + size_t *namelen, char **err); + +int ngx_http_lua_ffi_ssl_raw_client_addr(ngx_http_request_t *r, char **addr, + size_t *addrlen, int *addrtype, char **err); + +int ngx_http_lua_ffi_cert_pem_to_der(const unsigned char *pem, size_t pem_len, + unsigned char *der, char **err); + +int ngx_http_lua_ffi_priv_key_pem_to_der(const unsigned char *pem, + size_t pem_len, unsigned char *der, char **err); + +int ngx_http_lua_ffi_ssl_get_tls1_version(ngx_http_request_t *r, char **err); + +void *ngx_http_lua_ffi_parse_pem_cert(const unsigned char *pem, + size_t pem_len, char **err); + +void *ngx_http_lua_ffi_parse_pem_priv_key(const unsigned char *pem, + size_t pem_len, char **err); + +int ngx_http_lua_ffi_set_cert(void *r, void *cdata, char **err); + +int ngx_http_lua_ffi_set_priv_key(void *r, void *cdata, char **err); + +void ngx_http_lua_ffi_free_cert(void *cdata); + +void ngx_http_lua_ffi_free_priv_key(void *cdata); +]] + + +local _M = { version = base.version } + + +local charpp = ffi.new("char*[1]") +local intp = ffi.new("int[1]") + + +function _M.clear_certs() + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local rc = C.ngx_http_lua_ffi_ssl_clear_certs(r, errmsg) + if rc == FFI_OK then + return true + end + + return nil, ffi_str(errmsg[0]) +end + + +function _M.set_der_cert(data) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local rc = C.ngx_http_lua_ffi_ssl_set_der_certificate(r, data, #data, + errmsg) + if rc == FFI_OK then + return true + end + + return nil, ffi_str(errmsg[0]) +end + + +function _M.set_der_priv_key(data) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local rc = C.ngx_http_lua_ffi_ssl_set_der_private_key(r, data, #data, + errmsg) + if rc == FFI_OK then + return true + end + + return nil, ffi_str(errmsg[0]) +end + + +local addr_types = { + [0] = "unix", + [1] = "inet", + [2] = "inet6", +} + + +function _M.raw_server_addr() + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local sizep = get_size_ptr() + + local rc = C.ngx_http_lua_ffi_ssl_raw_server_addr(r, charpp, sizep, + intp, errmsg) + if rc == FFI_OK then + local typ = addr_types[intp[0]] + if not typ then + return nil, nil, "unknown address type: " .. intp[0] + end + return ffi_str(charpp[0], sizep[0]), typ + end + + return nil, nil, ffi_str(errmsg[0]) +end + + +function _M.server_name() + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local sizep = get_size_ptr() + + local rc = C.ngx_http_lua_ffi_ssl_server_name(r, charpp, sizep, errmsg) + if rc == FFI_OK then + return ffi_str(charpp[0], sizep[0]) + end + + if rc == FFI_DECLINED then + return nil + end + + return nil, ffi_str(errmsg[0]) +end + + +function _M.raw_client_addr() + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local sizep = get_size_ptr() + + local rc = C.ngx_http_lua_ffi_ssl_raw_client_addr(r, charpp, sizep, + intp, errmsg) + if rc == FFI_OK then + local typ = addr_types[intp[0]] + if not typ then + return nil, nil, "unknown address type: " .. intp[0] + end + return ffi_str(charpp[0], sizep[0]), typ + end + + return nil, nil, ffi_str(errmsg[0]) +end + + +function _M.cert_pem_to_der(pem) + local outbuf = get_string_buf(#pem) + + local sz = C.ngx_http_lua_ffi_cert_pem_to_der(pem, #pem, outbuf, errmsg) + if sz > 0 then + return ffi_str(outbuf, sz) + end + + return nil, ffi_str(errmsg[0]) +end + + +function _M.priv_key_pem_to_der(pem) + local outbuf = get_string_buf(#pem) + + local sz = C.ngx_http_lua_ffi_priv_key_pem_to_der(pem, #pem, outbuf, errmsg) + if sz > 0 then + return ffi_str(outbuf, sz) + end + + return nil, ffi_str(errmsg[0]) +end + + +local function get_tls1_version() + + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local ver = C.ngx_http_lua_ffi_ssl_get_tls1_version(r, errmsg) + + ver = tonumber(ver) + + if ver >= 0 then + return ver + end + + -- rc == FFI_ERROR + + return nil, ffi_str(errmsg[0]) +end +_M.get_tls1_version = get_tls1_version + + +function _M.parse_pem_cert(pem) + local cert = C.ngx_http_lua_ffi_parse_pem_cert(pem, #pem, errmsg) + if cert ~= nil then + return ffi_gc(cert, C.ngx_http_lua_ffi_free_cert) + end + + return nil, ffi_str(errmsg[0]) +end + + +function _M.parse_pem_priv_key(pem) + local pkey = C.ngx_http_lua_ffi_parse_pem_priv_key(pem, #pem, errmsg) + if pkey ~= nil then + return ffi_gc(pkey, C.ngx_http_lua_ffi_free_priv_key) + end + + return nil, ffi_str(errmsg[0]) +end + + +function _M.set_cert(cert) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local rc = C.ngx_http_lua_ffi_set_cert(r, cert, errmsg) + if rc == FFI_OK then + return true + end + + return nil, ffi_str(errmsg[0]) +end + + +function _M.set_priv_key(priv_key) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local rc = C.ngx_http_lua_ffi_set_priv_key(r, priv_key, errmsg) + if rc == FFI_OK then + return true + end + + return nil, ffi_str(errmsg[0]) +end + + +do + _M.SSL3_VERSION = 0x0300 + _M.TLS1_VERSION = 0x0301 + _M.TLS1_1_VERSION = 0x0302 + _M.TLS1_2_VERSION = 0x0303 + + local map = { + [_M.SSL3_VERSION] = "SSLv3", + [_M.TLS1_VERSION] = "TLSv1", + [_M.TLS1_1_VERSION] = "TLSv1.1", + [_M.TLS1_2_VERSION] = "TLSv1.2", + } + + function _M.get_tls1_version_str() + local ver, err = get_tls1_version() + if not ver then + return nil, err + end + return map[ver] + end +end + + +return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/ssl.md b/rootfs/etc/nginx/lua/vendor/ngx/ssl.md new file mode 100644 index 0000000000..477a963c6f --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/ssl.md @@ -0,0 +1,513 @@ +Name +==== + +ngx.ssl - Lua API for controlling NGINX downstream SSL handshakes + +Table of Contents +================= + +* [Name](#name) +* [Status](#status) +* [Synopsis](#synopsis) +* [Description](#description) +* [Methods](#methods) + * [clear_certs](#clear_certs) + * [cert_pem_to_der](#cert_pem_to_der) + * [set_der_cert](#set_der_cert) + * [priv_key_pem_to_der](#priv_key_pem_to_der) + * [set_der_priv_key](#set_der_priv_key) + * [server_name](#server_name) + * [raw_server_addr](#raw_server_addr) + * [raw_client_addr](#raw_client_addr) + * [get_tls1_version](#get_tls1_version) + * [parse_pem_cert](#parse_pem_cert) + * [parse_pem_priv_key](#parse_pem_priv_key) + * [set_cert](#set_cert) + * [set_priv_key](#set_priv_key) +* [Community](#community) + * [English Mailing List](#english-mailing-list) + * [Chinese Mailing List](#chinese-mailing-list) +* [Bugs and Patches](#bugs-and-patches) +* [Author](#author) +* [Copyright and License](#copyright-and-license) +* [See Also](#see-also) + +Status +====== + +This Lua module is currently considered experimental. + +Synopsis +======== + +```nginx +# Note: you do not need the following line if you are using +# OpenResty 1.9.7.2+. +lua_package_path "/path/to/lua-resty-core/lib/?.lua;;"; + +server { + listen 443 ssl; + server_name test.com; + + # useless placeholders: just to shut up NGINX configuration + # loader errors: + ssl_certificate /path/to/fallback.crt; + ssl_certificate_key /path/to/fallback.key; + + ssl_certificate_by_lua_block { + local ssl = require "ngx.ssl" + + -- clear the fallback certificates and private keys + -- set by the ssl_certificate and ssl_certificate_key + -- directives above: + local ok, err = ssl.clear_certs() + if not ok then + ngx.log(ngx.ERR, "failed to clear existing (fallback) certificates") + return ngx.exit(ngx.ERROR) + end + + -- assuming the user already defines the my_load_certificate_chain() + -- herself. + local pem_cert_chain = assert(my_load_certificate_chain()) + + local der_cert_chain, err = ssl.cert_pem_to_der(pem_cert_chain) + if not der_cert_chain then + ngx.log(ngx.ERR, "failed to convert certificate chain ", + "from PEM to DER: ", err) + return ngx.exit(ngx.ERROR) + end + + local ok, err = ssl.set_der_cert(der_cert_chain) + if not ok then + ngx.log(ngx.ERR, "failed to set DER cert: ", err) + return ngx.exit(ngx.ERROR) + end + + -- assuming the user already defines the my_load_private_key() + -- function herself. + local pem_pkey = assert(my_load_private_key()) + + local der_pkey, err = ssl.priv_key_pem_to_der(pem_pkey) + if not der_pkey then + ngx.log(ngx.ERR, "failed to convert private key ", + "from PEM to DER: ", err) + return ngx.exit(ngx.ERROR) + end + + local ok, err = ssl.set_der_priv_key(der_pkey) + if not ok then + ngx.log(ngx.ERR, "failed to set DER private key: ", err) + return ngx.exit(ngx.ERROR) + end + } + + location / { + root html; + } +} +``` + +Description +=========== + +This Lua module provides API functions to control the SSL handshake process in contexts like +[ssl_certificate_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_certificate_by_lua_block) +(of the [ngx_lua](https://github.com/openresty/lua-nginx-module#readme) module). + +For web servers serving many (like millions of) https sites, it is often desired to lazily +load and cache the SSL certificate chain and private key data for the https sites actually +being served by a particular server. This Lua module provides API to support such use cases +in the context of the [ssl_certificate_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_certificate_by_lua_block) +directive. + +To load the `ngx.ssl` module in Lua, just write + +```lua +local ssl = require "ngx.ssl" +``` + +[Back to TOC](#table-of-contents) + +Methods +======= + +clear_certs +----------- +**syntax:** *ok, err = ssl.clear_certs()* + +**context:** *ssl_certificate_by_lua** + +Clears any existing SSL certificates and/or private keys set on the current SSL connection. + +Returns `true` on success, or a `nil` value and a string describing the error otherwise. + +[Back to TOC](#table-of-contents) + +cert_pem_to_der +--------------- +**syntax:** *der_cert_chain, err = ssl.cert_pem_to_der(pem_cert_chain)* + +**context:** *any* + +Converts the PEM-formatted SSL certificate chain data into the DER format (for later uses +in the [set_der_cert](#set_der_cert) +function, for example). + +In case of failures, returns `nil` and a string describing the error. + +It is known that the `openssl` command-line utility may not convert the whole SSL +certificate chain from PEM to DER correctly. So always use this Lua function to do +the conversion. You can always use libraries like [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache#readme) +and/or ngx_lua APIs like [lua_shared_dict](https://github.com/openresty/lua-nginx-module#lua_shared_dict) +to do the caching of the DER-formatted results, for example. + +This function can be called in whatever contexts. + +[Back to TOC](#table-of-contents) + +set_der_cert +------------ +**syntax:** *ok, err = ssl.set_der_cert(der_cert_chain)* + +**context:** *ssl_certificate_by_lua** + +Sets the DER-formatted SSL certificate chain data for the current SSL connection. Note that +the DER data is +directly in the Lua string argument. *No* external file names are supported here. + +Returns `true` on success, or a `nil` value and a string describing the error otherwise. + +Note that, the SSL certificate chain is usually encoded in the PEM format. So you need +to use the [cert_pem_to_der](#cert_pem_to_der) +function to do the conversion first. + +[Back to TOC](#table-of-contents) + +priv_key_pem_to_der +------------------- +**syntax:** *der_priv_key, err = ssl.priv_key_pem_to_der(pem_priv_key)* + +**context:** *any* + +Converts the PEM-formatted SSL private key data into the DER format (for later uses +in the [set_der_priv_key](#set_der_priv_key) +function, for example). + +In case of failures, returns `nil` and a string describing the error. + +Alternatively, you can do the PEM to DER conversion *offline* with the `openssl` command-line utility, like below + +```bash +openssl rsa -in key.pem -outform DER -out key.der +``` + +This function can be called in whatever contexts. + +[Back to TOC](#table-of-contents) + +set_der_priv_key +---------------- +**syntax:** *ok, err = ssl.set_der_priv_key(der_priv_key)* + +**context:** *ssl_certificate_by_lua** + +Sets the DER-formatted prviate key for the current SSL connection. + +Returns `true` on success, or a `nil` value and a string describing the error otherwise. + +Usually, the private keys are encoded in the PEM format. You can either use the +[priv_key_pem_to_der](#priv_key_pem_to_der) function +to do the PEM to DER conversion or just use +the `openssl` command-line utility offline, like below + +```bash +openssl rsa -in key.pem -outform DER -out key.der +``` + +[Back to TOC](#table-of-contents) + +server_name +----------- +**syntax:** *name, err = ssl.server_name()* + +**context:** *any* + +Returns the TLS SNI (Server Name Indication) name set by the client. Returns `nil` +when the client does not set it. + +In case of failures, it returns `nil` *and* a string describing the error. + +Usually we use this SNI name as the domain name (like `www.openresty.org`) to +identify the current web site while loading the corresponding SSL certificate +chain and private key for the site. + +Please note that not all https clients set the SNI name, so when the SNI name is +missing from the client handshake request, we use the server IP address accessed +by the client to identify the site. See the [raw_server_addr](#raw_server_addr) method +for more details. + +This function can be called in whatever contexts where downstream https is used. + +[Back to TOC](#table-of-contents) + +raw_server_addr +--------------- +**syntax:** *addr_data, addr_type, err = ssl.raw_server_addr()* + +**context:** *any* + +Returns the raw server address actually accessed by the client in the current SSL connection. + +The first two return values are strings representing the address data and the address type, respectively. +The address values are interpreted differently according to the address type values: + +* `unix` +: The address data is a file path for the UNIX domain socket. +* `inet` +: The address data is a binary IPv4 address of 4 bytes long. +* `inet6` +: The address data is a binary IPv6 address of 16 bytes long. + +Returns two `nil` values and a Lua string describing the error. + +The following code snippet shows how to print out the UNIX domain socket address and +the IPv4 address as human-readable strings: + +```lua +local ssl = require "ngx.ssl" +local byte = string.byte + +local addr, addrtyp, err = ssl.raw_server_addr() +if not addr then + ngx.log(ngx.ERR, "failed to fetch raw server addr: ", err) + return +end + +if addrtyp == "inet" then -- IPv4 + ip = string.format("%d.%d.%d.%d", byte(addr, 1), byte(addr, 2), + byte(addr, 3), byte(addr, 4)) + print("Using IPv4 address: ", ip) + +elseif addrtyp == "unix" then -- UNIX + print("Using unix socket file ", addr) + +else -- IPv6 + -- leave as an exercise for the readers +end +``` + +This function can be called in whatever contexts where downstream https is used. + +[Back to TOC](#table-of-contents) + +raw_client_addr +--------------- +**syntax:** *addr, err = ssl.raw_client_addr()* + +**context:** *any* + +Returns the raw client address of the current SSL connection. + +The first two return values are strings representing the address data and the address type, respectively. +The address values are interpreted differently according to the address type values: + +* `unix` +: The address data is a file path for the UNIX domain socket. +* `inet` +: The address data is a binary IPv4 address of 4 bytes long. +* `inet6` +: The address data is a binary IPv6 address of 16 bytes long. + +Returns two `nil` values and a Lua string describing the error. + +The following code snippet shows how to print out the UNIX domain socket address and +the IPv4 address as human-readable strings: + +```lua +local ssl = require "ngx.ssl" +local byte = string.byte + +local addr, addrtyp, err = ssl.raw_client_addr() +if not addr then + ngx.log(ngx.ERR, "failed to fetch raw client addr: ", err) + return +end + +if addrtyp == "inet" then -- IPv4 + ip = string.format("%d.%d.%d.%d", byte(addr, 1), byte(addr, 2), + byte(addr, 3), byte(addr, 4)) + print("Client IPv4 address: ", ip) + +elseif addrtyp == "unix" then -- UNIX + print("Client unix socket file ", addr) + +else -- IPv6 + -- leave as an exercise for the readers +end +``` + +This function can be called in whatever contexts where downstream https is used. + +[Back to TOC](#table-of-contents) + +get_tls1_version +---------------- +**syntax:** *ver, err = ssl.get_tls1_version()* + +**context:** *any* + +Returns the TLS 1.x version number used by the current SSL connection. Returns `nil` and +a string describing the error otherwise. + +Typical return values are + +* `SSLv3` +* `TLSv1` +* `TLSv1.1` +* `TLSv1.2` + +This function can be called in whatever contexts where downstream https is used. + +[Back to TOC](#table-of-contents) + +parse_pem_cert +---------------- +**syntax:** *cert_chain, err = ssl.parse_pem_cert(pem_cert_chain)* + +**context:** *any* + +Converts the PEM-formated SSL certificate chain data into an opaque cdata pointer (for later uses +in the [set_cert](#set_cert) +function, for example). + +In case of failures, returns `nil` and a string describing the error. + +You can always use libraries like [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache#readme) +to cache the cdata result. + +This function can be called in whatever contexts. + +This function was first added in version `0.1.7`. + +[Back to TOC](#table-of-contents) + +parse_pem_priv_key +---------------- +**syntax:** *priv_key, err = ssl.parse_pem_priv_key(pem_priv_key)* + +**context:** *any* + +Converts the PEM-formatted SSL private key data into an opaque cdata pointer (for later uses +in the [set_priv_key](#set_priv_key) +function, for example). + +In case of failures, returns `nil` and a string describing the error. + +This function can be called in whatever contexts. + +This function was first added in version `0.1.7`. + +[Back to TOC](#table-of-contents) + +set_cert +------------ +**syntax:** *ok, err = ssl.set_cert(cert_chain)* + +**context:** *ssl_certificate_by_lua** + +Sets the SSL certificate chain opaque pointer returned by the +[parse_pem_cert](#parse_pem_cert) function for the current SSL connection. + +Returns `true` on success, or a `nil` value and a string describing the error otherwise. + +Note that this `set_cert` function will run slightly faster, in terms of CPU cycles wasted, than the +[set_der_cert](#set_der_cert) variant, since the first function uses opaque cdata pointers +which do not require any additional conversion needed to be performed by the SSL library during the SSL handshake. + +This function was first added in version `0.1.7`. + +[Back to TOC](#table-of-contents) + +set_priv_key +------------ +**syntax:** *ok, err = ssl.set_priv_key(priv_key)* + +**context:** *ssl_certificate_by_lua** + +Sets the SSL private key opaque pointer returned by the +[parse_pem_priv_key](#parse_pem_priv_key) function for the current SSL connection. + +Returns `true` on success, or a `nil` value and a string describing the error otherwise. + +Note that this `set_priv_key` function will run slightly faster, in terms of CPU cycles wasted, than the +[set_der_priv_key](#set_der_priv_key) variant, since the first function uses opaque cdata pointers +which do not require any additional conversion needed to be performed by the SSL library during the SSL handshake. + +This function was first added in version `0.1.7`. + +[Back to TOC](#table-of-contents) + +Community +========= + +[Back to TOC](#table-of-contents) + +English Mailing List +-------------------- + +The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. + +[Back to TOC](#table-of-contents) + +Chinese Mailing List +-------------------- + +The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. + +[Back to TOC](#table-of-contents) + +Bugs and Patches +================ + +Please report bugs or submit patches by + +1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), +1. or posting to the [OpenResty community](#community). + +[Back to TOC](#table-of-contents) + +Author +====== + +Yichun Zhang <agentzh@gmail.com> (agentzh), OpenResty Inc. + +[Back to TOC](#table-of-contents) + +Copyright and License +===================== + +This module is licensed under the BSD license. + +Copyright (C) 2015-2017, by Yichun "agentzh" Zhang, OpenResty Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[Back to TOC](#table-of-contents) + +See Also +======== +* the ngx_lua module: https://github.com/openresty/lua-nginx-module +* the [ngx.ocsp](ocsp.md) module. +* the [ssl_certificate_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_certificate_by_lua_block) directive. +* library [lua-resty-core](https://github.com/openresty/lua-resty-core) +* OpenResty: http://openresty.org + +[Back to TOC](#table-of-contents) diff --git a/rootfs/etc/nginx/lua/vendor/ngx/ssl/session.lua b/rootfs/etc/nginx/lua/vendor/ngx/ssl/session.lua new file mode 100644 index 0000000000..f3c24a7535 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/ssl/session.lua @@ -0,0 +1,109 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local base = require "resty.core.base" +base.allows_subsystem('http') + + +local ffi = require "ffi" +local C = ffi.C +local ffi_str = ffi.string +local getfenv = getfenv +local error = error +local errmsg = base.get_errmsg_ptr() +local get_string_buf = base.get_string_buf +local FFI_ERROR = base.FFI_ERROR + + +ffi.cdef[[ +int ngx_http_lua_ffi_ssl_set_serialized_session(ngx_http_request_t *r, + const unsigned char *buf, int len, char **err); + +int ngx_http_lua_ffi_ssl_get_serialized_session(ngx_http_request_t *r, + char *buf, char **err); + +int ngx_http_lua_ffi_ssl_get_session_id(ngx_http_request_t *r, + char *buf, char **err); + +int ngx_http_lua_ffi_ssl_get_serialized_session_size(ngx_http_request_t *r, + char **err); + +int ngx_http_lua_ffi_ssl_get_session_id_size(ngx_http_request_t *r, + char **err); +]] + + +local _M = { version = base.version } + + +-- return session, err +function _M.get_serialized_session() + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local len = C.ngx_http_lua_ffi_ssl_get_serialized_session_size(r, errmsg) + + if len < 0 then + return nil, ffi_str(errmsg[0]) + end + + if len > 4096 then + return nil, "session too big to serialize" + end + local buf = get_string_buf(len) + + local rc = C.ngx_http_lua_ffi_ssl_get_serialized_session(r, buf, errmsg) + + if rc == FFI_ERROR then + return nil, ffi_str(errmsg[0]) + end + + return ffi_str(buf, len) +end + + +-- return session_id, err +function _M.get_session_id() + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local len = C.ngx_http_lua_ffi_ssl_get_session_id_size(r, errmsg) + + if len < 0 then + return nil, ffi_str(errmsg[0]) + end + + local buf = get_string_buf(len) + + local rc = C.ngx_http_lua_ffi_ssl_get_session_id(r, buf, errmsg) + + if rc == FFI_ERROR then + return nil, ffi_str(errmsg[0]) + end + + return ffi_str(buf, len) +end + + +-- return ok, err +function _M.set_serialized_session(sess) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local rc = C.ngx_http_lua_ffi_ssl_set_serialized_session(r, sess, #sess, + errmsg) + if rc == FFI_ERROR then + return nil, ffi_str(errmsg[0]) + end + + return true +end + + +return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/ssl/session.md b/rootfs/etc/nginx/lua/vendor/ngx/ssl/session.md new file mode 100644 index 0000000000..b6671b37a7 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/ngx/ssl/session.md @@ -0,0 +1,277 @@ +Name +==== + +ngx.ssl.session - Lua API for manipulating SSL session data and IDs for NGINX downstream SSL connections. + +Table of Contents +================= + +* [Name](#name) +* [Status](#status) +* [Synopsis](#synopsis) +* [Description](#description) +* [Methods](#methods) + * [get_session_id](#get_session_id) + * [get_serialized_session](#get_serialized_session) + * [set_serialized_session](#set_serialized_session) +* [Community](#community) + * [English Mailing List](#english-mailing-list) + * [Chinese Mailing List](#chinese-mailing-list) +* [Bugs and Patches](#bugs-and-patches) +* [Author](#author) +* [Copyright and License](#copyright-and-license) +* [See Also](#see-also) + +Status +====== + +This Lua module is currently considered experimental. + +Synopsis +======== + +```nginx +# nginx.conf + +# Note: you do not need the following line if you are using +# OpenResty 1.11.2.1+. +lua_package_path "/path/to/lua-resty-core/lib/?.lua;;"; + +ssl_session_fetch_by_lua_block { + local ssl_sess = require "ngx.ssl.session" + + local sess_id, err = ssl_sess.get_session_id() + if not sess_id then + ngx.log(ngx.ERR, "failed to get session ID: ", err) + -- considered a cache miss, and just return... + return + end + + -- the user is supposed to implement the my_lookup_ssl_session_by_id + -- Lua function used below. She can look up an external memcached + -- or redis cluster, for example. And she can also introduce a local + -- cache layer at the same time... + local sess, err = my_lookup_ssl_session_by_id(sess_id) + if not sess then + if err then + ngx.log(ngx.ERR, "failed to look up the session by ID ", + sess_id, ": ", err) + return + end + + -- cache miss...just return + return + end + + local ok, err = ssl_sess.set_serialized_session(sess) + if not ok then + ngx.log(ngx.ERR, "failed to set SSL session for ID ", sess_id, + ": ", err) + -- consider it as a cache miss... + return + end + + -- done here, SSL session successfully set and should resume accordingly... +} + +ssl_session_store_by_lua_block { + local ssl_sess = require "ngx.ssl.session" + + local sess_id, err = ssl_sess.get_session_id() + if not sess_id then + ngx.log(ngx.ERR, "failed to get session ID: ", err) + -- just give up + return + end + + local sess, err = ssl_sess.get_serialized_session() + if not sess then + ngx.log(ngx.ERR, "failed to get SSL session from the ", + "current connection: ", err) + -- just give up + return + end + + -- for the best performance, we should avoid creating a closure + -- dynamically here on the hot code path. Instead, we should + -- put this function in one of our own Lua module files. this + -- example is just for demonstration purposes... + local function save_it(premature, sess_id, sess) + -- the user is supposed to implement the + -- my_save_ssl_session_by_id Lua function used below. + -- She can save to an external memcached + -- or redis cluster, for example. And she can also introduce + -- a local cache layer at the same time... + local sess, err = my_save_ssl_session_by_id(sess_id, sess) + if not sess then + if err then + ngx.log(ngx.ERR, "failed to save the session by ID ", + sess_id, ": ", err) + return ngx.exit(ngx.ERROR) + end + + -- cache miss...just return + return + end + end + + -- create a 0-delay timer here... + local ok, err = ngx.timer.at(0, save_it, sess_id, sess) + if not ok then + ngx.log(ngx.ERR, "failed to create a 0-delay timer: ", err) + return + end +} + +server { + listen 443 ssl; + server_name test.com; + + # well, we could configure ssl_certificate_by_lua* here as well... + ssl_certificate /path/to/server-cert.pem; + ssl_certificate_key /path/to/server-priv-key.pem; +} +``` + +Description +=========== + +This Lua module provides API functions for manipulating SSL session data and IDs for NGINX +downstream connections. It is mostly for the contexts [ssl_session_fetch_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_fetch_by_lua_block) +and [ssl_session_store_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_store_by_lua_block). + +This Lua API can be used to implement distributed SSL session caching for downstream SSL connections, thus saving a lot of full SSL handshakes which are very expensive. + +To load the `ngx.ssl.session` module in Lua, just write + +```lua +local ssl_sess = require "ngx.ssl.session" +``` + +[Back to TOC](#table-of-contents) + +Methods +======= + +get_session_id +-------------- +**syntax:** *id, err = ssl_sess.get_session_id()* + +**context:** *ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +Fetches the SSL session ID associated with the current downstream SSL connection. +The ID is returned as a Lua string. + +In case of errors, it returns `nil` and a string describing the error. + +This API function is usually called in the contexts of +[ssl_session_store_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_store_by_lua_block) +and [ssl_session_fetch_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_fetch_by_lua_block). + +[Back to TOC](#table-of-contents) + +get_serialized_session +---------------------- +**syntax:** *session, err = ssl_sess.get_serialized_session()* + +**context:** *ssl_session_store_by_lua** + +Returns the serialized form of the SSL sesson data of the current SSL connection, in a Lua string. + +This session can be cached in [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache), [lua_shared_dict](https://github.com/openresty/lua-nginx-module#lua_shared_dict), +and/or external data storage services like `memcached` and `redis`. The SSL session ID returned +by the [get_session_id](#get_session_id) function is usually used as the cache key. + +The returned SSL session data can later be loaded into other SSL connections using the same +session ID via the [set_serialized_session](#set_serialized_session) function. + +In case of errors, it returns `nil` and a string describing the error. + +This API function is usually called in the context of +[ssl_session_store_by_lua*](https://github.com/openresty/lua-nginx-module#ssl_session_store_by_lua_block) +where the SSL handshake has just completed. + +[Back to TOC](#table-of-contents) + +set_serialized_session +---------------------- +**syntax:** *ok, err = ssl_sess.set_serialized_session(session)* + +**context:** *ssl_session_fetch_by_lua** + +Sets the serialized SSL session provided as the argument to the current SSL connection. +If the SSL session is successfully set, the current SSL connection can resume the session +directly without going through the full SSL handshake process (which is very expensive in terms of CPU time). + +This API is usually used in the context of [ssl_session_fetch_by_lua*](https://github.com/openresty/lua-nginx-module#ssl_session_fetch_by_lua_block) +when a cache hit is found with the current SSL session ID. + +The serialized SSL session used as the argument should be originally returned by the +[get_serialized_session](#get_serialized_session) function. + +[Back to TOC](#table-of-contents) + +Community +========= + +[Back to TOC](#table-of-contents) + +English Mailing List +-------------------- + +The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. + +[Back to TOC](#table-of-contents) + +Chinese Mailing List +-------------------- + +The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. + +[Back to TOC](#table-of-contents) + +Bugs and Patches +================ + +Please report bugs or submit patches by + +1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), +1. or posting to the [OpenResty community](#community). + +[Back to TOC](#table-of-contents) + +Author +====== + +Yichun Zhang <agentzh@gmail.com> (agentzh), OpenResty Inc. + +[Back to TOC](#table-of-contents) + +Copyright and License +===================== + +This module is licensed under the BSD license. + +Copyright (C) 2016-2017, by Yichun "agentzh" Zhang, OpenResty Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[Back to TOC](#table-of-contents) + +See Also +======== +* the ngx_lua module: https://github.com/openresty/lua-nginx-module +* the [ssl_session_fetch_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_fetch_by_lua_block) directive. +* the [ssl_session_store_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_store_by_lua_block) directive. +* library [lua-resty-core](https://github.com/openresty/lua-resty-core) +* OpenResty: https://openresty.org + +[Back to TOC](#table-of-contents) diff --git a/rootfs/etc/nginx/lua/vendor/resty/core.lua b/rootfs/etc/nginx/lua/vendor/resty/core.lua new file mode 100644 index 0000000000..da6c778301 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core.lua @@ -0,0 +1,29 @@ +-- Copyright (C) Yichun Zhang (agentzh) + +local subsystem = ngx.config.subsystem + + +if subsystem == 'http' then + require "resty.core.uri" + require "resty.core.hash" + require "resty.core.base64" + require "resty.core.regex" + require "resty.core.exit" + require "resty.core.shdict" + require "resty.core.var" + require "resty.core.ctx" + require "resty.core.misc" + require "resty.core.request" + require "resty.core.response" + require "resty.core.time" + require "resty.core.worker" + require "resty.core.phase" +end + + +local base = require "resty.core.base" + + +return { + version = base.version +} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/base.lua b/rootfs/etc/nginx/lua/vendor/resty/core/base.lua new file mode 100644 index 0000000000..2093959e35 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core/base.lua @@ -0,0 +1,236 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local ffi = require 'ffi' +local ffi_new = ffi.new +local error = error +local select = select +local ceil = math.ceil +local subsystem = ngx.config.subsystem + + +local str_buf_size = 4096 +local str_buf +local size_ptr +local FREE_LIST_REF = 0 + + +if subsystem == 'http' then + if not ngx.config + or not ngx.config.ngx_lua_version + or ngx.config.ngx_lua_version < 10012 + then + error("ngx_http_lua_module 0.10.12+ required") + end + +elseif subsystem == 'stream' then + if not ngx.config + or not ngx.config.ngx_lua_version + or ngx.config.ngx_lua_version < 4 + then + error("ngx_stream_lua_module 0.0.4+ required") + end + +else + error("ngx_http_lua_module 0.10.12+ or " + .. "ngx_stream_lua_module 0.0.4+ required") +end + + +if string.find(jit.version, " 2.0", 1, true) then + ngx.log(ngx.ALERT, "use of lua-resty-core with LuaJIT 2.0 is ", + "not recommended; use LuaJIT 2.1+ instead") +end + + +local ok, new_tab = pcall(require, "table.new") +if not ok then + new_tab = function (narr, nrec) return {} end +end + + +local clear_tab +ok, clear_tab = pcall(require, "table.clear") +if not ok then + clear_tab = function (tab) + for k, _ in pairs(tab) do + tab[k] = nil + end + end +end + + +-- XXX for now LuaJIT 2.1 cannot compile require() +-- so we make the fast code path Lua only in our own +-- wrapper so that most of the require() calls in hot +-- Lua code paths can be JIT compiled. +do + local orig_require = require + local pkg_loaded = package.loaded + local function my_require(name) + local mod = pkg_loaded[name] + if mod then + return mod + end + return orig_require(name) + end + getfenv(0).require = my_require +end + + +if not pcall(ffi.typeof, "ngx_str_t") then + ffi.cdef[[ + typedef struct { + size_t len; + const unsigned char *data; + } ngx_str_t; + ]] +end + + +if subsystem == 'http' then + if not pcall(ffi.typeof, "ngx_http_request_t") then + ffi.cdef[[ + struct ngx_http_request_s; + typedef struct ngx_http_request_s ngx_http_request_t; + ]] + end + + if not pcall(ffi.typeof, "ngx_http_lua_ffi_str_t") then + ffi.cdef[[ + typedef struct { + int len; + const unsigned char *data; + } ngx_http_lua_ffi_str_t; + ]] + end + +elseif subsystem == 'stream' then + if not pcall(ffi.typeof, "ngx_stream_lua_request_t") then + ffi.cdef[[ + struct ngx_stream_lua_request_s; + typedef struct ngx_stream_lua_request_s ngx_stream_lua_request_t; + ]] + end + + if not pcall(ffi.typeof, "ngx_stream_lua_ffi_str_t") then + ffi.cdef[[ + typedef struct { + int len; + const unsigned char *data; + } ngx_stream_lua_ffi_str_t; + ]] + end + +else + error("unknown subsystem: " .. subsystem) +end + + +local c_buf_type = ffi.typeof("char[?]") + + +local _M = new_tab(0, 17) + + +_M.version = "0.1.13" +_M.new_tab = new_tab +_M.clear_tab = clear_tab + + +local errmsg + + +function _M.get_errmsg_ptr() + if not errmsg then + errmsg = ffi_new("char *[1]") + end + return errmsg +end + + +if not ngx then + return error("no existing ngx. table found") +end + + +function _M.set_string_buf_size(size) + if size <= 0 then + return + end + if str_buf then + str_buf = nil + end + str_buf_size = ceil(size) +end + + +function _M.get_string_buf_size() + return str_buf_size +end + + +function _M.get_size_ptr() + if not size_ptr then + size_ptr = ffi_new("size_t[1]") + end + + return size_ptr +end + + +function _M.get_string_buf(size, must_alloc) + -- ngx.log(ngx.ERR, "str buf size: ", str_buf_size) + if size > str_buf_size or must_alloc then + return ffi_new(c_buf_type, size) + end + + if not str_buf then + str_buf = ffi_new(c_buf_type, str_buf_size) + end + + return str_buf +end + + +function _M.ref_in_table(tb, key) + if key == nil then + return -1 + end + local ref = tb[FREE_LIST_REF] + if ref and ref ~= 0 then + tb[FREE_LIST_REF] = tb[ref] + + else + ref = #tb + 1 + end + tb[ref] = key + + -- print("ref key_id returned ", ref) + return ref +end + + +function _M.allows_subsystem(...) + local total = select("#", ...) + + for i = 1, total do + if select(i, ...) == subsystem then + return + end + end + + error("unsupported subsystem: " .. subsystem) +end + + +_M.FFI_OK = 0 +_M.FFI_NO_REQ_CTX = -100 +_M.FFI_BAD_CONTEXT = -101 +_M.FFI_ERROR = -1 +_M.FFI_BUSY = -3 +_M.FFI_DONE = -4 +_M.FFI_DECLINED = -5 + + +return _M diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/base64.lua b/rootfs/etc/nginx/lua/vendor/resty/core/base64.lua new file mode 100644 index 0000000000..83c0bf32bf --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core/base64.lua @@ -0,0 +1,90 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local ffi = require 'ffi' +local base = require "resty.core.base" + +local ffi_string = ffi.string +local C = ffi.C +local ngx = ngx +local type = type +local tostring = tostring +local error = error +local get_string_buf = base.get_string_buf +local get_size_ptr = base.get_size_ptr +local floor = math.floor + + +ffi.cdef[[ + size_t ngx_http_lua_ffi_encode_base64(const unsigned char *src, + size_t len, unsigned char *dst, + int no_padding); + + int ngx_http_lua_ffi_decode_base64(const unsigned char *src, + size_t len, unsigned char *dst, + size_t *dlen); +]] + + +local function base64_encoded_length(len, no_padding) + return no_padding and floor((len * 8 + 5) / 6) or + floor((len + 2) / 3) * 4 +end + + +ngx.encode_base64 = function (s, no_padding) + if type(s) ~= 'string' then + if not s then + s = '' + else + s = tostring(s) + end + end + + local slen = #s + local no_padding_bool = false; + local no_padding_int = 0; + + if no_padding then + if no_padding ~= true then + return error("boolean argument only") + end + + no_padding_bool = true + no_padding_int = 1; + end + + local dlen = base64_encoded_length(slen, no_padding_bool) + local dst = get_string_buf(dlen) + local r_dlen = C.ngx_http_lua_ffi_encode_base64(s, slen, dst, + no_padding_int) + -- if dlen ~= r_dlen then error("discrepancy in len") end + return ffi_string(dst, r_dlen) +end + + +local function base64_decoded_length(len) + return floor((len + 3) / 4) * 3 +end + + +ngx.decode_base64 = function (s) + if type(s) ~= 'string' then + return error("string argument only") + end + local slen = #s + local dlen = base64_decoded_length(slen) + -- print("dlen: ", tonumber(dlen)) + local dst = get_string_buf(dlen) + local pdlen = get_size_ptr() + local ok = C.ngx_http_lua_ffi_decode_base64(s, slen, dst, pdlen) + if ok == 0 then + return nil + end + return ffi_string(dst, pdlen[0]) +end + + +return { + version = base.version +} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/ctx.lua b/rootfs/etc/nginx/lua/vendor/resty/core/ctx.lua new file mode 100644 index 0000000000..c75261ff1c --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core/ctx.lua @@ -0,0 +1,82 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local ffi = require 'ffi' +local debug = require 'debug' +local base = require "resty.core.base" +local misc = require "resty.core.misc" + + +local register_getter = misc.register_ngx_magic_key_getter +local register_setter = misc.register_ngx_magic_key_setter +local registry = debug.getregistry() +local new_tab = base.new_tab +local ref_in_table = base.ref_in_table +local getfenv = getfenv +local C = ffi.C +local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX +local FFI_OK = base.FFI_OK +local error = error + + +ffi.cdef[[ +int ngx_http_lua_ffi_get_ctx_ref(ngx_http_request_t *r); +int ngx_http_lua_ffi_set_ctx_ref(ngx_http_request_t *r, int ref); +]] + + +local _M = { + _VERSION = base.version +} + + +local function get_ctx_table() + local r = getfenv(0).__ngx_req + + if not r then + return error("no request found") + end + + local ctx_ref = C.ngx_http_lua_ffi_get_ctx_ref(r) + if ctx_ref == FFI_NO_REQ_CTX then + return error("no request ctx found") + end + + local ctxs = registry.ngx_lua_ctx_tables + if ctx_ref < 0 then + local ctx = new_tab(0, 4) + ctx_ref = ref_in_table(ctxs, ctx) + if C.ngx_http_lua_ffi_set_ctx_ref(r, ctx_ref) ~= FFI_OK then + return nil + end + return ctx + end + return ctxs[ctx_ref] +end +register_getter("ctx", get_ctx_table) + + +local function set_ctx_table(ctx) + local r = getfenv(0).__ngx_req + + if not r then + return error("no request found") + end + + local ctx_ref = C.ngx_http_lua_ffi_get_ctx_ref(r) + if ctx_ref == FFI_NO_REQ_CTX then + return error("no request ctx found") + end + + local ctxs = registry.ngx_lua_ctx_tables + if ctx_ref < 0 then + ctx_ref = ref_in_table(ctxs, ctx) + C.ngx_http_lua_ffi_set_ctx_ref(r, ctx_ref) + return + end + ctxs[ctx_ref] = ctx +end +register_setter("ctx", set_ctx_table) + + +return _M diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/exit.lua b/rootfs/etc/nginx/lua/vendor/resty/core/exit.lua new file mode 100644 index 0000000000..210069cdd5 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core/exit.lua @@ -0,0 +1,48 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local ffi = require 'ffi' +local ffi_string = ffi.string +local C = ffi.C +local ngx = ngx +local error = error +local base = require "resty.core.base" +local get_string_buf = base.get_string_buf +local get_size_ptr = base.get_size_ptr +local getfenv = getfenv +local co_yield = coroutine._yield + + +ffi.cdef[[ + int ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, + unsigned char *err, size_t *errlen); +]] + + +local ERR_BUF_SIZE = 128 +local FFI_DONE = base.FFI_DONE + + +ngx.exit = function (rc) + local err = get_string_buf(ERR_BUF_SIZE) + local errlen = get_size_ptr() + local r = getfenv(0).__ngx_req + if r == nil then + return error("no request found") + end + errlen[0] = ERR_BUF_SIZE + rc = C.ngx_http_lua_ffi_exit(r, rc, err, errlen) + if rc == 0 then + -- print("yielding...") + return co_yield() + end + if rc == FFI_DONE then + return + end + return error(ffi_string(err, errlen[0])) +end + + +return { + version = base.version +} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/hash.lua b/rootfs/etc/nginx/lua/vendor/resty/core/hash.lua new file mode 100644 index 0000000000..79c934aed1 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core/hash.lua @@ -0,0 +1,80 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local ffi = require 'ffi' +local ffi_string = ffi.string +local ffi_new = ffi.new +local C = ffi.C +local ngx = ngx +local type = type +local tostring = tostring +local error = error +local base = require "resty.core.base" + + +ffi.cdef[[ + void ngx_http_lua_ffi_md5_bin(const unsigned char *src, size_t len, + unsigned char *dst); + + void ngx_http_lua_ffi_md5(const unsigned char *src, size_t len, + unsigned char *dst); + + int ngx_http_lua_ffi_sha1_bin(const unsigned char *src, size_t len, + unsigned char *dst); +]] + + +local MD5_DIGEST_LEN = 16 +local md5_buf = ffi_new("unsigned char[?]", MD5_DIGEST_LEN) + +ngx.md5_bin = function (s) + if type(s) ~= 'string' then + if not s then + s = '' + else + s = tostring(s) + end + end + C.ngx_http_lua_ffi_md5_bin(s, #s, md5_buf) + return ffi_string(md5_buf, MD5_DIGEST_LEN) +end + + +local MD5_HEX_DIGEST_LEN = MD5_DIGEST_LEN * 2 +local md5_hex_buf = ffi_new("unsigned char[?]", MD5_HEX_DIGEST_LEN) + +ngx.md5 = function (s) + if type(s) ~= 'string' then + if not s then + s = '' + else + s = tostring(s) + end + end + C.ngx_http_lua_ffi_md5(s, #s, md5_hex_buf) + return ffi_string(md5_hex_buf, MD5_HEX_DIGEST_LEN) +end + + +local SHA_DIGEST_LEN = 20 +local sha_buf = ffi_new("unsigned char[?]", SHA_DIGEST_LEN) + +ngx.sha1_bin = function (s) + if type(s) ~= 'string' then + if not s then + s = '' + else + s = tostring(s) + end + end + local ok = C.ngx_http_lua_ffi_sha1_bin(s, #s, sha_buf) + if ok == 0 then + return error("SHA-1 support missing in Nginx") + end + return ffi_string(sha_buf, SHA_DIGEST_LEN) +end + + +return { + version = base.version +} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/misc.lua b/rootfs/etc/nginx/lua/vendor/resty/core/misc.lua new file mode 100644 index 0000000000..2f30528d05 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core/misc.lua @@ -0,0 +1,155 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local base = require "resty.core.base" +local ffi = require "ffi" + + +local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX +local FFI_BAD_CONTEXT = base.FFI_BAD_CONTEXT +local new_tab = base.new_tab +local C = ffi.C +local getmetatable = getmetatable +local ngx_magic_key_getters = new_tab(0, 4) +local ngx_magic_key_setters = new_tab(0, 2) +local ngx = ngx +local getfenv = getfenv +local type = type +local error = error +local tonumber = tonumber + + +local _M = new_tab(0, 3) +_M._VERSION = base.version + + +local function register_getter(key, func) + ngx_magic_key_getters[key] = func +end +_M.register_ngx_magic_key_getter = register_getter + + +local function register_setter(key, func) + ngx_magic_key_setters[key] = func +end +_M.register_ngx_magic_key_setter = register_setter + + +local mt = getmetatable(ngx) + + +local old_index = mt.__index +mt.__index = function (tb, key) + local f = ngx_magic_key_getters[key] + if f then + return f() + end + return old_index(tb, key) +end + + +local old_newindex = mt.__newindex +mt.__newindex = function (tb, key, ctx) + local f = ngx_magic_key_setters[key] + if f then + return f(ctx) + end + return old_newindex(tb, key, ctx) +end + + +ffi.cdef[[ + int ngx_http_lua_ffi_get_resp_status(ngx_http_request_t *r); + int ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int r); + int ngx_http_lua_ffi_is_subrequest(ngx_http_request_t *r); + int ngx_http_lua_ffi_headers_sent(ngx_http_request_t *r); +]] + + +-- ngx.status + +local function get_status() + local r = getfenv(0).__ngx_req + + if not r then + return error("no request found") + end + + local rc = C.ngx_http_lua_ffi_get_resp_status(r) + + if rc == FFI_BAD_CONTEXT then + return error("API disabled in the current context") + end + + return rc +end +register_getter("status", get_status) + + +local function set_status(status) + local r = getfenv(0).__ngx_req + + if not r then + return error("no request found") + end + + if type(status) ~= 'number' then + status = tonumber(status) + end + + local rc = C.ngx_http_lua_ffi_set_resp_status(r, status) + + if rc == FFI_BAD_CONTEXT then + return error("API disabled in the current context") + end + + return +end +register_setter("status", set_status) + + +-- ngx.is_subrequest + +local function is_subreq() + local r = getfenv(0).__ngx_req + + if not r then + return error("no request found") + end + + local rc = C.ngx_http_lua_ffi_is_subrequest(r) + + if rc == FFI_BAD_CONTEXT then + return error("API disabled in the current context") + end + + return rc == 1 +end +register_getter("is_subrequest", is_subreq) + + +-- ngx.headers_sent + +local function headers_sent() + local r = getfenv(0).__ngx_req + + if not r then + return error("no request found") + end + + local rc = C.ngx_http_lua_ffi_headers_sent(r) + + if rc == FFI_NO_REQ_CTX then + return error("no request ctx found") + end + + if rc == FFI_BAD_CONTEXT then + return error("API disabled in the current context") + end + + return rc == 1 +end +register_getter("headers_sent", headers_sent) + + +return _M diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/phase.lua b/rootfs/etc/nginx/lua/vendor/resty/core/phase.lua new file mode 100644 index 0000000000..d83d0f3ea4 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core/phase.lua @@ -0,0 +1,57 @@ +local ffi = require 'ffi' +local base = require "resty.core.base" + +local C = ffi.C +local FFI_ERROR = base.FFI_ERROR +local error = error +local tostring = tostring + + +ffi.cdef[[ +int ngx_http_lua_ffi_get_phase(ngx_http_request_t *r, char **err) +]] + + +local errmsg = base.get_errmsg_ptr() +local context_names = { + [0x0001] = "set", + [0x0002] = "rewrite", + [0x0004] = "access", + [0x0008] = "content", + [0x0010] = "log", + [0x0020] = "header_filter", + [0x0040] = "body_filter", + [0x0080] = "timer", + [0x0100] = "init_worker", + [0x0200] = "balancer", + [0x0400] = "ssl_cert", + [0x0800] = "ssl_session_store", + [0x1000] = "ssl_session_fetch", +} + + +function ngx.get_phase() + local r = getfenv(0).__ngx_req + + -- if we have no request object, assume we are called from the "init" phase + if not r then + return "init" + end + + local context = C.ngx_http_lua_ffi_get_phase(r, errmsg) + if context == FFI_ERROR then -- NGX_ERROR + error(errmsg) + end + + local phase = context_names[context] + if not phase then + error("unknown phase: " .. tostring(context)) + end + + return phase +end + + +return { + version = base.version +} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/regex.lua b/rootfs/etc/nginx/lua/vendor/resty/core/regex.lua new file mode 100644 index 0000000000..cf17e77ded --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core/regex.lua @@ -0,0 +1,971 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local ffi = require 'ffi' +local base = require "resty.core.base" +local bit = require "bit" +require "resty.core.time" -- for ngx.now used by resty.lrucache +local lrucache = require "resty.lrucache" + +local lrucache_get = lrucache.get +local lrucache_set = lrucache.set +local ffi_string = ffi.string +local ffi_gc = ffi.gc +local ffi_copy = ffi.copy +local ffi_cast = ffi.cast +local C = ffi.C +local bor = bit.bor +local band = bit.band +local lshift = bit.lshift +local sub = string.sub +local fmt = string.format +local byte = string.byte +local ngx = ngx +local type = type +local tostring = tostring +local error = error +local setmetatable = setmetatable +local tonumber = tonumber +local get_string_buf = base.get_string_buf +local get_string_buf_size = base.get_string_buf_size +local new_tab = base.new_tab + + +if not ngx.re then + ngx.re = {} +end + + +local MAX_ERR_MSG_LEN = 128 + + +local FLAG_COMPILE_ONCE = 0x01 +local FLAG_DFA = 0x02 +local FLAG_JIT = 0x04 +local FLAG_DUPNAMES = 0x08 +local FLAG_NO_UTF8_CHECK = 0x10 + + +local PCRE_CASELESS = 0x0000001 +local PCRE_MULTILINE = 0x0000002 +local PCRE_DOTALL = 0x0000004 +local PCRE_EXTENDED = 0x0000008 +local PCRE_ANCHORED = 0x0000010 +local PCRE_UTF8 = 0x0000800 +local PCRE_DUPNAMES = 0x0080000 +local PCRE_JAVASCRIPT_COMPAT = 0x2000000 + + +local PCRE_ERROR_NOMATCH = -1 + + +local regex_match_cache +local regex_sub_func_cache = new_tab(0, 4) +local regex_sub_str_cache = new_tab(0, 4) +local max_regex_cache_size +local regex_cache_size = 0 +local script_engine + + +ffi.cdef[[ + typedef struct { + ngx_str_t value; + void *lengths; + void *values; + } ngx_http_lua_complex_value_t; + + typedef struct { + void *pool; + unsigned char *name_table; + int name_count; + int name_entry_size; + + int ncaptures; + int *captures; + + void *regex; + void *regex_sd; + + ngx_http_lua_complex_value_t *replace; + + const char *pattern; + } ngx_http_lua_regex_t; + + ngx_http_lua_regex_t * + ngx_http_lua_ffi_compile_regex(const unsigned char *pat, + size_t pat_len, int flags, + int pcre_opts, unsigned char *errstr, + size_t errstr_size); + + int ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, + const unsigned char *s, size_t len, int pos); + + void ngx_http_lua_ffi_destroy_regex(ngx_http_lua_regex_t *re); + + int ngx_http_lua_ffi_compile_replace_template(ngx_http_lua_regex_t *re, + const unsigned char + *replace_data, + size_t replace_len); + + struct ngx_http_lua_script_engine_s; + typedef struct ngx_http_lua_script_engine_s *ngx_http_lua_script_engine_t; + + ngx_http_lua_script_engine_t *ngx_http_lua_ffi_create_script_engine(void); + + void ngx_http_lua_ffi_init_script_engine(ngx_http_lua_script_engine_t *e, + const unsigned char *subj, + ngx_http_lua_regex_t *compiled, + int count); + + void ngx_http_lua_ffi_destroy_script_engine( + ngx_http_lua_script_engine_t *e); + + size_t ngx_http_lua_ffi_script_eval_len(ngx_http_lua_script_engine_t *e, + ngx_http_lua_complex_value_t *cv); + + size_t ngx_http_lua_ffi_script_eval_data(ngx_http_lua_script_engine_t *e, + ngx_http_lua_complex_value_t *cv, + unsigned char *dst); + + uint32_t ngx_http_lua_ffi_max_regex_cache_size(void); +]] + + +local c_str_type = ffi.typeof("const char *") + +local cached_re_opts = new_tab(0, 4) + +local _M = { + version = base.version +} + + +local buf_grow_ratio = 2 + + +function _M.set_buf_grow_ratio(ratio) + buf_grow_ratio = ratio +end + + +local function get_max_regex_cache_size() + if max_regex_cache_size then + return max_regex_cache_size + end + max_regex_cache_size = C.ngx_http_lua_ffi_max_regex_cache_size() + return max_regex_cache_size +end + + +local regex_cache_is_empty = true + + +function _M.is_regex_cache_empty() + return regex_cache_is_empty +end + + +local function lrucache_set_wrapper(...) + regex_cache_is_empty = false + lrucache_set(...) +end + + +local function parse_regex_opts(opts) + local t = cached_re_opts[opts] + if t then + return t[1], t[2] + end + + local flags = 0 + local pcre_opts = 0 + local len = #opts + + for i = 1, len do + local opt = byte(opts, i) + if opt == byte("o") then + flags = bor(flags, FLAG_COMPILE_ONCE) + + elseif opt == byte("j") then + flags = bor(flags, FLAG_JIT) + + elseif opt == byte("i") then + pcre_opts = bor(pcre_opts, PCRE_CASELESS) + + elseif opt == byte("s") then + pcre_opts = bor(pcre_opts, PCRE_DOTALL) + + elseif opt == byte("m") then + pcre_opts = bor(pcre_opts, PCRE_MULTILINE) + + elseif opt == byte("u") then + pcre_opts = bor(pcre_opts, PCRE_UTF8) + + elseif opt == byte("U") then + pcre_opts = bor(pcre_opts, PCRE_UTF8) + flags = bor(flags, FLAG_NO_UTF8_CHECK) + + elseif opt == byte("x") then + pcre_opts = bor(pcre_opts, PCRE_EXTENDED) + + elseif opt == byte("d") then + flags = bor(flags, FLAG_DFA) + + elseif opt == byte("a") then + pcre_opts = bor(pcre_opts, PCRE_ANCHORED) + + elseif opt == byte("D") then + pcre_opts = bor(pcre_opts, PCRE_DUPNAMES) + flags = bor(flags, FLAG_DUPNAMES) + + elseif opt == byte("J") then + pcre_opts = bor(pcre_opts, PCRE_JAVASCRIPT_COMPAT) + + else + return error(fmt('unknown flag "%s" (flags "%s")', + sub(opts, i, i), opts)) + end + end + + cached_re_opts[opts] = {flags, pcre_opts} + return flags, pcre_opts +end + + +local function collect_named_captures(compiled, flags, res) + local name_count = compiled.name_count + local name_table = compiled.name_table + local entry_size = compiled.name_entry_size + + local ind = 0 + local dup_names = (band(flags, FLAG_DUPNAMES) ~= 0) + for i = 1, name_count do + local n = bor(lshift(name_table[ind], 8), name_table[ind + 1]) + -- ngx.say("n = ", n) + local name = ffi_string(name_table + ind + 2) + local cap = res[n] + if dup_names then + -- unmatched captures (false) are not collected + if cap then + local old = res[name] + if old then + old[#old + 1] = cap + else + res[name] = {cap} + end + end + else + res[name] = cap + end + + ind = ind + entry_size + end +end + + +local function collect_captures(compiled, rc, subj, flags, res) + local cap = compiled.captures + local ncap = compiled.ncaptures + local name_count = compiled.name_count + + if not res then + res = new_tab(ncap, name_count) + end + + local i = 0 + local n = 0 + while i <= ncap do + if i > rc then + res[i] = false + else + local from = cap[n] + if from >= 0 then + local to = cap[n + 1] + res[i] = sub(subj, from + 1, to) + else + res[i] = false + end + end + i = i + 1 + n = n + 2 + end + + if name_count > 0 then + collect_named_captures(compiled, flags, res) + end + + return res +end + + +_M.collect_captures = collect_captures + + +local function destroy_compiled_regex(compiled) + C.ngx_http_lua_ffi_destroy_regex(ffi_gc(compiled, nil)) +end + + +_M.destroy_compiled_regex = destroy_compiled_regex + + +local function re_match_compile(regex, opts) + local flags = 0 + local pcre_opts = 0 + + if opts then + flags, pcre_opts = parse_regex_opts(opts) + else + opts = "" + end + + local compiled, key + local compile_once = (band(flags, FLAG_COMPILE_ONCE) == 1) + + -- FIXME: better put this in the outer scope when fixing the ngx.re API's + -- compatibility in the init_by_lua* context. + if not regex_match_cache then + local sz = get_max_regex_cache_size() + if sz <= 0 then + compile_once = false + else + regex_match_cache = lrucache.new(sz) + end + end + + if compile_once then + key = regex .. '\0' .. opts + compiled = lrucache_get(regex_match_cache, key) + end + + -- compile the regex + + if compiled == nil then + -- print("compiled regex not found, compiling regex...") + local errbuf = get_string_buf(MAX_ERR_MSG_LEN) + + compiled = C.ngx_http_lua_ffi_compile_regex(regex, #regex, + flags, pcre_opts, + errbuf, MAX_ERR_MSG_LEN) + + if compiled == nil then + return nil, ffi_string(errbuf) + end + + ffi_gc(compiled, C.ngx_http_lua_ffi_destroy_regex) + + -- print("ncaptures: ", compiled.ncaptures) + + if compile_once then + -- print("inserting compiled regex into cache") + lrucache_set_wrapper(regex_match_cache, key, compiled) + end + end + + return compiled, compile_once, flags +end + + +_M.re_match_compile = re_match_compile + + +local function re_match_helper(subj, regex, opts, ctx, want_caps, res, nth) + -- we need to cast this to strings to avoid exceptions when they are + -- something else. + subj = tostring(subj) + + local compiled, compile_once, flags = re_match_compile(regex, opts) + if compiled == nil then + -- compiled_once holds the error string + if not want_caps then + return nil, nil, compile_once + end + return nil, compile_once + end + + -- exec the compiled regex + + local rc + do + local pos + if ctx then + pos = ctx.pos + if not pos or pos <= 0 then + pos = 0 + else + pos = pos - 1 + end + + else + pos = 0 + end + + rc = C.ngx_http_lua_ffi_exec_regex(compiled, flags, subj, #subj, pos) + end + + if rc == PCRE_ERROR_NOMATCH then + if not compile_once then + destroy_compiled_regex(compiled) + end + return nil + end + + if rc < 0 then + if not compile_once then + destroy_compiled_regex(compiled) + end + if not want_caps then + return nil, nil, "pcre_exec() failed: " .. rc + end + return nil, "pcre_exec() failed: " .. rc + end + + if rc == 0 then + if band(flags, FLAG_DFA) == 0 then + if not want_caps then + return nil, nil, "capture size too small" + end + return nil, "capture size too small" + end + + rc = 1 + end + + -- print("cap 0: ", compiled.captures[0]) + -- print("cap 1: ", compiled.captures[1]) + + if ctx then + ctx.pos = compiled.captures[1] + 1 + end + + if not want_caps then + if not nth or nth < 0 then + nth = 0 + end + + if nth > compiled.ncaptures then + return nil, nil, "nth out of bound" + end + + if nth >= rc then + return nil, nil + end + + local from = compiled.captures[nth * 2] + 1 + local to = compiled.captures[nth * 2 + 1] + + if from < 0 or to < 0 then + return nil, nil + end + + return from, to + end + + res = collect_captures(compiled, rc, subj, flags, res) + + if not compile_once then + destroy_compiled_regex(compiled) + end + + return res +end + + +function ngx.re.match(subj, regex, opts, ctx, res) + return re_match_helper(subj, regex, opts, ctx, true, res) +end + + +function ngx.re.find(subj, regex, opts, ctx, nth) + return re_match_helper(subj, regex, opts, ctx, false, nil, nth) +end + + +do + local function destroy_re_gmatch_iterator(iterator) + if not iterator._compile_once then + destroy_compiled_regex(iterator._compiled) + end + iterator._compiled = nil + iterator._pos = nil + iterator._subj = nil + end + + + local function iterate_re_gmatch(self) + local compiled = self._compiled + local subj = self._subj + local subj_len = self._subj_len + local flags = self._flags + local pos = self._pos + + if not pos then + -- The iterator is exhausted. + return nil + end + + local rc = C.ngx_http_lua_ffi_exec_regex(compiled, flags, subj, + subj_len, pos) + + if rc == PCRE_ERROR_NOMATCH then + destroy_re_gmatch_iterator(self) + return nil + end + + if rc < 0 then + destroy_re_gmatch_iterator(self) + return nil, "pcre_exec() failed: " .. rc + end + + if rc == 0 then + if band(flags, FLAG_DFA) == 0 then + destroy_re_gmatch_iterator(self) + return nil, "capture size too small" + end + + rc = 1 + end + + local cp_pos = tonumber(compiled.captures[1]) + if cp_pos == compiled.captures[0] then + cp_pos = cp_pos + 1 + if cp_pos > subj_len then + local res = collect_captures(compiled, rc, subj, flags) + destroy_re_gmatch_iterator(self) + return res + end + end + self._pos = cp_pos + return collect_captures(compiled, rc, subj, flags) + end + + + local re_gmatch_iterator_mt = { __call = iterate_re_gmatch } + + function ngx.re.gmatch(subj, regex, opts) + subj = tostring(subj) + + local compiled, compile_once, flags = re_match_compile(regex, opts) + if compiled == nil then + -- compiled_once holds the error string + return nil, compile_once + end + + local re_gmatch_iterator = { + _compiled = compiled, + _compile_once = compile_once, + _subj = subj, + _subj_len = #subj, + _flags = flags, + _pos = 0, + } + + return setmetatable(re_gmatch_iterator, re_gmatch_iterator_mt) + end +end -- do + + +local function new_script_engine(subj, compiled, count) + if not script_engine then + script_engine = C.ngx_http_lua_ffi_create_script_engine() + if script_engine == nil then + return nil + end + ffi_gc(script_engine, C.ngx_http_lua_ffi_destroy_script_engine) + end + + C.ngx_http_lua_ffi_init_script_engine(script_engine, subj, compiled, + count) + return script_engine +end + + +local function check_buf_size(buf, buf_size, pos, len, new_len, must_alloc) + if new_len > buf_size then + buf_size = buf_size * buf_grow_ratio + if buf_size < new_len then + buf_size = new_len + end + local new_buf = get_string_buf(buf_size, must_alloc) + ffi_copy(new_buf, buf, len) + buf = new_buf + pos = buf + len + end + return buf, buf_size, pos, new_len +end + + +_M.check_buf_size = check_buf_size + + +local function re_sub_compile(regex, opts, replace, func) + local flags = 0 + local pcre_opts = 0 + + if opts then + flags, pcre_opts = parse_regex_opts(opts) + else + opts = "" + end + + local compiled + local compile_once = (band(flags, FLAG_COMPILE_ONCE) == 1) + if compile_once then + if func then + local subcache = regex_sub_func_cache[opts] + if subcache then + -- print("cache hit!") + compiled = subcache[regex] + end + + else + local subcache = regex_sub_str_cache[opts] + if subcache then + local subsubcache = subcache[regex] + if subsubcache then + -- print("cache hit!") + compiled = subsubcache[replace] + end + end + end + end + + -- compile the regex + + if compiled == nil then + -- print("compiled regex not found, compiling regex...") + local errbuf = get_string_buf(MAX_ERR_MSG_LEN) + + compiled = C.ngx_http_lua_ffi_compile_regex(regex, #regex, flags, + pcre_opts, errbuf, + MAX_ERR_MSG_LEN) + + if compiled == nil then + return nil, ffi_string(errbuf) + end + + ffi_gc(compiled, C.ngx_http_lua_ffi_destroy_regex) + + if func == nil then + local rc = + C.ngx_http_lua_ffi_compile_replace_template(compiled, + replace, #replace) + if rc ~= 0 then + if not compile_once then + destroy_compiled_regex(compiled) + end + return nil, "failed to compile the replacement template" + end + end + + -- print("ncaptures: ", compiled.ncaptures) + + if compile_once then + if regex_cache_size < get_max_regex_cache_size() then + -- print("inserting compiled regex into cache") + if func then + local subcache = regex_sub_func_cache[opts] + if not subcache then + regex_sub_func_cache[opts] = {[regex] = compiled} + + else + subcache[regex] = compiled + end + + else + local subcache = regex_sub_str_cache[opts] + if not subcache then + regex_sub_str_cache[opts] = + {[regex] = {[replace] = compiled}} + + else + local subsubcache = subcache[regex] + if not subsubcache then + subcache[regex] = {[replace] = compiled} + + else + subsubcache[replace] = compiled + end + end + end + + regex_cache_size = regex_cache_size + 1 + else + compile_once = false + end + end + end + + return compiled, compile_once, flags +end + + +_M.re_sub_compile = re_sub_compile + + +local function re_sub_func_helper(subj, regex, replace, opts, global) + local compiled, compile_once, flags = + re_sub_compile(regex, opts, nil, replace) + if not compiled then + -- error string is in compile_once + return nil, nil, compile_once + end + + -- exec the compiled regex + + subj = tostring(subj) + local subj_len = #subj + local count = 0 + local pos = 0 + local cp_pos = 0 + + local dst_buf_size = get_string_buf_size() + -- Note: we have to always allocate the string buffer because + -- the user might call whatever resty.core's API functions recursively + -- in the user callback function. + local dst_buf = get_string_buf(dst_buf_size, true) + local dst_pos = dst_buf + local dst_len = 0 + + while true do + local rc = C.ngx_http_lua_ffi_exec_regex(compiled, flags, subj, + subj_len, pos) + if rc == PCRE_ERROR_NOMATCH then + break + end + + if rc < 0 then + if not compile_once then + destroy_compiled_regex(compiled) + end + return nil, nil, "pcre_exec() failed: " .. rc + end + + if rc == 0 then + if band(flags, FLAG_DFA) == 0 then + if not compile_once then + destroy_compiled_regex(compiled) + end + return nil, nil, "capture size too small" + end + + rc = 1 + end + + count = count + 1 + local prefix_len = compiled.captures[0] - cp_pos + + local res = collect_captures(compiled, rc, subj, flags) + + local piece = tostring(replace(res)) + local piece_len = #piece + + local new_dst_len = dst_len + prefix_len + piece_len + dst_buf, dst_buf_size, dst_pos, dst_len = + check_buf_size(dst_buf, dst_buf_size, dst_pos, dst_len, + new_dst_len, true) + + if prefix_len > 0 then + ffi_copy(dst_pos, ffi_cast(c_str_type, subj) + cp_pos, + prefix_len) + dst_pos = dst_pos + prefix_len + end + + if piece_len > 0 then + ffi_copy(dst_pos, piece, piece_len) + dst_pos = dst_pos + piece_len + end + + cp_pos = compiled.captures[1] + pos = cp_pos + if pos == compiled.captures[0] then + pos = pos + 1 + if pos > subj_len then + break + end + end + + if not global then + break + end + end + + if not compile_once then + destroy_compiled_regex(compiled) + end + + if count > 0 then + if pos < subj_len then + local suffix_len = subj_len - cp_pos + + local new_dst_len = dst_len + suffix_len + local _ + dst_buf, _, dst_pos, dst_len = + check_buf_size(dst_buf, dst_buf_size, dst_pos, dst_len, + new_dst_len, true) + + ffi_copy(dst_pos, ffi_cast(c_str_type, subj) + cp_pos, + suffix_len) + end + return ffi_string(dst_buf, dst_len), count + end + + return subj, 0 +end + + +local function re_sub_str_helper(subj, regex, replace, opts, global) + local compiled, compile_once, flags = + re_sub_compile(regex, opts, replace, nil) + if not compiled then + -- error string is in compile_once + return nil, nil, compile_once + end + + -- exec the compiled regex + + subj = tostring(subj) + local subj_len = #subj + local count = 0 + local pos = 0 + local cp_pos = 0 + + local dst_buf_size = get_string_buf_size() + local dst_buf = get_string_buf(dst_buf_size) + local dst_pos = dst_buf + local dst_len = 0 + + while true do + local rc = C.ngx_http_lua_ffi_exec_regex(compiled, flags, subj, + subj_len, pos) + if rc == PCRE_ERROR_NOMATCH then + break + end + + if rc < 0 then + if not compile_once then + destroy_compiled_regex(compiled) + end + return nil, nil, "pcre_exec() failed: " .. rc + end + + if rc == 0 then + if band(flags, FLAG_DFA) == 0 then + if not compile_once then + destroy_compiled_regex(compiled) + end + return nil, nil, "capture size too small" + end + + rc = 1 + end + + count = count + 1 + local prefix_len = compiled.captures[0] - cp_pos + + local cv = compiled.replace + if cv.lengths ~= nil then + local e = new_script_engine(subj, compiled, rc) + if e == nil then + return nil, nil, "failed to create script engine" + end + + local bit_len = C.ngx_http_lua_ffi_script_eval_len(e, cv) + local new_dst_len = dst_len + prefix_len + bit_len + dst_buf, dst_buf_size, dst_pos, dst_len = + check_buf_size(dst_buf, dst_buf_size, dst_pos, dst_len, + new_dst_len) + + if prefix_len > 0 then + ffi_copy(dst_pos, ffi_cast(c_str_type, subj) + cp_pos, + prefix_len) + dst_pos = dst_pos + prefix_len + end + + if bit_len > 0 then + C.ngx_http_lua_ffi_script_eval_data(e, cv, dst_pos) + dst_pos = dst_pos + bit_len + end + + else + local bit_len = cv.value.len + + dst_buf, dst_buf_size, dst_pos, dst_len = + check_buf_size(dst_buf, dst_buf_size, dst_pos, dst_len, + dst_len + prefix_len + bit_len) + + if prefix_len > 0 then + ffi_copy(dst_pos, ffi_cast(c_str_type, subj) + cp_pos, + prefix_len) + dst_pos = dst_pos + prefix_len + end + + if bit_len > 0 then + ffi_copy(dst_pos, cv.value.data, bit_len) + dst_pos = dst_pos + bit_len + end + end + + cp_pos = compiled.captures[1] + pos = cp_pos + if pos == compiled.captures[0] then + pos = pos + 1 + if pos > subj_len then + break + end + end + + if not global then + break + end + end + + if not compile_once then + destroy_compiled_regex(compiled) + end + + if count > 0 then + if pos < subj_len then + local suffix_len = subj_len - cp_pos + + local new_dst_len = dst_len + suffix_len + local _ + dst_buf, _, dst_pos, dst_len = + check_buf_size(dst_buf, dst_buf_size, dst_pos, dst_len, + new_dst_len) + + ffi_copy(dst_pos, ffi_cast(c_str_type, subj) + cp_pos, + suffix_len) + end + return ffi_string(dst_buf, dst_len), count + end + + return subj, 0 +end + + +local function re_sub_helper(subj, regex, replace, opts, global) + local repl_type = type(replace) + if repl_type == "function" then + return re_sub_func_helper(subj, regex, replace, opts, global) + end + + if repl_type ~= "string" then + replace = tostring(replace) + end + + return re_sub_str_helper(subj, regex, replace, opts, global) +end + + +function ngx.re.sub(subj, regex, replace, opts) + return re_sub_helper(subj, regex, replace, opts, false) +end + + +function ngx.re.gsub(subj, regex, replace, opts) + return re_sub_helper(subj, regex, replace, opts, true) +end + + +return _M diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/request.lua b/rootfs/etc/nginx/lua/vendor/resty/core/request.lua new file mode 100644 index 0000000000..c737366f85 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core/request.lua @@ -0,0 +1,351 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local ffi = require 'ffi' +local base = require "resty.core.base" + + +local FFI_BAD_CONTEXT = base.FFI_BAD_CONTEXT +local FFI_DECLINED = base.FFI_DECLINED +local FFI_OK = base.FFI_OK +local new_tab = base.new_tab +local C = ffi.C +local ffi_cast = ffi.cast +local ffi_str = ffi.string +local get_string_buf = base.get_string_buf +local get_size_ptr = base.get_size_ptr +local setmetatable = setmetatable +local gsub = ngx.re.gsub +local lower = string.lower +local rawget = rawget +local ngx = ngx +local getfenv = getfenv +local type = type +local error = error +local tostring = tostring +local tonumber = tonumber + + +ffi.cdef[[ + typedef struct { + ngx_http_lua_ffi_str_t key; + ngx_http_lua_ffi_str_t value; + } ngx_http_lua_ffi_table_elt_t; + + int ngx_http_lua_ffi_req_get_headers_count(ngx_http_request_t *r, + int max); + + int ngx_http_lua_ffi_req_get_headers(ngx_http_request_t *r, + ngx_http_lua_ffi_table_elt_t *out, int count, int raw); + + int ngx_http_lua_ffi_req_get_uri_args_count(ngx_http_request_t *r, + int max); + + size_t ngx_http_lua_ffi_req_get_querystring_len(ngx_http_request_t *r); + + int ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, + unsigned char *buf, ngx_http_lua_ffi_table_elt_t *out, int count); + + double ngx_http_lua_ffi_req_start_time(ngx_http_request_t *r); + + int ngx_http_lua_ffi_req_get_method(ngx_http_request_t *r); + + int ngx_http_lua_ffi_req_get_method_name(ngx_http_request_t *r, + char *name, size_t *len); + + int ngx_http_lua_ffi_req_set_method(ngx_http_request_t *r, int method); + + int ngx_http_lua_ffi_req_header_set_single_value(ngx_http_request_t *r, + const unsigned char *key, size_t key_len, const unsigned char *value, + size_t value_len); +]] + + +local table_elt_type = ffi.typeof("ngx_http_lua_ffi_table_elt_t*") +local table_elt_size = ffi.sizeof("ngx_http_lua_ffi_table_elt_t") +local req_headers_mt = { + __index = function (tb, key) + return rawget(tb, (gsub(lower(key), '_', '-', "jo"))) + end +} + + +function ngx.req.get_headers(max_headers, raw) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + if not max_headers then + max_headers = -1 + end + + if not raw then + raw = 0 + else + raw = 1 + end + + local n = C.ngx_http_lua_ffi_req_get_headers_count(r, max_headers) + if n == FFI_BAD_CONTEXT then + return error("API disabled in the current context") + end + + if n == 0 then + return {} + end + + local raw_buf = get_string_buf(n * table_elt_size) + local buf = ffi_cast(table_elt_type, raw_buf) + + local rc = C.ngx_http_lua_ffi_req_get_headers(r, buf, n, raw) + if rc == 0 then + local headers = new_tab(0, n) + for i = 0, n - 1 do + local h = buf[i] + + local key = h.key + key = ffi_str(key.data, key.len) + + local value = h.value + value = ffi_str(value.data, value.len) + + local existing = headers[key] + if existing then + if type(existing) == "table" then + existing[#existing + 1] = value + else + headers[key] = {existing, value} + end + + else + headers[key] = value + end + end + if raw == 0 then + return setmetatable(headers, req_headers_mt) + end + return headers + end + + return nil +end + + +function ngx.req.get_uri_args(max_args) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + if not max_args then + max_args = -1 + end + + local n = C.ngx_http_lua_ffi_req_get_uri_args_count(r, max_args) + if n == FFI_BAD_CONTEXT then + return error("API disabled in the current context") + end + + if n == 0 then + return {} + end + + local args_len = C.ngx_http_lua_ffi_req_get_querystring_len(r) + + local strbuf = get_string_buf(args_len + n * table_elt_size) + local kvbuf = ffi_cast(table_elt_type, strbuf + args_len) + + local nargs = C.ngx_http_lua_ffi_req_get_uri_args(r, strbuf, kvbuf, n) + + local args = new_tab(0, nargs) + for i = 0, nargs - 1 do + local arg = kvbuf[i] + + local key = arg.key + key = ffi_str(key.data, key.len) + + local value = arg.value + local len = value.len + if len == -1 then + value = true + else + value = ffi_str(value.data, len) + end + + local existing = args[key] + if existing then + if type(existing) == "table" then + existing[#existing + 1] = value + else + args[key] = {existing, value} + end + + else + args[key] = value + end + end + return args +end + + +function ngx.req.start_time() + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + return tonumber(C.ngx_http_lua_ffi_req_start_time(r)) +end + + +do + local methods = { + [0x0002] = "GET", + [0x0004] = "HEAD", + [0x0008] = "POST", + [0x0010] = "PUT", + [0x0020] = "DELETE", + [0x0040] = "MKCOL", + [0x0080] = "COPY", + [0x0100] = "MOVE", + [0x0200] = "OPTIONS", + [0x0400] = "PROPFIND", + [0x0800] = "PROPPATCH", + [0x1000] = "LOCK", + [0x2000] = "UNLOCK", + [0x4000] = "PATCH", + [0x8000] = "TRACE", + } + + function ngx.req.get_method() + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + do + local id = C.ngx_http_lua_ffi_req_get_method(r) + if id == FFI_BAD_CONTEXT then + return error("API disabled in the current context") + end + + local method = methods[id] + if method then + return method + end + end + + local buf = get_string_buf(32) + local sizep = get_size_ptr() + sizep[0] = 32 + + local rc = C.ngx_http_lua_ffi_req_get_method_name(r, buf, sizep) + if rc ~= 0 then + return nil + end + + return ffi_str(buf, sizep[0]) + end +end -- do + + +function ngx.req.set_method(method) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + if type(method) ~= "number" then + return error("bad method number") + end + + local rc = C.ngx_http_lua_ffi_req_set_method(r, method) + if rc == FFI_OK then + return + end + + if rc == FFI_BAD_CONTEXT then + return error("API disabled in the current context") + end + + if rc == FFI_DECLINED then + return error("unsupported HTTP method: " .. method) + end + + return error("unknown error: " .. rc) +end + + +do + local orig_func = ngx.req.set_header + + function ngx.req.set_header(name, value) + if type(value) == "table" then + return orig_func(name, value) + end + + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + if type(name) ~= "string" then + name = tostring(name) + end + + local rc + if not value then + rc = C.ngx_http_lua_ffi_req_header_set_single_value(r, name, + #name, nil, 0) + + else + if type(value) ~= "string" then + value = tostring(value) + end + + rc = C.ngx_http_lua_ffi_req_header_set_single_value(r, name, + #name, value, #value) + end + + if rc == FFI_OK or rc == FFI_DECLINED then + return + end + + if rc == FFI_BAD_CONTEXT then + return error("API disabled in the current context") + end + + return error("error") + end +end -- do + + +function ngx.req.clear_header(name) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + if type(name) ~= "string" then + name = tostring(name) + end + + local rc = C.ngx_http_lua_ffi_req_header_set_single_value(r, name, #name, + nil, 0) + + if rc == FFI_OK or rc == FFI_DECLINED then + return + end + + if rc == FFI_BAD_CONTEXT then + return error("API disabled in the current context") + end + + return error("error") +end + + +return { + version = base.version +} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/response.lua b/rootfs/etc/nginx/lua/vendor/resty/core/response.lua new file mode 100644 index 0000000000..2944d75d19 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core/response.lua @@ -0,0 +1,165 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local ffi = require 'ffi' +local base = require "resty.core.base" + + +local C = ffi.C +local ffi_cast = ffi.cast +local ffi_str = ffi.string +local new_tab = base.new_tab +local FFI_BAD_CONTEXT = base.FFI_BAD_CONTEXT +local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX +local FFI_DECLINED = base.FFI_DECLINED +local get_string_buf = base.get_string_buf +local getmetatable = getmetatable +local type = type +local tostring = tostring +local getfenv = getfenv +local error = error +local ngx = ngx + + +local MAX_HEADER_VALUES = 100 +local errmsg = base.get_errmsg_ptr() +local ffi_str_type = ffi.typeof("ngx_http_lua_ffi_str_t*") +local ffi_str_size = ffi.sizeof("ngx_http_lua_ffi_str_t") + + +ffi.cdef[[ + int ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, + const char *key_data, size_t key_len, int is_nil, + const char *sval, size_t sval_len, ngx_http_lua_ffi_str_t *mvals, + size_t mvals_len, char **errmsg); + + int ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, + const unsigned char *key, size_t key_len, + unsigned char *key_buf, ngx_http_lua_ffi_str_t *values, + int max_nvalues); +]] + + +local function set_resp_header(tb, key, value) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + if type(key) ~= "string" then + key = tostring(key) + end + + local rc + if value == nil then + rc = C.ngx_http_lua_ffi_set_resp_header(r, key, #key, true, nil, 0, + nil, 0, errmsg) + else + local sval, sval_len, mvals, mvals_len, buf + + if type(value) == "table" then + mvals_len = #value + buf = get_string_buf(ffi_str_size * mvals_len) + mvals = ffi_cast(ffi_str_type, buf) + for i = 1, mvals_len do + local s = value[i] + if type(s) ~= "string" then + s = tostring(s) + value[i] = s + end + local str = mvals[i - 1] + str.data = s + str.len = #s + end + + sval_len = 0 + + else + if type(value) ~= "string" then + sval = tostring(value) + else + sval = value + end + sval_len = #sval + + mvals_len = 0 + end + + rc = C.ngx_http_lua_ffi_set_resp_header(r, key, #key, false, sval, + sval_len, mvals, mvals_len, + errmsg) + end + + if rc == 0 or rc == FFI_DECLINED then + return + end + + if rc == FFI_NO_REQ_CTX then + return error("no request ctx found") + end + + if rc == FFI_BAD_CONTEXT then + return error("API disabled in the current context") + end + + -- rc == FFI_ERROR + return error(ffi_str(errmsg[0])) +end + + +local function get_resp_header(tb, key) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + if type(key) ~= "string" then + key = tostring(key) + end + + local key_len = #key + + local key_buf = get_string_buf(key_len + ffi_str_size * MAX_HEADER_VALUES) + local values = ffi_cast(ffi_str_type, key_buf + key_len) + local n = C.ngx_http_lua_ffi_get_resp_header(r, key, key_len, key_buf, + values, MAX_HEADER_VALUES) + + -- print("retval: ", n) + + if n == FFI_BAD_CONTEXT then + return error("API disabled in the current context") + end + + if n == 0 then + return nil + end + + if n == 1 then + local v = values[0] + return ffi_str(v.data, v.len) + end + + if n > 0 then + local ret = new_tab(n, 0) + for i = 1, n do + local v = values[i - 1] + ret[i] = ffi_str(v.data, v.len) + end + return ret + end + + -- n == FFI_ERROR + return error("no memory") +end + + +do + local mt = getmetatable(ngx.header) + mt.__newindex = set_resp_header + mt.__index = get_resp_header +end + + +return { + version = base.version +} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/shdict.lua b/rootfs/etc/nginx/lua/vendor/resty/core/shdict.lua new file mode 100644 index 0000000000..55f2a88a91 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core/shdict.lua @@ -0,0 +1,538 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local ffi = require 'ffi' +local base = require "resty.core.base" + +local ffi_new = ffi.new +local ffi_str = ffi.string +local C = ffi.C +local get_string_buf = base.get_string_buf +local get_string_buf_size = base.get_string_buf_size +local get_size_ptr = base.get_size_ptr +local tonumber = tonumber +local tostring = tostring +local next = next +local type = type +local error = error +local ngx_shared = ngx.shared +local getmetatable = getmetatable +local FFI_ERROR = base.FFI_ERROR +local FFI_DECLINED = base.FFI_DECLINED + + +ffi.cdef[[ + int ngx_http_lua_ffi_shdict_get(void *zone, const unsigned char *key, + size_t key_len, int *value_type, unsigned char **str_value_buf, + size_t *str_value_len, double *num_value, int *user_flags, + int get_stale, int *is_stale, char **errmsg); + + int ngx_http_lua_ffi_shdict_incr(void *zone, const unsigned char *key, + size_t key_len, double *value, char **err, int has_init, double init, + long init_ttl, int *forcible); + + int ngx_http_lua_ffi_shdict_store(void *zone, int op, + const unsigned char *key, size_t key_len, int value_type, + const unsigned char *str_value_buf, size_t str_value_len, + double num_value, int exptime, int user_flags, char **errmsg, + int *forcible); + + int ngx_http_lua_ffi_shdict_flush_all(void *zone); + + int ngx_http_lua_ffi_shdict_get_ttl(void *zone, + const unsigned char *key, size_t key_len); + + int ngx_http_lua_ffi_shdict_set_expire(void *zone, + const unsigned char *key, size_t key_len, int exptime); + + size_t ngx_http_lua_ffi_shdict_capacity(void *zone); +]] + +if not pcall(function () return C.ngx_http_lua_ffi_shdict_free_space end) then + ffi.cdef[[ + size_t ngx_http_lua_ffi_shdict_free_space(void *zone); + ]] +end + +if not pcall(function () return C.free end) then + ffi.cdef[[ + void free(void *ptr); + ]] +end + + +local value_type = ffi_new("int[1]") +local user_flags = ffi_new("int[1]") +local num_value = ffi_new("double[1]") +local is_stale = ffi_new("int[1]") +local forcible = ffi_new("int[1]") +local str_value_buf = ffi_new("unsigned char *[1]") +local errmsg = base.get_errmsg_ptr() + + +local function check_zone(zone) + if not zone or type(zone) ~= "table" then + return error("bad \"zone\" argument") + end + + zone = zone[1] + if type(zone) ~= "userdata" then + return error("bad \"zone\" argument") + end + + return zone +end + + +local function shdict_store(zone, op, key, value, exptime, flags) + zone = check_zone(zone) + + if not exptime then + exptime = 0 + elseif exptime < 0 then + return error('bad "exptime" argument') + end + + if not flags then + flags = 0 + end + + if key == nil then + return nil, "nil key" + end + + if type(key) ~= "string" then + key = tostring(key) + end + + local key_len = #key + if key_len == 0 then + return nil, "empty key" + end + if key_len > 65535 then + return nil, "key too long" + end + + local str_val_buf + local str_val_len = 0 + local num_val = 0 + local valtyp = type(value) + + -- print("value type: ", valtyp) + -- print("exptime: ", exptime) + + if valtyp == "string" then + valtyp = 4 -- LUA_TSTRING + str_val_buf = value + str_val_len = #value + + elseif valtyp == "number" then + valtyp = 3 -- LUA_TNUMBER + num_val = value + + elseif value == nil then + valtyp = 0 -- LUA_TNIL + + elseif valtyp == "boolean" then + valtyp = 1 -- LUA_TBOOLEAN + num_val = value and 1 or 0 + + else + return nil, "bad value type" + end + + local rc = C.ngx_http_lua_ffi_shdict_store(zone, op, key, key_len, + valtyp, str_val_buf, + str_val_len, num_val, + exptime * 1000, flags, errmsg, + forcible) + + -- print("rc == ", rc) + + if rc == 0 then -- NGX_OK + return true, nil, forcible[0] == 1 + end + + -- NGX_DECLINED or NGX_ERROR + return false, ffi_str(errmsg[0]), forcible[0] == 1 +end + + +local function shdict_set(zone, key, value, exptime, flags) + return shdict_store(zone, 0, key, value, exptime, flags) +end + + +local function shdict_safe_set(zone, key, value, exptime, flags) + return shdict_store(zone, 0x0004, key, value, exptime, flags) +end + + +local function shdict_add(zone, key, value, exptime, flags) + return shdict_store(zone, 0x0001, key, value, exptime, flags) +end + + +local function shdict_safe_add(zone, key, value, exptime, flags) + return shdict_store(zone, 0x0005, key, value, exptime, flags) +end + + +local function shdict_replace(zone, key, value, exptime, flags) + return shdict_store(zone, 0x0002, key, value, exptime, flags) +end + + +local function shdict_delete(zone, key) + return shdict_set(zone, key, nil) +end + + +local function shdict_get(zone, key) + zone = check_zone(zone) + + if key == nil then + return nil, "nil key" + end + + if type(key) ~= "string" then + key = tostring(key) + end + + local key_len = #key + if key_len == 0 then + return nil, "empty key" + end + if key_len > 65535 then + return nil, "key too long" + end + + local size = get_string_buf_size() + local buf = get_string_buf(size) + str_value_buf[0] = buf + local value_len = get_size_ptr() + value_len[0] = size + + local rc = C.ngx_http_lua_ffi_shdict_get(zone, key, key_len, value_type, + str_value_buf, value_len, + num_value, user_flags, 0, + is_stale, errmsg) + if rc ~= 0 then + if errmsg[0] then + return nil, ffi_str(errmsg[0]) + end + + return error("failed to get the key") + end + + local typ = value_type[0] + + if typ == 0 then -- LUA_TNIL + return nil + end + + local flags = tonumber(user_flags[0]) + + local val + + if typ == 4 then -- LUA_TSTRING + if str_value_buf[0] ~= buf then + -- ngx.say("len: ", tonumber(value_len[0])) + buf = str_value_buf[0] + val = ffi_str(buf, value_len[0]) + C.free(buf) + else + val = ffi_str(buf, value_len[0]) + end + + elseif typ == 3 then -- LUA_TNUMBER + val = tonumber(num_value[0]) + + elseif typ == 1 then -- LUA_TBOOLEAN + val = (tonumber(buf[0]) ~= 0) + + else + return error("unknown value type: " .. typ) + end + + if flags ~= 0 then + return val, flags + end + + return val +end + + +local function shdict_get_stale(zone, key) + zone = check_zone(zone) + + if key == nil then + return nil, "nil key" + end + + if type(key) ~= "string" then + key = tostring(key) + end + + local key_len = #key + if key_len == 0 then + return nil, "empty key" + end + if key_len > 65535 then + return nil, "key too long" + end + + local size = get_string_buf_size() + local buf = get_string_buf(size) + str_value_buf[0] = buf + local value_len = get_size_ptr() + value_len[0] = size + + local rc = C.ngx_http_lua_ffi_shdict_get(zone, key, key_len, value_type, + str_value_buf, value_len, + num_value, user_flags, 1, + is_stale, errmsg) + if rc ~= 0 then + if errmsg[0] then + return nil, ffi_str(errmsg[0]) + end + + return error("failed to get the key") + end + + local typ = value_type[0] + + if typ == 0 then -- LUA_TNIL + return nil + end + + local flags = tonumber(user_flags[0]) + local val + + if typ == 4 then -- LUA_TSTRING + if str_value_buf[0] ~= buf then + -- ngx.say("len: ", tonumber(value_len[0])) + buf = str_value_buf[0] + val = ffi_str(buf, value_len[0]) + C.free(buf) + else + val = ffi_str(buf, value_len[0]) + end + + elseif typ == 3 then -- LUA_TNUMBER + val = tonumber(num_value[0]) + + elseif typ == 1 then -- LUA_TBOOLEAN + val = (tonumber(buf[0]) ~= 0) + + else + return error("unknown value type: " .. typ) + end + + if flags ~= 0 then + return val, flags, is_stale[0] == 1 + end + + return val, nil, is_stale[0] == 1 +end + + +local function shdict_incr(zone, key, value, init, init_ttl) + zone = check_zone(zone) + + if key == nil then + return nil, "nil key" + end + + if type(key) ~= "string" then + key = tostring(key) + end + + local key_len = #key + if key_len == 0 then + return nil, "empty key" + end + if key_len > 65535 then + return nil, "key too long" + end + + if type(value) ~= "number" then + value = tonumber(value) + end + num_value[0] = value + + if init then + local typ = type(init) + if typ ~= "number" then + init = tonumber(init) + + if not init then + return error("bad init arg: number expected, got " .. typ) + end + end + end + + if init_ttl ~= nil then + local typ = type(init_ttl) + if typ ~= "number" then + init_ttl = tonumber(init_ttl) + + if not init_ttl then + error("bad init_ttl arg: number expected, got " .. typ, 2) + end + end + + if init_ttl < 0 then + error('bad "init_ttl" argument', 2) + end + + if not init then + error('must provide "init" when providing "init_ttl"', 2) + end + + else + init_ttl = 0 + end + + local rc = C.ngx_http_lua_ffi_shdict_incr(zone, key, key_len, num_value, + errmsg, init and 1 or 0, + init or 0, init_ttl * 1000, + forcible) + if rc ~= 0 then -- ~= NGX_OK + return nil, ffi_str(errmsg[0]) + end + + if not init then + return tonumber(num_value[0]) + end + + return tonumber(num_value[0]), nil, forcible[0] == 1 +end + + +local function shdict_flush_all(zone) + zone = check_zone(zone) + + C.ngx_http_lua_ffi_shdict_flush_all(zone) +end + + +local function shdict_ttl(zone, key) + zone = check_zone(zone) + + if key == nil then + return nil, "nil key" + end + + if type(key) ~= "string" then + key = tostring(key) + end + + local key_len = #key + if key_len == 0 then + return nil, "empty key" + end + + if key_len > 65535 then + return nil, "key too long" + end + + local rc = C.ngx_http_lua_ffi_shdict_get_ttl(zone, key, key_len) + + if rc == FFI_ERROR then + return nil, "bad zone" + end + + if rc == FFI_DECLINED then + return nil, "not found" + end + + return tonumber(rc) / 1000 +end + + +local function shdict_expire(zone, key, exptime) + zone = check_zone(zone) + + if not exptime then + error('bad "exptime" argument', 2) + end + + if key == nil then + return nil, "nil key" + end + + if type(key) ~= "string" then + key = tostring(key) + end + + local key_len = #key + if key_len == 0 then + return nil, "empty key" + end + + if key_len > 65535 then + return nil, "key too long" + end + + local rc = C.ngx_http_lua_ffi_shdict_set_expire(zone, key, key_len, + exptime * 1000) + + if rc == FFI_ERROR then + return nil, "bad zone" + end + + if rc == FFI_DECLINED then + return nil, "not found" + end + + -- NGINX_OK/FFI_OK + + return true +end + + +local function shdict_capacity(zone) + zone = check_zone(zone) + + return tonumber(C.ngx_http_lua_ffi_shdict_capacity(zone)) +end + + +local function shdict_free_space(zone) + zone = check_zone(zone) + + return tonumber(C.ngx_http_lua_ffi_shdict_free_space(zone)) +end + + +if ngx_shared then + local _, dict = next(ngx_shared, nil) + if dict then + local mt = getmetatable(dict) + if mt then + mt = mt.__index + if mt then + mt.get = shdict_get + mt.get_stale = shdict_get_stale + mt.incr = shdict_incr + mt.set = shdict_set + mt.safe_set = shdict_safe_set + mt.add = shdict_add + mt.safe_add = shdict_safe_add + mt.replace = shdict_replace + mt.delete = shdict_delete + mt.flush_all = shdict_flush_all + mt.ttl = shdict_ttl + mt.expire = shdict_expire + mt.capacity = shdict_capacity + mt.free_space = shdict_free_space + end + end + end +end + + +return { + version = base.version +} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/time.lua b/rootfs/etc/nginx/lua/vendor/resty/core/time.lua new file mode 100644 index 0000000000..e4313ff5bd --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core/time.lua @@ -0,0 +1,121 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local ffi = require 'ffi' +local base = require "resty.core.base" + + +local error = error +local tonumber = tonumber +local type = type +local C = ffi.C +local ffi_new = ffi.new +local ffi_str = ffi.string +local time_val = ffi_new("long[1]") +local get_string_buf = base.get_string_buf +local ngx = ngx +local FFI_ERROR = base.FFI_ERROR + + +ffi.cdef[[ +double ngx_http_lua_ffi_now(void); +long ngx_http_lua_ffi_time(void); +void ngx_http_lua_ffi_today(unsigned char *buf); +void ngx_http_lua_ffi_localtime(unsigned char *buf); +void ngx_http_lua_ffi_utctime(unsigned char *buf); +void ngx_http_lua_ffi_update_time(void); +int ngx_http_lua_ffi_cookie_time(unsigned char *buf, long t); +void ngx_http_lua_ffi_http_time(unsigned char *buf, long t); +void ngx_http_lua_ffi_parse_http_time(const unsigned char *str, size_t len, + long *time); +]] + + +function ngx.now() + return tonumber(C.ngx_http_lua_ffi_now()) +end + + +function ngx.time() + return tonumber(C.ngx_http_lua_ffi_time()) +end + + +function ngx.update_time() + C.ngx_http_lua_ffi_update_time() +end + + +function ngx.today() + -- the format of today is 2010-11-19 + local today_buf_size = 10 + local buf = get_string_buf(today_buf_size) + C.ngx_http_lua_ffi_today(buf) + return ffi_str(buf, today_buf_size) +end + + +function ngx.localtime() + -- the format of localtime is 2010-11-19 20:56:31 + local localtime_buf_size = 19 + local buf = get_string_buf(localtime_buf_size) + C.ngx_http_lua_ffi_localtime(buf) + return ffi_str(buf, localtime_buf_size) +end + + +function ngx.utctime() + -- the format of utctime is 2010-11-19 20:56:31 + local utctime_buf_size = 19 + local buf = get_string_buf(utctime_buf_size) + C.ngx_http_lua_ffi_utctime(buf) + return ffi_str(buf, utctime_buf_size) +end + + +function ngx.cookie_time(sec) + if type(sec) ~= "number" then + error("number argument only", 2) + end + + -- the format of cookie time is Mon, 28-Sep-2038 06:00:00 GMT + -- or Mon, 28-Sep-18 06:00:00 GMT + local cookie_time_buf_size = 29 + local buf = get_string_buf(cookie_time_buf_size) + local used_size = C.ngx_http_lua_ffi_cookie_time(buf, sec) + return ffi_str(buf, used_size) +end + + +function ngx.http_time(sec) + if type(sec) ~= "number" then + error("number argument only", 2) + end + + -- the format of http time is Mon, 28 Sep 1970 06:00:00 GMT + local http_time_buf_size = 29 + local buf = get_string_buf(http_time_buf_size) + C.ngx_http_lua_ffi_http_time(buf, sec) + return ffi_str(buf, http_time_buf_size) +end + + +function ngx.parse_http_time(time_str) + if type(time_str) ~= "string" then + error("string argument only", 2) + end + + C.ngx_http_lua_ffi_parse_http_time(time_str, #time_str, time_val) + + local res = time_val[0] + if res == FFI_ERROR then + return nil + end + + return tonumber(res) +end + + +return { + version = base.version +} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/uri.lua b/rootfs/etc/nginx/lua/vendor/resty/core/uri.lua new file mode 100644 index 0000000000..af0e655725 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core/uri.lua @@ -0,0 +1,64 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local ffi = require 'ffi' +local ffi_string = ffi.string +local C = ffi.C +local ngx = ngx +local type = type +local tostring = tostring +local base = require "resty.core.base" +local get_string_buf = base.get_string_buf + + +ffi.cdef[[ + size_t ngx_http_lua_ffi_uri_escaped_length(const unsigned char *src, + size_t len); + + void ngx_http_lua_ffi_escape_uri(const unsigned char *src, size_t len, + unsigned char *dst); + + size_t ngx_http_lua_ffi_unescape_uri(const unsigned char *src, + size_t len, unsigned char *dst); +]] + + +ngx.escape_uri = function (s) + if type(s) ~= 'string' then + if not s then + s = '' + else + s = tostring(s) + end + end + local slen = #s + local dlen = C.ngx_http_lua_ffi_uri_escaped_length(s, slen) + -- print("dlen: ", tonumber(dlen)) + if dlen == slen then + return s + end + local dst = get_string_buf(dlen) + C.ngx_http_lua_ffi_escape_uri(s, slen, dst) + return ffi_string(dst, dlen) +end + + +ngx.unescape_uri = function (s) + if type(s) ~= 'string' then + if not s then + s = '' + else + s = tostring(s) + end + end + local slen = #s + local dlen = slen + local dst = get_string_buf(dlen) + dlen = C.ngx_http_lua_ffi_unescape_uri(s, slen, dst) + return ffi_string(dst, dlen) +end + + +return { + version = base.version, +} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/var.lua b/rootfs/etc/nginx/lua/vendor/resty/core/var.lua new file mode 100644 index 0000000000..6aa4060aaa --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core/var.lua @@ -0,0 +1,130 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local ffi = require 'ffi' +local base = require "resty.core.base" + +local ffi_new = ffi.new +local ffi_str = ffi.string +local C = ffi.C +local type = type +local getfenv = getfenv +local get_string_buf = base.get_string_buf +local get_size_ptr = base.get_size_ptr +local error = error +local tostring = tostring +local ngx_var = ngx.var +local getmetatable = getmetatable + +local ERR_BUF_SIZE = 256 + + +ffi.cdef[[ + int ngx_http_lua_ffi_var_get(ngx_http_request_t *r, + const char *name_data, size_t name_len, char *lowcase_buf, + int capture_id, char **value, size_t *value_len, char **err); + + int ngx_http_lua_ffi_var_set(ngx_http_request_t *r, + const unsigned char *name_data, size_t name_len, + unsigned char *lowcase_buf, const unsigned char *value, + size_t value_len, unsigned char *errbuf, size_t *errlen); +]] + + +local value_ptr = ffi_new("unsigned char *[1]") +local errmsg = base.get_errmsg_ptr() + + +local function var_get(self, name) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + local value_len = get_size_ptr() + local rc + if type(name) == "number" then + rc = C.ngx_http_lua_ffi_var_get(r, nil, 0, nil, name, value_ptr, + value_len, errmsg) + + else + if type(name) ~= "string" then + return error("bad variable name") + end + + local name_len = #name + local lowcase_buf = get_string_buf(name_len) + + rc = C.ngx_http_lua_ffi_var_get(r, name, name_len, lowcase_buf, 0, + value_ptr, value_len, errmsg) + end + + -- ngx.log(ngx.WARN, "rc = ", rc) + + if rc == 0 then -- NGX_OK + return ffi_str(value_ptr[0], value_len[0]) + end + + if rc == -5 then -- NGX_DECLINED + return nil + end + + if rc == -1 then -- NGX_ERROR + return error(ffi_str(errmsg[0])) + end +end + + +local function var_set(self, name, value) + local r = getfenv(0).__ngx_req + if not r then + return error("no request found") + end + + if type(name) ~= "string" then + return error("bad variable name") + end + local name_len = #name + + local errlen = get_size_ptr() + errlen[0] = ERR_BUF_SIZE + local lowcase_buf = get_string_buf(name_len + ERR_BUF_SIZE) + + local value_len + if value == nil then + value_len = 0 + else + if type(value) ~= 'string' then + value = tostring(value) + end + value_len = #value + end + + local errbuf = lowcase_buf + name_len + local rc = C.ngx_http_lua_ffi_var_set(r, name, name_len, lowcase_buf, + value, value_len, errbuf, errlen) + + -- ngx.log(ngx.WARN, "rc = ", rc) + + if rc == 0 then -- NGX_OK + return + end + + if rc == -1 then -- NGX_ERROR + return error(ffi_str(errbuf, errlen[0])) + end +end + + +if ngx_var then + local mt = getmetatable(ngx_var) + if mt then + mt.__index = var_get + mt.__newindex = var_set + end +end + + +return { + version = base.version +} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/worker.lua b/rootfs/etc/nginx/lua/vendor/resty/core/worker.lua new file mode 100644 index 0000000000..0da8086ccb --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/core/worker.lua @@ -0,0 +1,46 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local ffi = require 'ffi' +local base = require "resty.core.base" + + +local C = ffi.C + + +ffi.cdef[[ +int ngx_http_lua_ffi_worker_pid(void); +int ngx_http_lua_ffi_worker_exiting(void); +int ngx_http_lua_ffi_worker_id(void); +int ngx_http_lua_ffi_worker_count(void); +]] + + +function ngx.worker.exiting() + return C.ngx_http_lua_ffi_worker_exiting() ~= 0 +end + + +function ngx.worker.pid() + return C.ngx_http_lua_ffi_worker_pid() +end + + +function ngx.worker.id() + local id = C.ngx_http_lua_ffi_worker_id() + if id < 0 then + return nil + end + + return id +end + + +function ngx.worker.count() + return C.ngx_http_lua_ffi_worker_count() +end + + +return { + _VERSION = base.version +} From 95891af0c3f62f6d0feaf5cf031ce27be3f76821 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Fri, 2 Mar 2018 15:56:07 -0500 Subject: [PATCH 03/34] include lrucache --- .../etc/nginx/lua/vendor/resty/lrucache.lua | 227 ++++++++ .../lua/vendor/resty/lrucache/pureffi.lua | 534 ++++++++++++++++++ 2 files changed, 761 insertions(+) create mode 100644 rootfs/etc/nginx/lua/vendor/resty/lrucache.lua create mode 100644 rootfs/etc/nginx/lua/vendor/resty/lrucache/pureffi.lua diff --git a/rootfs/etc/nginx/lua/vendor/resty/lrucache.lua b/rootfs/etc/nginx/lua/vendor/resty/lrucache.lua new file mode 100644 index 0000000000..55f872fd82 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/lrucache.lua @@ -0,0 +1,227 @@ +-- Copyright (C) Yichun Zhang (agentzh) + + +local ffi = require "ffi" +local ffi_new = ffi.new +local ffi_sizeof = ffi.sizeof +local ffi_cast = ffi.cast +local ffi_fill = ffi.fill +local ngx_now = ngx.now +local uintptr_t = ffi.typeof("uintptr_t") +local setmetatable = setmetatable +local tonumber = tonumber + + +-- queue data types +-- +-- this queue is a double-ended queue and the first node +-- is reserved for the queue itself. +-- the implementation is mostly borrowed from nginx's ngx_queue_t data +-- structure. + +ffi.cdef[[ + typedef struct lrucache_queue_s lrucache_queue_t; + struct lrucache_queue_s { + double expire; /* in seconds */ + lrucache_queue_t *prev; + lrucache_queue_t *next; + }; +]] + +local queue_arr_type = ffi.typeof("lrucache_queue_t[?]") +local queue_type = ffi.typeof("lrucache_queue_t") +local NULL = ffi.null + + +-- queue utility functions + +local function queue_insert_tail(h, x) + local last = h[0].prev + x.prev = last + last.next = x + x.next = h + h[0].prev = x +end + + +local function queue_init(size) + if not size then + size = 0 + end + local q = ffi_new(queue_arr_type, size + 1) + ffi_fill(q, ffi_sizeof(queue_type, size + 1), 0) + + if size == 0 then + q[0].prev = q + q[0].next = q + + else + local prev = q[0] + for i = 1, size do + local e = q + i + prev.next = e + e.prev = prev + prev = e + end + + local last = q[size] + last.next = q + q[0].prev = last + end + + return q +end + + +local function queue_is_empty(q) + -- print("q: ", tostring(q), "q.prev: ", tostring(q), ": ", q == q.prev) + return q == q[0].prev +end + + +local function queue_remove(x) + local prev = x.prev + local next = x.next + + next.prev = prev + prev.next = next + + -- for debugging purpose only: + x.prev = NULL + x.next = NULL +end + + +local function queue_insert_head(h, x) + x.next = h[0].next + x.next.prev = x + x.prev = h + h[0].next = x +end + + +local function queue_last(h) + return h[0].prev +end + + +local function queue_head(h) + return h[0].next +end + + +-- true module stuffs + +local _M = { + _VERSION = '0.07' +} +local mt = { __index = _M } + + +local function ptr2num(ptr) + return tonumber(ffi_cast(uintptr_t, ptr)) +end + + +function _M.new(size) + if size < 1 then + return nil, "size too small" + end + + local self = { + hasht = {}, + free_queue = queue_init(size), + cache_queue = queue_init(), + key2node = {}, + node2key = {}, + } + return setmetatable(self, mt) +end + + +function _M.get(self, key) + local hasht = self.hasht + local val = hasht[key] + if val == nil then + return nil + end + + local node = self.key2node[key] + + -- print(key, ": moving node ", tostring(node), " to cache queue head") + local cache_queue = self.cache_queue + queue_remove(node) + queue_insert_head(cache_queue, node) + + if node.expire >= 0 and node.expire < ngx_now() then + -- print("expired: ", node.expire, " > ", ngx_now()) + return nil, val + end + return val +end + + +function _M.delete(self, key) + self.hasht[key] = nil + + local key2node = self.key2node + local node = key2node[key] + + if not node then + return false + end + + key2node[key] = nil + self.node2key[ptr2num(node)] = nil + + queue_remove(node) + queue_insert_tail(self.free_queue, node) + return true +end + + +function _M.set(self, key, value, ttl) + local hasht = self.hasht + hasht[key] = value + + local key2node = self.key2node + local node = key2node[key] + if not node then + local free_queue = self.free_queue + local node2key = self.node2key + + if queue_is_empty(free_queue) then + -- evict the least recently used key + -- assert(not queue_is_empty(self.cache_queue)) + node = queue_last(self.cache_queue) + + local oldkey = node2key[ptr2num(node)] + -- print(key, ": evicting oldkey: ", oldkey, ", oldnode: ", + -- tostring(node)) + if oldkey then + hasht[oldkey] = nil + key2node[oldkey] = nil + end + + else + -- take a free queue node + node = queue_head(free_queue) + -- print(key, ": get a new free node: ", tostring(node)) + end + + node2key[ptr2num(node)] = key + key2node[key] = node + end + + queue_remove(node) + queue_insert_head(self.cache_queue, node) + + if ttl then + node.expire = ngx_now() + ttl + else + node.expire = -1 + end +end + + +return _M diff --git a/rootfs/etc/nginx/lua/vendor/resty/lrucache/pureffi.lua b/rootfs/etc/nginx/lua/vendor/resty/lrucache/pureffi.lua new file mode 100644 index 0000000000..fd3f1b7748 --- /dev/null +++ b/rootfs/etc/nginx/lua/vendor/resty/lrucache/pureffi.lua @@ -0,0 +1,534 @@ +-- Copyright (C) Yichun Zhang (agentzh) +-- Copyright (C) Shuxin Yang + +--[[ + This module implements a key/value cache store. We adopt LRU as our +replace/evict policy. Each key/value pair is tagged with a Time-to-Live (TTL); +from user's perspective, stale pairs are automatically removed from the cache. + +Why FFI +------- + In Lua, expression "table[key] = nil" does not *PHYSICALLY* remove the value +associated with the key; it just set the value to be nil! So the table will +keep growing with large number of the key/nil pairs which will be purged until +resize() operator is called. + + This "feature" is terribly ill-suited to what we need. Therefore we have to +rely on FFI to build a hash-table where any entry can be physically deleted +immediately. + +Under the hood: +-------------- + In concept, we introduce three data structures to implement the cache store: + 1. key/value vector for storing keys and values. + 2. a queue to mimic the LRU. + 3. hash-table for looking up the value for a given key. + + Unfortunately, efficiency and clarity usually come at each other cost. The +data strucutres we are using are slightly more complicated than what we +described above. + + o. Lua does not have efficient way to store a vector of pair. So, we use + two vectors for key/value pair: one for keys and the other for values + (_M.key_v and _M.val_v, respectively), and i-th key corresponds to + i-th value. + + A key/value pair is identified by the "id" field in a "node" (we shall + discuss node later) + + o. The queue is nothing more than a doubly-linked list of "node" linked via + lrucache_pureffi_queue_s::{next|prev} fields. + + o. The hash-table has two parts: + - the _M.bucket_v[] a vector of bucket, indiced by hash-value, and + - a bucket is a singly-linked list of "node" via the + lrucache_pureffi_queue_s::conflict field. + + A key must be a string, and the hash value of a key is evaluated by: + crc32(key-cast-to-pointer) % size(_M.bucket_v). + We mandate size(_M.bucket_v) being a power-of-two in order to avoid + expensive modulo operation. + + At the heart of the module is an array of "node" (of type + lrucache_pureffi_queue_s). A node: + - keeps the meta-data of its corresponding key/value pair + (embodied by the "id", and "expire" field); + - is a part of LRU queue (embodied by "prev" and "next" fields); + - is a part of hash-table (embodied by the "conflict" field). +]] + +local ffi = require "ffi" +local bit = require "bit" + + +local ffi_new = ffi.new +local ffi_sizeof = ffi.sizeof +local ffi_cast = ffi.cast +local ffi_fill = ffi.fill +local ngx_now = ngx.now +local uintptr_t = ffi.typeof("uintptr_t") +local c_str_t = ffi.typeof("const char*") +local int_t = ffi.typeof("int") +local int_array_t = ffi.typeof("int[?]") + + +local crc_tab = ffi.new("const unsigned int[256]", { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, + 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, + 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, + 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, + 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, + 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, + 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, + 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, + 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, + 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, + 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }); + +local setmetatable = setmetatable +local tonumber = tonumber +local tostring = tostring +local type = type + +local brshift = bit.rshift +local bxor = bit.bxor +local band = bit.band + +local ok, tab_new = pcall(require, "table.new") +if not ok then + tab_new = function (narr, nrec) return {} end +end + +-- queue data types +-- +-- this queue is a double-ended queue and the first node +-- is reserved for the queue itself. +-- the implementation is mostly borrowed from nginx's ngx_queue_t data +-- structure. + +ffi.cdef[[ + /* A lrucache_pureffi_queue_s node hook together three data structures: + * o. the key/value store as embodied by the "id" (which is in essence the + * indentifier of key/pair pair) and the "expire" (which is a metadata + * of the corresponding key/pair pair). + * o. The LRU queue via the prev/next fields. + * o. The hash-tabble as embodied by the "conflict" field. + */ + typedef struct lrucache_pureffi_queue_s lrucache_pureffi_queue_t; + struct lrucache_pureffi_queue_s { + /* Each node is assigned a unique ID at construction time, and the + * ID remain immutatble, regardless the node is in active-list or + * free-list. The queue header is assigned ID 0. Since queue-header + * is a sentinel node, 0 denodes "invalid ID". + * + * Intuitively, we can view the "id" as the identifier of key/value + * pair. + */ + int id; + + /* The bucket of the hash-table is implemented as a singly-linked list. + * The "conflict" refers to the ID of the next node in the bucket. + */ + int conflict; + + double expire; /* in seconds */ + + lrucache_pureffi_queue_t *prev; + lrucache_pureffi_queue_t *next; + }; +]] + +local queue_arr_type = ffi.typeof("lrucache_pureffi_queue_t[?]") +--local queue_ptr_type = ffi.typeof("lrucache_pureffi_queue_t*") +local queue_type = ffi.typeof("lrucache_pureffi_queue_t") +local NULL = ffi.null + + +--======================================================================== +-- +-- Queue utility functions +-- +--======================================================================== + +-- Append the element "x" to the given queue "h". +local function queue_insert_tail(h, x) + local last = h[0].prev + x.prev = last + last.next = x + x.next = h + h[0].prev = x +end + + +--[[ +Allocate a queue with size + 1 elements. Elements are linked together in a +circular way, i.e. the last element's "next" points to the first element, +while the first element's "prev" element points to the last element. +]] +local function queue_init(size) + if not size then + size = 0 + end + local q = ffi_new(queue_arr_type, size + 1) + ffi_fill(q, ffi_sizeof(queue_type, size + 1), 0) + + if size == 0 then + q[0].prev = q + q[0].next = q + + else + local prev = q[0] + for i = 1, size do + local e = q[i] + e.id = i + prev.next = e + e.prev = prev + prev = e + end + + local last = q[size] + last.next = q + q[0].prev = last + end + + return q +end + + +local function queue_is_empty(q) + -- print("q: ", tostring(q), "q.prev: ", tostring(q), ": ", q == q.prev) + return q == q[0].prev +end + + +local function queue_remove(x) + local prev = x.prev + local next = x.next + + next.prev = prev + prev.next = next + + -- for debugging purpose only: + x.prev = NULL + x.next = NULL +end + + +-- Insert the element "x" the to the given queue "h" +local function queue_insert_head(h, x) + x.next = h[0].next + x.next.prev = x + x.prev = h + h[0].next = x +end + + +local function queue_last(h) + return h[0].prev +end + + +local function queue_head(h) + return h[0].next +end + + +--======================================================================== +-- +-- Miscellaneous Utility Functions +-- +--======================================================================== + +local function ptr2num(ptr) + return tonumber(ffi_cast(uintptr_t, ptr)) +end + + +local function crc32_ptr(ptr) + local p = brshift(ptr2num(ptr), 3) + local b = band(p, 255) + local crc32 = crc_tab[b] + + b = band(brshift(p, 8), 255) + crc32 = bxor(brshift(crc32, 8), crc_tab[band(bxor(crc32, b), 255)]) + + b = band(brshift(p, 16), 255) + crc32 = bxor(brshift(crc32, 8), crc_tab[band(bxor(crc32, b), 255)]) + + --b = band(brshift(p, 24), 255) + --crc32 = bxor(brshift(crc32, 8), crc_tab[band(bxor(crc32, b), 255)]) + return crc32 +end + + +--======================================================================== +-- +-- Implementation of "export" functions +-- +--======================================================================== + +local _M = { + _VERSION = '0.07' +} +local mt = { __index = _M } + + +-- "size" specifies the maximum number of entries in the LRU queue, and the +-- "load_factor" designates the 'load factor' of the hash-table we are using +-- internally. The default value of load-factor is 0.5 (i.e. 50%); if the +-- load-factor is specified, it will be clamped to the range of [0.1, 1](i.e. +-- if load-factor is greater than 1, it will be saturated to 1, likewise, +-- if load-factor is smaller than 0.1, it will be clamped to 0.1). +function _M.new(size, load_factor) + if size < 1 then + return nil, "size too small" + end + + -- Determine bucket size, which must be power of two. + local load_f = load_factor + if not load_factor then + load_f = 0.5 + elseif load_factor > 1 then + load_f = 1 + elseif load_factor < 0.1 then + load_f = 0.1 + end + + local bs_min = size / load_f + -- The bucket_sz *MUST* be a power-of-two. See the hash_string(). + local bucket_sz = 1 + repeat + bucket_sz = bucket_sz * 2 + until bucket_sz >= bs_min + + local self = { + size = size, + bucket_sz = bucket_sz, + free_queue = queue_init(size), + cache_queue = queue_init(0), + node_v = nil, + key_v = tab_new(size, 0), + val_v = tab_new(size, 0), + bucket_v = ffi_new(int_array_t, bucket_sz) + } + -- "note_v" is an array of all the nodes used in the LRU queue. Exprpession + -- node_v[i] evaluates to the element of ID "i". + self.node_v = self.free_queue + + -- Allocate the array-part of the key_v, val_v, bucket_v. + --local key_v = self.key_v + --local val_v = self.val_v + --local bucket_v = self.bucket_v + ffi_fill(self.bucket_v, ffi_sizeof(int_t, bucket_sz), 0) + + return setmetatable(self, mt) +end + + +local function hash_string(self, str) + local c_str = ffi_cast(c_str_t, str) + + local hv = crc32_ptr(c_str) + hv = band(hv, self.bucket_sz - 1) + -- Hint: bucket is 0-based + return hv +end + + +-- Search the node associated with the key in the bucket, if found returns +-- the the id of the node, and the id of its previous node in the conflict list. +-- The "bucket_hdr_id" is the ID of the first node in the bucket +local function _find_node_in_bucket(key, key_v, node_v, bucket_hdr_id) + if bucket_hdr_id ~= 0 then + local prev = 0 + local cur = bucket_hdr_id + + while cur ~= 0 and key_v[cur] ~= key do + prev = cur + cur = node_v[cur].conflict + end + + if cur ~= 0 then + return cur, prev + end + end +end + + +-- Return the node corresponding to the key/val. +local function find_key(self, key) + local key_hash = hash_string(self, key) + return _find_node_in_bucket(key, self.key_v, self.node_v, + self.bucket_v[key_hash]) +end + + +--[[ This function tries to + 1. Remove the given key and the associated value from the key/value store, + 2. Remove the entry associated with the key from the hash-table. + + NOTE: all queues remain intact. + + If there was a node bound to the key/val, return that node; otherwise, + nil is returned. +]] +local function remove_key(self, key) + local key_v = self.key_v + local val_v = self.val_v + local node_v = self.node_v + local bucket_v = self.bucket_v + + local key_hash = hash_string(self, key) + local cur, prev = + _find_node_in_bucket(key, key_v, node_v, bucket_v[key_hash]) + + if cur then + -- In an attempt to make key and val dead. + key_v[cur] = nil + val_v[cur] = nil + + -- Remove the node from the hash table + local next_node = node_v[cur].conflict + if prev ~= 0 then + node_v[prev].conflict = next_node + else + bucket_v[key_hash] = next_node + end + node_v[cur].conflict = 0 + + return cur + end +end + + +--[[ Bind the key/val with the given node, and insert the node into the Hashtab. + NOTE: this function does not touch any queue +]] +local function insert_key(self, key, val, node) + -- Bind the key/val with the node + local node_id = node.id + self.key_v[node_id] = key + self.val_v[node_id] = val + + -- Insert the node into the hash-table + local key_hash = hash_string(self, key) + local bucket_v = self.bucket_v + node.conflict = bucket_v[key_hash] + bucket_v[key_hash] = node_id +end + + +function _M.get(self, key) + if type(key) ~= "string" then + key = tostring(key) + end + + local node_id = find_key(self, key) + if not node_id then + return nil + end + + -- print(key, ": moving node ", tostring(node), " to cache queue head") + local cache_queue = self.cache_queue + local node = self.node_v + node_id + queue_remove(node) + queue_insert_head(cache_queue, node) + + local expire = node.expire + if expire >= 0 and expire < ngx_now() then + -- print("expired: ", node.expire, " > ", ngx_now()) + return nil, self.val_v[node_id] + end + + return self.val_v[node_id] +end + + +function _M.delete(self, key) + if type(key) ~= "string" then + key = tostring(key) + end + + local node_id = remove_key(self, key); + if not node_id then + return false + end + + local node = self.node_v + node_id + queue_remove(node) + queue_insert_tail(self.free_queue, node) + return true +end + + +function _M.set(self, key, value, ttl) + if type(key) ~= "string" then + key = tostring(key) + end + + local node_id = find_key(self, key) + local node + if not node_id then + local free_queue = self.free_queue + if queue_is_empty(free_queue) then + -- evict the least recently used key + -- assert(not queue_is_empty(self.cache_queue)) + node = queue_last(self.cache_queue) + remove_key(self, self.key_v[node.id]) + else + -- take a free queue node + node = queue_head(free_queue) + -- print(key, ": get a new free node: ", tostring(node)) + end + + -- insert the key + insert_key(self, key, value, node) + else + node = self.node_v + node_id + self.val_v[node_id] = value + end + + queue_remove(node) + queue_insert_head(self.cache_queue, node) + + if ttl then + node.expire = ngx_now() + ttl + else + node.expire = -1 + end +end + + +return _M From 5f6106e5d01730ed540d53046c43fe62527de1be Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Fri, 2 Mar 2018 16:07:45 -0500 Subject: [PATCH 04/34] use luajit instead of standard lua --- images/nginx/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/nginx/Dockerfile b/images/nginx/Dockerfile index dcec3f2c5e..7994eba7c0 100644 --- a/images/nginx/Dockerfile +++ b/images/nginx/Dockerfile @@ -41,7 +41,7 @@ RUN apt-get update && apt-get dist-upgrade -y && \ libperl-dev \ cmake \ util-linux \ - lua5.1 liblua5.1-0 liblua5.1-dev lua5.1-cjson \ + libluajit-5.1-dev lua5.1-cjson \ lmdb-utils \ libjemalloc1 libjemalloc-dev \ wget \ From b1b725792defe0b0121e694e180fb0fcd03dc73d Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Fri, 2 Mar 2018 16:08:24 -0500 Subject: [PATCH 05/34] implemented a dumb balancer --- rootfs/etc/nginx/lua/balancer.lua | 62 +++++++++++++++++++++++++++- rootfs/etc/nginx/template/nginx.tmpl | 5 +++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/rootfs/etc/nginx/lua/balancer.lua b/rootfs/etc/nginx/lua/balancer.lua index b1b7f15227..352e743f35 100644 --- a/rootfs/etc/nginx/lua/balancer.lua +++ b/rootfs/etc/nginx/lua/balancer.lua @@ -1,8 +1,66 @@ -_M = {} +local ngx_balancer = require("ngx.balancer") +local ngx_upstream = require("ngx.upstream") +local math = require("math") +local dynamic_upstreams_dict = ngx.shared.dynamic_upstreams +local json = require("cjson") + +local _M = {} + +local function split_pair(pair, seperator) + local i = pair:find(seperator) + if i == nil then + return pair, nil + else + local name = pair:sub(1, i - 1) + local value = pair:sub(i + 1, -1) + return name, value + end +end + +local function get_dynamic_peers(upstream_name) + local peers_data = dynamic_upstreams_dict:get(upstream_name) + if not peers_data then + return nil + end + + local ok, peers = pcall(json.decode, peers_data) + if not ok then + ngx.log(ngx.WARN, "error decoding peers for upstream pool: " .. upstream_name) + return nil + end + + return peers +end + +local function get_peers(upstream_name) + return get_dynamic_peers(upstream_name) or ngx_upstream.get_primary_peers(upstream_name) +end + +local function balance(peers) + local offset = math.random(1, #peers) + local peer = peers[offset] + return split_pair(peer.name, ':') +end --- curl localhost:18080/lua_dicts function _M.call() ngx.log(ngx.WARN, "I'm the balancer") + + ngx_balancer.set_more_tries(1) + + local peers = get_peers(ngx.var.proxy_upstream_name) + if not peers or #peers == 0 then + ngx.log(ngx.ERR, "no upstream peers available") + return + end + + local host, port = balance(peers) + + local ok, err = ngx_balancer.set_current_peer(host, port) + if ok then + ngx.log(ngx.DEBUG, "current peer is set to " .. tostring(host) .. ":" .. tostring(port)) + else + ngx.log(ngx.ERR, "error while setting current upstream peer to: " .. tostring(err)) + end end return _M diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index 40c7cd2c39..c996d0d5ec 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -33,6 +33,11 @@ events { http { lua_package_path "/etc/nginx/lua/?.lua;/etc/nginx/lua/vendor/?.lua;;"; + lua_shared_dict dynamic_upstreams 1M; + init_by_lua_block { + require "resty.core" + collectgarbage("collect") + } {{/* we use the value of the header X-Forwarded-For to be able to use the geo_ip module */}} {{ if $cfg.UseProxyProtocol }} From 66927ee4263f653df6f992aa60fbb133b57da686 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Fri, 2 Mar 2018 17:07:03 -0500 Subject: [PATCH 06/34] first working version! --- rootfs/etc/nginx/lua/balancer.lua | 39 +++++++++++++++----- rootfs/etc/nginx/lua/dicts_handler.lua | 50 +++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 9 deletions(-) diff --git a/rootfs/etc/nginx/lua/balancer.lua b/rootfs/etc/nginx/lua/balancer.lua index 352e743f35..b42baf868b 100644 --- a/rootfs/etc/nginx/lua/balancer.lua +++ b/rootfs/etc/nginx/lua/balancer.lua @@ -6,6 +6,24 @@ local json = require("cjson") local _M = {} +-- http://nginx.org/en/docs/http/ngx_http_upstream_module.html#example +-- CAVEAT: nginx is giving out : instead of , so the docs are wrong +-- 127.0.0.1:26157 : 127.0.0.1:26157 , ngx.var.upstream_addr +-- 200 : 200 , ngx.var.upstream_status +-- 0.00 : 0.00, ngx.var.upstream_response_time +local function split_upstream_var(var) + if not var then + return nil, nil + end + local t = {} + for v in var:gmatch("[^%s|,]+") do + if v ~= ":" then + t[#t+1] = v + end + end + return t +end + local function split_pair(pair, seperator) local i = pair:find(seperator) if i == nil then @@ -17,16 +35,21 @@ local function split_pair(pair, seperator) end end +-- dynamic peers are stored per upstream name +-- : " : : " local function get_dynamic_peers(upstream_name) - local peers_data = dynamic_upstreams_dict:get(upstream_name) - if not peers_data then + local peers_string = dynamic_upstreams_dict:get(upstream_name) + if not peers_string then return nil end - local ok, peers = pcall(json.decode, peers_data) - if not ok then - ngx.log(ngx.WARN, "error decoding peers for upstream pool: " .. upstream_name) - return nil + local raw_peers = split_upstream_var(peers_string) + local peers = {} + for i, p in pairs(raw_peers) do + peers[i] = { + name = p, + down = false + } end return peers @@ -39,7 +62,7 @@ end local function balance(peers) local offset = math.random(1, #peers) local peer = peers[offset] - return split_pair(peer.name, ':') + return split_pair(peer.name, ":") end function _M.call() @@ -57,7 +80,7 @@ function _M.call() local ok, err = ngx_balancer.set_current_peer(host, port) if ok then - ngx.log(ngx.DEBUG, "current peer is set to " .. tostring(host) .. ":" .. tostring(port)) + ngx.log(ngx.WARN, "current peer is set to " .. tostring(host) .. ":" .. tostring(port)) else ngx.log(ngx.ERR, "error while setting current upstream peer to: " .. tostring(err)) end diff --git a/rootfs/etc/nginx/lua/dicts_handler.lua b/rootfs/etc/nginx/lua/dicts_handler.lua index 8c2baf92b7..1a22eb93db 100644 --- a/rootfs/etc/nginx/lua/dicts_handler.lua +++ b/rootfs/etc/nginx/lua/dicts_handler.lua @@ -1,7 +1,55 @@ -_M = {} +local router = require 'router' +local json = require("cjson") +local _M = {} + +--curl -XPOST -d '{"key": "upstream-default-backend", "value": "172.17.0.4:8080 : 172.17.0.4:8081 : 172.17.0.5:8080", "ttl": 0}' localhost:18080/lua_dicts/dynamic_upstreams/keys function _M.call() ngx.log(ngx.WARN, "I'm the dicts handler") + + local r = router.new() + + r:match({ + POST = { + ["/lua_dicts/:name/keys"] = function(params) + local dict = ngx.shared[params.name] + if not dict then + return params.name .. " could not be found" + end + + ngx.req.read_body() -- explicitly read the req body + local ok, body = pcall(json.decode, ngx.req.get_body_data()) + if not ok then + return "could not parse request body: " .. tostring(body) + end + + if body.value == json.null then + body.value = nil + end + + local success, err = dict:set(body.key, body.value, body.ttl or 0) + if not success then + return err + end + + ngx.print(tostring(body.key) .. " is set to " .. tostring(body.value) .. " in " .. tostring(params.name)) + end + } + }) + + local ok, errmsg = r:execute(ngx.var.request_method, ngx.var.request_uri, ngx.req.get_uri_args()) + if ok then + if errmsg then + ngx.status = 400 + ngx.print(tostring(errmsg)) + else + ngx.status = 200 + end + else + ngx.status = 404 + ngx.print("Not found!") + ngx.log(ngx.ERROR, errmsg) + end end return _M From 0875dc8cc3a3cf2bd53dce5dcf6db148a3e31e2f Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Fri, 2 Mar 2018 17:44:30 -0500 Subject: [PATCH 07/34] move upstream_balancer out of loop --- rootfs/etc/nginx/template/nginx.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index c996d0d5ec..fdb5db548f 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -343,6 +343,8 @@ http { {{ end }} } + {{ end }} + upstream upstream_balancer { server 0.0.0.1; # placeholder @@ -354,8 +356,6 @@ http { keepalive 1000; } - {{ end }} - {{/* build the maps that will be use to validate the Whitelist */}} {{ range $index, $server := $servers }} {{ range $location := $server.Locations }} From 1962c222d0e15276ae73489888244162be185c55 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Fri, 2 Mar 2018 22:23:26 -0500 Subject: [PATCH 08/34] skip reload and post to nginx on endpoints changes --- internal/ingress/controller/controller.go | 73 ++++++++++++++++++++++- internal/ingress/controller/nginx.go | 10 ++-- 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/internal/ingress/controller/controller.go b/internal/ingress/controller/controller.go index 879cf3a267..a69a24660e 100644 --- a/internal/ingress/controller/controller.go +++ b/internal/ingress/controller/controller.go @@ -17,9 +17,12 @@ limitations under the License. package controller import ( + "bytes" + "encoding/json" "fmt" "math/rand" "net" + "net/http" "reflect" "sort" "strconv" @@ -167,11 +170,79 @@ func (n *NGINXController) syncIngress(item interface{}) error { if !n.isForceReload() && n.runningConfig.Equal(&pcfg) { glog.V(3).Infof("skipping backend reload (no changes detected)") return nil + } else if !n.isForceReload() && len(n.runningConfig.Backends) == len(pcfg.Backends) { + // check whether the configuration change is only about endpoints + + newBackends := make([]*ingress.Backend, 0, len(pcfg.Backends)) + runningBackends := make([]*ingress.Backend, 0, len(n.runningConfig.Backends)) + for i := 0; i < len(n.runningConfig.Backends); i++ { + newBackends = append(newBackends, pcfg.Backends[i].DeepCopy()) + runningBackends = append(runningBackends, n.runningConfig.Backends[i].DeepCopy()) + } + + for i := 0; i < len(n.runningConfig.Backends); i++ { + pcfg.Backends[i].Endpoints = []ingress.Endpoint{} + n.runningConfig.Backends[i].Endpoints = []ingress.Endpoint{} + } + if n.runningConfig.Equal(&pcfg) { + // so configuration change is only about endpoints and force reload is not set + // we can skip reload and dynamically update endpoints + glog.Infof("only endpoints have changed, skipping reload and posting them to Nginx via HTTP request") + + // reset backends + pcfg.Backends = newBackends + n.runningConfig.Backends = runningBackends + + for _, backend := range pcfg.Backends { + found := false + for _, runningBackend := range n.runningConfig.Backends { + if backend.Equal(runningBackend) { + found = true + break + } + } + if !found { + // endpoints of this backend have been updated, needs to be posted to Nginx + buf, err := json.Marshal(backend.Endpoints) + if err != nil { + glog.Errorf("unexpected error when json encoding endpoints: \n%v", err) + // TODO(elvinefendi) implement retry logic + continue + } + + // TODO(elvinefendi) set port dynamically + resp, err := http.Post("http://localhost:18080/configuration/backends/"+backend.Name+"/endpoints", "application/json", bytes.NewReader(buf)) + if err != nil { + glog.Errorf("unexpected error when POSTing HTTP request: \n%v", err) + // TODO(elvinefendi) implement retry logic + continue + } + + defer func() { + if err := resp.Body.Close(); err != nil { + glog.Warningf("error while closing response body: \n%v", err) + } + }() + + if resp.StatusCode != http.StatusCreated { + glog.Errorf("Unexpected error code: %v", resp.StatusCode) + } else { + glog.Infof("endpoints for " + backend.Name + " have been updated") + } + } else { + glog.Infof(backend.Name + " is same as running config. number of endpoints: " + string(len(backend.Endpoints))) + } + } + + n.OnUpdate(pcfg, true) + n.runningConfig = &pcfg + return nil + } } glog.Infof("backend reload required") - err := n.OnUpdate(pcfg) + err := n.OnUpdate(pcfg, false) if err != nil { incReloadErrorCount() glog.Errorf("unexpected failure restarting the backend: \n%v", err) diff --git a/internal/ingress/controller/nginx.go b/internal/ingress/controller/nginx.go index ef3e53735b..f68cab7481 100644 --- a/internal/ingress/controller/nginx.go +++ b/internal/ingress/controller/nginx.go @@ -448,7 +448,7 @@ Error: %v // // returning nill implies the backend will be reloaded. // if an error is returned means requeue the update -func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) error { +func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration, skipReload bool) error { cfg := n.store.GetBackendConfiguration() cfg.Resolver = n.resolver @@ -664,9 +664,11 @@ func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) error { return err } - o, err := exec.Command(n.binary, "-s", "reload", "-c", cfgPath).CombinedOutput() - if err != nil { - return fmt.Errorf("%v\n%v", err, string(o)) + if !skipReload { + o, err := exec.Command(n.binary, "-s", "reload", "-c", cfgPath).CombinedOutput() + if err != nil { + return fmt.Errorf("%v\n%v", err, string(o)) + } } return nil From 81afc460297c9a416d4c710083959a3b2e2ab207 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Fri, 2 Mar 2018 23:56:43 -0500 Subject: [PATCH 09/34] make the endpoint processing in lua side --- rootfs/etc/nginx/lua/balancer.lua | 3 +- .../{dicts_handler.lua => configuration.lua} | 28 +++++++++---------- rootfs/etc/nginx/template/nginx.tmpl | 6 ++-- 3 files changed, 18 insertions(+), 19 deletions(-) rename rootfs/etc/nginx/lua/{dicts_handler.lua => configuration.lua} (54%) diff --git a/rootfs/etc/nginx/lua/balancer.lua b/rootfs/etc/nginx/lua/balancer.lua index b42baf868b..f8011388d0 100644 --- a/rootfs/etc/nginx/lua/balancer.lua +++ b/rootfs/etc/nginx/lua/balancer.lua @@ -1,9 +1,10 @@ local ngx_balancer = require("ngx.balancer") local ngx_upstream = require("ngx.upstream") local math = require("math") -local dynamic_upstreams_dict = ngx.shared.dynamic_upstreams local json = require("cjson") +local dynamic_upstreams_dict = ngx.shared.dynamic_upstreams + local _M = {} -- http://nginx.org/en/docs/http/ngx_http_upstream_module.html#example diff --git a/rootfs/etc/nginx/lua/dicts_handler.lua b/rootfs/etc/nginx/lua/configuration.lua similarity index 54% rename from rootfs/etc/nginx/lua/dicts_handler.lua rename to rootfs/etc/nginx/lua/configuration.lua index 1a22eb93db..999a8f6ab1 100644 --- a/rootfs/etc/nginx/lua/dicts_handler.lua +++ b/rootfs/etc/nginx/lua/configuration.lua @@ -1,6 +1,8 @@ local router = require 'router' local json = require("cjson") +local dynamic_upstreams_dict = ngx.shared.dynamic_upstreams + local _M = {} --curl -XPOST -d '{"key": "upstream-default-backend", "value": "172.17.0.4:8080 : 172.17.0.4:8081 : 172.17.0.5:8080", "ttl": 0}' localhost:18080/lua_dicts/dynamic_upstreams/keys @@ -11,28 +13,26 @@ function _M.call() r:match({ POST = { - ["/lua_dicts/:name/keys"] = function(params) - local dict = ngx.shared[params.name] - if not dict then - return params.name .. " could not be found" - end - + ["/configuration/backends/:name/endpoints"] = function(params) ngx.req.read_body() -- explicitly read the req body - local ok, body = pcall(json.decode, ngx.req.get_body_data()) + local ok, endpoints = pcall(json.decode, ngx.req.get_body_data()) if not ok then - return "could not parse request body: " .. tostring(body) + return "could not parse request body: " .. tostring(endpoints) end - if body.value == json.null then - body.value = nil + endpoints_with_ports = {} + for i, endpoint in pairs(endpoints) do + endpoints_with_ports[i] = endpoint.address .. ":" .. endpoint.port end + endpoints_string = table.concat(endpoints_with_ports, " : ") - local success, err = dict:set(body.key, body.value, body.ttl or 0) + local success, err = dynamic_upstreams_dict:set(params.name, endpoints_string, 0) if not success then return err end - ngx.print(tostring(body.key) .. " is set to " .. tostring(body.value) .. " in " .. tostring(params.name)) + ngx.status = 201 + ngx.print("endpoints for '" .. tostring(params.name) .. "' updated to '" .. endpoints_string .. "'") end } }) @@ -42,13 +42,11 @@ function _M.call() if errmsg then ngx.status = 400 ngx.print(tostring(errmsg)) - else - ngx.status = 200 end else + ngx.log(ngx.ERROR, errmsg) ngx.status = 404 ngx.print("Not found!") - ngx.log(ngx.ERROR, errmsg) end end diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index fdb5db548f..5fa3b0d889 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -471,10 +471,10 @@ http { {{ end }} } - location /lua_dicts { + location /configuration { content_by_lua_block { - local dicts_handler = require("dicts_handler") - dicts_handler.call() + local configuration = require("configuration") + configuration.call() } } From 760ddfb4ade1762e0e784a4379ea4d5b74a26c2a Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sat, 3 Mar 2018 02:12:25 -0500 Subject: [PATCH 10/34] sync with upstream --- images/nginx/Dockerfile | 4 +--- images/nginx/build.sh | 39 +-------------------------------------- 2 files changed, 2 insertions(+), 41 deletions(-) diff --git a/images/nginx/Dockerfile b/images/nginx/Dockerfile index 7994eba7c0..fd360590f4 100644 --- a/images/nginx/Dockerfile +++ b/images/nginx/Dockerfile @@ -41,17 +41,15 @@ RUN apt-get update && apt-get dist-upgrade -y && \ libperl-dev \ cmake \ util-linux \ - libluajit-5.1-dev lua5.1-cjson \ lmdb-utils \ libjemalloc1 libjemalloc-dev \ wget \ libcurl4-openssl-dev \ procps \ git g++ pkgconf flex bison doxygen libyajl-dev liblmdb-dev libtool dh-autoreconf libxml2 libpcre++-dev libxml2-dev \ + lua-cjson \ || exit 1 -RUN ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so - COPY build.sh / RUN /build.sh diff --git a/images/nginx/build.sh b/images/nginx/build.sh index cef742bfca..f913699adf 100755 --- a/images/nginx/build.sh +++ b/images/nginx/build.sh @@ -56,41 +56,6 @@ if [[ ${ARCH} == "ppc64le" ]]; then clean-install software-properties-common fi -apt-get update && apt-get dist-upgrade -y - -# install required packages to build -clean-install \ - bash \ - build-essential \ - curl ca-certificates \ - libgeoip1 \ - libgeoip-dev \ - patch \ - libpcre3 \ - libpcre3-dev \ - libssl-dev \ - zlib1g \ - zlib1g-dev \ - libaio1 \ - libaio-dev \ - openssl \ - libperl-dev \ - cmake \ - util-linux \ - lua5.1 liblua5.1-0 liblua5.1-dev \ - lmdb-utils \ - libjemalloc1 libjemalloc-dev \ - wget \ - libcurl4-openssl-dev \ - procps \ - git g++ pkgconf flex bison doxygen libyajl-dev liblmdb-dev libtool dh-autoreconf libxml2 libpcre++-dev libxml2-dev \ - lua-cjson \ - || exit 1 - -ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so - -mkdir -p /etc/nginx - if [[ ${ARCH} == "s390x" ]]; then # avoid error: # git: ../nptl/pthread_mutex_lock.c:81: __pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed. @@ -342,9 +307,7 @@ WITH_MODULES="--add-module=$BUILD_PATH/ngx_devel_kit-$NDK_VERSION \ --add-dynamic-module=$BUILD_PATH/nginx-opentracing-$NGINX_OPENTRACING_VERSION/jaeger \ --add-dynamic-module=$BUILD_PATH/nginx-opentracing-$NGINX_OPENTRACING_VERSION/zipkin \ --add-dynamic-module=$BUILD_PATH/ModSecurity-nginx-$MODSECURITY_VERSION \ - --add-module=$BUILD_PATH/ngx_brotli \ - --add-module=$BUILD_PATH/lua-nginx-module-$LUA_VERSION \ - --add-module=$BUILD_PATH/lua-upstream-nginx-module-$LUA_UPSTREAM_VERSION" + --add-module=$BUILD_PATH/ngx_brotli" ./configure \ --prefix=/usr/share/nginx \ From c8c6a89f131e7c124db5205a6dbb5a6745aecd10 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sat, 3 Mar 2018 02:17:58 -0500 Subject: [PATCH 11/34] no that resty core is part of nginx build we dont need to explicitly include --- rootfs/etc/nginx/lua/vendor/ngx/balancer.lua | 210 ---- rootfs/etc/nginx/lua/vendor/ngx/balancer.md | 304 ------ rootfs/etc/nginx/lua/vendor/ngx/base64.lua | 89 -- rootfs/etc/nginx/lua/vendor/ngx/base64.md | 137 --- rootfs/etc/nginx/lua/vendor/ngx/errlog.lua | 133 --- rootfs/etc/nginx/lua/vendor/ngx/errlog.md | 429 -------- rootfs/etc/nginx/lua/vendor/ngx/ocsp.lua | 150 --- rootfs/etc/nginx/lua/vendor/ngx/ocsp.md | 298 ------ rootfs/etc/nginx/lua/vendor/ngx/process.lua | 74 -- rootfs/etc/nginx/lua/vendor/ngx/process.md | 230 ----- rootfs/etc/nginx/lua/vendor/ngx/re.lua | 284 ----- rootfs/etc/nginx/lua/vendor/ngx/re.md | 249 ----- rootfs/etc/nginx/lua/vendor/ngx/semaphore.lua | 152 --- rootfs/etc/nginx/lua/vendor/ngx/semaphore.md | 356 ------- rootfs/etc/nginx/lua/vendor/ngx/ssl.lua | 313 ------ rootfs/etc/nginx/lua/vendor/ngx/ssl.md | 513 --------- .../etc/nginx/lua/vendor/ngx/ssl/session.lua | 109 -- .../etc/nginx/lua/vendor/ngx/ssl/session.md | 277 ----- rootfs/etc/nginx/lua/vendor/resty/core.lua | 29 - .../etc/nginx/lua/vendor/resty/core/base.lua | 236 ----- .../nginx/lua/vendor/resty/core/base64.lua | 90 -- .../etc/nginx/lua/vendor/resty/core/ctx.lua | 82 -- .../etc/nginx/lua/vendor/resty/core/exit.lua | 48 - .../etc/nginx/lua/vendor/resty/core/hash.lua | 80 -- .../etc/nginx/lua/vendor/resty/core/misc.lua | 155 --- .../etc/nginx/lua/vendor/resty/core/phase.lua | 57 - .../etc/nginx/lua/vendor/resty/core/regex.lua | 971 ------------------ .../nginx/lua/vendor/resty/core/request.lua | 351 ------- .../nginx/lua/vendor/resty/core/response.lua | 165 --- .../nginx/lua/vendor/resty/core/shdict.lua | 538 ---------- .../etc/nginx/lua/vendor/resty/core/time.lua | 121 --- .../etc/nginx/lua/vendor/resty/core/uri.lua | 64 -- .../etc/nginx/lua/vendor/resty/core/var.lua | 130 --- .../nginx/lua/vendor/resty/core/worker.lua | 46 - .../etc/nginx/lua/vendor/resty/lrucache.lua | 227 ---- .../lua/vendor/resty/lrucache/pureffi.lua | 534 ---------- 36 files changed, 8231 deletions(-) delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/balancer.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/balancer.md delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/base64.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/base64.md delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/errlog.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/errlog.md delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/ocsp.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/ocsp.md delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/process.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/process.md delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/re.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/re.md delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/semaphore.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/semaphore.md delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/ssl.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/ssl.md delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/ssl/session.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/ngx/ssl/session.md delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/base.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/base64.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/ctx.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/exit.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/hash.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/misc.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/phase.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/regex.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/request.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/response.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/shdict.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/time.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/uri.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/var.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/core/worker.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/lrucache.lua delete mode 100644 rootfs/etc/nginx/lua/vendor/resty/lrucache/pureffi.lua diff --git a/rootfs/etc/nginx/lua/vendor/ngx/balancer.lua b/rootfs/etc/nginx/lua/vendor/ngx/balancer.lua deleted file mode 100644 index b947043d73..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/balancer.lua +++ /dev/null @@ -1,210 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local base = require "resty.core.base" -base.allows_subsystem('http', 'stream') - - -local ffi = require "ffi" -local C = ffi.C -local ffi_str = ffi.string -local errmsg = base.get_errmsg_ptr() -local FFI_OK = base.FFI_OK -local FFI_ERROR = base.FFI_ERROR -local int_out = ffi.new("int[1]") -local getfenv = getfenv -local error = error -local type = type -local tonumber = tonumber -local max = math.max -local subsystem = ngx.config.subsystem -local ngx_lua_ffi_balancer_set_current_peer -local ngx_lua_ffi_balancer_set_more_tries -local ngx_lua_ffi_balancer_get_last_failure -local ngx_lua_ffi_balancer_set_timeouts -- used by both stream and http - - -if subsystem == 'http' then - ffi.cdef[[ - int ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, - const unsigned char *addr, size_t addr_len, int port, char **err); - - int ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r, - int count, char **err); - - int ngx_http_lua_ffi_balancer_get_last_failure(ngx_http_request_t *r, - int *status, char **err); - - int ngx_http_lua_ffi_balancer_set_timeouts(ngx_http_request_t *r, - long connect_timeout, long send_timeout, - long read_timeout, char **err); - ]] - - ngx_lua_ffi_balancer_set_current_peer = - C.ngx_http_lua_ffi_balancer_set_current_peer - - ngx_lua_ffi_balancer_set_more_tries = - C.ngx_http_lua_ffi_balancer_set_more_tries - - ngx_lua_ffi_balancer_get_last_failure = - C.ngx_http_lua_ffi_balancer_get_last_failure - - ngx_lua_ffi_balancer_set_timeouts = - C.ngx_http_lua_ffi_balancer_set_timeouts - -elseif subsystem == 'stream' then - ffi.cdef[[ - int ngx_stream_lua_ffi_balancer_set_current_peer( - ngx_stream_lua_request_t *r, - const unsigned char *addr, size_t addr_len, int port, char **err); - - int ngx_stream_lua_ffi_balancer_set_more_tries(ngx_stream_lua_request_t *r, - int count, char **err); - - int ngx_stream_lua_ffi_balancer_get_last_failure( - ngx_stream_lua_request_t *r, int *status, char **err); - - int ngx_stream_lua_ffi_balancer_set_timeouts(ngx_stream_lua_request_t *r, - long connect_timeout, long timeout, char **err); - ]] - - ngx_lua_ffi_balancer_set_current_peer = - C.ngx_stream_lua_ffi_balancer_set_current_peer - - ngx_lua_ffi_balancer_set_more_tries = - C.ngx_stream_lua_ffi_balancer_set_more_tries - - ngx_lua_ffi_balancer_get_last_failure = - C.ngx_stream_lua_ffi_balancer_get_last_failure - - local ngx_stream_lua_ffi_balancer_set_timeouts = - C.ngx_stream_lua_ffi_balancer_set_timeouts - - ngx_lua_ffi_balancer_set_timeouts = - function(r, connect_timeout, send_timeout, read_timeout, err) - local timeout = max(send_timeout, read_timeout) - - return ngx_stream_lua_ffi_balancer_set_timeouts(r, connect_timeout, - timeout, err) - end - -else - error("unknown subsystem: " .. subsystem) -end - - -local peer_state_names = { - [1] = "keepalive", - [2] = "next", - [4] = "failed", -} - - -local _M = { version = base.version } - - -function _M.set_current_peer(addr, port) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - if not port then - port = 0 - elseif type(port) ~= "number" then - port = tonumber(port) - end - - local rc = ngx_lua_ffi_balancer_set_current_peer(r, addr, #addr, - port, errmsg) - if rc == FFI_OK then - return true - end - - return nil, ffi_str(errmsg[0]) -end - - -function _M.set_more_tries(count) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local rc = ngx_lua_ffi_balancer_set_more_tries(r, count, errmsg) - if rc == FFI_OK then - if errmsg[0] == nil then - return true - end - return true, ffi_str(errmsg[0]) -- return the warning - end - - return nil, ffi_str(errmsg[0]) -end - - -function _M.get_last_failure() - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local state = ngx_lua_ffi_balancer_get_last_failure(r, int_out, errmsg) - - if state == 0 then - return nil - end - - if state == FFI_ERROR then - return nil, nil, ffi_str(errmsg[0]) - end - - return peer_state_names[state] or "unknown", int_out[0] -end - - -function _M.set_timeouts(connect_timeout, send_timeout, read_timeout) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - if not connect_timeout then - connect_timeout = 0 - elseif type(connect_timeout) ~= "number" or connect_timeout <= 0 then - return error("bad connect timeout") - else - connect_timeout = connect_timeout * 1000 - end - - if not send_timeout then - send_timeout = 0 - elseif type(send_timeout) ~= "number" or send_timeout <= 0 then - return error("bad send timeout") - else - send_timeout = send_timeout * 1000 - end - - if not read_timeout then - read_timeout = 0 - elseif type(read_timeout) ~= "number" or read_timeout <= 0 then - return error("bad read timeout") - else - read_timeout = read_timeout * 1000 - end - - local rc - - rc = ngx_lua_ffi_balancer_set_timeouts(r, connect_timeout, - send_timeout, read_timeout, - errmsg) - - if rc == FFI_OK then - return true - end - - return false, ffi_str(errmsg[0]) -end - - -return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/balancer.md b/rootfs/etc/nginx/lua/vendor/ngx/balancer.md deleted file mode 100644 index b2f852be18..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/balancer.md +++ /dev/null @@ -1,304 +0,0 @@ -Name -==== - -ngx.balancer - Lua API for defining dynamic upstream balancers in Lua - -Table of Contents -================= - -* [Name](#name) -* [Status](#status) -* [Synopsis](#synopsis) -* [Description](#description) -* [Methods](#methods) - * [set_current_peer](#set_current_peer) - * [set_more_tries](#set_more_tries) - * [get_last_failure](#get_last_failure) - * [set_timeouts](#set_timeouts) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Bugs and Patches](#bugs-and-patches) -* [Author](#author) -* [Copyright and License](#copyright-and-license) -* [See Also](#see-also) - -Status -====== - -This Lua module is currently considered experimental. - -Synopsis -======== - -http subsystem --------------- - -```nginx -http { - upstream backend { - server 0.0.0.1; # just an invalid address as a place holder - - balancer_by_lua_block { - local balancer = require "ngx.balancer" - - -- well, usually we calculate the peer's host and port - -- according to some balancing policies instead of using - -- hard-coded values like below - local host = "127.0.0.2" - local port = 8080 - - local ok, err = balancer.set_current_peer(host, port) - if not ok then - ngx.log(ngx.ERR, "failed to set the current peer: ", err) - return ngx.exit(500) - end - } - - keepalive 10; # connection pool - } - - server { - # this is the real entry point - listen 80; - - location / { - # make use of the upstream named "backend" defined above: - proxy_pass http://backend/fake; - } - } - - server { - # this server is just for mocking up a backend peer here... - listen 127.0.0.2:8080; - - location = /fake { - echo "this is the fake backend peer..."; - } - } -} -``` - -stream subsystem ----------------- - -```nginx -stream { - upstream backend { - server 0.0.0.1:1234; # just an invalid address as a place holder - - balancer_by_lua_block { - local balancer = require "ngx.balancer" - - -- well, usually we calculate the peer's host and port - -- according to some balancing policies instead of using - -- hard-coded values like below - local host = "127.0.0.2" - local port = 8080 - - local ok, err = balancer.set_current_peer(host, port) - if not ok then - ngx.log(ngx.ERR, "failed to set the current peer: ", err) - return ngx.exit(ngx.ERR) - end - } - } - - server { - # this is the real entry point - listen 10000; - - location / { - # make use of the upstream named "backend" defined above: - proxy_pass backend; - } - } - - server { - # this server is just for mocking up a backend peer here... - listen 127.0.0.2:8080; - - echo "this is the fake backend peer..."; - } -} -``` - -Description -=========== - -This Lua module provides API functions to allow defining highly dynamic NGINX load balancers for -any existing nginx upstream modules like [ngx_http_proxy_module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html), -[ngx_http_fastcgi_module](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html) and -[ngx_stream_proxy_module](https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html). - -It allows you to dynamically select a backend peer to connect to (or retry) on a per-request -basis from a list of backend peers which may also be dynamic. - -[Back to TOC](#table-of-contents) - -Methods -======= - -All the methods of this module are static (or module-level). That is, you do not need an object (or instance) -to call these methods. - -[Back to TOC](#table-of-contents) - -set_current_peer ----------------- -**syntax:** *ok, err = balancer.set_current_peer(host, port)* - -**context:** *balancer_by_lua** - -Sets the peer address (host and port) for the current backend query (which may be a retry). - -Domain names in `host` do not make sense. You need to use OpenResty libraries like -[lua-resty-dns](https://github.com/openresty/lua-resty-dns) to obtain IP address(es) from -all the domain names before entering the `balancer_by_lua*` handler (for example, -you can perform DNS lookups in an earlier phase like [access_by_lua*](https://github.com/openresty/lua-nginx-module#access_by_lua) -and pass the results to the `balancer_by_lua*` handler via [ngx.ctx](https://github.com/openresty/lua-nginx-module#ngxctx). - -[Back to TOC](#table-of-contents) - -set_more_tries --------------- -**syntax:** *ok, err = balancer.set_more_tries(count)* - -**context:** *balancer_by_lua** - -Sets the tries performed when the current attempt (which may be a retry) fails (as determined -by directives like [proxy_next_upstream](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream), depending on what -particular nginx uptream module you are currently using). Note that the current attempt is *excluded* in the `count` number set here. - -Please note that, the total number of tries in a single downstream request cannot exceed the -hard limit configured by directives like [proxy_next_upstream_tries](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream_tries), -depending on what concrete nginx upstream module you are using. When exceeding this limit, -the `count` value will get reduced to meet the limit and the second return value will be -the string `"reduced tries due to limit"`, which is a warning, while the first return value -is still a `true` value. - -[Back to TOC](#table-of-contents) - -get_last_failure ----------------- -**syntax:** *state_name, status_code = balancer.get_last_failure()* - -**context:** *balancer_by_lua** - -Retrieves the failure details about the previous failed attempt (if any) when the `next_upstream` retrying -mechanism is in action. When there was indeed a failed previous attempt, it returned a string describing -that attempt's state name, as well as an integer describing the status code of that attempt. - -Possible state names are as follows: -* `"next"` - Failures due to bad status codes sent from the backend server. The origin's response is sane though, which means the backend connection -can still be reused for future requests. -* `"failed"` - Fatal errors while communicating to the backend server (like connection timeouts, connection resets, and etc). In this case, -the backend connection must be aborted and cannot get reused. - -Possible status codes are those HTTP error status codes like `502` and `504`. - -For stream module, `status_code` will always be 0 (ngx.OK) and is provided for compatibility reasons. - -When the current attempt is the first attempt for the current downstream request (which means -there is no previous attempts at all), this -method always returns a single `nil` value. - -[Back to TOC](#table-of-contents) - -set_timeouts ------------- -**syntax:** `ok, err = balancer.set_timeouts(connect_timeout, send_timeout, read_timeout)` - -**context:** *balancer_by_lua** - -Sets the upstream timeout (connect, send and read) in seconds for the current and any -subsequent backend requests (which might be a retry). - -If you want to inherit the timeout value of the global `nginx.conf` configuration (like `proxy_connect_timeout`), then -just specify the `nil` value for the corresponding argument (like the `connect_timeout` argument). - -Zero and negative timeout values are not allowed. - -You can specify millisecond precision in the timeout values by using floating point numbers like 0.001 (which means 1ms). - -**Note:** `send_timeout` and `read_timeout` are controlled by the same config -[`proxy_timeout`](https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_timeout) -for `ngx_stream_proxy_module`. To keep API compatibility, this function will use `max(send_timeout, read_timeout)` -as the value for setting `proxy_timeout`. - -Returns `true` when the operation is successful; returns `nil` and a string describing the error -otherwise. - -This only affects the current downstream request. It is not a global change. - -For the best performance, you should use the [OpenResty](https://openresty.org/) bundle. - -This function was first added in the `0.1.7` version of this library. - -[Back to TOC](#table-of-contents) - -Community -========= - -[Back to TOC](#table-of-contents) - -English Mailing List --------------------- - -The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. - -[Back to TOC](#table-of-contents) - -Chinese Mailing List --------------------- - -The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. - -[Back to TOC](#table-of-contents) - -Bugs and Patches -================ - -Please report bugs or submit patches by - -1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), -1. or posting to the [OpenResty community](#community). - -[Back to TOC](#table-of-contents) - -Author -====== - -Yichun Zhang <agentzh@gmail.com> (agentzh), OpenResty Inc. - -[Back to TOC](#table-of-contents) - -Copyright and License -===================== - -This module is licensed under the BSD license. - -Copyright (C) 2015-2017, by Yichun "agentzh" Zhang, OpenResty Inc. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -[Back to TOC](#table-of-contents) - -See Also -======== -* the ngx_lua module: https://github.com/openresty/lua-nginx-module -* the [balancer_by_lua*](https://github.com/openresty/lua-nginx-module#balancer_by_lua_block) directive. -* library [lua-resty-core](https://github.com/openresty/lua-resty-core) -* OpenResty: http://openresty.org - -[Back to TOC](#table-of-contents) diff --git a/rootfs/etc/nginx/lua/vendor/ngx/base64.lua b/rootfs/etc/nginx/lua/vendor/ngx/base64.lua deleted file mode 100644 index a8a6aaf447..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/base64.lua +++ /dev/null @@ -1,89 +0,0 @@ --- Copyright (C) by Yichun Zhang (agentzh) --- Copyright (C) by OpenResty Inc. - -local ffi = require("ffi") -local base = require("resty.core.base") - - -local ffi_str = ffi.string -local type = type -local C = ffi.C -local NGX_ERROR = ngx.ERROR - - -local _M = { version = base.version } - - -ffi.cdef[[ -typedef intptr_t ngx_int_t; - -void ngx_encode_base64url(ngx_str_t *dst, ngx_str_t *src); -ngx_int_t ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src); -]] - - -local get_string_buf = base.get_string_buf - - -local dst_str_t = ffi.new("ngx_str_t[1]") -local src_str_t = ffi.new("ngx_str_t[1]") - - -local function base64_encoded_length(len) - return ((len + 2) / 3) * 4 -end - - -local function base64_decoded_length(len) - return ((len + 3) / 4) * 3 -end - - -function _M.encode_base64url(s) - if type(s) ~= "string" then - return nil, "must provide a string" - end - - local len = #s - local trans_len = base64_encoded_length(len) - local src = src_str_t[0] - local dst = dst_str_t[0] - - src.data = s - src.len = len - - dst.data = get_string_buf(trans_len) - dst.len = trans_len - - C.ngx_encode_base64url(dst_str_t, src_str_t) - - return ffi_str(dst.data, dst.len) -end - - -function _M.decode_base64url(s) - if type(s) ~= "string" then - return nil, "must provide a string" - end - - local len = #s - local trans_len = base64_decoded_length(len) - local src = src_str_t[0] - local dst = dst_str_t[0] - - src.data = s - src.len = len - - dst.data = get_string_buf(trans_len) - dst.len = trans_len - - local ret = C.ngx_decode_base64url(dst_str_t, src_str_t) - if ret == NGX_ERROR then - return nil, "invalid input" - end - - return ffi_str(dst.data, dst.len) -end - - -return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/base64.md b/rootfs/etc/nginx/lua/vendor/ngx/base64.md deleted file mode 100644 index a410b21885..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/base64.md +++ /dev/null @@ -1,137 +0,0 @@ -Name -==== - -`ngx.base64` - urlsafe base64 encode/decode functions OpenResty/ngx\_lua. - -Table of Contents -================= - -* [Name](#name) -* [Status](#status) -* [Synopsis](#synopsis) -* [Methods](#methods) - * [encode\_base64url](#encode_base64url) - * [decode\_base64url](#decode_base64url) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Bugs and Patches](#bugs-and-patches) -* [Author](#author) -* [Copyright and License](#copyright-and-license) -* [See Also](#see-also) - -Status -====== - -This Lua module is production ready. - -Synopsis -======== - -```lua -local b64 = require("ngx.base64") -local res, err - -res = b64.encode_base64url("foo") - -res, err = b64.decode_base64url(res) -if not res then - -- invalid input - ngx.log(ngx.ERR, err) -end - -assert(res == "foo") -``` - -[Back to TOC](#table-of-contents) - -Methods -======= - -encode\_base64url ------------------ -**syntax:** *encoded = base64.encode_base64url(input)* - -**context:** *any* - -Encode `input` using base64url rules. Returns the encoded string. - -[Back to TOC](#table-of-contents) - -decode\_base64url ------------------ -**syntax:** *decoded, err = base64.decode_base64url(input)* - -**context:** *any* - -Decode `input` using base64url rules. Returns the decoded string. - -If the `input` is not a valid base64url encoded string, `decoded `will be `nil` -and `err` will be a string describing the error. - -[Back to TOC](#table-of-contents) - - -Community -========= - -[Back to TOC](#table-of-contents) - -English Mailing List --------------------- - -The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. - -[Back to TOC](#table-of-contents) - -Chinese Mailing List --------------------- - -The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. - -[Back to TOC](#table-of-contents) - -Bugs and Patches -================ - -Please report bugs or submit patches by - -1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), -1. or posting to the [OpenResty community](#community). - -[Back to TOC](#table-of-contents) - -Author -====== - -Datong Sun <datong@openresty.com> (dndx), OpenResty Inc. - -[Back to TOC](#table-of-contents) - -Copyright and License -===================== - -This module is licensed under the BSD license. - -Copyright (C) 2017, by Yichun "agentzh" Zhang, OpenResty Inc. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -[Back to TOC](#table-of-contents) - -See Also -======== -* library [lua-resty-core](https://github.com/openresty/lua-resty-core) -* the ngx_lua module: https://github.com/openresty/lua-nginx-module -* OpenResty: http://openresty.org - -[Back to TOC](#table-of-contents) - diff --git a/rootfs/etc/nginx/lua/vendor/ngx/errlog.lua b/rootfs/etc/nginx/lua/vendor/ngx/errlog.lua deleted file mode 100644 index 94dc41d743..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/errlog.lua +++ /dev/null @@ -1,133 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local base = require "resty.core.base" -base.allows_subsystem('http') - - -local ffi = require 'ffi' -local ffi_string = ffi.string -local get_string_buf = base.get_string_buf -local get_size_ptr = base.get_size_ptr -local C = ffi.C -local new_tab = base.new_tab -local ffi_new = ffi.new -local charpp = ffi_new("char *[1]") -local intp = ffi.new("int[1]") -local num_value = ffi_new("double[1]") -local getfenv = getfenv -local tonumber = tonumber -local type = type - - -local _M = { version = base.version } - - -ffi.cdef[[ -int ngx_http_lua_ffi_errlog_set_filter_level(int level, unsigned char *err, - size_t *errlen); -int ngx_http_lua_ffi_errlog_get_msg(char **log, int *loglevel, - unsigned char *err, size_t *errlen, double *log_time); - -int ngx_http_lua_ffi_errlog_get_sys_filter_level(ngx_http_request_t *r); - -int ngx_http_lua_ffi_raw_log(ngx_http_request_t *r, int level, - const unsigned char *s, size_t s_len); -]] - - -local ERR_BUF_SIZE = 128 -local FFI_ERROR = base.FFI_ERROR - - -function _M.set_filter_level(level) - if not level then - return nil, [[missing "level" argument]] - end - - local err = get_string_buf(ERR_BUF_SIZE) - local errlen = get_size_ptr() - errlen[0] = ERR_BUF_SIZE - local rc = C.ngx_http_lua_ffi_errlog_set_filter_level(level, err, errlen) - - if rc == FFI_ERROR then - return nil, ffi_string(err, errlen[0]) - end - - return true -end - - -function _M.get_logs(max, logs) - local err = get_string_buf(ERR_BUF_SIZE) - local errlen = get_size_ptr() - errlen[0] = ERR_BUF_SIZE - - local log = charpp - local loglevel = intp - local log_time = num_value - - max = max or 10 - - if not logs then - logs = new_tab(max * 3 + 1, 0) - end - - local count = 0 - - for i = 1, max do - local loglen = C.ngx_http_lua_ffi_errlog_get_msg(log, loglevel, err, - errlen, log_time) - if loglen == FFI_ERROR then - return nil, ffi_string(err, errlen[0]) - end - - if loglen > 0 then - logs[count + 1] = loglevel[0] - logs[count + 2] = log_time[0] - logs[count + 3] = ffi_string(log[0], loglen) - - count = count + 3 - end - - if loglen < 0 then -- no error log - logs[count + 1] = nil - break - end - - if i == max then -- last one - logs[count + 1] = nil - break - end - end - - return logs -end - - -function _M.get_sys_filter_level() - local r = getfenv(0).__ngx_req - return tonumber(C.ngx_http_lua_ffi_errlog_get_sys_filter_level(r)) -end - - -function _M.raw_log(level, msg) - if type(level) ~= "number" then - error("bad argument #1 to 'raw_log' (must be a number)", 2) - end - - if type(msg) ~= "string" then - error("bad argument #2 to 'raw_log' (must be a string)", 2) - end - - local r = getfenv(0).__ngx_req - - local rc = C.ngx_http_lua_ffi_raw_log(r, level, msg, #msg) - - if rc == FFI_ERROR then - error("bad log level") - end -end - - -return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/errlog.md b/rootfs/etc/nginx/lua/vendor/ngx/errlog.md deleted file mode 100644 index c51c86f335..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/errlog.md +++ /dev/null @@ -1,429 +0,0 @@ -Name -==== - -`ngx.errlog` - manage nginx error log data in Lua for OpenResty/ngx_lua. - -Table of Contents -================= - -* [Name](#name) -* [Status](#status) -* [Synopsis](#synopsis) - * [Capturing nginx error logs with specified log filtering level](#capturing-nginx-error-logs-with-specified-log-filtering-level) -* [Methods](#methods) - * [set_filter_level](#set_filter_level) - * [get_logs](#get_logs) - * [get_sys_filter_level](#get_sys_filter_level) - * [raw_log](#raw_log) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Bugs and Patches](#bugs-and-patches) -* [Author](#author) -* [Copyright and License](#copyright-and-license) -* [See Also](#see-also) - -Status -====== - -This Lua module is currently considered experimental. - -The API is still in flux and may change in the future without notice. - -Synopsis -======== - -Capturing nginx error logs with specified log filtering level -------------------------------------------------------------- - -```nginx -error logs/error.log info; - -http { - # enable capturing error logs - lua_capture_error_log 32m; - - init_by_lua_block { - local errlog = require "ngx.errlog" - local status, err = errlog.set_filter_level(ngx.WARN) - if not status then - ngx.log(ngx.ERR, err) - return - end - ngx.log(ngx.WARN, "set error filter level: WARN") - } - - server { - # ... - location = /t { - content_by_lua_block { - local errlog = require "ngx.errlog" - ngx.log(ngx.INFO, "test1") - ngx.log(ngx.WARN, "test2") - ngx.log(ngx.ERR, "test3") - - local logs, err = errlog.get_logs(10) - if not logs then - ngx.say("FAILED ", err) - return - end - - for i = 1, #logs, 3 do - ngx.say("level: ", logs[i], " time: ", logs[i + 1], - " data: ", logs[i + 2]) - end - } - } - } -} - -``` - -The example location above produces a response like this: - -``` -level: 5 time: 1498546995.304 data: 2017/06/27 15:03:15 [warn] 46877#0: - [lua] init_by_lua:8: set error filter level: WARN -level: 5 time: 1498546999.178 data: 2017/06/27 15:03:19 [warn] 46879#0: *1 - [lua] test.lua:5: test2, client: 127.0.0.1, server: localhost, ...... -level: 4 time: 1498546999.178 data: 2017/06/27 15:03:19 [error] 46879#0: *1 - [lua] test.lua:6: test3, client: 127.0.0.1, server: localhost, ...... -``` - -[Back to TOC](#table-of-contents) - -Methods -======= - -set_filter_level ------------------ -**syntax:** *status, err = log_module.set_filter_level(log_level)* - -**context:** *init_by_lua** - -Specifies the filter log level, only to capture and buffer the error logs with a log level -no lower than the specified level. - -If we don't call this API, all of the error logs will be captured by default. - -In case of error, `nil` will be returned as well as a string describing the -error. - -This API should always work with directive -[lua_capture_error_log](https://github.com/openresty/lua-nginx-module#lua_capture_error_log). - -See [Nginx log level constants](https://github.com/openresty/lua-nginx-module#nginx-log-level-constants) for all nginx log levels. - -For example, - -```lua - init_by_lua_block { - local errlog = require "ngx.errlog" - errlog.set_filter_level(ngx.WARN) - } -``` - -*NOTE:* The debugging logs since when OpenResty or NGINX is not built with `--with-debug`, all the debug level logs are suppressed regardless. - -[Back to TOC](#table-of-contents) - -get_logs --------- -**syntax:** *res, err = log_module.get_logs(max?, res?)* - -**context:** *any* - -Fetches the captured nginx error log messages if any in the global data buffer -specified by `ngx_lua`'s -[lua_capture_error_log](https://github.com/openresty/lua-nginx-module#lua_capture_error_log) -directive. Upon return, this Lua function also *removes* those messages from -that global capturing buffer to make room for future new error log data. - -In case of error, `nil` will be returned as well as a string describing the -error. - -The optional `max` argument is a number that when specified, will prevent -`errlog.get_logs` from adding more than `max` messages to the `res` array. - -```lua -for i = 1, 20 do - ngx.log(ngx.ERR, "test") -end - -local errlog = require "ngx.errlog" -local res = errlog.get_logs(10) --- the number of messages in the `res` table is 10 and the `res` table --- has 30 elements. -``` - -The resulting table has the following structure: - -```lua -{ level1, time1, msg1, level2, time2, msg2, ... } -``` - -The `levelX` values are constants defined below: - -https://github.com/openresty/lua-nginx-module/#nginx-log-level-constants - -The `timeX` values are UNIX timestamps in seconds with millisecond precision. The sub-second part is presented as the decimal part. -The time format is exactly the same as the value returned by [ngx.now](https://github.com/openresty/lua-nginx-module/#ngxnow). It is -also subject to NGINX core's time caching. - -The `msgX` values are the error log message texts. - -So to traverse this array, the user can use a loop like this: - -```lua -for i = 1, #res, 3 do - local level = res[i] - if not level then - break - end - - local time = res[i + 1] - local msg = res[i + 2] - - -- handle the current message with log level in `level`, - -- log time in `time`, and log message body in `msg`. -end -``` - -Specifying `max <= 0` disables this behavior, meaning that the number of -results won't be limited. - -The optional 2th argument `res` can be a user-supplied Lua table -to hold the result instead of creating a brand new table. This can avoid -unnecessary table dynamic allocations on hot Lua code paths. It is used like this: - -```lua -local errlog = require "ngx.errlog" -local new_tab = require "table.new" - -local buffer = new_tab(100 * 3, 0) -- for 100 messages - -local errlog = require "ngx.errlog" -local res, err = errlog.get_logs(0, buffer) -if res then - -- res is the same table as `buffer` - for i = 1, #res, 3 do - local level = res[i] - if not level then - break - end - local time = res[i + 1] - local msg = res[i + 2] - ... - end -end -``` - -When provided with a `res` table, `errlog.get_logs` won't clear the table -for performance reasons, but will rather insert a trailing `nil` value -after the last table element. - -When the trailing `nil` is not enough for your purpose, you should -clear the table yourself before feeding it into the `errlog.get_logs` function. - -[Back to TOC](#table-of-contents) - -get_sys_filter_level --------------------- -**syntax:** *log_level = log_module.get_sys_filter_level()* - -**context:** *any* - -Return the nginx core's error log filter level (defined via the [error_log](http://nginx.org/r/error_log) -configuration directive in `nginx.conf`) as an integer value matching the nginx error log level -constants documented below: - -https://github.com/openresty/lua-nginx-module/#nginx-log-level-constants - -For example: - -```lua -local errlog = require "ngx.errlog" -local log_level = errlog.get_sys_filter_level() --- Now the filter level is always one level higher than system default log level on priority -local status, err = errlog.set_filter_level(log_level - 1) -if not status then - ngx.log(ngx.ERR, err) - return -end -``` - -[Back to TOC](#table-of-contents) - -raw_log -------- -**syntax:** *log_module.raw_log(log_level, msg)* - -**context:** *any* - -Log `msg` to the error logs with the given logging level. - -Just like the [ngx.log](https://github.com/openresty/lua-nginx-module#ngxlog) -API, the `log_level` argument can take constants like `ngx.ERR` and `ngx.WARN`. -Check out [Nginx log level constants for -details.](https://github.com/openresty/lua-nginx-module#nginx-log-level-constants) - -However, unlike the `ngx.log` API which accepts variadic arguments, this -function only accepts a single string as its second argument `msg`. - -This function differs from `ngx.log` in the way that it will not prefix the -written logs with any sort of debug information (such as the caller's file -and line number). - -For example, while `ngx.log` would produce - -``` -2017/07/09 19:36:25 [notice] 25932#0: *1 [lua] content_by_lua(nginx.conf:51):5: hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" -``` - -from - -```lua -ngx.log(ngx.NOTICE, "hello world") -``` - -the `errlog.raw_log()` call produces - -``` -2017/07/09 19:36:25 [notice] 25932#0: *1 hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" -``` - -from - -```lua -local errlog = require "ngx.errlog" -errlog.raw_log(ngx.NOTICE, "hello world") -``` - -This function is best suited when the format and/or stack level of the debug -information proposed by `ngx.log` is not desired. A good example of this would -be a custom logging function which prefixes each log with a namespace in -an application: - -``` -1. local function my_log(lvl, ...) -2. ngx.log(lvl, "[prefix] ", ...) -3. end -4. -5. my_log(ngx.ERR, "error") -``` - -Here, the produced log would indicate that this error was logged at line `2.`, -when in reality, we wish the investigator of that log to realize it was logged -at line `5.` right away. - -For such use cases (or other formatting reasons), one may use `raw_log` to -create a logging utility that supports such requirements. Here is a suggested -implementation: - -```lua -local errlog = require "ngx.errlog" - -local function my_log(lvl, ...) - -- log to error logs with our custom prefix, stack level - -- and separator - local n = select("#", ...) - local t = { ... } - local info = debug.getinfo(2, "Sl") - - local prefix = string.format("(%s):%d:", info.short_src, info.currentline) - local buf = { prefix } - - for i = 1, n do - buf[i + 1] = tostring(t[i]) - end - - local msg = table.concat(buf, " ") - - errlog.raw_log(lvl, msg) -- line 19. -end - -local function my_function() - -- do something and log - - my_log(ngx.ERR, "hello from", "raw_log:", true) -- line 25. -end - -my_function() -``` - -This utility function will produce the following log, explicitly stating that -the error was logged on line `25.`: - -``` -2017/07/09 20:03:07 [error] 26795#0: *2 (/path/to/file.lua):25: hello from raw_log: true, context: ngx.timer -``` - -As a reminder to the reader, one must be wary of the cost of string -concatenation on the Lua land, and should prefer the combined use of a buffer -table and `table.concat` to avoid unnecessary GC pressure. - -[Back to TOC](#table-of-contents) - -Community -========= - -[Back to TOC](#table-of-contents) - -English Mailing List --------------------- - -The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. - -[Back to TOC](#table-of-contents) - -Chinese Mailing List --------------------- - -The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. - -[Back to TOC](#table-of-contents) - -Bugs and Patches -================ - -Please report bugs or submit patches by - -1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), -1. or posting to the [OpenResty community](#community). - -[Back to TOC](#table-of-contents) - -Author -====== - -Yuansheng Wang <membphis@gmail.com> (membphis), OpenResty Inc. - -[Back to TOC](#table-of-contents) - -Copyright and License -===================== - -This module is licensed under the BSD license. - -Copyright (C) 2017, by Yichun "agentzh" Zhang, OpenResty Inc. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -[Back to TOC](#table-of-contents) - -See Also -======== -* library [lua-resty-core](https://github.com/openresty/lua-resty-core) -* the ngx_lua module: https://github.com/openresty/lua-nginx-module -* OpenResty: http://openresty.org - -[Back to TOC](#table-of-contents) - diff --git a/rootfs/etc/nginx/lua/vendor/ngx/ocsp.lua b/rootfs/etc/nginx/lua/vendor/ngx/ocsp.lua deleted file mode 100644 index 53c1acc957..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/ocsp.lua +++ /dev/null @@ -1,150 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local base = require "resty.core.base" -base.allows_subsystem('http') - - -local ffi = require "ffi" -local C = ffi.C -local ffi_str = ffi.string -local getfenv = getfenv -local error = error -local tonumber = tonumber -local errmsg = base.get_errmsg_ptr() -local get_string_buf = base.get_string_buf -local get_string_buf_size = base.get_string_buf_size -local get_size_ptr = base.get_size_ptr -local FFI_DECLINED = base.FFI_DECLINED -local FFI_OK = base.FFI_OK -local FFI_BUSY = base.FFI_BUSY - - -ffi.cdef[[ -int ngx_http_lua_ffi_ssl_get_ocsp_responder_from_der_chain( - const char *chain_data, size_t chain_len, char *out, size_t *out_size, - char **err); - -int ngx_http_lua_ffi_ssl_create_ocsp_request(const char *chain_data, - size_t chain_len, unsigned char *out, size_t *out_size, char **err); - -int ngx_http_lua_ffi_ssl_validate_ocsp_response(const unsigned char *resp, - size_t resp_len, const char *chain_data, size_t chain_len, - unsigned char *errbuf, size_t *errbuf_size); - -int ngx_http_lua_ffi_ssl_set_ocsp_status_resp(ngx_http_request_t *r, - const unsigned char *resp, size_t resp_len, char **err); -]] - - -local _M = { version = base.version } - - -function _M.get_ocsp_responder_from_der_chain(certs, maxlen) - - local buf_size = maxlen - if not buf_size then - buf_size = get_string_buf_size() - end - local buf = get_string_buf(buf_size) - - local sizep = get_size_ptr() - sizep[0] = buf_size - - local rc = C.ngx_http_lua_ffi_ssl_get_ocsp_responder_from_der_chain(certs, - #certs, buf, sizep, errmsg) - - if rc == FFI_DECLINED then - return nil - end - - if rc == FFI_OK then - return ffi_str(buf, sizep[0]) - end - - if rc == FFI_BUSY then - return ffi_str(buf, sizep[0]), "truncated" - end - - return nil, ffi_str(errmsg[0]) -end - - -function _M.create_ocsp_request(certs, maxlen) - - local buf_size = maxlen - if not buf_size then - buf_size = get_string_buf_size() - end - local buf = get_string_buf(buf_size) - - local sizep = get_size_ptr() - sizep[0] = buf_size - - local rc = C.ngx_http_lua_ffi_ssl_create_ocsp_request(certs, - #certs, buf, sizep, - errmsg) - - if rc == FFI_OK then - return ffi_str(buf, sizep[0]) - end - - if rc == FFI_BUSY then - return nil, ffi_str(errmsg[0]) .. ": " .. tonumber(sizep[0]) - .. " > " .. buf_size - end - - return nil, ffi_str(errmsg[0]) -end - - -function _M.validate_ocsp_response(resp, chain, max_errmsg_len) - - local errbuf_size = max_errmsg_len - if not errbuf_size then - errbuf_size = get_string_buf_size() - end - local errbuf = get_string_buf(errbuf_size) - - local sizep = get_size_ptr() - sizep[0] = errbuf_size - - local rc = C.ngx_http_lua_ffi_ssl_validate_ocsp_response( - resp, #resp, chain, #chain, errbuf, sizep) - - if rc == FFI_OK then - return true - end - - -- rc == FFI_ERROR - - return nil, ffi_str(errbuf, sizep[0]) -end - - -function _M.set_ocsp_status_resp(ocsp_resp) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local rc = C.ngx_http_lua_ffi_ssl_set_ocsp_status_resp(r, ocsp_resp, - #ocsp_resp, - errmsg) - - if rc == FFI_DECLINED then - -- no client status req - return true, "no status req" - end - - if rc == FFI_OK then - return true - end - - -- rc == FFI_ERROR - - return nil, ffi_str(errmsg[0]) -end - - -return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/ocsp.md b/rootfs/etc/nginx/lua/vendor/ngx/ocsp.md deleted file mode 100644 index 62c230810c..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/ocsp.md +++ /dev/null @@ -1,298 +0,0 @@ -Name -==== - -ngx.ocsp - Lua API for implementing OCSP stapling in ssl_certificate_by_lua* - -Table of Contents -================= - -* [Name](#name) -* [Status](#status) -* [Synopsis](#synopsis) -* [Description](#description) -* [Methods](#methods) - * [get_ocsp_responder_from_der_chain](#get_ocsp_responder_from_der_chain) - * [create_ocsp_request](#create_ocsp_request) - * [validate_ocsp_response](#validate_ocsp_response) - * [set_ocsp_status_resp](#set_ocsp_status_resp) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Bugs and Patches](#bugs-and-patches) -* [Author](#author) -* [Copyright and License](#copyright-and-license) -* [See Also](#see-also) - -Status -====== - -This Lua module is currently considered experimental. - -Synopsis -======== - -```nginx -# Note: you do not need the following line if you are using -# OpenResty 1.9.7.2+. -lua_package_path "/path/to/lua-resty-core/lib/?.lua;;"; - -server { - listen 443 ssl; - server_name test.com; - - # useless placeholders: just to shut up NGINX configuration - # loader errors: - ssl_certificate /path/to/fallback.crt; - ssl_certificate_key /path/to/fallback.key; - - ssl_certificate_by_lua_block { - local ssl = require "ngx.ssl" - local ocsp = require "ngx.ocsp" - local http = require "resty.http.simple" - - -- assuming the user already defines the my_load_certificate_chain() - -- herself. - local pem_cert_chain = assert(my_load_certificate_chain()) - - local der_cert_chain, err = ssl.cert_pem_to_der(pem_cert_chain) - if not der_cert_chain then - ngx.log(ngx.ERR, "failed to convert certificate chain ", - "from PEM to DER: ", err) - return ngx.exit(ngx.ERROR) - end - - local ocsp_url, err = ocsp.get_ocsp_responder_from_der_chain(der_cert_chain) - if not ocsp_url then - ngx.log(ngx.ERR, "failed to get OCSP responder: ", err) - return ngx.exit(ngx.ERROR) - end - - print("ocsp_url: ", ocsp_url) - - -- use cosocket-based HTTP client libraries like lua-resty-http-simple - -- to send the request (url + ocsp_req as POST params or URL args) to - -- CA's OCSP server. assuming the server returns the OCSP response - -- in the Lua variable, resp. - - local schema, host, port, ocsp_uri, err = parse_url(ocsp_url) - - local ocsp_req, err = ocsp.create_ocsp_request(der_cert_chain) - if not ocsp_req then - ngx.log(ngx.ERR, "failed to create OCSP request: ", err) - return ngx.exit(ngx.ERROR) - end - - local res, err = http.request(host, port, { - path = ocsp_uri, - headers = { Host = host, - ["Content-Type"] = "application/ocsp-request" }, - timeout = 10000, -- 10 sec - method = "POST", - body = ocsp_req, - maxsize = 102400, -- 100KB - }) - - if not res then - ngx.log(ngx.ERR, "OCSP responder query failed: ", err) - return ngx.exit(ngx.ERROR) - end - - local http_status = res.status - - if http_status ~= 200 then - ngx.log(ngx.ERR, "OCSP responder returns bad HTTP status code ", - http_status) - return ngx.exit(ngx.ERROR) - end - - local ocsp_resp = res.body - - if ocsp_resp and #ocsp_resp > 0 then - local ok, err = ocsp.validate_ocsp_response(ocsp_resp, der_cert_chain) - if not ok then - ngx.log(ngx.ERR, "failed to validate OCSP response: ", err) - return ngx.exit(ngx.ERROR) - end - - -- set the OCSP stapling - ok, err = ocsp.set_ocsp_status_resp(ocsp_resp) - if not ok then - ngx.log(ngx.ERR, "failed to set ocsp status resp: ", err) - return ngx.exit(ngx.ERROR) - end - end - } - - location / { - root html; - } -} - -``` - -Description -=========== - -This Lua module provides API to perform OCSP queries, OCSP response validations, and -OCSP stapling planting. - -Usually, this module is used together with the [ngx.ssl](ssl.md) module in the -context of [ssl_certificate_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_certificate_by_lua_block) -(of the [ngx_lua](https://github.com/openresty/lua-nginx-module#readme) module). - -To load the `ngx.ocsp` module in Lua, just write - -```lua -local ocsp = require "ngx.ocsp" -``` - -[Back to TOC](#table-of-contents) - -Methods -======= - -get_ocsp_responder_from_der_chain ---------------------------------- -**syntax:** *ocsp_url, err = ocsp.get_ocsp_responder_from_der_chain(der_cert_chain, max_len)* - -**context:** *any* - -Extracts the OCSP responder URL (like `"http://test.com/ocsp/"`) from the SSL server certificate chain in the DER format. - -Usually the SSL server certificate chain is originally formatted in PEM. You can use the Lua API -provided by the [ngx.ssl](ssl.md) module to do the PEM to DER conversion. - -The optional `max_len` argument specifies the maximum length of OCSP URL allowed. This determines -the buffer size; so do not specify an unnecessarily large value here. It defaults to the internal -string buffer size used throughout this `lua-resty-core` library (usually default to 4KB). - -In case of failures, returns `nil` and a string describing the error. - -[Back to TOC](#table-of-contents) - -create_ocsp_request -------------------- -**syntax:** *ocsp_req, err = ocsp.create_ocsp_request(der_cert_chain, max_len)* - -**context:** *any* - -Builds an OCSP request from the SSL server certificate chain in the DER format, which -can be used to send to the OCSP server for validation. - -The optional `max_len` argument specifies the maximum length of the OCSP request allowed. -This value determines the size of the internal buffer allocated, so do not specify an -unnecessarily large value here. It defaults to the internal string buffer size used -throughout this `lua-resty-core` library (usually defaults to 4KB). - -In case of failures, returns `nil` and a string describing the error. - -The raw OCSP response data can be used as the request body directly if the POST method -is used for the OCSP request. But for GET requests, you need to do base64 encoding and -then URL encoding on the data yourself before appending it to the OCSP URL obtained -by the [get_ocsp_responder_from_der_chain](#get_ocsp_responder_from_der_chain) function. - -[Back to TOC](#table-of-contents) - -validate_ocsp_response ----------------------- -**syntax:** *ok, err = ocsp.validate_ocsp_response(ocsp_resp, der_cert_chain, max_err_msg_len)* - -**context:** *any* - -Validates the raw OCSP response data specified by the `ocsp_resp` argument using the SSL -server certificate chain in DER format as specified in the `der_cert_chain` argument. - -Returns true when the validation is successful. - -In case of failures, returns `nil` and a string -describing the failure. The maximum -length of the error string is controlled by the optional `max_err_msg` argument (which defaults -to the default internal string buffer size used throughout this `lua-resty-core` library, usually -being 4KB). - -[Back to TOC](#table-of-contents) - -set_ocsp_status_resp --------------------- -**syntax:** *ok, err = ocsp.set_ocsp_status_resp(ocsp_resp)* - -**context:** *ssl_certificate_by_lua** - -Sets the OCSP response as the OCSP stapling for the current SSL connection. - -Returns `true` in case of successes. If the SSL client does not send a "status request" -at all, then this method still returns `true` but also with a string as the warning -`"no status req"`. - -In case of failures, returns `nil` and a string describing the error. - -The OCSP response is returned from CA's OCSP server. See the [create_ocsp_request](#create_ocsp_request) -function for how to create an OCSP request and also [validate_ocsp_response](#validate_ocsp_response) -for how to validate the OCSP response. - -[Back to TOC](#table-of-contents) - -Community -========= - -[Back to TOC](#table-of-contents) - -English Mailing List --------------------- - -The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. - -[Back to TOC](#table-of-contents) - -Chinese Mailing List --------------------- - -The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. - -[Back to TOC](#table-of-contents) - -Bugs and Patches -================ - -Please report bugs or submit patches by - -1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), -1. or posting to the [OpenResty community](#community). - -[Back to TOC](#table-of-contents) - -Author -====== - -Yichun Zhang <agentzh@gmail.com> (agentzh), OpenResty Inc. - -[Back to TOC](#table-of-contents) - -Copyright and License -===================== - -This module is licensed under the BSD license. - -Copyright (C) 2015-2017, by Yichun "agentzh" Zhang, OpenResty Inc. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -[Back to TOC](#table-of-contents) - -See Also -======== -* the ngx_lua module: https://github.com/openresty/lua-nginx-module -* the [ngx.ssl](ssl.md) module. -* the [ssl_certificate_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_certificate_by_lua_block) directive. -* library [lua-resty-core](https://github.com/openresty/lua-resty-core) -* OpenResty: http://openresty.org - -[Back to TOC](#table-of-contents) diff --git a/rootfs/etc/nginx/lua/vendor/ngx/process.lua b/rootfs/etc/nginx/lua/vendor/ngx/process.lua deleted file mode 100644 index 80fa2b19a4..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/process.lua +++ /dev/null @@ -1,74 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local base = require "resty.core.base" -base.allows_subsystem('http') - - -local ffi = require 'ffi' -local errmsg = base.get_errmsg_ptr() -local FFI_ERROR = base.FFI_ERROR -local ffi_str = ffi.string -local ngx_phase = ngx.get_phase -local tonumber = tonumber - - -local process_type_names = { - [0 ] = "single", - [1 ] = "master", - [2 ] = "signaller", - [3 ] = "worker", - [4 ] = "helper", - [99] = "privileged agent", -} - - -local C = ffi.C -local _M = { version = base.version } - - -ffi.cdef[[ -int ngx_http_lua_ffi_enable_privileged_agent(char **err); -int ngx_http_lua_ffi_get_process_type(void); -void ngx_http_lua_ffi_process_signal_graceful_exit(void); -int ngx_http_lua_ffi_master_pid(void); -]] - - -function _M.type() - local typ = C.ngx_http_lua_ffi_get_process_type() - return process_type_names[tonumber(typ)] -end - - -function _M.enable_privileged_agent() - if ngx_phase() ~= "init" then - return nil, "API disabled in the current context" - end - - local rc = C.ngx_http_lua_ffi_enable_privileged_agent(errmsg) - - if rc == FFI_ERROR then - return nil, ffi_str(errmsg[0]) - end - - return true -end - - -function _M.signal_graceful_exit() - C.ngx_http_lua_ffi_process_signal_graceful_exit() -end - - -function _M.get_master_pid() - local pid = C.ngx_http_lua_ffi_master_pid() - if pid == FFI_ERROR then - return nil - end - - return tonumber(pid) -end - - -return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/process.md b/rootfs/etc/nginx/lua/vendor/ngx/process.md deleted file mode 100644 index 30b6630dd3..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/process.md +++ /dev/null @@ -1,230 +0,0 @@ -Name -==== - -`ngx.process` - manage the nginx processes for OpenResty/ngx_lua. - -Table of Contents -================= - -* [Name](#name) -* [Status](#status) -* [Synopsis](#synopsis) -* [Functions](#functions) - * [type](#type) - * [enable_privileged_agent](#enable_privileged_agent) - * [signal_graceful_exit](#signal_graceful_exit) - * [get_master_pid](#get_master_pid) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Bugs and Patches](#bugs-and-patches) -* [Author](#author) -* [Copyright and License](#copyright-and-license) -* [See Also](#see-also) - -Status -====== - -This Lua module is currently considered experimental. -The API is still in flux and may change in the future without notice. - -Synopsis -======== - -Enables privileged agent process, gets process type, and then gets the master process PID: - -```nginx -# http config -init_by_lua_block { - local process = require "ngx.process" - - -- enables privileged agent process - local ok, err = process.enable_privileged_agent() - if not ok then - ngx.log(ngx.ERR, "enables privileged agent failed error:", err) - end - - -- output process type - ngx.log(ngx.INFO, "process type: ", process.type()) -} - -init_worker_by_lua_block { - local process = require "ngx.process" - ngx.log(ngx.INFO, "process type: ", process.type()) -} - -server { - # ... - location = /t { - content_by_lua_block { - local process = require "ngx.process" - ngx.say("process type: ", process.type()) - ngx.say("master process pid: ", process.get_master_pid() or "-") - } - } -} - -``` - -The example config above produces an output to `error.log` when -server starts: - -``` -[lua] init_by_lua:11: process type: master -[lua] init_worker_by_lua:3: process type: privileged agent -[lua] init_worker_by_lua:3: process type: worker -``` - -The example location above produces the following response body: - -``` -process type: worker -master process pid: 8261 -``` - -[Back to TOC](#table-of-contents) - -Functions -========= - -type ----- -**syntax:** *type_name = process_module.type()* - -**context:** *any* - -Returns the current process's type name. Here are all of the names: - -``` -single -master -signaller -worker -helper -privileged agent -``` - -For example, - -```lua - local process = require "ngx.process" - ngx.say("process type:", process.type()) -- RESPONSE: worker -``` - -[Back to TOC](#table-of-contents) - -enable_privileged_agent ------------------------ -**syntax:** *ok, err = process_module.enable_privileged_agent()* - -**context:** *init_by_lua** - -Enables the privileged agent process in Nginx. - -The priviledged agent process does not listen on any virtual server ports like those worker processes. -And it uses the same system account as the nginx master process, which is usually a privileged account -like `root`. - -The `init_worker_by_lua*` directive handler still runs in the privileged agent process. And one can -use the [type](#type) function provided by this module to check if the current process is a privileged -agent. - -In case of failures, returns `nil` and a string describing the error. - -[Back to TOC](#table-of-contents) - -signal_graceful_exit --------------------- -**syntax:** *process_module.signal_graceful_exit()* - -**context:** *any* - -Signals the *current* nginx (worker) process to quit gracefully, i.e., after all the timers have expired (in time or expired prematurely). - -Note that this API function simply sets the nginx global C variable `ngx_quit` to signal the nginx event -loop directly. No UNIX signals or IPC are involved here. - -WARNING: the official NGINX core does not perform the graceful exiting procedure when the [master_process](http://nginx.org/r/master_process) -directive is turned `off`. The OpenResty's NGINX core has a -[custom patch](https://github.com/openresty/openresty/blob/master/patches/nginx-1.11.2-single_process_graceful_exit.patch) -applied, which fixes this issue. - -[Back to TOC](#table-of-contents) - -get_master_pid --------------- -**syntax:** *pid = process_module.get_master_pid()* - -**context:** *any* - -Returns a number value for the nginx master process's process ID (or PID). - -This function requires NGINX 1.13.8+ cores to work properly. Otherwise it returns `nil`. - -This feature first appeared in lua-resty-core v0.1.14. - -[Back to TOC](#table-of-contents) - -Community -========= - -[Back to TOC](#table-of-contents) - -English Mailing List --------------------- - -The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. - -[Back to TOC](#table-of-contents) - -Chinese Mailing List --------------------- - -The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. - -[Back to TOC](#table-of-contents) - -Bugs and Patches -================ - -Please report bugs or submit patches by - -1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), -1. or posting to the [OpenResty community](#community). - -[Back to TOC](#table-of-contents) - -Author -====== - -Yuansheng Wang <membphis@gmail.com> (membphis), OpenResty Inc. - -[Back to TOC](#table-of-contents) - -Copyright and License -===================== - -This module is licensed under the BSD license. - -Copyright (C) 2017, by Yichun "agentzh" Zhang, OpenResty Inc. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -[Back to TOC](#table-of-contents) - -See Also -======== -* library [lua-resty-core](https://github.com/openresty/lua-resty-core) -* the ngx_lua module: https://github.com/openresty/lua-nginx-module -* OpenResty: http://openresty.org - -[Back to TOC](#table-of-contents) - diff --git a/rootfs/etc/nginx/lua/vendor/ngx/re.lua b/rootfs/etc/nginx/lua/vendor/ngx/re.lua deleted file mode 100644 index 09dd2ea560..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/re.lua +++ /dev/null @@ -1,284 +0,0 @@ --- I hereby assign copyright in this code to the lua-resty-core project, --- to be licensed under the same terms as the rest of the code. - - -local base = require "resty.core.base" -base.allows_subsystem('http') - - -local ffi = require 'ffi' -local bit = require "bit" -local core_regex = require "resty.core.regex" - - -local C = ffi.C -local ffi_str = ffi.string -local sub = string.sub -local error = error -local type = type -local band = bit.band -local new_tab = base.new_tab -local tostring = tostring -local math_max = math.max -local math_min = math.min -local is_regex_cache_empty = core_regex.is_regex_cache_empty -local re_match_compile = core_regex.re_match_compile -local destroy_compiled_regex = core_regex.destroy_compiled_regex -local get_string_buf = base.get_string_buf -local get_size_ptr = base.get_size_ptr -local FFI_OK = base.FFI_OK - - -local MAX_ERR_MSG_LEN = 128 -local FLAG_DFA = 0x02 -local PCRE_ERROR_NOMATCH = -1 -local DEFAULT_SPLIT_RES_SIZE = 4 - - -local split_ctx = new_tab(0, 1) - - -ffi.cdef[[ -int ngx_http_lua_ffi_set_jit_stack_size(int size, unsigned char *errstr, - size_t *errstr_size); -]] - - -local _M = { version = base.version } - - -local function re_split_helper(subj, compiled, compile_once, flags, ctx) - local rc - do - local pos = math_max(ctx.pos, 0) - - rc = C.ngx_http_lua_ffi_exec_regex(compiled, flags, subj, #subj, pos) - end - - if rc == PCRE_ERROR_NOMATCH then - return nil, nil, nil - end - - if rc < 0 then - if not compile_once then - destroy_compiled_regex(compiled) - end - return nil, nil, nil, "pcre_exec() failed: " .. rc - end - - if rc == 0 then - if band(flags, FLAG_DFA) == 0 then - if not compile_once then - destroy_compiled_regex(compiled) - end - return nil, nil, nil, "capture size too small" - end - - rc = 1 - end - - local caps = compiled.captures - local ncaps = compiled.ncaptures - - local from = caps[0] - local to = caps[1] - - if from < 0 or to < 0 then - return nil, nil, nil - end - - if from == to then - -- empty match, skip to next char - ctx.pos = to + 1 - - else - ctx.pos = to - end - - -- convert to Lua string indexes - - from = from + 1 - to = to + 1 - - -- retrieve the first sub-match capture if any - - if ncaps > 0 and rc > 1 then - return from, to, sub(subj, caps[2] + 1, caps[3]) - end - - return from, to -end - - -function _M.split(subj, regex, opts, ctx, max, res) - -- we need to cast this to strings to avoid exceptions when they are - -- something else. - -- needed because of further calls to string.sub in this function. - subj = tostring(subj) - - if not ctx then - ctx = split_ctx - ctx.pos = 1 -- set or reset upvalue field - - elseif not ctx.pos then - -- ctx provided by user but missing pos field - ctx.pos = 1 - end - - max = max or 0 - - if not res then - -- limit the initial arr_n size of res to a reasonable value - -- 0 < narr <= DEFAULT_SPLIT_RES_SIZE - local narr = DEFAULT_SPLIT_RES_SIZE - if max > 0 then - -- the user specified a valid max limiter if max > 0 - narr = math_min(narr, max) - end - - res = new_tab(narr, 0) - - elseif type(res) ~= "table" then - error("res is not a table", 2) - end - - local len = #subj - if ctx.pos > len then - res[1] = nil - return res - end - - -- compile regex - - local compiled, compile_once, flags = re_match_compile(regex, opts) - if compiled == nil then - -- compiled_once holds the error string - return nil, compile_once - end - - local sub_idx = ctx.pos - local res_idx = 0 - local last_empty_match - - -- update to split_helper PCRE indexes - ctx.pos = sub_idx - 1 - - -- splitting: with and without a max limiter - - if max > 0 then - local count = 1 - - while count < max do - local from, to, capture, err = re_split_helper(subj, compiled, - compile_once, flags, ctx) - if err then - return nil, err - end - - if not from then - break - end - - if last_empty_match then - sub_idx = last_empty_match - end - - if from == to then - last_empty_match = from - end - - if from > sub_idx or not last_empty_match then - count = count + 1 - res_idx = res_idx + 1 - res[res_idx] = sub(subj, sub_idx, from - 1) - - if capture then - res_idx = res_idx + 1 - res[res_idx] = capture - end - - sub_idx = to - - if sub_idx >= len then - break - end - end - end - - else - while true do - local from, to, capture, err = re_split_helper(subj, compiled, - compile_once, flags, ctx) - if err then - return nil, err - end - - if not from then - break - end - - if last_empty_match then - sub_idx = last_empty_match - end - - if from == to then - last_empty_match = from - end - - if from > sub_idx or not last_empty_match then - res_idx = res_idx + 1 - res[res_idx] = sub(subj, sub_idx, from - 1) - - if capture then - res_idx = res_idx + 1 - res[res_idx] = capture - end - - sub_idx = to - - if sub_idx >= len then - break - end - end - end - - end - - if not compile_once then - destroy_compiled_regex(compiled) - end - - -- trailing nil for non-cleared res tables - - res[res_idx + 1] = sub(subj, sub_idx) - res[res_idx + 2] = nil - - return res -end - - -function _M.opt(option, value) - if option == "jit_stack_size" then - if not is_regex_cache_empty() then - error("changing jit stack size is not allowed when some " .. - "regexs have already been compiled and cached") - end - - local errbuf = get_string_buf(MAX_ERR_MSG_LEN) - local sizep = get_size_ptr() - sizep[0] = MAX_ERR_MSG_LEN - - local rc = C.ngx_http_lua_ffi_set_jit_stack_size(value, errbuf, sizep) - - if rc == FFI_OK then - return - end - - error(ffi_str(errbuf, sizep[0])) - end - - error("unrecognized option name") -end - - -return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/re.md b/rootfs/etc/nginx/lua/vendor/ngx/re.md deleted file mode 100644 index 1c97ff6680..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/re.md +++ /dev/null @@ -1,249 +0,0 @@ -Name -==== - -ngx.re - Lua API for convenience utilities for `ngx.re`. - -Table of Contents -================= - -* [Name](#name) -* [Status](#status) -* [Synopsis](#synopsis) -* [Description](#description) -* [Methods](#methods) - * [split](#split) - * [opt](#opt) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Bugs and Patches](#bugs-and-patches) -* [Author](#author) -* [Copyright and License](#copyright-and-license) -* [See Also](#see-also) - -Status -====== - -This Lua module is currently considered experimental. - -Synopsis -======== - -```lua -local ngx_re = require "ngx.re" - --- split -local res, err = ngx_re.split("a,b,c,d", ",") ---> res is now {"a", "b", "c", "d"} - --- opt -ngx_re.opt("jit_stack_size", 128 * 1024) ---> the PCRE jit stack can now handle more complex regular expressions -``` - -[Back to TOC](#table-of-contents) - -Description -=========== - -This Lua module provides a Lua API which implements convenience utilities for -the `ngx.re` API. - -[Back to TOC](#table-of-contents) - -Methods -======= - -All the methods of this module are static (or module-level). That is, you do -not need an object (or instance) to call these methods. - -[Back to TOC](#table-of-contents) - -split ------ -**syntax:** *res, err = ngx_re.split(subject, regex, options?, ctx?, max?, res?)* - -Splits the `subject` string using the Perl compatible regular expression -`regex` with the optional `options`. - -This function returns a Lua (array) table (with integer keys) containing the -splitted values. - -In case of error, `nil` will be returned as well as a string describing the -error. - -When `regex` contains a sub-match capturing group, and when such a match is -found, the first submatch capture will be inserted in between each splitted -value, like so: - -```lua -local ngx_re = require "ngx.re" - -local res, err = ngx_re.split("a,b,c,d", "(,)") --- res is now {"a", ",", "b", ",", "c", ",", "d"} -``` - -When `regex` is empty string `""`, the `subject` will be split into chars, -like so: - -```lua -local ngx_re = require "ngx.re" - -local res, err = ngx_re.split("abcd", "") --- res is now {"a", "b", "c", "d"} -``` - -The optional `ctx` table argument can be a Lua table holding an optional `pos` -field. When the `pos` field in the `ctx` table argument is specified, -`ngx_re.split` will start splitting the `subject` from that index: - -```lua -local ngx_re = require "ngx.re" - -local res, err = ngx_re.split("a,b,c,d", ",", nil, {pos = 5}) --- res is now {"c", "d"} -``` - -The optional `max` argument is a number that when specified, will prevent -`ngx_re.split` from adding more than `max` matches to the `res` array: - -```lua -local ngx_re = require "ngx.re" - -local res, err = ngx_re.split("a,b,c,d", ",", nil, nil, 3) --- res is now {"a", "b", "c,d"} -``` - -Specifying `max <= 0` disables this behavior, meaning that the number of -results won't be limited. - -The optional 6th argument `res` can be a table that `ngx_re.split` will re-use -to hold the results instead of creating a new one, which can improve -performance in hot code paths. It is used like so: - -```lua -local ngx_re = require "ngx.re" - -local my_table = {"hello world"} - -local res, err = ngx_re.split("a,b,c,d", ",", nil, nil, nil, my_table) --- res/my_table is now {"a", "b", "c", "d"} -``` - -When provided with a `res` table, `ngx_re.split` won't clear the table -for performance reasons, but will rather insert a trailing `nil` value -when the split is completed: - -```lua -local ngx_re = require "ngx.re" - -local my_table = {"W", "X", "Y", "Z"} - -local res, err = ngx_re.split("a,b", ",", nil, nil, nil, my_table) --- res/my_table is now {"a", "b", nil, "Z"} -``` - -When the trailing `nil` is not enough for your purpose, you should -clear the table yourself before feeding it into the `split` function. - -[Back to TOC](#table-of-contents) - -opt ------ -**syntax:** *ngx_re.opt(option, value)* - -Allows changing of regex settings. Currently, it can only change the -`jit_stack_size` of the PCRE engine, like so: - -```nginx - - init_by_lua_block { require "ngx.re".opt("jit_stack_size", 200 * 1024) } - - server { - location /re { - content_by_lua_block { - -- full regex and string are taken from https://github.com/JuliaLang/julia/issues/8278 - local very_long_string = [[71.163.72.113 - - [30/Jul/2014:16:40:55 -0700] ...]] - local very_complicated_regex = [[([\d\.]+) ([\w.-]+) ([\w.-]+) (\[.+\]) ...]] - local from, to, err = ngx.re.find(very_long_string, very_complicated_regex, "jo") - - -- with the regular jit_stack_size, we would get the error 'pcre_exec() failed: -27' - -- instead, we get a match - ngx.print(from .. "-" .. to) -- prints '1-1563' - } - } - } -``` - -The `jit_stack_size` cannot be set to a value lower than PCRE's default of 32K. - -This method requires the PCRE library enabled in Nginx. - -This feature was first introduced in the `v0.1.12` release. - -[Back to TOC](#table-of-contents) - -Community -========= - -[Back to TOC](#table-of-contents) - -English Mailing List --------------------- - -The [openresty-en](https://groups.google.com/group/openresty-en) mailing list -is for English speakers. - -[Back to TOC](#table-of-contents) - -Chinese Mailing List --------------------- - -The [openresty](https://groups.google.com/group/openresty) mailing list is for -Chinese speakers. - -[Back to TOC](#table-of-contents) - -Bugs and Patches -================ - -Please report bugs or submit patches by - -1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), -1. or posting to the [OpenResty community](#community). - -[Back to TOC](#table-of-contents) - -Author -====== - -Thibault Charbonnier - ([@thibaultcha](https://github.com/thibaultcha)) - -[Back to TOC](#table-of-contents) - -Copyright and License -===================== - -This module is licensed under the BSD license. - -Copyright (C) 2016-2017, by Yichun "agentzh" Zhang, OpenResty Inc. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -[Back to TOC](#table-of-contents) - -See Also -======== -* library [lua-resty-core](https://github.com/openresty/lua-resty-core) -* the ngx_lua module: https://github.com/openresty/lua-nginx-module -* OpenResty: http://openresty.org - -[Back to TOC](#table-of-contents) diff --git a/rootfs/etc/nginx/lua/vendor/ngx/semaphore.lua b/rootfs/etc/nginx/lua/vendor/ngx/semaphore.lua deleted file mode 100644 index cd5101bb12..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/semaphore.lua +++ /dev/null @@ -1,152 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) --- Copyright (C) cuiweixie --- I hereby assign copyright in this code to the lua-resty-core project, --- to be licensed under the same terms as the rest of the code. - - -local base = require "resty.core.base" -base.allows_subsystem('http') - - -local ffi = require 'ffi' -local FFI_OK = base.FFI_OK -local FFI_ERROR = base.FFI_ERROR -local FFI_DECLINED = base.FFI_DECLINED -local ffi_new = ffi.new -local ffi_str = ffi.string -local ffi_gc = ffi.gc -local C = ffi.C -local type = type -local error = error -local tonumber = tonumber -local getfenv = getfenv -local get_string_buf = base.get_string_buf -local get_size_ptr = base.get_size_ptr -local setmetatable = setmetatable -local co_yield = coroutine._yield -local ERR_BUF_SIZE = 128 - - -local errmsg = base.get_errmsg_ptr() - - -ffi.cdef[[ - struct ngx_http_lua_sema_s; - typedef struct ngx_http_lua_sema_s ngx_http_lua_sema_t; - - int ngx_http_lua_ffi_sema_new(ngx_http_lua_sema_t **psem, - int n, char **errmsg); - - int ngx_http_lua_ffi_sema_post(ngx_http_lua_sema_t *sem, int n); - - int ngx_http_lua_ffi_sema_count(ngx_http_lua_sema_t *sem); - - int ngx_http_lua_ffi_sema_wait(ngx_http_request_t *r, - ngx_http_lua_sema_t *sem, int wait_ms, - unsigned char *errstr, size_t *errlen); - - void ngx_http_lua_ffi_sema_gc(ngx_http_lua_sema_t *sem); -]] - - -local psem = ffi_new("ngx_http_lua_sema_t *[1]") - - -local _M = { version = base.version } -local mt = { __index = _M } - - -function _M.new(n) - n = tonumber(n) or 0 - if n < 0 then - return error("no negative number") - end - - local ret = C.ngx_http_lua_ffi_sema_new(psem, n, errmsg) - if ret == FFI_ERROR then - return nil, ffi_str(errmsg[0]) - end - - local sem = psem[0] - - ffi_gc(sem, C.ngx_http_lua_ffi_sema_gc) - - return setmetatable({ sem = sem }, mt) -end - - -function _M.wait(self, seconds) - if type(self) ~= "table" or type(self.sem) ~= "cdata" then - return error("not a semaphore instance") - end - - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local milliseconds = tonumber(seconds) * 1000 - if milliseconds < 0 then - return error("no negative number") - end - - local cdata_sem = self.sem - - local err = get_string_buf(ERR_BUF_SIZE) - local errlen = get_size_ptr() - errlen[0] = ERR_BUF_SIZE - - local ret = C.ngx_http_lua_ffi_sema_wait(r, cdata_sem, - milliseconds, err, errlen) - - if ret == FFI_ERROR then - return nil, ffi_str(err, errlen[0]) - end - - if ret == FFI_OK then - return true - end - - if ret == FFI_DECLINED then - return nil, "timeout" - end - - -- Note: we cannot use the tail-call form here since we - -- might need the current function call's activation - -- record to hold the reference to our semaphore object - -- to prevent it from getting GC'd prematurely. - local ok - ok, err = co_yield() - return ok, err -end - - -function _M.post(self, n) - if type(self) ~= "table" or type(self.sem) ~= "cdata" then - return error("not a semaphore instance") - end - - local cdata_sem = self.sem - - local num = n and tonumber(n) or 1 - if num < 1 then - return error("no negative number") - end - - -- always return NGX_OK - C.ngx_http_lua_ffi_sema_post(cdata_sem, num) - - return true -end - - -function _M.count(self) - if type(self) ~= "table" or type(self.sem) ~= "cdata" then - return error("not a semaphore instance") - end - - return C.ngx_http_lua_ffi_sema_count(self.sem) -end - - -return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/semaphore.md b/rootfs/etc/nginx/lua/vendor/ngx/semaphore.md deleted file mode 100644 index 8c9314fa6d..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/semaphore.md +++ /dev/null @@ -1,356 +0,0 @@ -Name -==== - -ngx.semaphore - light thread semaphore for OpenResty/ngx_lua. - -Table of Contents -================= - -* [Name](#name) -* [Status](#status) -* [Synopsis](#synopsis) - * [Synchronizing threads in the same context](#synchronizing-threads-in-the-same-context) - * [Synchronizing threads in different contexts](#synchronizing-threads-in-different-contexts) -* [Description](#description) -* [Methods](#methods) - * [new](#new) - * [post](#post) - * [wait](#wait) - * [count](#count) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Bugs and Patches](#bugs-and-patches) -* [Author](#author) -* [Copyright and License](#copyright-and-license) -* [See Also](#see-also) - -Status -====== - -This Lua module is currently considered experimental. - -Synopsis -======== - -Synchronizing threads in the same context ------------------------------------------ - -```nginx -location = /t { - content_by_lua_block { - local semaphore = require "ngx.semaphore" - local sema = semaphore.new() - - local function handler() - ngx.say("sub thread: waiting on sema...") - - local ok, err = sema:wait(1) -- wait for a second at most - if not ok then - ngx.say("sub thread: failed to wait on sema: ", err) - else - ngx.say("sub thread: waited successfully.") - end - end - - local co = ngx.thread.spawn(handler) - - ngx.say("main thread: sleeping for a little while...") - - ngx.sleep(0.1) -- wait a bit - - ngx.say("main thread: posting to sema...") - - sema:post(1) - - ngx.say("main thread: end.") - } -} -``` - -The example location above produces a response output like this: - -``` -sub thread: waiting on sema... -main thread: sleeping for a little while... -main thread: posting to sema... -main thread: end. -sub thread: waited successfully. -``` - -[Back to TOC](#table-of-contents) - -Synchronizing threads in different contexts -------------------------------------------- - -```nginx -location = /t { - content_by_lua_block { - local semaphore = require "ngx.semaphore" - local sema = semaphore.new() - - local outputs = {} - local i = 1 - - local function out(s) - outputs[i] = s - i = i + 1 - end - - local function handler() - out("timer thread: sleeping for a little while...") - - ngx.sleep(0.1) -- wait a bit - - out("timer thread: posting on sema...") - - sema:post(1) - end - - assert(ngx.timer.at(0, handler)) - - out("main thread: waiting on sema...") - - local ok, err = sema:wait(1) -- wait for a second at most - if not ok then - out("main thread: failed to wait on sema: ", err) - else - out("main thread: waited successfully.") - end - - out("main thread: end.") - - ngx.say(table.concat(outputs, "\n")) - } -} -``` - -The example location above produces a response body like this - -``` -main thread: waiting on sema... -timer thread: sleeping for a little while... -timer thread: posting on sema... -main thread: waited successfully. -main thread: end. -``` - -The same applies to different request contexts as long as these requests are served -by the same nginx worker process. - -[Back to TOC](#table-of-contents) - -Description -=========== - -This module provides an efficient semaphore API for the OpenResty/ngx_lua module. With -semaphores, "light threads" (created by [ngx.thread.spawn](https://github.com/openresty/lua-nginx-module#ngxthreadspawn), -[ngx.timer.at](https://github.com/openresty/lua-nginx-module#ngxtimerat), and etc.) can -synchronize among each other very efficiently without constant polling and sleeping. - -"Light threads" in different contexts (like in different requests) can share the same -semaphore instance as long as these "light threads" reside in the same NGINX worker -process and the [lua_code_cache](https://github.com/openresty/lua-nginx-module#lua_code_cache) -directive is turned on (which is the default). For inter-process "light thread" synchronization, -it is recommended to use the [lua-resty-lock](https://github.com/openresty/lua-resty-lock) library instead -(which is a bit less efficient than this semaphore API though). - -This semaphore API has a pure userland implementation which does not involve any system calls nor -block any operating system threads. It works closely with the event model of NGINX without -introducing any extra delay. - -Like other APIs provided by this `lua-resty-core` library, the LuaJIT FFI feature is required. - -[Back to TOC](#table-of-contents) - -Methods -======= - -[Back to TOC](#table-of-contents) - -new ---- -**syntax:** *sema, err = semaphore_module.new(n?)* - -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** - -Creates and returns a new semaphore instance that has `n` (default to `0`) resources. - -For example, - -```lua - local semaphore = require "ngx.semaphore" - local sema, err = semaphore.new() - if not sema then - ngx.say("create semaphore failed: ", err) - end -``` - -Often the semaphore object created is shared on the NGINX worker process by mounting in a custom Lua module, as -documented below: - -https://github.com/openresty/lua-nginx-module#data-sharing-within-an-nginx-worker - -[Back to TOC](#table-of-contents) - -post --------- -**syntax:** *sema:post(n?)* - -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** - -Releases `n` (default to `1`) "resources" to the semaphore instance. - -This will not yield the current running "light thread". - -At most `n` "light threads" will be waken up when the current running "light thread" later yields (or terminates). - -```lua --- typically, we get the semaphore instance from upvalue or globally shared data --- See https://github.com/openresty/lua-nginx-module#data-sharing-within-an-nginx-worker - -local semaphore = require "ngx.semaphore" -local sema = semaphore.new() - -sema:post(2) -- releases 2 resources -``` - -[Back to TOC](#table-of-contents) - -wait ----- -**syntax:** *ok, err = sema:wait(timeout)* - -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** - -Requests a resource from the semaphore instance. - -Returns `true` immediately when there is resources available for the current running "light thread". -Otherwise the current "light thread" will enter the waiting queue and yield execution. -The current "light thread" will be automatically waken up and the `wait` function call -will return `true` when there is resources available for it, or return `nil` and a string describing -the error in case of failure (like `"timeout"`). - -The `timeout` argument specifies the maximum time this function call should wait for (in seconds). - -When the `timeout` argument is 0, it means "no wait", that is, when there is no readily available -"resources" for the current running "light thread", this `wait` function call returns immediately -`nil` and the error string `"timeout"`. - -You can specify millisecond precision in the timeout value by using floating point numbers like 0.001 (which means 1ms). - -"Light threads" created by different contexts (like request handlers) can wait on the -same semaphore instance without problem. - -See [Synopsis](#synopsis) for code examples. - -[Back to TOC](#table-of-contents) - -count --------- -**syntax:** *count = sema:count()* - -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, -content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** - -Returns the number of resources readily available in the `sema` semaphore instance (if any). - -When the returned number is negative, it means the number of "light threads" waiting on -this semaphore. - -Consider the following example, - -```lua -local semaphore = require "ngx.semaphore" -local sema = semaphore.new(0) - -ngx.say("count: ", sema:count()) -- count: 0 - -local function handler(id) - local ok, err = sema:wait(1) - if not ok then - ngx.say("err: ", err) - else - ngx.say("wait success") - end -end - -local co1 = ngx.thread.spawn(handler) -local co2 = ngx.thread.spawn(handler) - -ngx.say("count: ", sema:count()) -- count: -2 - -sema:post(1) - -ngx.say("count: ", sema:count()) -- count: -1 - -sema:post(2) - -ngx.say("count: ", sema:count()) -- count: 1 -``` - -[Back to TOC](#table-of-contents) - -Community -========= - -[Back to TOC](#table-of-contents) - -English Mailing List --------------------- - -The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. - -[Back to TOC](#table-of-contents) - -Chinese Mailing List --------------------- - -The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. - -[Back to TOC](#table-of-contents) - -Bugs and Patches -================ - -Please report bugs or submit patches by - -1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), -1. or posting to the [OpenResty community](#community). - -[Back to TOC](#table-of-contents) - -Author -====== - -Weixie Cui, Kugou Inc. - -[Back to TOC](#table-of-contents) - -Copyright and License -===================== - -This module is licensed under the BSD license. - -Copyright (C) 2015-2017, by Yichun "agentzh" Zhang, OpenResty Inc. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -[Back to TOC](#table-of-contents) - -See Also -======== -* library [lua-resty-core](https://github.com/openresty/lua-resty-core) -* the ngx_lua module: https://github.com/openresty/lua-nginx-module -* OpenResty: http://openresty.org - -[Back to TOC](#table-of-contents) - diff --git a/rootfs/etc/nginx/lua/vendor/ngx/ssl.lua b/rootfs/etc/nginx/lua/vendor/ngx/ssl.lua deleted file mode 100644 index ecedb61d14..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/ssl.lua +++ /dev/null @@ -1,313 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local base = require "resty.core.base" -base.allows_subsystem('http') - - -local ffi = require "ffi" -local C = ffi.C -local ffi_str = ffi.string -local ffi_gc = ffi.gc -local getfenv = getfenv -local error = error -local tonumber = tonumber -local errmsg = base.get_errmsg_ptr() -local get_string_buf = base.get_string_buf -local get_size_ptr = base.get_size_ptr -local FFI_DECLINED = base.FFI_DECLINED -local FFI_OK = base.FFI_OK - - -ffi.cdef[[ - -struct ngx_ssl_conn_s; -typedef struct ngx_ssl_conn_s ngx_ssl_conn_t; - -int ngx_http_lua_ffi_ssl_set_der_certificate(ngx_http_request_t *r, - const char *data, size_t len, char **err); - -int ngx_http_lua_ffi_ssl_clear_certs(ngx_http_request_t *r, char **err); - -int ngx_http_lua_ffi_ssl_set_der_private_key(ngx_http_request_t *r, - const char *data, size_t len, char **err); - -int ngx_http_lua_ffi_ssl_raw_server_addr(ngx_http_request_t *r, char **addr, - size_t *addrlen, int *addrtype, char **err); - -int ngx_http_lua_ffi_ssl_server_name(ngx_http_request_t *r, char **name, - size_t *namelen, char **err); - -int ngx_http_lua_ffi_ssl_raw_client_addr(ngx_http_request_t *r, char **addr, - size_t *addrlen, int *addrtype, char **err); - -int ngx_http_lua_ffi_cert_pem_to_der(const unsigned char *pem, size_t pem_len, - unsigned char *der, char **err); - -int ngx_http_lua_ffi_priv_key_pem_to_der(const unsigned char *pem, - size_t pem_len, unsigned char *der, char **err); - -int ngx_http_lua_ffi_ssl_get_tls1_version(ngx_http_request_t *r, char **err); - -void *ngx_http_lua_ffi_parse_pem_cert(const unsigned char *pem, - size_t pem_len, char **err); - -void *ngx_http_lua_ffi_parse_pem_priv_key(const unsigned char *pem, - size_t pem_len, char **err); - -int ngx_http_lua_ffi_set_cert(void *r, void *cdata, char **err); - -int ngx_http_lua_ffi_set_priv_key(void *r, void *cdata, char **err); - -void ngx_http_lua_ffi_free_cert(void *cdata); - -void ngx_http_lua_ffi_free_priv_key(void *cdata); -]] - - -local _M = { version = base.version } - - -local charpp = ffi.new("char*[1]") -local intp = ffi.new("int[1]") - - -function _M.clear_certs() - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local rc = C.ngx_http_lua_ffi_ssl_clear_certs(r, errmsg) - if rc == FFI_OK then - return true - end - - return nil, ffi_str(errmsg[0]) -end - - -function _M.set_der_cert(data) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local rc = C.ngx_http_lua_ffi_ssl_set_der_certificate(r, data, #data, - errmsg) - if rc == FFI_OK then - return true - end - - return nil, ffi_str(errmsg[0]) -end - - -function _M.set_der_priv_key(data) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local rc = C.ngx_http_lua_ffi_ssl_set_der_private_key(r, data, #data, - errmsg) - if rc == FFI_OK then - return true - end - - return nil, ffi_str(errmsg[0]) -end - - -local addr_types = { - [0] = "unix", - [1] = "inet", - [2] = "inet6", -} - - -function _M.raw_server_addr() - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local sizep = get_size_ptr() - - local rc = C.ngx_http_lua_ffi_ssl_raw_server_addr(r, charpp, sizep, - intp, errmsg) - if rc == FFI_OK then - local typ = addr_types[intp[0]] - if not typ then - return nil, nil, "unknown address type: " .. intp[0] - end - return ffi_str(charpp[0], sizep[0]), typ - end - - return nil, nil, ffi_str(errmsg[0]) -end - - -function _M.server_name() - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local sizep = get_size_ptr() - - local rc = C.ngx_http_lua_ffi_ssl_server_name(r, charpp, sizep, errmsg) - if rc == FFI_OK then - return ffi_str(charpp[0], sizep[0]) - end - - if rc == FFI_DECLINED then - return nil - end - - return nil, ffi_str(errmsg[0]) -end - - -function _M.raw_client_addr() - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local sizep = get_size_ptr() - - local rc = C.ngx_http_lua_ffi_ssl_raw_client_addr(r, charpp, sizep, - intp, errmsg) - if rc == FFI_OK then - local typ = addr_types[intp[0]] - if not typ then - return nil, nil, "unknown address type: " .. intp[0] - end - return ffi_str(charpp[0], sizep[0]), typ - end - - return nil, nil, ffi_str(errmsg[0]) -end - - -function _M.cert_pem_to_der(pem) - local outbuf = get_string_buf(#pem) - - local sz = C.ngx_http_lua_ffi_cert_pem_to_der(pem, #pem, outbuf, errmsg) - if sz > 0 then - return ffi_str(outbuf, sz) - end - - return nil, ffi_str(errmsg[0]) -end - - -function _M.priv_key_pem_to_der(pem) - local outbuf = get_string_buf(#pem) - - local sz = C.ngx_http_lua_ffi_priv_key_pem_to_der(pem, #pem, outbuf, errmsg) - if sz > 0 then - return ffi_str(outbuf, sz) - end - - return nil, ffi_str(errmsg[0]) -end - - -local function get_tls1_version() - - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local ver = C.ngx_http_lua_ffi_ssl_get_tls1_version(r, errmsg) - - ver = tonumber(ver) - - if ver >= 0 then - return ver - end - - -- rc == FFI_ERROR - - return nil, ffi_str(errmsg[0]) -end -_M.get_tls1_version = get_tls1_version - - -function _M.parse_pem_cert(pem) - local cert = C.ngx_http_lua_ffi_parse_pem_cert(pem, #pem, errmsg) - if cert ~= nil then - return ffi_gc(cert, C.ngx_http_lua_ffi_free_cert) - end - - return nil, ffi_str(errmsg[0]) -end - - -function _M.parse_pem_priv_key(pem) - local pkey = C.ngx_http_lua_ffi_parse_pem_priv_key(pem, #pem, errmsg) - if pkey ~= nil then - return ffi_gc(pkey, C.ngx_http_lua_ffi_free_priv_key) - end - - return nil, ffi_str(errmsg[0]) -end - - -function _M.set_cert(cert) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local rc = C.ngx_http_lua_ffi_set_cert(r, cert, errmsg) - if rc == FFI_OK then - return true - end - - return nil, ffi_str(errmsg[0]) -end - - -function _M.set_priv_key(priv_key) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local rc = C.ngx_http_lua_ffi_set_priv_key(r, priv_key, errmsg) - if rc == FFI_OK then - return true - end - - return nil, ffi_str(errmsg[0]) -end - - -do - _M.SSL3_VERSION = 0x0300 - _M.TLS1_VERSION = 0x0301 - _M.TLS1_1_VERSION = 0x0302 - _M.TLS1_2_VERSION = 0x0303 - - local map = { - [_M.SSL3_VERSION] = "SSLv3", - [_M.TLS1_VERSION] = "TLSv1", - [_M.TLS1_1_VERSION] = "TLSv1.1", - [_M.TLS1_2_VERSION] = "TLSv1.2", - } - - function _M.get_tls1_version_str() - local ver, err = get_tls1_version() - if not ver then - return nil, err - end - return map[ver] - end -end - - -return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/ssl.md b/rootfs/etc/nginx/lua/vendor/ngx/ssl.md deleted file mode 100644 index 477a963c6f..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/ssl.md +++ /dev/null @@ -1,513 +0,0 @@ -Name -==== - -ngx.ssl - Lua API for controlling NGINX downstream SSL handshakes - -Table of Contents -================= - -* [Name](#name) -* [Status](#status) -* [Synopsis](#synopsis) -* [Description](#description) -* [Methods](#methods) - * [clear_certs](#clear_certs) - * [cert_pem_to_der](#cert_pem_to_der) - * [set_der_cert](#set_der_cert) - * [priv_key_pem_to_der](#priv_key_pem_to_der) - * [set_der_priv_key](#set_der_priv_key) - * [server_name](#server_name) - * [raw_server_addr](#raw_server_addr) - * [raw_client_addr](#raw_client_addr) - * [get_tls1_version](#get_tls1_version) - * [parse_pem_cert](#parse_pem_cert) - * [parse_pem_priv_key](#parse_pem_priv_key) - * [set_cert](#set_cert) - * [set_priv_key](#set_priv_key) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Bugs and Patches](#bugs-and-patches) -* [Author](#author) -* [Copyright and License](#copyright-and-license) -* [See Also](#see-also) - -Status -====== - -This Lua module is currently considered experimental. - -Synopsis -======== - -```nginx -# Note: you do not need the following line if you are using -# OpenResty 1.9.7.2+. -lua_package_path "/path/to/lua-resty-core/lib/?.lua;;"; - -server { - listen 443 ssl; - server_name test.com; - - # useless placeholders: just to shut up NGINX configuration - # loader errors: - ssl_certificate /path/to/fallback.crt; - ssl_certificate_key /path/to/fallback.key; - - ssl_certificate_by_lua_block { - local ssl = require "ngx.ssl" - - -- clear the fallback certificates and private keys - -- set by the ssl_certificate and ssl_certificate_key - -- directives above: - local ok, err = ssl.clear_certs() - if not ok then - ngx.log(ngx.ERR, "failed to clear existing (fallback) certificates") - return ngx.exit(ngx.ERROR) - end - - -- assuming the user already defines the my_load_certificate_chain() - -- herself. - local pem_cert_chain = assert(my_load_certificate_chain()) - - local der_cert_chain, err = ssl.cert_pem_to_der(pem_cert_chain) - if not der_cert_chain then - ngx.log(ngx.ERR, "failed to convert certificate chain ", - "from PEM to DER: ", err) - return ngx.exit(ngx.ERROR) - end - - local ok, err = ssl.set_der_cert(der_cert_chain) - if not ok then - ngx.log(ngx.ERR, "failed to set DER cert: ", err) - return ngx.exit(ngx.ERROR) - end - - -- assuming the user already defines the my_load_private_key() - -- function herself. - local pem_pkey = assert(my_load_private_key()) - - local der_pkey, err = ssl.priv_key_pem_to_der(pem_pkey) - if not der_pkey then - ngx.log(ngx.ERR, "failed to convert private key ", - "from PEM to DER: ", err) - return ngx.exit(ngx.ERROR) - end - - local ok, err = ssl.set_der_priv_key(der_pkey) - if not ok then - ngx.log(ngx.ERR, "failed to set DER private key: ", err) - return ngx.exit(ngx.ERROR) - end - } - - location / { - root html; - } -} -``` - -Description -=========== - -This Lua module provides API functions to control the SSL handshake process in contexts like -[ssl_certificate_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_certificate_by_lua_block) -(of the [ngx_lua](https://github.com/openresty/lua-nginx-module#readme) module). - -For web servers serving many (like millions of) https sites, it is often desired to lazily -load and cache the SSL certificate chain and private key data for the https sites actually -being served by a particular server. This Lua module provides API to support such use cases -in the context of the [ssl_certificate_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_certificate_by_lua_block) -directive. - -To load the `ngx.ssl` module in Lua, just write - -```lua -local ssl = require "ngx.ssl" -``` - -[Back to TOC](#table-of-contents) - -Methods -======= - -clear_certs ------------ -**syntax:** *ok, err = ssl.clear_certs()* - -**context:** *ssl_certificate_by_lua** - -Clears any existing SSL certificates and/or private keys set on the current SSL connection. - -Returns `true` on success, or a `nil` value and a string describing the error otherwise. - -[Back to TOC](#table-of-contents) - -cert_pem_to_der ---------------- -**syntax:** *der_cert_chain, err = ssl.cert_pem_to_der(pem_cert_chain)* - -**context:** *any* - -Converts the PEM-formatted SSL certificate chain data into the DER format (for later uses -in the [set_der_cert](#set_der_cert) -function, for example). - -In case of failures, returns `nil` and a string describing the error. - -It is known that the `openssl` command-line utility may not convert the whole SSL -certificate chain from PEM to DER correctly. So always use this Lua function to do -the conversion. You can always use libraries like [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache#readme) -and/or ngx_lua APIs like [lua_shared_dict](https://github.com/openresty/lua-nginx-module#lua_shared_dict) -to do the caching of the DER-formatted results, for example. - -This function can be called in whatever contexts. - -[Back to TOC](#table-of-contents) - -set_der_cert ------------- -**syntax:** *ok, err = ssl.set_der_cert(der_cert_chain)* - -**context:** *ssl_certificate_by_lua** - -Sets the DER-formatted SSL certificate chain data for the current SSL connection. Note that -the DER data is -directly in the Lua string argument. *No* external file names are supported here. - -Returns `true` on success, or a `nil` value and a string describing the error otherwise. - -Note that, the SSL certificate chain is usually encoded in the PEM format. So you need -to use the [cert_pem_to_der](#cert_pem_to_der) -function to do the conversion first. - -[Back to TOC](#table-of-contents) - -priv_key_pem_to_der -------------------- -**syntax:** *der_priv_key, err = ssl.priv_key_pem_to_der(pem_priv_key)* - -**context:** *any* - -Converts the PEM-formatted SSL private key data into the DER format (for later uses -in the [set_der_priv_key](#set_der_priv_key) -function, for example). - -In case of failures, returns `nil` and a string describing the error. - -Alternatively, you can do the PEM to DER conversion *offline* with the `openssl` command-line utility, like below - -```bash -openssl rsa -in key.pem -outform DER -out key.der -``` - -This function can be called in whatever contexts. - -[Back to TOC](#table-of-contents) - -set_der_priv_key ----------------- -**syntax:** *ok, err = ssl.set_der_priv_key(der_priv_key)* - -**context:** *ssl_certificate_by_lua** - -Sets the DER-formatted prviate key for the current SSL connection. - -Returns `true` on success, or a `nil` value and a string describing the error otherwise. - -Usually, the private keys are encoded in the PEM format. You can either use the -[priv_key_pem_to_der](#priv_key_pem_to_der) function -to do the PEM to DER conversion or just use -the `openssl` command-line utility offline, like below - -```bash -openssl rsa -in key.pem -outform DER -out key.der -``` - -[Back to TOC](#table-of-contents) - -server_name ------------ -**syntax:** *name, err = ssl.server_name()* - -**context:** *any* - -Returns the TLS SNI (Server Name Indication) name set by the client. Returns `nil` -when the client does not set it. - -In case of failures, it returns `nil` *and* a string describing the error. - -Usually we use this SNI name as the domain name (like `www.openresty.org`) to -identify the current web site while loading the corresponding SSL certificate -chain and private key for the site. - -Please note that not all https clients set the SNI name, so when the SNI name is -missing from the client handshake request, we use the server IP address accessed -by the client to identify the site. See the [raw_server_addr](#raw_server_addr) method -for more details. - -This function can be called in whatever contexts where downstream https is used. - -[Back to TOC](#table-of-contents) - -raw_server_addr ---------------- -**syntax:** *addr_data, addr_type, err = ssl.raw_server_addr()* - -**context:** *any* - -Returns the raw server address actually accessed by the client in the current SSL connection. - -The first two return values are strings representing the address data and the address type, respectively. -The address values are interpreted differently according to the address type values: - -* `unix` -: The address data is a file path for the UNIX domain socket. -* `inet` -: The address data is a binary IPv4 address of 4 bytes long. -* `inet6` -: The address data is a binary IPv6 address of 16 bytes long. - -Returns two `nil` values and a Lua string describing the error. - -The following code snippet shows how to print out the UNIX domain socket address and -the IPv4 address as human-readable strings: - -```lua -local ssl = require "ngx.ssl" -local byte = string.byte - -local addr, addrtyp, err = ssl.raw_server_addr() -if not addr then - ngx.log(ngx.ERR, "failed to fetch raw server addr: ", err) - return -end - -if addrtyp == "inet" then -- IPv4 - ip = string.format("%d.%d.%d.%d", byte(addr, 1), byte(addr, 2), - byte(addr, 3), byte(addr, 4)) - print("Using IPv4 address: ", ip) - -elseif addrtyp == "unix" then -- UNIX - print("Using unix socket file ", addr) - -else -- IPv6 - -- leave as an exercise for the readers -end -``` - -This function can be called in whatever contexts where downstream https is used. - -[Back to TOC](#table-of-contents) - -raw_client_addr ---------------- -**syntax:** *addr, err = ssl.raw_client_addr()* - -**context:** *any* - -Returns the raw client address of the current SSL connection. - -The first two return values are strings representing the address data and the address type, respectively. -The address values are interpreted differently according to the address type values: - -* `unix` -: The address data is a file path for the UNIX domain socket. -* `inet` -: The address data is a binary IPv4 address of 4 bytes long. -* `inet6` -: The address data is a binary IPv6 address of 16 bytes long. - -Returns two `nil` values and a Lua string describing the error. - -The following code snippet shows how to print out the UNIX domain socket address and -the IPv4 address as human-readable strings: - -```lua -local ssl = require "ngx.ssl" -local byte = string.byte - -local addr, addrtyp, err = ssl.raw_client_addr() -if not addr then - ngx.log(ngx.ERR, "failed to fetch raw client addr: ", err) - return -end - -if addrtyp == "inet" then -- IPv4 - ip = string.format("%d.%d.%d.%d", byte(addr, 1), byte(addr, 2), - byte(addr, 3), byte(addr, 4)) - print("Client IPv4 address: ", ip) - -elseif addrtyp == "unix" then -- UNIX - print("Client unix socket file ", addr) - -else -- IPv6 - -- leave as an exercise for the readers -end -``` - -This function can be called in whatever contexts where downstream https is used. - -[Back to TOC](#table-of-contents) - -get_tls1_version ----------------- -**syntax:** *ver, err = ssl.get_tls1_version()* - -**context:** *any* - -Returns the TLS 1.x version number used by the current SSL connection. Returns `nil` and -a string describing the error otherwise. - -Typical return values are - -* `SSLv3` -* `TLSv1` -* `TLSv1.1` -* `TLSv1.2` - -This function can be called in whatever contexts where downstream https is used. - -[Back to TOC](#table-of-contents) - -parse_pem_cert ----------------- -**syntax:** *cert_chain, err = ssl.parse_pem_cert(pem_cert_chain)* - -**context:** *any* - -Converts the PEM-formated SSL certificate chain data into an opaque cdata pointer (for later uses -in the [set_cert](#set_cert) -function, for example). - -In case of failures, returns `nil` and a string describing the error. - -You can always use libraries like [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache#readme) -to cache the cdata result. - -This function can be called in whatever contexts. - -This function was first added in version `0.1.7`. - -[Back to TOC](#table-of-contents) - -parse_pem_priv_key ----------------- -**syntax:** *priv_key, err = ssl.parse_pem_priv_key(pem_priv_key)* - -**context:** *any* - -Converts the PEM-formatted SSL private key data into an opaque cdata pointer (for later uses -in the [set_priv_key](#set_priv_key) -function, for example). - -In case of failures, returns `nil` and a string describing the error. - -This function can be called in whatever contexts. - -This function was first added in version `0.1.7`. - -[Back to TOC](#table-of-contents) - -set_cert ------------- -**syntax:** *ok, err = ssl.set_cert(cert_chain)* - -**context:** *ssl_certificate_by_lua** - -Sets the SSL certificate chain opaque pointer returned by the -[parse_pem_cert](#parse_pem_cert) function for the current SSL connection. - -Returns `true` on success, or a `nil` value and a string describing the error otherwise. - -Note that this `set_cert` function will run slightly faster, in terms of CPU cycles wasted, than the -[set_der_cert](#set_der_cert) variant, since the first function uses opaque cdata pointers -which do not require any additional conversion needed to be performed by the SSL library during the SSL handshake. - -This function was first added in version `0.1.7`. - -[Back to TOC](#table-of-contents) - -set_priv_key ------------- -**syntax:** *ok, err = ssl.set_priv_key(priv_key)* - -**context:** *ssl_certificate_by_lua** - -Sets the SSL private key opaque pointer returned by the -[parse_pem_priv_key](#parse_pem_priv_key) function for the current SSL connection. - -Returns `true` on success, or a `nil` value and a string describing the error otherwise. - -Note that this `set_priv_key` function will run slightly faster, in terms of CPU cycles wasted, than the -[set_der_priv_key](#set_der_priv_key) variant, since the first function uses opaque cdata pointers -which do not require any additional conversion needed to be performed by the SSL library during the SSL handshake. - -This function was first added in version `0.1.7`. - -[Back to TOC](#table-of-contents) - -Community -========= - -[Back to TOC](#table-of-contents) - -English Mailing List --------------------- - -The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. - -[Back to TOC](#table-of-contents) - -Chinese Mailing List --------------------- - -The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. - -[Back to TOC](#table-of-contents) - -Bugs and Patches -================ - -Please report bugs or submit patches by - -1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), -1. or posting to the [OpenResty community](#community). - -[Back to TOC](#table-of-contents) - -Author -====== - -Yichun Zhang <agentzh@gmail.com> (agentzh), OpenResty Inc. - -[Back to TOC](#table-of-contents) - -Copyright and License -===================== - -This module is licensed under the BSD license. - -Copyright (C) 2015-2017, by Yichun "agentzh" Zhang, OpenResty Inc. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -[Back to TOC](#table-of-contents) - -See Also -======== -* the ngx_lua module: https://github.com/openresty/lua-nginx-module -* the [ngx.ocsp](ocsp.md) module. -* the [ssl_certificate_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_certificate_by_lua_block) directive. -* library [lua-resty-core](https://github.com/openresty/lua-resty-core) -* OpenResty: http://openresty.org - -[Back to TOC](#table-of-contents) diff --git a/rootfs/etc/nginx/lua/vendor/ngx/ssl/session.lua b/rootfs/etc/nginx/lua/vendor/ngx/ssl/session.lua deleted file mode 100644 index f3c24a7535..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/ssl/session.lua +++ /dev/null @@ -1,109 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local base = require "resty.core.base" -base.allows_subsystem('http') - - -local ffi = require "ffi" -local C = ffi.C -local ffi_str = ffi.string -local getfenv = getfenv -local error = error -local errmsg = base.get_errmsg_ptr() -local get_string_buf = base.get_string_buf -local FFI_ERROR = base.FFI_ERROR - - -ffi.cdef[[ -int ngx_http_lua_ffi_ssl_set_serialized_session(ngx_http_request_t *r, - const unsigned char *buf, int len, char **err); - -int ngx_http_lua_ffi_ssl_get_serialized_session(ngx_http_request_t *r, - char *buf, char **err); - -int ngx_http_lua_ffi_ssl_get_session_id(ngx_http_request_t *r, - char *buf, char **err); - -int ngx_http_lua_ffi_ssl_get_serialized_session_size(ngx_http_request_t *r, - char **err); - -int ngx_http_lua_ffi_ssl_get_session_id_size(ngx_http_request_t *r, - char **err); -]] - - -local _M = { version = base.version } - - --- return session, err -function _M.get_serialized_session() - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local len = C.ngx_http_lua_ffi_ssl_get_serialized_session_size(r, errmsg) - - if len < 0 then - return nil, ffi_str(errmsg[0]) - end - - if len > 4096 then - return nil, "session too big to serialize" - end - local buf = get_string_buf(len) - - local rc = C.ngx_http_lua_ffi_ssl_get_serialized_session(r, buf, errmsg) - - if rc == FFI_ERROR then - return nil, ffi_str(errmsg[0]) - end - - return ffi_str(buf, len) -end - - --- return session_id, err -function _M.get_session_id() - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local len = C.ngx_http_lua_ffi_ssl_get_session_id_size(r, errmsg) - - if len < 0 then - return nil, ffi_str(errmsg[0]) - end - - local buf = get_string_buf(len) - - local rc = C.ngx_http_lua_ffi_ssl_get_session_id(r, buf, errmsg) - - if rc == FFI_ERROR then - return nil, ffi_str(errmsg[0]) - end - - return ffi_str(buf, len) -end - - --- return ok, err -function _M.set_serialized_session(sess) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local rc = C.ngx_http_lua_ffi_ssl_set_serialized_session(r, sess, #sess, - errmsg) - if rc == FFI_ERROR then - return nil, ffi_str(errmsg[0]) - end - - return true -end - - -return _M diff --git a/rootfs/etc/nginx/lua/vendor/ngx/ssl/session.md b/rootfs/etc/nginx/lua/vendor/ngx/ssl/session.md deleted file mode 100644 index b6671b37a7..0000000000 --- a/rootfs/etc/nginx/lua/vendor/ngx/ssl/session.md +++ /dev/null @@ -1,277 +0,0 @@ -Name -==== - -ngx.ssl.session - Lua API for manipulating SSL session data and IDs for NGINX downstream SSL connections. - -Table of Contents -================= - -* [Name](#name) -* [Status](#status) -* [Synopsis](#synopsis) -* [Description](#description) -* [Methods](#methods) - * [get_session_id](#get_session_id) - * [get_serialized_session](#get_serialized_session) - * [set_serialized_session](#set_serialized_session) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Bugs and Patches](#bugs-and-patches) -* [Author](#author) -* [Copyright and License](#copyright-and-license) -* [See Also](#see-also) - -Status -====== - -This Lua module is currently considered experimental. - -Synopsis -======== - -```nginx -# nginx.conf - -# Note: you do not need the following line if you are using -# OpenResty 1.11.2.1+. -lua_package_path "/path/to/lua-resty-core/lib/?.lua;;"; - -ssl_session_fetch_by_lua_block { - local ssl_sess = require "ngx.ssl.session" - - local sess_id, err = ssl_sess.get_session_id() - if not sess_id then - ngx.log(ngx.ERR, "failed to get session ID: ", err) - -- considered a cache miss, and just return... - return - end - - -- the user is supposed to implement the my_lookup_ssl_session_by_id - -- Lua function used below. She can look up an external memcached - -- or redis cluster, for example. And she can also introduce a local - -- cache layer at the same time... - local sess, err = my_lookup_ssl_session_by_id(sess_id) - if not sess then - if err then - ngx.log(ngx.ERR, "failed to look up the session by ID ", - sess_id, ": ", err) - return - end - - -- cache miss...just return - return - end - - local ok, err = ssl_sess.set_serialized_session(sess) - if not ok then - ngx.log(ngx.ERR, "failed to set SSL session for ID ", sess_id, - ": ", err) - -- consider it as a cache miss... - return - end - - -- done here, SSL session successfully set and should resume accordingly... -} - -ssl_session_store_by_lua_block { - local ssl_sess = require "ngx.ssl.session" - - local sess_id, err = ssl_sess.get_session_id() - if not sess_id then - ngx.log(ngx.ERR, "failed to get session ID: ", err) - -- just give up - return - end - - local sess, err = ssl_sess.get_serialized_session() - if not sess then - ngx.log(ngx.ERR, "failed to get SSL session from the ", - "current connection: ", err) - -- just give up - return - end - - -- for the best performance, we should avoid creating a closure - -- dynamically here on the hot code path. Instead, we should - -- put this function in one of our own Lua module files. this - -- example is just for demonstration purposes... - local function save_it(premature, sess_id, sess) - -- the user is supposed to implement the - -- my_save_ssl_session_by_id Lua function used below. - -- She can save to an external memcached - -- or redis cluster, for example. And she can also introduce - -- a local cache layer at the same time... - local sess, err = my_save_ssl_session_by_id(sess_id, sess) - if not sess then - if err then - ngx.log(ngx.ERR, "failed to save the session by ID ", - sess_id, ": ", err) - return ngx.exit(ngx.ERROR) - end - - -- cache miss...just return - return - end - end - - -- create a 0-delay timer here... - local ok, err = ngx.timer.at(0, save_it, sess_id, sess) - if not ok then - ngx.log(ngx.ERR, "failed to create a 0-delay timer: ", err) - return - end -} - -server { - listen 443 ssl; - server_name test.com; - - # well, we could configure ssl_certificate_by_lua* here as well... - ssl_certificate /path/to/server-cert.pem; - ssl_certificate_key /path/to/server-priv-key.pem; -} -``` - -Description -=========== - -This Lua module provides API functions for manipulating SSL session data and IDs for NGINX -downstream connections. It is mostly for the contexts [ssl_session_fetch_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_fetch_by_lua_block) -and [ssl_session_store_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_store_by_lua_block). - -This Lua API can be used to implement distributed SSL session caching for downstream SSL connections, thus saving a lot of full SSL handshakes which are very expensive. - -To load the `ngx.ssl.session` module in Lua, just write - -```lua -local ssl_sess = require "ngx.ssl.session" -``` - -[Back to TOC](#table-of-contents) - -Methods -======= - -get_session_id --------------- -**syntax:** *id, err = ssl_sess.get_session_id()* - -**context:** *ssl_session_fetch_by_lua*, ssl_session_store_by_lua** - -Fetches the SSL session ID associated with the current downstream SSL connection. -The ID is returned as a Lua string. - -In case of errors, it returns `nil` and a string describing the error. - -This API function is usually called in the contexts of -[ssl_session_store_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_store_by_lua_block) -and [ssl_session_fetch_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_fetch_by_lua_block). - -[Back to TOC](#table-of-contents) - -get_serialized_session ----------------------- -**syntax:** *session, err = ssl_sess.get_serialized_session()* - -**context:** *ssl_session_store_by_lua** - -Returns the serialized form of the SSL sesson data of the current SSL connection, in a Lua string. - -This session can be cached in [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache), [lua_shared_dict](https://github.com/openresty/lua-nginx-module#lua_shared_dict), -and/or external data storage services like `memcached` and `redis`. The SSL session ID returned -by the [get_session_id](#get_session_id) function is usually used as the cache key. - -The returned SSL session data can later be loaded into other SSL connections using the same -session ID via the [set_serialized_session](#set_serialized_session) function. - -In case of errors, it returns `nil` and a string describing the error. - -This API function is usually called in the context of -[ssl_session_store_by_lua*](https://github.com/openresty/lua-nginx-module#ssl_session_store_by_lua_block) -where the SSL handshake has just completed. - -[Back to TOC](#table-of-contents) - -set_serialized_session ----------------------- -**syntax:** *ok, err = ssl_sess.set_serialized_session(session)* - -**context:** *ssl_session_fetch_by_lua** - -Sets the serialized SSL session provided as the argument to the current SSL connection. -If the SSL session is successfully set, the current SSL connection can resume the session -directly without going through the full SSL handshake process (which is very expensive in terms of CPU time). - -This API is usually used in the context of [ssl_session_fetch_by_lua*](https://github.com/openresty/lua-nginx-module#ssl_session_fetch_by_lua_block) -when a cache hit is found with the current SSL session ID. - -The serialized SSL session used as the argument should be originally returned by the -[get_serialized_session](#get_serialized_session) function. - -[Back to TOC](#table-of-contents) - -Community -========= - -[Back to TOC](#table-of-contents) - -English Mailing List --------------------- - -The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. - -[Back to TOC](#table-of-contents) - -Chinese Mailing List --------------------- - -The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. - -[Back to TOC](#table-of-contents) - -Bugs and Patches -================ - -Please report bugs or submit patches by - -1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), -1. or posting to the [OpenResty community](#community). - -[Back to TOC](#table-of-contents) - -Author -====== - -Yichun Zhang <agentzh@gmail.com> (agentzh), OpenResty Inc. - -[Back to TOC](#table-of-contents) - -Copyright and License -===================== - -This module is licensed under the BSD license. - -Copyright (C) 2016-2017, by Yichun "agentzh" Zhang, OpenResty Inc. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -[Back to TOC](#table-of-contents) - -See Also -======== -* the ngx_lua module: https://github.com/openresty/lua-nginx-module -* the [ssl_session_fetch_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_fetch_by_lua_block) directive. -* the [ssl_session_store_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_store_by_lua_block) directive. -* library [lua-resty-core](https://github.com/openresty/lua-resty-core) -* OpenResty: https://openresty.org - -[Back to TOC](#table-of-contents) diff --git a/rootfs/etc/nginx/lua/vendor/resty/core.lua b/rootfs/etc/nginx/lua/vendor/resty/core.lua deleted file mode 100644 index da6c778301..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core.lua +++ /dev/null @@ -1,29 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - -local subsystem = ngx.config.subsystem - - -if subsystem == 'http' then - require "resty.core.uri" - require "resty.core.hash" - require "resty.core.base64" - require "resty.core.regex" - require "resty.core.exit" - require "resty.core.shdict" - require "resty.core.var" - require "resty.core.ctx" - require "resty.core.misc" - require "resty.core.request" - require "resty.core.response" - require "resty.core.time" - require "resty.core.worker" - require "resty.core.phase" -end - - -local base = require "resty.core.base" - - -return { - version = base.version -} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/base.lua b/rootfs/etc/nginx/lua/vendor/resty/core/base.lua deleted file mode 100644 index 2093959e35..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core/base.lua +++ /dev/null @@ -1,236 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local ffi = require 'ffi' -local ffi_new = ffi.new -local error = error -local select = select -local ceil = math.ceil -local subsystem = ngx.config.subsystem - - -local str_buf_size = 4096 -local str_buf -local size_ptr -local FREE_LIST_REF = 0 - - -if subsystem == 'http' then - if not ngx.config - or not ngx.config.ngx_lua_version - or ngx.config.ngx_lua_version < 10012 - then - error("ngx_http_lua_module 0.10.12+ required") - end - -elseif subsystem == 'stream' then - if not ngx.config - or not ngx.config.ngx_lua_version - or ngx.config.ngx_lua_version < 4 - then - error("ngx_stream_lua_module 0.0.4+ required") - end - -else - error("ngx_http_lua_module 0.10.12+ or " - .. "ngx_stream_lua_module 0.0.4+ required") -end - - -if string.find(jit.version, " 2.0", 1, true) then - ngx.log(ngx.ALERT, "use of lua-resty-core with LuaJIT 2.0 is ", - "not recommended; use LuaJIT 2.1+ instead") -end - - -local ok, new_tab = pcall(require, "table.new") -if not ok then - new_tab = function (narr, nrec) return {} end -end - - -local clear_tab -ok, clear_tab = pcall(require, "table.clear") -if not ok then - clear_tab = function (tab) - for k, _ in pairs(tab) do - tab[k] = nil - end - end -end - - --- XXX for now LuaJIT 2.1 cannot compile require() --- so we make the fast code path Lua only in our own --- wrapper so that most of the require() calls in hot --- Lua code paths can be JIT compiled. -do - local orig_require = require - local pkg_loaded = package.loaded - local function my_require(name) - local mod = pkg_loaded[name] - if mod then - return mod - end - return orig_require(name) - end - getfenv(0).require = my_require -end - - -if not pcall(ffi.typeof, "ngx_str_t") then - ffi.cdef[[ - typedef struct { - size_t len; - const unsigned char *data; - } ngx_str_t; - ]] -end - - -if subsystem == 'http' then - if not pcall(ffi.typeof, "ngx_http_request_t") then - ffi.cdef[[ - struct ngx_http_request_s; - typedef struct ngx_http_request_s ngx_http_request_t; - ]] - end - - if not pcall(ffi.typeof, "ngx_http_lua_ffi_str_t") then - ffi.cdef[[ - typedef struct { - int len; - const unsigned char *data; - } ngx_http_lua_ffi_str_t; - ]] - end - -elseif subsystem == 'stream' then - if not pcall(ffi.typeof, "ngx_stream_lua_request_t") then - ffi.cdef[[ - struct ngx_stream_lua_request_s; - typedef struct ngx_stream_lua_request_s ngx_stream_lua_request_t; - ]] - end - - if not pcall(ffi.typeof, "ngx_stream_lua_ffi_str_t") then - ffi.cdef[[ - typedef struct { - int len; - const unsigned char *data; - } ngx_stream_lua_ffi_str_t; - ]] - end - -else - error("unknown subsystem: " .. subsystem) -end - - -local c_buf_type = ffi.typeof("char[?]") - - -local _M = new_tab(0, 17) - - -_M.version = "0.1.13" -_M.new_tab = new_tab -_M.clear_tab = clear_tab - - -local errmsg - - -function _M.get_errmsg_ptr() - if not errmsg then - errmsg = ffi_new("char *[1]") - end - return errmsg -end - - -if not ngx then - return error("no existing ngx. table found") -end - - -function _M.set_string_buf_size(size) - if size <= 0 then - return - end - if str_buf then - str_buf = nil - end - str_buf_size = ceil(size) -end - - -function _M.get_string_buf_size() - return str_buf_size -end - - -function _M.get_size_ptr() - if not size_ptr then - size_ptr = ffi_new("size_t[1]") - end - - return size_ptr -end - - -function _M.get_string_buf(size, must_alloc) - -- ngx.log(ngx.ERR, "str buf size: ", str_buf_size) - if size > str_buf_size or must_alloc then - return ffi_new(c_buf_type, size) - end - - if not str_buf then - str_buf = ffi_new(c_buf_type, str_buf_size) - end - - return str_buf -end - - -function _M.ref_in_table(tb, key) - if key == nil then - return -1 - end - local ref = tb[FREE_LIST_REF] - if ref and ref ~= 0 then - tb[FREE_LIST_REF] = tb[ref] - - else - ref = #tb + 1 - end - tb[ref] = key - - -- print("ref key_id returned ", ref) - return ref -end - - -function _M.allows_subsystem(...) - local total = select("#", ...) - - for i = 1, total do - if select(i, ...) == subsystem then - return - end - end - - error("unsupported subsystem: " .. subsystem) -end - - -_M.FFI_OK = 0 -_M.FFI_NO_REQ_CTX = -100 -_M.FFI_BAD_CONTEXT = -101 -_M.FFI_ERROR = -1 -_M.FFI_BUSY = -3 -_M.FFI_DONE = -4 -_M.FFI_DECLINED = -5 - - -return _M diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/base64.lua b/rootfs/etc/nginx/lua/vendor/resty/core/base64.lua deleted file mode 100644 index 83c0bf32bf..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core/base64.lua +++ /dev/null @@ -1,90 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local ffi = require 'ffi' -local base = require "resty.core.base" - -local ffi_string = ffi.string -local C = ffi.C -local ngx = ngx -local type = type -local tostring = tostring -local error = error -local get_string_buf = base.get_string_buf -local get_size_ptr = base.get_size_ptr -local floor = math.floor - - -ffi.cdef[[ - size_t ngx_http_lua_ffi_encode_base64(const unsigned char *src, - size_t len, unsigned char *dst, - int no_padding); - - int ngx_http_lua_ffi_decode_base64(const unsigned char *src, - size_t len, unsigned char *dst, - size_t *dlen); -]] - - -local function base64_encoded_length(len, no_padding) - return no_padding and floor((len * 8 + 5) / 6) or - floor((len + 2) / 3) * 4 -end - - -ngx.encode_base64 = function (s, no_padding) - if type(s) ~= 'string' then - if not s then - s = '' - else - s = tostring(s) - end - end - - local slen = #s - local no_padding_bool = false; - local no_padding_int = 0; - - if no_padding then - if no_padding ~= true then - return error("boolean argument only") - end - - no_padding_bool = true - no_padding_int = 1; - end - - local dlen = base64_encoded_length(slen, no_padding_bool) - local dst = get_string_buf(dlen) - local r_dlen = C.ngx_http_lua_ffi_encode_base64(s, slen, dst, - no_padding_int) - -- if dlen ~= r_dlen then error("discrepancy in len") end - return ffi_string(dst, r_dlen) -end - - -local function base64_decoded_length(len) - return floor((len + 3) / 4) * 3 -end - - -ngx.decode_base64 = function (s) - if type(s) ~= 'string' then - return error("string argument only") - end - local slen = #s - local dlen = base64_decoded_length(slen) - -- print("dlen: ", tonumber(dlen)) - local dst = get_string_buf(dlen) - local pdlen = get_size_ptr() - local ok = C.ngx_http_lua_ffi_decode_base64(s, slen, dst, pdlen) - if ok == 0 then - return nil - end - return ffi_string(dst, pdlen[0]) -end - - -return { - version = base.version -} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/ctx.lua b/rootfs/etc/nginx/lua/vendor/resty/core/ctx.lua deleted file mode 100644 index c75261ff1c..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core/ctx.lua +++ /dev/null @@ -1,82 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local ffi = require 'ffi' -local debug = require 'debug' -local base = require "resty.core.base" -local misc = require "resty.core.misc" - - -local register_getter = misc.register_ngx_magic_key_getter -local register_setter = misc.register_ngx_magic_key_setter -local registry = debug.getregistry() -local new_tab = base.new_tab -local ref_in_table = base.ref_in_table -local getfenv = getfenv -local C = ffi.C -local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX -local FFI_OK = base.FFI_OK -local error = error - - -ffi.cdef[[ -int ngx_http_lua_ffi_get_ctx_ref(ngx_http_request_t *r); -int ngx_http_lua_ffi_set_ctx_ref(ngx_http_request_t *r, int ref); -]] - - -local _M = { - _VERSION = base.version -} - - -local function get_ctx_table() - local r = getfenv(0).__ngx_req - - if not r then - return error("no request found") - end - - local ctx_ref = C.ngx_http_lua_ffi_get_ctx_ref(r) - if ctx_ref == FFI_NO_REQ_CTX then - return error("no request ctx found") - end - - local ctxs = registry.ngx_lua_ctx_tables - if ctx_ref < 0 then - local ctx = new_tab(0, 4) - ctx_ref = ref_in_table(ctxs, ctx) - if C.ngx_http_lua_ffi_set_ctx_ref(r, ctx_ref) ~= FFI_OK then - return nil - end - return ctx - end - return ctxs[ctx_ref] -end -register_getter("ctx", get_ctx_table) - - -local function set_ctx_table(ctx) - local r = getfenv(0).__ngx_req - - if not r then - return error("no request found") - end - - local ctx_ref = C.ngx_http_lua_ffi_get_ctx_ref(r) - if ctx_ref == FFI_NO_REQ_CTX then - return error("no request ctx found") - end - - local ctxs = registry.ngx_lua_ctx_tables - if ctx_ref < 0 then - ctx_ref = ref_in_table(ctxs, ctx) - C.ngx_http_lua_ffi_set_ctx_ref(r, ctx_ref) - return - end - ctxs[ctx_ref] = ctx -end -register_setter("ctx", set_ctx_table) - - -return _M diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/exit.lua b/rootfs/etc/nginx/lua/vendor/resty/core/exit.lua deleted file mode 100644 index 210069cdd5..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core/exit.lua +++ /dev/null @@ -1,48 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local ffi = require 'ffi' -local ffi_string = ffi.string -local C = ffi.C -local ngx = ngx -local error = error -local base = require "resty.core.base" -local get_string_buf = base.get_string_buf -local get_size_ptr = base.get_size_ptr -local getfenv = getfenv -local co_yield = coroutine._yield - - -ffi.cdef[[ - int ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, - unsigned char *err, size_t *errlen); -]] - - -local ERR_BUF_SIZE = 128 -local FFI_DONE = base.FFI_DONE - - -ngx.exit = function (rc) - local err = get_string_buf(ERR_BUF_SIZE) - local errlen = get_size_ptr() - local r = getfenv(0).__ngx_req - if r == nil then - return error("no request found") - end - errlen[0] = ERR_BUF_SIZE - rc = C.ngx_http_lua_ffi_exit(r, rc, err, errlen) - if rc == 0 then - -- print("yielding...") - return co_yield() - end - if rc == FFI_DONE then - return - end - return error(ffi_string(err, errlen[0])) -end - - -return { - version = base.version -} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/hash.lua b/rootfs/etc/nginx/lua/vendor/resty/core/hash.lua deleted file mode 100644 index 79c934aed1..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core/hash.lua +++ /dev/null @@ -1,80 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local ffi = require 'ffi' -local ffi_string = ffi.string -local ffi_new = ffi.new -local C = ffi.C -local ngx = ngx -local type = type -local tostring = tostring -local error = error -local base = require "resty.core.base" - - -ffi.cdef[[ - void ngx_http_lua_ffi_md5_bin(const unsigned char *src, size_t len, - unsigned char *dst); - - void ngx_http_lua_ffi_md5(const unsigned char *src, size_t len, - unsigned char *dst); - - int ngx_http_lua_ffi_sha1_bin(const unsigned char *src, size_t len, - unsigned char *dst); -]] - - -local MD5_DIGEST_LEN = 16 -local md5_buf = ffi_new("unsigned char[?]", MD5_DIGEST_LEN) - -ngx.md5_bin = function (s) - if type(s) ~= 'string' then - if not s then - s = '' - else - s = tostring(s) - end - end - C.ngx_http_lua_ffi_md5_bin(s, #s, md5_buf) - return ffi_string(md5_buf, MD5_DIGEST_LEN) -end - - -local MD5_HEX_DIGEST_LEN = MD5_DIGEST_LEN * 2 -local md5_hex_buf = ffi_new("unsigned char[?]", MD5_HEX_DIGEST_LEN) - -ngx.md5 = function (s) - if type(s) ~= 'string' then - if not s then - s = '' - else - s = tostring(s) - end - end - C.ngx_http_lua_ffi_md5(s, #s, md5_hex_buf) - return ffi_string(md5_hex_buf, MD5_HEX_DIGEST_LEN) -end - - -local SHA_DIGEST_LEN = 20 -local sha_buf = ffi_new("unsigned char[?]", SHA_DIGEST_LEN) - -ngx.sha1_bin = function (s) - if type(s) ~= 'string' then - if not s then - s = '' - else - s = tostring(s) - end - end - local ok = C.ngx_http_lua_ffi_sha1_bin(s, #s, sha_buf) - if ok == 0 then - return error("SHA-1 support missing in Nginx") - end - return ffi_string(sha_buf, SHA_DIGEST_LEN) -end - - -return { - version = base.version -} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/misc.lua b/rootfs/etc/nginx/lua/vendor/resty/core/misc.lua deleted file mode 100644 index 2f30528d05..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core/misc.lua +++ /dev/null @@ -1,155 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local base = require "resty.core.base" -local ffi = require "ffi" - - -local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX -local FFI_BAD_CONTEXT = base.FFI_BAD_CONTEXT -local new_tab = base.new_tab -local C = ffi.C -local getmetatable = getmetatable -local ngx_magic_key_getters = new_tab(0, 4) -local ngx_magic_key_setters = new_tab(0, 2) -local ngx = ngx -local getfenv = getfenv -local type = type -local error = error -local tonumber = tonumber - - -local _M = new_tab(0, 3) -_M._VERSION = base.version - - -local function register_getter(key, func) - ngx_magic_key_getters[key] = func -end -_M.register_ngx_magic_key_getter = register_getter - - -local function register_setter(key, func) - ngx_magic_key_setters[key] = func -end -_M.register_ngx_magic_key_setter = register_setter - - -local mt = getmetatable(ngx) - - -local old_index = mt.__index -mt.__index = function (tb, key) - local f = ngx_magic_key_getters[key] - if f then - return f() - end - return old_index(tb, key) -end - - -local old_newindex = mt.__newindex -mt.__newindex = function (tb, key, ctx) - local f = ngx_magic_key_setters[key] - if f then - return f(ctx) - end - return old_newindex(tb, key, ctx) -end - - -ffi.cdef[[ - int ngx_http_lua_ffi_get_resp_status(ngx_http_request_t *r); - int ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int r); - int ngx_http_lua_ffi_is_subrequest(ngx_http_request_t *r); - int ngx_http_lua_ffi_headers_sent(ngx_http_request_t *r); -]] - - --- ngx.status - -local function get_status() - local r = getfenv(0).__ngx_req - - if not r then - return error("no request found") - end - - local rc = C.ngx_http_lua_ffi_get_resp_status(r) - - if rc == FFI_BAD_CONTEXT then - return error("API disabled in the current context") - end - - return rc -end -register_getter("status", get_status) - - -local function set_status(status) - local r = getfenv(0).__ngx_req - - if not r then - return error("no request found") - end - - if type(status) ~= 'number' then - status = tonumber(status) - end - - local rc = C.ngx_http_lua_ffi_set_resp_status(r, status) - - if rc == FFI_BAD_CONTEXT then - return error("API disabled in the current context") - end - - return -end -register_setter("status", set_status) - - --- ngx.is_subrequest - -local function is_subreq() - local r = getfenv(0).__ngx_req - - if not r then - return error("no request found") - end - - local rc = C.ngx_http_lua_ffi_is_subrequest(r) - - if rc == FFI_BAD_CONTEXT then - return error("API disabled in the current context") - end - - return rc == 1 -end -register_getter("is_subrequest", is_subreq) - - --- ngx.headers_sent - -local function headers_sent() - local r = getfenv(0).__ngx_req - - if not r then - return error("no request found") - end - - local rc = C.ngx_http_lua_ffi_headers_sent(r) - - if rc == FFI_NO_REQ_CTX then - return error("no request ctx found") - end - - if rc == FFI_BAD_CONTEXT then - return error("API disabled in the current context") - end - - return rc == 1 -end -register_getter("headers_sent", headers_sent) - - -return _M diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/phase.lua b/rootfs/etc/nginx/lua/vendor/resty/core/phase.lua deleted file mode 100644 index d83d0f3ea4..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core/phase.lua +++ /dev/null @@ -1,57 +0,0 @@ -local ffi = require 'ffi' -local base = require "resty.core.base" - -local C = ffi.C -local FFI_ERROR = base.FFI_ERROR -local error = error -local tostring = tostring - - -ffi.cdef[[ -int ngx_http_lua_ffi_get_phase(ngx_http_request_t *r, char **err) -]] - - -local errmsg = base.get_errmsg_ptr() -local context_names = { - [0x0001] = "set", - [0x0002] = "rewrite", - [0x0004] = "access", - [0x0008] = "content", - [0x0010] = "log", - [0x0020] = "header_filter", - [0x0040] = "body_filter", - [0x0080] = "timer", - [0x0100] = "init_worker", - [0x0200] = "balancer", - [0x0400] = "ssl_cert", - [0x0800] = "ssl_session_store", - [0x1000] = "ssl_session_fetch", -} - - -function ngx.get_phase() - local r = getfenv(0).__ngx_req - - -- if we have no request object, assume we are called from the "init" phase - if not r then - return "init" - end - - local context = C.ngx_http_lua_ffi_get_phase(r, errmsg) - if context == FFI_ERROR then -- NGX_ERROR - error(errmsg) - end - - local phase = context_names[context] - if not phase then - error("unknown phase: " .. tostring(context)) - end - - return phase -end - - -return { - version = base.version -} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/regex.lua b/rootfs/etc/nginx/lua/vendor/resty/core/regex.lua deleted file mode 100644 index cf17e77ded..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core/regex.lua +++ /dev/null @@ -1,971 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local ffi = require 'ffi' -local base = require "resty.core.base" -local bit = require "bit" -require "resty.core.time" -- for ngx.now used by resty.lrucache -local lrucache = require "resty.lrucache" - -local lrucache_get = lrucache.get -local lrucache_set = lrucache.set -local ffi_string = ffi.string -local ffi_gc = ffi.gc -local ffi_copy = ffi.copy -local ffi_cast = ffi.cast -local C = ffi.C -local bor = bit.bor -local band = bit.band -local lshift = bit.lshift -local sub = string.sub -local fmt = string.format -local byte = string.byte -local ngx = ngx -local type = type -local tostring = tostring -local error = error -local setmetatable = setmetatable -local tonumber = tonumber -local get_string_buf = base.get_string_buf -local get_string_buf_size = base.get_string_buf_size -local new_tab = base.new_tab - - -if not ngx.re then - ngx.re = {} -end - - -local MAX_ERR_MSG_LEN = 128 - - -local FLAG_COMPILE_ONCE = 0x01 -local FLAG_DFA = 0x02 -local FLAG_JIT = 0x04 -local FLAG_DUPNAMES = 0x08 -local FLAG_NO_UTF8_CHECK = 0x10 - - -local PCRE_CASELESS = 0x0000001 -local PCRE_MULTILINE = 0x0000002 -local PCRE_DOTALL = 0x0000004 -local PCRE_EXTENDED = 0x0000008 -local PCRE_ANCHORED = 0x0000010 -local PCRE_UTF8 = 0x0000800 -local PCRE_DUPNAMES = 0x0080000 -local PCRE_JAVASCRIPT_COMPAT = 0x2000000 - - -local PCRE_ERROR_NOMATCH = -1 - - -local regex_match_cache -local regex_sub_func_cache = new_tab(0, 4) -local regex_sub_str_cache = new_tab(0, 4) -local max_regex_cache_size -local regex_cache_size = 0 -local script_engine - - -ffi.cdef[[ - typedef struct { - ngx_str_t value; - void *lengths; - void *values; - } ngx_http_lua_complex_value_t; - - typedef struct { - void *pool; - unsigned char *name_table; - int name_count; - int name_entry_size; - - int ncaptures; - int *captures; - - void *regex; - void *regex_sd; - - ngx_http_lua_complex_value_t *replace; - - const char *pattern; - } ngx_http_lua_regex_t; - - ngx_http_lua_regex_t * - ngx_http_lua_ffi_compile_regex(const unsigned char *pat, - size_t pat_len, int flags, - int pcre_opts, unsigned char *errstr, - size_t errstr_size); - - int ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, - const unsigned char *s, size_t len, int pos); - - void ngx_http_lua_ffi_destroy_regex(ngx_http_lua_regex_t *re); - - int ngx_http_lua_ffi_compile_replace_template(ngx_http_lua_regex_t *re, - const unsigned char - *replace_data, - size_t replace_len); - - struct ngx_http_lua_script_engine_s; - typedef struct ngx_http_lua_script_engine_s *ngx_http_lua_script_engine_t; - - ngx_http_lua_script_engine_t *ngx_http_lua_ffi_create_script_engine(void); - - void ngx_http_lua_ffi_init_script_engine(ngx_http_lua_script_engine_t *e, - const unsigned char *subj, - ngx_http_lua_regex_t *compiled, - int count); - - void ngx_http_lua_ffi_destroy_script_engine( - ngx_http_lua_script_engine_t *e); - - size_t ngx_http_lua_ffi_script_eval_len(ngx_http_lua_script_engine_t *e, - ngx_http_lua_complex_value_t *cv); - - size_t ngx_http_lua_ffi_script_eval_data(ngx_http_lua_script_engine_t *e, - ngx_http_lua_complex_value_t *cv, - unsigned char *dst); - - uint32_t ngx_http_lua_ffi_max_regex_cache_size(void); -]] - - -local c_str_type = ffi.typeof("const char *") - -local cached_re_opts = new_tab(0, 4) - -local _M = { - version = base.version -} - - -local buf_grow_ratio = 2 - - -function _M.set_buf_grow_ratio(ratio) - buf_grow_ratio = ratio -end - - -local function get_max_regex_cache_size() - if max_regex_cache_size then - return max_regex_cache_size - end - max_regex_cache_size = C.ngx_http_lua_ffi_max_regex_cache_size() - return max_regex_cache_size -end - - -local regex_cache_is_empty = true - - -function _M.is_regex_cache_empty() - return regex_cache_is_empty -end - - -local function lrucache_set_wrapper(...) - regex_cache_is_empty = false - lrucache_set(...) -end - - -local function parse_regex_opts(opts) - local t = cached_re_opts[opts] - if t then - return t[1], t[2] - end - - local flags = 0 - local pcre_opts = 0 - local len = #opts - - for i = 1, len do - local opt = byte(opts, i) - if opt == byte("o") then - flags = bor(flags, FLAG_COMPILE_ONCE) - - elseif opt == byte("j") then - flags = bor(flags, FLAG_JIT) - - elseif opt == byte("i") then - pcre_opts = bor(pcre_opts, PCRE_CASELESS) - - elseif opt == byte("s") then - pcre_opts = bor(pcre_opts, PCRE_DOTALL) - - elseif opt == byte("m") then - pcre_opts = bor(pcre_opts, PCRE_MULTILINE) - - elseif opt == byte("u") then - pcre_opts = bor(pcre_opts, PCRE_UTF8) - - elseif opt == byte("U") then - pcre_opts = bor(pcre_opts, PCRE_UTF8) - flags = bor(flags, FLAG_NO_UTF8_CHECK) - - elseif opt == byte("x") then - pcre_opts = bor(pcre_opts, PCRE_EXTENDED) - - elseif opt == byte("d") then - flags = bor(flags, FLAG_DFA) - - elseif opt == byte("a") then - pcre_opts = bor(pcre_opts, PCRE_ANCHORED) - - elseif opt == byte("D") then - pcre_opts = bor(pcre_opts, PCRE_DUPNAMES) - flags = bor(flags, FLAG_DUPNAMES) - - elseif opt == byte("J") then - pcre_opts = bor(pcre_opts, PCRE_JAVASCRIPT_COMPAT) - - else - return error(fmt('unknown flag "%s" (flags "%s")', - sub(opts, i, i), opts)) - end - end - - cached_re_opts[opts] = {flags, pcre_opts} - return flags, pcre_opts -end - - -local function collect_named_captures(compiled, flags, res) - local name_count = compiled.name_count - local name_table = compiled.name_table - local entry_size = compiled.name_entry_size - - local ind = 0 - local dup_names = (band(flags, FLAG_DUPNAMES) ~= 0) - for i = 1, name_count do - local n = bor(lshift(name_table[ind], 8), name_table[ind + 1]) - -- ngx.say("n = ", n) - local name = ffi_string(name_table + ind + 2) - local cap = res[n] - if dup_names then - -- unmatched captures (false) are not collected - if cap then - local old = res[name] - if old then - old[#old + 1] = cap - else - res[name] = {cap} - end - end - else - res[name] = cap - end - - ind = ind + entry_size - end -end - - -local function collect_captures(compiled, rc, subj, flags, res) - local cap = compiled.captures - local ncap = compiled.ncaptures - local name_count = compiled.name_count - - if not res then - res = new_tab(ncap, name_count) - end - - local i = 0 - local n = 0 - while i <= ncap do - if i > rc then - res[i] = false - else - local from = cap[n] - if from >= 0 then - local to = cap[n + 1] - res[i] = sub(subj, from + 1, to) - else - res[i] = false - end - end - i = i + 1 - n = n + 2 - end - - if name_count > 0 then - collect_named_captures(compiled, flags, res) - end - - return res -end - - -_M.collect_captures = collect_captures - - -local function destroy_compiled_regex(compiled) - C.ngx_http_lua_ffi_destroy_regex(ffi_gc(compiled, nil)) -end - - -_M.destroy_compiled_regex = destroy_compiled_regex - - -local function re_match_compile(regex, opts) - local flags = 0 - local pcre_opts = 0 - - if opts then - flags, pcre_opts = parse_regex_opts(opts) - else - opts = "" - end - - local compiled, key - local compile_once = (band(flags, FLAG_COMPILE_ONCE) == 1) - - -- FIXME: better put this in the outer scope when fixing the ngx.re API's - -- compatibility in the init_by_lua* context. - if not regex_match_cache then - local sz = get_max_regex_cache_size() - if sz <= 0 then - compile_once = false - else - regex_match_cache = lrucache.new(sz) - end - end - - if compile_once then - key = regex .. '\0' .. opts - compiled = lrucache_get(regex_match_cache, key) - end - - -- compile the regex - - if compiled == nil then - -- print("compiled regex not found, compiling regex...") - local errbuf = get_string_buf(MAX_ERR_MSG_LEN) - - compiled = C.ngx_http_lua_ffi_compile_regex(regex, #regex, - flags, pcre_opts, - errbuf, MAX_ERR_MSG_LEN) - - if compiled == nil then - return nil, ffi_string(errbuf) - end - - ffi_gc(compiled, C.ngx_http_lua_ffi_destroy_regex) - - -- print("ncaptures: ", compiled.ncaptures) - - if compile_once then - -- print("inserting compiled regex into cache") - lrucache_set_wrapper(regex_match_cache, key, compiled) - end - end - - return compiled, compile_once, flags -end - - -_M.re_match_compile = re_match_compile - - -local function re_match_helper(subj, regex, opts, ctx, want_caps, res, nth) - -- we need to cast this to strings to avoid exceptions when they are - -- something else. - subj = tostring(subj) - - local compiled, compile_once, flags = re_match_compile(regex, opts) - if compiled == nil then - -- compiled_once holds the error string - if not want_caps then - return nil, nil, compile_once - end - return nil, compile_once - end - - -- exec the compiled regex - - local rc - do - local pos - if ctx then - pos = ctx.pos - if not pos or pos <= 0 then - pos = 0 - else - pos = pos - 1 - end - - else - pos = 0 - end - - rc = C.ngx_http_lua_ffi_exec_regex(compiled, flags, subj, #subj, pos) - end - - if rc == PCRE_ERROR_NOMATCH then - if not compile_once then - destroy_compiled_regex(compiled) - end - return nil - end - - if rc < 0 then - if not compile_once then - destroy_compiled_regex(compiled) - end - if not want_caps then - return nil, nil, "pcre_exec() failed: " .. rc - end - return nil, "pcre_exec() failed: " .. rc - end - - if rc == 0 then - if band(flags, FLAG_DFA) == 0 then - if not want_caps then - return nil, nil, "capture size too small" - end - return nil, "capture size too small" - end - - rc = 1 - end - - -- print("cap 0: ", compiled.captures[0]) - -- print("cap 1: ", compiled.captures[1]) - - if ctx then - ctx.pos = compiled.captures[1] + 1 - end - - if not want_caps then - if not nth or nth < 0 then - nth = 0 - end - - if nth > compiled.ncaptures then - return nil, nil, "nth out of bound" - end - - if nth >= rc then - return nil, nil - end - - local from = compiled.captures[nth * 2] + 1 - local to = compiled.captures[nth * 2 + 1] - - if from < 0 or to < 0 then - return nil, nil - end - - return from, to - end - - res = collect_captures(compiled, rc, subj, flags, res) - - if not compile_once then - destroy_compiled_regex(compiled) - end - - return res -end - - -function ngx.re.match(subj, regex, opts, ctx, res) - return re_match_helper(subj, regex, opts, ctx, true, res) -end - - -function ngx.re.find(subj, regex, opts, ctx, nth) - return re_match_helper(subj, regex, opts, ctx, false, nil, nth) -end - - -do - local function destroy_re_gmatch_iterator(iterator) - if not iterator._compile_once then - destroy_compiled_regex(iterator._compiled) - end - iterator._compiled = nil - iterator._pos = nil - iterator._subj = nil - end - - - local function iterate_re_gmatch(self) - local compiled = self._compiled - local subj = self._subj - local subj_len = self._subj_len - local flags = self._flags - local pos = self._pos - - if not pos then - -- The iterator is exhausted. - return nil - end - - local rc = C.ngx_http_lua_ffi_exec_regex(compiled, flags, subj, - subj_len, pos) - - if rc == PCRE_ERROR_NOMATCH then - destroy_re_gmatch_iterator(self) - return nil - end - - if rc < 0 then - destroy_re_gmatch_iterator(self) - return nil, "pcre_exec() failed: " .. rc - end - - if rc == 0 then - if band(flags, FLAG_DFA) == 0 then - destroy_re_gmatch_iterator(self) - return nil, "capture size too small" - end - - rc = 1 - end - - local cp_pos = tonumber(compiled.captures[1]) - if cp_pos == compiled.captures[0] then - cp_pos = cp_pos + 1 - if cp_pos > subj_len then - local res = collect_captures(compiled, rc, subj, flags) - destroy_re_gmatch_iterator(self) - return res - end - end - self._pos = cp_pos - return collect_captures(compiled, rc, subj, flags) - end - - - local re_gmatch_iterator_mt = { __call = iterate_re_gmatch } - - function ngx.re.gmatch(subj, regex, opts) - subj = tostring(subj) - - local compiled, compile_once, flags = re_match_compile(regex, opts) - if compiled == nil then - -- compiled_once holds the error string - return nil, compile_once - end - - local re_gmatch_iterator = { - _compiled = compiled, - _compile_once = compile_once, - _subj = subj, - _subj_len = #subj, - _flags = flags, - _pos = 0, - } - - return setmetatable(re_gmatch_iterator, re_gmatch_iterator_mt) - end -end -- do - - -local function new_script_engine(subj, compiled, count) - if not script_engine then - script_engine = C.ngx_http_lua_ffi_create_script_engine() - if script_engine == nil then - return nil - end - ffi_gc(script_engine, C.ngx_http_lua_ffi_destroy_script_engine) - end - - C.ngx_http_lua_ffi_init_script_engine(script_engine, subj, compiled, - count) - return script_engine -end - - -local function check_buf_size(buf, buf_size, pos, len, new_len, must_alloc) - if new_len > buf_size then - buf_size = buf_size * buf_grow_ratio - if buf_size < new_len then - buf_size = new_len - end - local new_buf = get_string_buf(buf_size, must_alloc) - ffi_copy(new_buf, buf, len) - buf = new_buf - pos = buf + len - end - return buf, buf_size, pos, new_len -end - - -_M.check_buf_size = check_buf_size - - -local function re_sub_compile(regex, opts, replace, func) - local flags = 0 - local pcre_opts = 0 - - if opts then - flags, pcre_opts = parse_regex_opts(opts) - else - opts = "" - end - - local compiled - local compile_once = (band(flags, FLAG_COMPILE_ONCE) == 1) - if compile_once then - if func then - local subcache = regex_sub_func_cache[opts] - if subcache then - -- print("cache hit!") - compiled = subcache[regex] - end - - else - local subcache = regex_sub_str_cache[opts] - if subcache then - local subsubcache = subcache[regex] - if subsubcache then - -- print("cache hit!") - compiled = subsubcache[replace] - end - end - end - end - - -- compile the regex - - if compiled == nil then - -- print("compiled regex not found, compiling regex...") - local errbuf = get_string_buf(MAX_ERR_MSG_LEN) - - compiled = C.ngx_http_lua_ffi_compile_regex(regex, #regex, flags, - pcre_opts, errbuf, - MAX_ERR_MSG_LEN) - - if compiled == nil then - return nil, ffi_string(errbuf) - end - - ffi_gc(compiled, C.ngx_http_lua_ffi_destroy_regex) - - if func == nil then - local rc = - C.ngx_http_lua_ffi_compile_replace_template(compiled, - replace, #replace) - if rc ~= 0 then - if not compile_once then - destroy_compiled_regex(compiled) - end - return nil, "failed to compile the replacement template" - end - end - - -- print("ncaptures: ", compiled.ncaptures) - - if compile_once then - if regex_cache_size < get_max_regex_cache_size() then - -- print("inserting compiled regex into cache") - if func then - local subcache = regex_sub_func_cache[opts] - if not subcache then - regex_sub_func_cache[opts] = {[regex] = compiled} - - else - subcache[regex] = compiled - end - - else - local subcache = regex_sub_str_cache[opts] - if not subcache then - regex_sub_str_cache[opts] = - {[regex] = {[replace] = compiled}} - - else - local subsubcache = subcache[regex] - if not subsubcache then - subcache[regex] = {[replace] = compiled} - - else - subsubcache[replace] = compiled - end - end - end - - regex_cache_size = regex_cache_size + 1 - else - compile_once = false - end - end - end - - return compiled, compile_once, flags -end - - -_M.re_sub_compile = re_sub_compile - - -local function re_sub_func_helper(subj, regex, replace, opts, global) - local compiled, compile_once, flags = - re_sub_compile(regex, opts, nil, replace) - if not compiled then - -- error string is in compile_once - return nil, nil, compile_once - end - - -- exec the compiled regex - - subj = tostring(subj) - local subj_len = #subj - local count = 0 - local pos = 0 - local cp_pos = 0 - - local dst_buf_size = get_string_buf_size() - -- Note: we have to always allocate the string buffer because - -- the user might call whatever resty.core's API functions recursively - -- in the user callback function. - local dst_buf = get_string_buf(dst_buf_size, true) - local dst_pos = dst_buf - local dst_len = 0 - - while true do - local rc = C.ngx_http_lua_ffi_exec_regex(compiled, flags, subj, - subj_len, pos) - if rc == PCRE_ERROR_NOMATCH then - break - end - - if rc < 0 then - if not compile_once then - destroy_compiled_regex(compiled) - end - return nil, nil, "pcre_exec() failed: " .. rc - end - - if rc == 0 then - if band(flags, FLAG_DFA) == 0 then - if not compile_once then - destroy_compiled_regex(compiled) - end - return nil, nil, "capture size too small" - end - - rc = 1 - end - - count = count + 1 - local prefix_len = compiled.captures[0] - cp_pos - - local res = collect_captures(compiled, rc, subj, flags) - - local piece = tostring(replace(res)) - local piece_len = #piece - - local new_dst_len = dst_len + prefix_len + piece_len - dst_buf, dst_buf_size, dst_pos, dst_len = - check_buf_size(dst_buf, dst_buf_size, dst_pos, dst_len, - new_dst_len, true) - - if prefix_len > 0 then - ffi_copy(dst_pos, ffi_cast(c_str_type, subj) + cp_pos, - prefix_len) - dst_pos = dst_pos + prefix_len - end - - if piece_len > 0 then - ffi_copy(dst_pos, piece, piece_len) - dst_pos = dst_pos + piece_len - end - - cp_pos = compiled.captures[1] - pos = cp_pos - if pos == compiled.captures[0] then - pos = pos + 1 - if pos > subj_len then - break - end - end - - if not global then - break - end - end - - if not compile_once then - destroy_compiled_regex(compiled) - end - - if count > 0 then - if pos < subj_len then - local suffix_len = subj_len - cp_pos - - local new_dst_len = dst_len + suffix_len - local _ - dst_buf, _, dst_pos, dst_len = - check_buf_size(dst_buf, dst_buf_size, dst_pos, dst_len, - new_dst_len, true) - - ffi_copy(dst_pos, ffi_cast(c_str_type, subj) + cp_pos, - suffix_len) - end - return ffi_string(dst_buf, dst_len), count - end - - return subj, 0 -end - - -local function re_sub_str_helper(subj, regex, replace, opts, global) - local compiled, compile_once, flags = - re_sub_compile(regex, opts, replace, nil) - if not compiled then - -- error string is in compile_once - return nil, nil, compile_once - end - - -- exec the compiled regex - - subj = tostring(subj) - local subj_len = #subj - local count = 0 - local pos = 0 - local cp_pos = 0 - - local dst_buf_size = get_string_buf_size() - local dst_buf = get_string_buf(dst_buf_size) - local dst_pos = dst_buf - local dst_len = 0 - - while true do - local rc = C.ngx_http_lua_ffi_exec_regex(compiled, flags, subj, - subj_len, pos) - if rc == PCRE_ERROR_NOMATCH then - break - end - - if rc < 0 then - if not compile_once then - destroy_compiled_regex(compiled) - end - return nil, nil, "pcre_exec() failed: " .. rc - end - - if rc == 0 then - if band(flags, FLAG_DFA) == 0 then - if not compile_once then - destroy_compiled_regex(compiled) - end - return nil, nil, "capture size too small" - end - - rc = 1 - end - - count = count + 1 - local prefix_len = compiled.captures[0] - cp_pos - - local cv = compiled.replace - if cv.lengths ~= nil then - local e = new_script_engine(subj, compiled, rc) - if e == nil then - return nil, nil, "failed to create script engine" - end - - local bit_len = C.ngx_http_lua_ffi_script_eval_len(e, cv) - local new_dst_len = dst_len + prefix_len + bit_len - dst_buf, dst_buf_size, dst_pos, dst_len = - check_buf_size(dst_buf, dst_buf_size, dst_pos, dst_len, - new_dst_len) - - if prefix_len > 0 then - ffi_copy(dst_pos, ffi_cast(c_str_type, subj) + cp_pos, - prefix_len) - dst_pos = dst_pos + prefix_len - end - - if bit_len > 0 then - C.ngx_http_lua_ffi_script_eval_data(e, cv, dst_pos) - dst_pos = dst_pos + bit_len - end - - else - local bit_len = cv.value.len - - dst_buf, dst_buf_size, dst_pos, dst_len = - check_buf_size(dst_buf, dst_buf_size, dst_pos, dst_len, - dst_len + prefix_len + bit_len) - - if prefix_len > 0 then - ffi_copy(dst_pos, ffi_cast(c_str_type, subj) + cp_pos, - prefix_len) - dst_pos = dst_pos + prefix_len - end - - if bit_len > 0 then - ffi_copy(dst_pos, cv.value.data, bit_len) - dst_pos = dst_pos + bit_len - end - end - - cp_pos = compiled.captures[1] - pos = cp_pos - if pos == compiled.captures[0] then - pos = pos + 1 - if pos > subj_len then - break - end - end - - if not global then - break - end - end - - if not compile_once then - destroy_compiled_regex(compiled) - end - - if count > 0 then - if pos < subj_len then - local suffix_len = subj_len - cp_pos - - local new_dst_len = dst_len + suffix_len - local _ - dst_buf, _, dst_pos, dst_len = - check_buf_size(dst_buf, dst_buf_size, dst_pos, dst_len, - new_dst_len) - - ffi_copy(dst_pos, ffi_cast(c_str_type, subj) + cp_pos, - suffix_len) - end - return ffi_string(dst_buf, dst_len), count - end - - return subj, 0 -end - - -local function re_sub_helper(subj, regex, replace, opts, global) - local repl_type = type(replace) - if repl_type == "function" then - return re_sub_func_helper(subj, regex, replace, opts, global) - end - - if repl_type ~= "string" then - replace = tostring(replace) - end - - return re_sub_str_helper(subj, regex, replace, opts, global) -end - - -function ngx.re.sub(subj, regex, replace, opts) - return re_sub_helper(subj, regex, replace, opts, false) -end - - -function ngx.re.gsub(subj, regex, replace, opts) - return re_sub_helper(subj, regex, replace, opts, true) -end - - -return _M diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/request.lua b/rootfs/etc/nginx/lua/vendor/resty/core/request.lua deleted file mode 100644 index c737366f85..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core/request.lua +++ /dev/null @@ -1,351 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local ffi = require 'ffi' -local base = require "resty.core.base" - - -local FFI_BAD_CONTEXT = base.FFI_BAD_CONTEXT -local FFI_DECLINED = base.FFI_DECLINED -local FFI_OK = base.FFI_OK -local new_tab = base.new_tab -local C = ffi.C -local ffi_cast = ffi.cast -local ffi_str = ffi.string -local get_string_buf = base.get_string_buf -local get_size_ptr = base.get_size_ptr -local setmetatable = setmetatable -local gsub = ngx.re.gsub -local lower = string.lower -local rawget = rawget -local ngx = ngx -local getfenv = getfenv -local type = type -local error = error -local tostring = tostring -local tonumber = tonumber - - -ffi.cdef[[ - typedef struct { - ngx_http_lua_ffi_str_t key; - ngx_http_lua_ffi_str_t value; - } ngx_http_lua_ffi_table_elt_t; - - int ngx_http_lua_ffi_req_get_headers_count(ngx_http_request_t *r, - int max); - - int ngx_http_lua_ffi_req_get_headers(ngx_http_request_t *r, - ngx_http_lua_ffi_table_elt_t *out, int count, int raw); - - int ngx_http_lua_ffi_req_get_uri_args_count(ngx_http_request_t *r, - int max); - - size_t ngx_http_lua_ffi_req_get_querystring_len(ngx_http_request_t *r); - - int ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, - unsigned char *buf, ngx_http_lua_ffi_table_elt_t *out, int count); - - double ngx_http_lua_ffi_req_start_time(ngx_http_request_t *r); - - int ngx_http_lua_ffi_req_get_method(ngx_http_request_t *r); - - int ngx_http_lua_ffi_req_get_method_name(ngx_http_request_t *r, - char *name, size_t *len); - - int ngx_http_lua_ffi_req_set_method(ngx_http_request_t *r, int method); - - int ngx_http_lua_ffi_req_header_set_single_value(ngx_http_request_t *r, - const unsigned char *key, size_t key_len, const unsigned char *value, - size_t value_len); -]] - - -local table_elt_type = ffi.typeof("ngx_http_lua_ffi_table_elt_t*") -local table_elt_size = ffi.sizeof("ngx_http_lua_ffi_table_elt_t") -local req_headers_mt = { - __index = function (tb, key) - return rawget(tb, (gsub(lower(key), '_', '-', "jo"))) - end -} - - -function ngx.req.get_headers(max_headers, raw) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - if not max_headers then - max_headers = -1 - end - - if not raw then - raw = 0 - else - raw = 1 - end - - local n = C.ngx_http_lua_ffi_req_get_headers_count(r, max_headers) - if n == FFI_BAD_CONTEXT then - return error("API disabled in the current context") - end - - if n == 0 then - return {} - end - - local raw_buf = get_string_buf(n * table_elt_size) - local buf = ffi_cast(table_elt_type, raw_buf) - - local rc = C.ngx_http_lua_ffi_req_get_headers(r, buf, n, raw) - if rc == 0 then - local headers = new_tab(0, n) - for i = 0, n - 1 do - local h = buf[i] - - local key = h.key - key = ffi_str(key.data, key.len) - - local value = h.value - value = ffi_str(value.data, value.len) - - local existing = headers[key] - if existing then - if type(existing) == "table" then - existing[#existing + 1] = value - else - headers[key] = {existing, value} - end - - else - headers[key] = value - end - end - if raw == 0 then - return setmetatable(headers, req_headers_mt) - end - return headers - end - - return nil -end - - -function ngx.req.get_uri_args(max_args) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - if not max_args then - max_args = -1 - end - - local n = C.ngx_http_lua_ffi_req_get_uri_args_count(r, max_args) - if n == FFI_BAD_CONTEXT then - return error("API disabled in the current context") - end - - if n == 0 then - return {} - end - - local args_len = C.ngx_http_lua_ffi_req_get_querystring_len(r) - - local strbuf = get_string_buf(args_len + n * table_elt_size) - local kvbuf = ffi_cast(table_elt_type, strbuf + args_len) - - local nargs = C.ngx_http_lua_ffi_req_get_uri_args(r, strbuf, kvbuf, n) - - local args = new_tab(0, nargs) - for i = 0, nargs - 1 do - local arg = kvbuf[i] - - local key = arg.key - key = ffi_str(key.data, key.len) - - local value = arg.value - local len = value.len - if len == -1 then - value = true - else - value = ffi_str(value.data, len) - end - - local existing = args[key] - if existing then - if type(existing) == "table" then - existing[#existing + 1] = value - else - args[key] = {existing, value} - end - - else - args[key] = value - end - end - return args -end - - -function ngx.req.start_time() - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - return tonumber(C.ngx_http_lua_ffi_req_start_time(r)) -end - - -do - local methods = { - [0x0002] = "GET", - [0x0004] = "HEAD", - [0x0008] = "POST", - [0x0010] = "PUT", - [0x0020] = "DELETE", - [0x0040] = "MKCOL", - [0x0080] = "COPY", - [0x0100] = "MOVE", - [0x0200] = "OPTIONS", - [0x0400] = "PROPFIND", - [0x0800] = "PROPPATCH", - [0x1000] = "LOCK", - [0x2000] = "UNLOCK", - [0x4000] = "PATCH", - [0x8000] = "TRACE", - } - - function ngx.req.get_method() - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - do - local id = C.ngx_http_lua_ffi_req_get_method(r) - if id == FFI_BAD_CONTEXT then - return error("API disabled in the current context") - end - - local method = methods[id] - if method then - return method - end - end - - local buf = get_string_buf(32) - local sizep = get_size_ptr() - sizep[0] = 32 - - local rc = C.ngx_http_lua_ffi_req_get_method_name(r, buf, sizep) - if rc ~= 0 then - return nil - end - - return ffi_str(buf, sizep[0]) - end -end -- do - - -function ngx.req.set_method(method) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - if type(method) ~= "number" then - return error("bad method number") - end - - local rc = C.ngx_http_lua_ffi_req_set_method(r, method) - if rc == FFI_OK then - return - end - - if rc == FFI_BAD_CONTEXT then - return error("API disabled in the current context") - end - - if rc == FFI_DECLINED then - return error("unsupported HTTP method: " .. method) - end - - return error("unknown error: " .. rc) -end - - -do - local orig_func = ngx.req.set_header - - function ngx.req.set_header(name, value) - if type(value) == "table" then - return orig_func(name, value) - end - - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - if type(name) ~= "string" then - name = tostring(name) - end - - local rc - if not value then - rc = C.ngx_http_lua_ffi_req_header_set_single_value(r, name, - #name, nil, 0) - - else - if type(value) ~= "string" then - value = tostring(value) - end - - rc = C.ngx_http_lua_ffi_req_header_set_single_value(r, name, - #name, value, #value) - end - - if rc == FFI_OK or rc == FFI_DECLINED then - return - end - - if rc == FFI_BAD_CONTEXT then - return error("API disabled in the current context") - end - - return error("error") - end -end -- do - - -function ngx.req.clear_header(name) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - if type(name) ~= "string" then - name = tostring(name) - end - - local rc = C.ngx_http_lua_ffi_req_header_set_single_value(r, name, #name, - nil, 0) - - if rc == FFI_OK or rc == FFI_DECLINED then - return - end - - if rc == FFI_BAD_CONTEXT then - return error("API disabled in the current context") - end - - return error("error") -end - - -return { - version = base.version -} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/response.lua b/rootfs/etc/nginx/lua/vendor/resty/core/response.lua deleted file mode 100644 index 2944d75d19..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core/response.lua +++ /dev/null @@ -1,165 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local ffi = require 'ffi' -local base = require "resty.core.base" - - -local C = ffi.C -local ffi_cast = ffi.cast -local ffi_str = ffi.string -local new_tab = base.new_tab -local FFI_BAD_CONTEXT = base.FFI_BAD_CONTEXT -local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX -local FFI_DECLINED = base.FFI_DECLINED -local get_string_buf = base.get_string_buf -local getmetatable = getmetatable -local type = type -local tostring = tostring -local getfenv = getfenv -local error = error -local ngx = ngx - - -local MAX_HEADER_VALUES = 100 -local errmsg = base.get_errmsg_ptr() -local ffi_str_type = ffi.typeof("ngx_http_lua_ffi_str_t*") -local ffi_str_size = ffi.sizeof("ngx_http_lua_ffi_str_t") - - -ffi.cdef[[ - int ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, - const char *key_data, size_t key_len, int is_nil, - const char *sval, size_t sval_len, ngx_http_lua_ffi_str_t *mvals, - size_t mvals_len, char **errmsg); - - int ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, - const unsigned char *key, size_t key_len, - unsigned char *key_buf, ngx_http_lua_ffi_str_t *values, - int max_nvalues); -]] - - -local function set_resp_header(tb, key, value) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - if type(key) ~= "string" then - key = tostring(key) - end - - local rc - if value == nil then - rc = C.ngx_http_lua_ffi_set_resp_header(r, key, #key, true, nil, 0, - nil, 0, errmsg) - else - local sval, sval_len, mvals, mvals_len, buf - - if type(value) == "table" then - mvals_len = #value - buf = get_string_buf(ffi_str_size * mvals_len) - mvals = ffi_cast(ffi_str_type, buf) - for i = 1, mvals_len do - local s = value[i] - if type(s) ~= "string" then - s = tostring(s) - value[i] = s - end - local str = mvals[i - 1] - str.data = s - str.len = #s - end - - sval_len = 0 - - else - if type(value) ~= "string" then - sval = tostring(value) - else - sval = value - end - sval_len = #sval - - mvals_len = 0 - end - - rc = C.ngx_http_lua_ffi_set_resp_header(r, key, #key, false, sval, - sval_len, mvals, mvals_len, - errmsg) - end - - if rc == 0 or rc == FFI_DECLINED then - return - end - - if rc == FFI_NO_REQ_CTX then - return error("no request ctx found") - end - - if rc == FFI_BAD_CONTEXT then - return error("API disabled in the current context") - end - - -- rc == FFI_ERROR - return error(ffi_str(errmsg[0])) -end - - -local function get_resp_header(tb, key) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - if type(key) ~= "string" then - key = tostring(key) - end - - local key_len = #key - - local key_buf = get_string_buf(key_len + ffi_str_size * MAX_HEADER_VALUES) - local values = ffi_cast(ffi_str_type, key_buf + key_len) - local n = C.ngx_http_lua_ffi_get_resp_header(r, key, key_len, key_buf, - values, MAX_HEADER_VALUES) - - -- print("retval: ", n) - - if n == FFI_BAD_CONTEXT then - return error("API disabled in the current context") - end - - if n == 0 then - return nil - end - - if n == 1 then - local v = values[0] - return ffi_str(v.data, v.len) - end - - if n > 0 then - local ret = new_tab(n, 0) - for i = 1, n do - local v = values[i - 1] - ret[i] = ffi_str(v.data, v.len) - end - return ret - end - - -- n == FFI_ERROR - return error("no memory") -end - - -do - local mt = getmetatable(ngx.header) - mt.__newindex = set_resp_header - mt.__index = get_resp_header -end - - -return { - version = base.version -} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/shdict.lua b/rootfs/etc/nginx/lua/vendor/resty/core/shdict.lua deleted file mode 100644 index 55f2a88a91..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core/shdict.lua +++ /dev/null @@ -1,538 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local ffi = require 'ffi' -local base = require "resty.core.base" - -local ffi_new = ffi.new -local ffi_str = ffi.string -local C = ffi.C -local get_string_buf = base.get_string_buf -local get_string_buf_size = base.get_string_buf_size -local get_size_ptr = base.get_size_ptr -local tonumber = tonumber -local tostring = tostring -local next = next -local type = type -local error = error -local ngx_shared = ngx.shared -local getmetatable = getmetatable -local FFI_ERROR = base.FFI_ERROR -local FFI_DECLINED = base.FFI_DECLINED - - -ffi.cdef[[ - int ngx_http_lua_ffi_shdict_get(void *zone, const unsigned char *key, - size_t key_len, int *value_type, unsigned char **str_value_buf, - size_t *str_value_len, double *num_value, int *user_flags, - int get_stale, int *is_stale, char **errmsg); - - int ngx_http_lua_ffi_shdict_incr(void *zone, const unsigned char *key, - size_t key_len, double *value, char **err, int has_init, double init, - long init_ttl, int *forcible); - - int ngx_http_lua_ffi_shdict_store(void *zone, int op, - const unsigned char *key, size_t key_len, int value_type, - const unsigned char *str_value_buf, size_t str_value_len, - double num_value, int exptime, int user_flags, char **errmsg, - int *forcible); - - int ngx_http_lua_ffi_shdict_flush_all(void *zone); - - int ngx_http_lua_ffi_shdict_get_ttl(void *zone, - const unsigned char *key, size_t key_len); - - int ngx_http_lua_ffi_shdict_set_expire(void *zone, - const unsigned char *key, size_t key_len, int exptime); - - size_t ngx_http_lua_ffi_shdict_capacity(void *zone); -]] - -if not pcall(function () return C.ngx_http_lua_ffi_shdict_free_space end) then - ffi.cdef[[ - size_t ngx_http_lua_ffi_shdict_free_space(void *zone); - ]] -end - -if not pcall(function () return C.free end) then - ffi.cdef[[ - void free(void *ptr); - ]] -end - - -local value_type = ffi_new("int[1]") -local user_flags = ffi_new("int[1]") -local num_value = ffi_new("double[1]") -local is_stale = ffi_new("int[1]") -local forcible = ffi_new("int[1]") -local str_value_buf = ffi_new("unsigned char *[1]") -local errmsg = base.get_errmsg_ptr() - - -local function check_zone(zone) - if not zone or type(zone) ~= "table" then - return error("bad \"zone\" argument") - end - - zone = zone[1] - if type(zone) ~= "userdata" then - return error("bad \"zone\" argument") - end - - return zone -end - - -local function shdict_store(zone, op, key, value, exptime, flags) - zone = check_zone(zone) - - if not exptime then - exptime = 0 - elseif exptime < 0 then - return error('bad "exptime" argument') - end - - if not flags then - flags = 0 - end - - if key == nil then - return nil, "nil key" - end - - if type(key) ~= "string" then - key = tostring(key) - end - - local key_len = #key - if key_len == 0 then - return nil, "empty key" - end - if key_len > 65535 then - return nil, "key too long" - end - - local str_val_buf - local str_val_len = 0 - local num_val = 0 - local valtyp = type(value) - - -- print("value type: ", valtyp) - -- print("exptime: ", exptime) - - if valtyp == "string" then - valtyp = 4 -- LUA_TSTRING - str_val_buf = value - str_val_len = #value - - elseif valtyp == "number" then - valtyp = 3 -- LUA_TNUMBER - num_val = value - - elseif value == nil then - valtyp = 0 -- LUA_TNIL - - elseif valtyp == "boolean" then - valtyp = 1 -- LUA_TBOOLEAN - num_val = value and 1 or 0 - - else - return nil, "bad value type" - end - - local rc = C.ngx_http_lua_ffi_shdict_store(zone, op, key, key_len, - valtyp, str_val_buf, - str_val_len, num_val, - exptime * 1000, flags, errmsg, - forcible) - - -- print("rc == ", rc) - - if rc == 0 then -- NGX_OK - return true, nil, forcible[0] == 1 - end - - -- NGX_DECLINED or NGX_ERROR - return false, ffi_str(errmsg[0]), forcible[0] == 1 -end - - -local function shdict_set(zone, key, value, exptime, flags) - return shdict_store(zone, 0, key, value, exptime, flags) -end - - -local function shdict_safe_set(zone, key, value, exptime, flags) - return shdict_store(zone, 0x0004, key, value, exptime, flags) -end - - -local function shdict_add(zone, key, value, exptime, flags) - return shdict_store(zone, 0x0001, key, value, exptime, flags) -end - - -local function shdict_safe_add(zone, key, value, exptime, flags) - return shdict_store(zone, 0x0005, key, value, exptime, flags) -end - - -local function shdict_replace(zone, key, value, exptime, flags) - return shdict_store(zone, 0x0002, key, value, exptime, flags) -end - - -local function shdict_delete(zone, key) - return shdict_set(zone, key, nil) -end - - -local function shdict_get(zone, key) - zone = check_zone(zone) - - if key == nil then - return nil, "nil key" - end - - if type(key) ~= "string" then - key = tostring(key) - end - - local key_len = #key - if key_len == 0 then - return nil, "empty key" - end - if key_len > 65535 then - return nil, "key too long" - end - - local size = get_string_buf_size() - local buf = get_string_buf(size) - str_value_buf[0] = buf - local value_len = get_size_ptr() - value_len[0] = size - - local rc = C.ngx_http_lua_ffi_shdict_get(zone, key, key_len, value_type, - str_value_buf, value_len, - num_value, user_flags, 0, - is_stale, errmsg) - if rc ~= 0 then - if errmsg[0] then - return nil, ffi_str(errmsg[0]) - end - - return error("failed to get the key") - end - - local typ = value_type[0] - - if typ == 0 then -- LUA_TNIL - return nil - end - - local flags = tonumber(user_flags[0]) - - local val - - if typ == 4 then -- LUA_TSTRING - if str_value_buf[0] ~= buf then - -- ngx.say("len: ", tonumber(value_len[0])) - buf = str_value_buf[0] - val = ffi_str(buf, value_len[0]) - C.free(buf) - else - val = ffi_str(buf, value_len[0]) - end - - elseif typ == 3 then -- LUA_TNUMBER - val = tonumber(num_value[0]) - - elseif typ == 1 then -- LUA_TBOOLEAN - val = (tonumber(buf[0]) ~= 0) - - else - return error("unknown value type: " .. typ) - end - - if flags ~= 0 then - return val, flags - end - - return val -end - - -local function shdict_get_stale(zone, key) - zone = check_zone(zone) - - if key == nil then - return nil, "nil key" - end - - if type(key) ~= "string" then - key = tostring(key) - end - - local key_len = #key - if key_len == 0 then - return nil, "empty key" - end - if key_len > 65535 then - return nil, "key too long" - end - - local size = get_string_buf_size() - local buf = get_string_buf(size) - str_value_buf[0] = buf - local value_len = get_size_ptr() - value_len[0] = size - - local rc = C.ngx_http_lua_ffi_shdict_get(zone, key, key_len, value_type, - str_value_buf, value_len, - num_value, user_flags, 1, - is_stale, errmsg) - if rc ~= 0 then - if errmsg[0] then - return nil, ffi_str(errmsg[0]) - end - - return error("failed to get the key") - end - - local typ = value_type[0] - - if typ == 0 then -- LUA_TNIL - return nil - end - - local flags = tonumber(user_flags[0]) - local val - - if typ == 4 then -- LUA_TSTRING - if str_value_buf[0] ~= buf then - -- ngx.say("len: ", tonumber(value_len[0])) - buf = str_value_buf[0] - val = ffi_str(buf, value_len[0]) - C.free(buf) - else - val = ffi_str(buf, value_len[0]) - end - - elseif typ == 3 then -- LUA_TNUMBER - val = tonumber(num_value[0]) - - elseif typ == 1 then -- LUA_TBOOLEAN - val = (tonumber(buf[0]) ~= 0) - - else - return error("unknown value type: " .. typ) - end - - if flags ~= 0 then - return val, flags, is_stale[0] == 1 - end - - return val, nil, is_stale[0] == 1 -end - - -local function shdict_incr(zone, key, value, init, init_ttl) - zone = check_zone(zone) - - if key == nil then - return nil, "nil key" - end - - if type(key) ~= "string" then - key = tostring(key) - end - - local key_len = #key - if key_len == 0 then - return nil, "empty key" - end - if key_len > 65535 then - return nil, "key too long" - end - - if type(value) ~= "number" then - value = tonumber(value) - end - num_value[0] = value - - if init then - local typ = type(init) - if typ ~= "number" then - init = tonumber(init) - - if not init then - return error("bad init arg: number expected, got " .. typ) - end - end - end - - if init_ttl ~= nil then - local typ = type(init_ttl) - if typ ~= "number" then - init_ttl = tonumber(init_ttl) - - if not init_ttl then - error("bad init_ttl arg: number expected, got " .. typ, 2) - end - end - - if init_ttl < 0 then - error('bad "init_ttl" argument', 2) - end - - if not init then - error('must provide "init" when providing "init_ttl"', 2) - end - - else - init_ttl = 0 - end - - local rc = C.ngx_http_lua_ffi_shdict_incr(zone, key, key_len, num_value, - errmsg, init and 1 or 0, - init or 0, init_ttl * 1000, - forcible) - if rc ~= 0 then -- ~= NGX_OK - return nil, ffi_str(errmsg[0]) - end - - if not init then - return tonumber(num_value[0]) - end - - return tonumber(num_value[0]), nil, forcible[0] == 1 -end - - -local function shdict_flush_all(zone) - zone = check_zone(zone) - - C.ngx_http_lua_ffi_shdict_flush_all(zone) -end - - -local function shdict_ttl(zone, key) - zone = check_zone(zone) - - if key == nil then - return nil, "nil key" - end - - if type(key) ~= "string" then - key = tostring(key) - end - - local key_len = #key - if key_len == 0 then - return nil, "empty key" - end - - if key_len > 65535 then - return nil, "key too long" - end - - local rc = C.ngx_http_lua_ffi_shdict_get_ttl(zone, key, key_len) - - if rc == FFI_ERROR then - return nil, "bad zone" - end - - if rc == FFI_DECLINED then - return nil, "not found" - end - - return tonumber(rc) / 1000 -end - - -local function shdict_expire(zone, key, exptime) - zone = check_zone(zone) - - if not exptime then - error('bad "exptime" argument', 2) - end - - if key == nil then - return nil, "nil key" - end - - if type(key) ~= "string" then - key = tostring(key) - end - - local key_len = #key - if key_len == 0 then - return nil, "empty key" - end - - if key_len > 65535 then - return nil, "key too long" - end - - local rc = C.ngx_http_lua_ffi_shdict_set_expire(zone, key, key_len, - exptime * 1000) - - if rc == FFI_ERROR then - return nil, "bad zone" - end - - if rc == FFI_DECLINED then - return nil, "not found" - end - - -- NGINX_OK/FFI_OK - - return true -end - - -local function shdict_capacity(zone) - zone = check_zone(zone) - - return tonumber(C.ngx_http_lua_ffi_shdict_capacity(zone)) -end - - -local function shdict_free_space(zone) - zone = check_zone(zone) - - return tonumber(C.ngx_http_lua_ffi_shdict_free_space(zone)) -end - - -if ngx_shared then - local _, dict = next(ngx_shared, nil) - if dict then - local mt = getmetatable(dict) - if mt then - mt = mt.__index - if mt then - mt.get = shdict_get - mt.get_stale = shdict_get_stale - mt.incr = shdict_incr - mt.set = shdict_set - mt.safe_set = shdict_safe_set - mt.add = shdict_add - mt.safe_add = shdict_safe_add - mt.replace = shdict_replace - mt.delete = shdict_delete - mt.flush_all = shdict_flush_all - mt.ttl = shdict_ttl - mt.expire = shdict_expire - mt.capacity = shdict_capacity - mt.free_space = shdict_free_space - end - end - end -end - - -return { - version = base.version -} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/time.lua b/rootfs/etc/nginx/lua/vendor/resty/core/time.lua deleted file mode 100644 index e4313ff5bd..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core/time.lua +++ /dev/null @@ -1,121 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local ffi = require 'ffi' -local base = require "resty.core.base" - - -local error = error -local tonumber = tonumber -local type = type -local C = ffi.C -local ffi_new = ffi.new -local ffi_str = ffi.string -local time_val = ffi_new("long[1]") -local get_string_buf = base.get_string_buf -local ngx = ngx -local FFI_ERROR = base.FFI_ERROR - - -ffi.cdef[[ -double ngx_http_lua_ffi_now(void); -long ngx_http_lua_ffi_time(void); -void ngx_http_lua_ffi_today(unsigned char *buf); -void ngx_http_lua_ffi_localtime(unsigned char *buf); -void ngx_http_lua_ffi_utctime(unsigned char *buf); -void ngx_http_lua_ffi_update_time(void); -int ngx_http_lua_ffi_cookie_time(unsigned char *buf, long t); -void ngx_http_lua_ffi_http_time(unsigned char *buf, long t); -void ngx_http_lua_ffi_parse_http_time(const unsigned char *str, size_t len, - long *time); -]] - - -function ngx.now() - return tonumber(C.ngx_http_lua_ffi_now()) -end - - -function ngx.time() - return tonumber(C.ngx_http_lua_ffi_time()) -end - - -function ngx.update_time() - C.ngx_http_lua_ffi_update_time() -end - - -function ngx.today() - -- the format of today is 2010-11-19 - local today_buf_size = 10 - local buf = get_string_buf(today_buf_size) - C.ngx_http_lua_ffi_today(buf) - return ffi_str(buf, today_buf_size) -end - - -function ngx.localtime() - -- the format of localtime is 2010-11-19 20:56:31 - local localtime_buf_size = 19 - local buf = get_string_buf(localtime_buf_size) - C.ngx_http_lua_ffi_localtime(buf) - return ffi_str(buf, localtime_buf_size) -end - - -function ngx.utctime() - -- the format of utctime is 2010-11-19 20:56:31 - local utctime_buf_size = 19 - local buf = get_string_buf(utctime_buf_size) - C.ngx_http_lua_ffi_utctime(buf) - return ffi_str(buf, utctime_buf_size) -end - - -function ngx.cookie_time(sec) - if type(sec) ~= "number" then - error("number argument only", 2) - end - - -- the format of cookie time is Mon, 28-Sep-2038 06:00:00 GMT - -- or Mon, 28-Sep-18 06:00:00 GMT - local cookie_time_buf_size = 29 - local buf = get_string_buf(cookie_time_buf_size) - local used_size = C.ngx_http_lua_ffi_cookie_time(buf, sec) - return ffi_str(buf, used_size) -end - - -function ngx.http_time(sec) - if type(sec) ~= "number" then - error("number argument only", 2) - end - - -- the format of http time is Mon, 28 Sep 1970 06:00:00 GMT - local http_time_buf_size = 29 - local buf = get_string_buf(http_time_buf_size) - C.ngx_http_lua_ffi_http_time(buf, sec) - return ffi_str(buf, http_time_buf_size) -end - - -function ngx.parse_http_time(time_str) - if type(time_str) ~= "string" then - error("string argument only", 2) - end - - C.ngx_http_lua_ffi_parse_http_time(time_str, #time_str, time_val) - - local res = time_val[0] - if res == FFI_ERROR then - return nil - end - - return tonumber(res) -end - - -return { - version = base.version -} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/uri.lua b/rootfs/etc/nginx/lua/vendor/resty/core/uri.lua deleted file mode 100644 index af0e655725..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core/uri.lua +++ /dev/null @@ -1,64 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local ffi = require 'ffi' -local ffi_string = ffi.string -local C = ffi.C -local ngx = ngx -local type = type -local tostring = tostring -local base = require "resty.core.base" -local get_string_buf = base.get_string_buf - - -ffi.cdef[[ - size_t ngx_http_lua_ffi_uri_escaped_length(const unsigned char *src, - size_t len); - - void ngx_http_lua_ffi_escape_uri(const unsigned char *src, size_t len, - unsigned char *dst); - - size_t ngx_http_lua_ffi_unescape_uri(const unsigned char *src, - size_t len, unsigned char *dst); -]] - - -ngx.escape_uri = function (s) - if type(s) ~= 'string' then - if not s then - s = '' - else - s = tostring(s) - end - end - local slen = #s - local dlen = C.ngx_http_lua_ffi_uri_escaped_length(s, slen) - -- print("dlen: ", tonumber(dlen)) - if dlen == slen then - return s - end - local dst = get_string_buf(dlen) - C.ngx_http_lua_ffi_escape_uri(s, slen, dst) - return ffi_string(dst, dlen) -end - - -ngx.unescape_uri = function (s) - if type(s) ~= 'string' then - if not s then - s = '' - else - s = tostring(s) - end - end - local slen = #s - local dlen = slen - local dst = get_string_buf(dlen) - dlen = C.ngx_http_lua_ffi_unescape_uri(s, slen, dst) - return ffi_string(dst, dlen) -end - - -return { - version = base.version, -} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/var.lua b/rootfs/etc/nginx/lua/vendor/resty/core/var.lua deleted file mode 100644 index 6aa4060aaa..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core/var.lua +++ /dev/null @@ -1,130 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local ffi = require 'ffi' -local base = require "resty.core.base" - -local ffi_new = ffi.new -local ffi_str = ffi.string -local C = ffi.C -local type = type -local getfenv = getfenv -local get_string_buf = base.get_string_buf -local get_size_ptr = base.get_size_ptr -local error = error -local tostring = tostring -local ngx_var = ngx.var -local getmetatable = getmetatable - -local ERR_BUF_SIZE = 256 - - -ffi.cdef[[ - int ngx_http_lua_ffi_var_get(ngx_http_request_t *r, - const char *name_data, size_t name_len, char *lowcase_buf, - int capture_id, char **value, size_t *value_len, char **err); - - int ngx_http_lua_ffi_var_set(ngx_http_request_t *r, - const unsigned char *name_data, size_t name_len, - unsigned char *lowcase_buf, const unsigned char *value, - size_t value_len, unsigned char *errbuf, size_t *errlen); -]] - - -local value_ptr = ffi_new("unsigned char *[1]") -local errmsg = base.get_errmsg_ptr() - - -local function var_get(self, name) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - local value_len = get_size_ptr() - local rc - if type(name) == "number" then - rc = C.ngx_http_lua_ffi_var_get(r, nil, 0, nil, name, value_ptr, - value_len, errmsg) - - else - if type(name) ~= "string" then - return error("bad variable name") - end - - local name_len = #name - local lowcase_buf = get_string_buf(name_len) - - rc = C.ngx_http_lua_ffi_var_get(r, name, name_len, lowcase_buf, 0, - value_ptr, value_len, errmsg) - end - - -- ngx.log(ngx.WARN, "rc = ", rc) - - if rc == 0 then -- NGX_OK - return ffi_str(value_ptr[0], value_len[0]) - end - - if rc == -5 then -- NGX_DECLINED - return nil - end - - if rc == -1 then -- NGX_ERROR - return error(ffi_str(errmsg[0])) - end -end - - -local function var_set(self, name, value) - local r = getfenv(0).__ngx_req - if not r then - return error("no request found") - end - - if type(name) ~= "string" then - return error("bad variable name") - end - local name_len = #name - - local errlen = get_size_ptr() - errlen[0] = ERR_BUF_SIZE - local lowcase_buf = get_string_buf(name_len + ERR_BUF_SIZE) - - local value_len - if value == nil then - value_len = 0 - else - if type(value) ~= 'string' then - value = tostring(value) - end - value_len = #value - end - - local errbuf = lowcase_buf + name_len - local rc = C.ngx_http_lua_ffi_var_set(r, name, name_len, lowcase_buf, - value, value_len, errbuf, errlen) - - -- ngx.log(ngx.WARN, "rc = ", rc) - - if rc == 0 then -- NGX_OK - return - end - - if rc == -1 then -- NGX_ERROR - return error(ffi_str(errbuf, errlen[0])) - end -end - - -if ngx_var then - local mt = getmetatable(ngx_var) - if mt then - mt.__index = var_get - mt.__newindex = var_set - end -end - - -return { - version = base.version -} diff --git a/rootfs/etc/nginx/lua/vendor/resty/core/worker.lua b/rootfs/etc/nginx/lua/vendor/resty/core/worker.lua deleted file mode 100644 index 0da8086ccb..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/core/worker.lua +++ /dev/null @@ -1,46 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local ffi = require 'ffi' -local base = require "resty.core.base" - - -local C = ffi.C - - -ffi.cdef[[ -int ngx_http_lua_ffi_worker_pid(void); -int ngx_http_lua_ffi_worker_exiting(void); -int ngx_http_lua_ffi_worker_id(void); -int ngx_http_lua_ffi_worker_count(void); -]] - - -function ngx.worker.exiting() - return C.ngx_http_lua_ffi_worker_exiting() ~= 0 -end - - -function ngx.worker.pid() - return C.ngx_http_lua_ffi_worker_pid() -end - - -function ngx.worker.id() - local id = C.ngx_http_lua_ffi_worker_id() - if id < 0 then - return nil - end - - return id -end - - -function ngx.worker.count() - return C.ngx_http_lua_ffi_worker_count() -end - - -return { - _VERSION = base.version -} diff --git a/rootfs/etc/nginx/lua/vendor/resty/lrucache.lua b/rootfs/etc/nginx/lua/vendor/resty/lrucache.lua deleted file mode 100644 index 55f872fd82..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/lrucache.lua +++ /dev/null @@ -1,227 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) - - -local ffi = require "ffi" -local ffi_new = ffi.new -local ffi_sizeof = ffi.sizeof -local ffi_cast = ffi.cast -local ffi_fill = ffi.fill -local ngx_now = ngx.now -local uintptr_t = ffi.typeof("uintptr_t") -local setmetatable = setmetatable -local tonumber = tonumber - - --- queue data types --- --- this queue is a double-ended queue and the first node --- is reserved for the queue itself. --- the implementation is mostly borrowed from nginx's ngx_queue_t data --- structure. - -ffi.cdef[[ - typedef struct lrucache_queue_s lrucache_queue_t; - struct lrucache_queue_s { - double expire; /* in seconds */ - lrucache_queue_t *prev; - lrucache_queue_t *next; - }; -]] - -local queue_arr_type = ffi.typeof("lrucache_queue_t[?]") -local queue_type = ffi.typeof("lrucache_queue_t") -local NULL = ffi.null - - --- queue utility functions - -local function queue_insert_tail(h, x) - local last = h[0].prev - x.prev = last - last.next = x - x.next = h - h[0].prev = x -end - - -local function queue_init(size) - if not size then - size = 0 - end - local q = ffi_new(queue_arr_type, size + 1) - ffi_fill(q, ffi_sizeof(queue_type, size + 1), 0) - - if size == 0 then - q[0].prev = q - q[0].next = q - - else - local prev = q[0] - for i = 1, size do - local e = q + i - prev.next = e - e.prev = prev - prev = e - end - - local last = q[size] - last.next = q - q[0].prev = last - end - - return q -end - - -local function queue_is_empty(q) - -- print("q: ", tostring(q), "q.prev: ", tostring(q), ": ", q == q.prev) - return q == q[0].prev -end - - -local function queue_remove(x) - local prev = x.prev - local next = x.next - - next.prev = prev - prev.next = next - - -- for debugging purpose only: - x.prev = NULL - x.next = NULL -end - - -local function queue_insert_head(h, x) - x.next = h[0].next - x.next.prev = x - x.prev = h - h[0].next = x -end - - -local function queue_last(h) - return h[0].prev -end - - -local function queue_head(h) - return h[0].next -end - - --- true module stuffs - -local _M = { - _VERSION = '0.07' -} -local mt = { __index = _M } - - -local function ptr2num(ptr) - return tonumber(ffi_cast(uintptr_t, ptr)) -end - - -function _M.new(size) - if size < 1 then - return nil, "size too small" - end - - local self = { - hasht = {}, - free_queue = queue_init(size), - cache_queue = queue_init(), - key2node = {}, - node2key = {}, - } - return setmetatable(self, mt) -end - - -function _M.get(self, key) - local hasht = self.hasht - local val = hasht[key] - if val == nil then - return nil - end - - local node = self.key2node[key] - - -- print(key, ": moving node ", tostring(node), " to cache queue head") - local cache_queue = self.cache_queue - queue_remove(node) - queue_insert_head(cache_queue, node) - - if node.expire >= 0 and node.expire < ngx_now() then - -- print("expired: ", node.expire, " > ", ngx_now()) - return nil, val - end - return val -end - - -function _M.delete(self, key) - self.hasht[key] = nil - - local key2node = self.key2node - local node = key2node[key] - - if not node then - return false - end - - key2node[key] = nil - self.node2key[ptr2num(node)] = nil - - queue_remove(node) - queue_insert_tail(self.free_queue, node) - return true -end - - -function _M.set(self, key, value, ttl) - local hasht = self.hasht - hasht[key] = value - - local key2node = self.key2node - local node = key2node[key] - if not node then - local free_queue = self.free_queue - local node2key = self.node2key - - if queue_is_empty(free_queue) then - -- evict the least recently used key - -- assert(not queue_is_empty(self.cache_queue)) - node = queue_last(self.cache_queue) - - local oldkey = node2key[ptr2num(node)] - -- print(key, ": evicting oldkey: ", oldkey, ", oldnode: ", - -- tostring(node)) - if oldkey then - hasht[oldkey] = nil - key2node[oldkey] = nil - end - - else - -- take a free queue node - node = queue_head(free_queue) - -- print(key, ": get a new free node: ", tostring(node)) - end - - node2key[ptr2num(node)] = key - key2node[key] = node - end - - queue_remove(node) - queue_insert_head(self.cache_queue, node) - - if ttl then - node.expire = ngx_now() + ttl - else - node.expire = -1 - end -end - - -return _M diff --git a/rootfs/etc/nginx/lua/vendor/resty/lrucache/pureffi.lua b/rootfs/etc/nginx/lua/vendor/resty/lrucache/pureffi.lua deleted file mode 100644 index fd3f1b7748..0000000000 --- a/rootfs/etc/nginx/lua/vendor/resty/lrucache/pureffi.lua +++ /dev/null @@ -1,534 +0,0 @@ --- Copyright (C) Yichun Zhang (agentzh) --- Copyright (C) Shuxin Yang - ---[[ - This module implements a key/value cache store. We adopt LRU as our -replace/evict policy. Each key/value pair is tagged with a Time-to-Live (TTL); -from user's perspective, stale pairs are automatically removed from the cache. - -Why FFI -------- - In Lua, expression "table[key] = nil" does not *PHYSICALLY* remove the value -associated with the key; it just set the value to be nil! So the table will -keep growing with large number of the key/nil pairs which will be purged until -resize() operator is called. - - This "feature" is terribly ill-suited to what we need. Therefore we have to -rely on FFI to build a hash-table where any entry can be physically deleted -immediately. - -Under the hood: --------------- - In concept, we introduce three data structures to implement the cache store: - 1. key/value vector for storing keys and values. - 2. a queue to mimic the LRU. - 3. hash-table for looking up the value for a given key. - - Unfortunately, efficiency and clarity usually come at each other cost. The -data strucutres we are using are slightly more complicated than what we -described above. - - o. Lua does not have efficient way to store a vector of pair. So, we use - two vectors for key/value pair: one for keys and the other for values - (_M.key_v and _M.val_v, respectively), and i-th key corresponds to - i-th value. - - A key/value pair is identified by the "id" field in a "node" (we shall - discuss node later) - - o. The queue is nothing more than a doubly-linked list of "node" linked via - lrucache_pureffi_queue_s::{next|prev} fields. - - o. The hash-table has two parts: - - the _M.bucket_v[] a vector of bucket, indiced by hash-value, and - - a bucket is a singly-linked list of "node" via the - lrucache_pureffi_queue_s::conflict field. - - A key must be a string, and the hash value of a key is evaluated by: - crc32(key-cast-to-pointer) % size(_M.bucket_v). - We mandate size(_M.bucket_v) being a power-of-two in order to avoid - expensive modulo operation. - - At the heart of the module is an array of "node" (of type - lrucache_pureffi_queue_s). A node: - - keeps the meta-data of its corresponding key/value pair - (embodied by the "id", and "expire" field); - - is a part of LRU queue (embodied by "prev" and "next" fields); - - is a part of hash-table (embodied by the "conflict" field). -]] - -local ffi = require "ffi" -local bit = require "bit" - - -local ffi_new = ffi.new -local ffi_sizeof = ffi.sizeof -local ffi_cast = ffi.cast -local ffi_fill = ffi.fill -local ngx_now = ngx.now -local uintptr_t = ffi.typeof("uintptr_t") -local c_str_t = ffi.typeof("const char*") -local int_t = ffi.typeof("int") -local int_array_t = ffi.typeof("int[?]") - - -local crc_tab = ffi.new("const unsigned int[256]", { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, - 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, - 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, - 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, - 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, - 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, - 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, - 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, - 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, - 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, - 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, - 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, - 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, - 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, - 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, - 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, - 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, - 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, - 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, - 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, - 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, - 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }); - -local setmetatable = setmetatable -local tonumber = tonumber -local tostring = tostring -local type = type - -local brshift = bit.rshift -local bxor = bit.bxor -local band = bit.band - -local ok, tab_new = pcall(require, "table.new") -if not ok then - tab_new = function (narr, nrec) return {} end -end - --- queue data types --- --- this queue is a double-ended queue and the first node --- is reserved for the queue itself. --- the implementation is mostly borrowed from nginx's ngx_queue_t data --- structure. - -ffi.cdef[[ - /* A lrucache_pureffi_queue_s node hook together three data structures: - * o. the key/value store as embodied by the "id" (which is in essence the - * indentifier of key/pair pair) and the "expire" (which is a metadata - * of the corresponding key/pair pair). - * o. The LRU queue via the prev/next fields. - * o. The hash-tabble as embodied by the "conflict" field. - */ - typedef struct lrucache_pureffi_queue_s lrucache_pureffi_queue_t; - struct lrucache_pureffi_queue_s { - /* Each node is assigned a unique ID at construction time, and the - * ID remain immutatble, regardless the node is in active-list or - * free-list. The queue header is assigned ID 0. Since queue-header - * is a sentinel node, 0 denodes "invalid ID". - * - * Intuitively, we can view the "id" as the identifier of key/value - * pair. - */ - int id; - - /* The bucket of the hash-table is implemented as a singly-linked list. - * The "conflict" refers to the ID of the next node in the bucket. - */ - int conflict; - - double expire; /* in seconds */ - - lrucache_pureffi_queue_t *prev; - lrucache_pureffi_queue_t *next; - }; -]] - -local queue_arr_type = ffi.typeof("lrucache_pureffi_queue_t[?]") ---local queue_ptr_type = ffi.typeof("lrucache_pureffi_queue_t*") -local queue_type = ffi.typeof("lrucache_pureffi_queue_t") -local NULL = ffi.null - - ---======================================================================== --- --- Queue utility functions --- ---======================================================================== - --- Append the element "x" to the given queue "h". -local function queue_insert_tail(h, x) - local last = h[0].prev - x.prev = last - last.next = x - x.next = h - h[0].prev = x -end - - ---[[ -Allocate a queue with size + 1 elements. Elements are linked together in a -circular way, i.e. the last element's "next" points to the first element, -while the first element's "prev" element points to the last element. -]] -local function queue_init(size) - if not size then - size = 0 - end - local q = ffi_new(queue_arr_type, size + 1) - ffi_fill(q, ffi_sizeof(queue_type, size + 1), 0) - - if size == 0 then - q[0].prev = q - q[0].next = q - - else - local prev = q[0] - for i = 1, size do - local e = q[i] - e.id = i - prev.next = e - e.prev = prev - prev = e - end - - local last = q[size] - last.next = q - q[0].prev = last - end - - return q -end - - -local function queue_is_empty(q) - -- print("q: ", tostring(q), "q.prev: ", tostring(q), ": ", q == q.prev) - return q == q[0].prev -end - - -local function queue_remove(x) - local prev = x.prev - local next = x.next - - next.prev = prev - prev.next = next - - -- for debugging purpose only: - x.prev = NULL - x.next = NULL -end - - --- Insert the element "x" the to the given queue "h" -local function queue_insert_head(h, x) - x.next = h[0].next - x.next.prev = x - x.prev = h - h[0].next = x -end - - -local function queue_last(h) - return h[0].prev -end - - -local function queue_head(h) - return h[0].next -end - - ---======================================================================== --- --- Miscellaneous Utility Functions --- ---======================================================================== - -local function ptr2num(ptr) - return tonumber(ffi_cast(uintptr_t, ptr)) -end - - -local function crc32_ptr(ptr) - local p = brshift(ptr2num(ptr), 3) - local b = band(p, 255) - local crc32 = crc_tab[b] - - b = band(brshift(p, 8), 255) - crc32 = bxor(brshift(crc32, 8), crc_tab[band(bxor(crc32, b), 255)]) - - b = band(brshift(p, 16), 255) - crc32 = bxor(brshift(crc32, 8), crc_tab[band(bxor(crc32, b), 255)]) - - --b = band(brshift(p, 24), 255) - --crc32 = bxor(brshift(crc32, 8), crc_tab[band(bxor(crc32, b), 255)]) - return crc32 -end - - ---======================================================================== --- --- Implementation of "export" functions --- ---======================================================================== - -local _M = { - _VERSION = '0.07' -} -local mt = { __index = _M } - - --- "size" specifies the maximum number of entries in the LRU queue, and the --- "load_factor" designates the 'load factor' of the hash-table we are using --- internally. The default value of load-factor is 0.5 (i.e. 50%); if the --- load-factor is specified, it will be clamped to the range of [0.1, 1](i.e. --- if load-factor is greater than 1, it will be saturated to 1, likewise, --- if load-factor is smaller than 0.1, it will be clamped to 0.1). -function _M.new(size, load_factor) - if size < 1 then - return nil, "size too small" - end - - -- Determine bucket size, which must be power of two. - local load_f = load_factor - if not load_factor then - load_f = 0.5 - elseif load_factor > 1 then - load_f = 1 - elseif load_factor < 0.1 then - load_f = 0.1 - end - - local bs_min = size / load_f - -- The bucket_sz *MUST* be a power-of-two. See the hash_string(). - local bucket_sz = 1 - repeat - bucket_sz = bucket_sz * 2 - until bucket_sz >= bs_min - - local self = { - size = size, - bucket_sz = bucket_sz, - free_queue = queue_init(size), - cache_queue = queue_init(0), - node_v = nil, - key_v = tab_new(size, 0), - val_v = tab_new(size, 0), - bucket_v = ffi_new(int_array_t, bucket_sz) - } - -- "note_v" is an array of all the nodes used in the LRU queue. Exprpession - -- node_v[i] evaluates to the element of ID "i". - self.node_v = self.free_queue - - -- Allocate the array-part of the key_v, val_v, bucket_v. - --local key_v = self.key_v - --local val_v = self.val_v - --local bucket_v = self.bucket_v - ffi_fill(self.bucket_v, ffi_sizeof(int_t, bucket_sz), 0) - - return setmetatable(self, mt) -end - - -local function hash_string(self, str) - local c_str = ffi_cast(c_str_t, str) - - local hv = crc32_ptr(c_str) - hv = band(hv, self.bucket_sz - 1) - -- Hint: bucket is 0-based - return hv -end - - --- Search the node associated with the key in the bucket, if found returns --- the the id of the node, and the id of its previous node in the conflict list. --- The "bucket_hdr_id" is the ID of the first node in the bucket -local function _find_node_in_bucket(key, key_v, node_v, bucket_hdr_id) - if bucket_hdr_id ~= 0 then - local prev = 0 - local cur = bucket_hdr_id - - while cur ~= 0 and key_v[cur] ~= key do - prev = cur - cur = node_v[cur].conflict - end - - if cur ~= 0 then - return cur, prev - end - end -end - - --- Return the node corresponding to the key/val. -local function find_key(self, key) - local key_hash = hash_string(self, key) - return _find_node_in_bucket(key, self.key_v, self.node_v, - self.bucket_v[key_hash]) -end - - ---[[ This function tries to - 1. Remove the given key and the associated value from the key/value store, - 2. Remove the entry associated with the key from the hash-table. - - NOTE: all queues remain intact. - - If there was a node bound to the key/val, return that node; otherwise, - nil is returned. -]] -local function remove_key(self, key) - local key_v = self.key_v - local val_v = self.val_v - local node_v = self.node_v - local bucket_v = self.bucket_v - - local key_hash = hash_string(self, key) - local cur, prev = - _find_node_in_bucket(key, key_v, node_v, bucket_v[key_hash]) - - if cur then - -- In an attempt to make key and val dead. - key_v[cur] = nil - val_v[cur] = nil - - -- Remove the node from the hash table - local next_node = node_v[cur].conflict - if prev ~= 0 then - node_v[prev].conflict = next_node - else - bucket_v[key_hash] = next_node - end - node_v[cur].conflict = 0 - - return cur - end -end - - ---[[ Bind the key/val with the given node, and insert the node into the Hashtab. - NOTE: this function does not touch any queue -]] -local function insert_key(self, key, val, node) - -- Bind the key/val with the node - local node_id = node.id - self.key_v[node_id] = key - self.val_v[node_id] = val - - -- Insert the node into the hash-table - local key_hash = hash_string(self, key) - local bucket_v = self.bucket_v - node.conflict = bucket_v[key_hash] - bucket_v[key_hash] = node_id -end - - -function _M.get(self, key) - if type(key) ~= "string" then - key = tostring(key) - end - - local node_id = find_key(self, key) - if not node_id then - return nil - end - - -- print(key, ": moving node ", tostring(node), " to cache queue head") - local cache_queue = self.cache_queue - local node = self.node_v + node_id - queue_remove(node) - queue_insert_head(cache_queue, node) - - local expire = node.expire - if expire >= 0 and expire < ngx_now() then - -- print("expired: ", node.expire, " > ", ngx_now()) - return nil, self.val_v[node_id] - end - - return self.val_v[node_id] -end - - -function _M.delete(self, key) - if type(key) ~= "string" then - key = tostring(key) - end - - local node_id = remove_key(self, key); - if not node_id then - return false - end - - local node = self.node_v + node_id - queue_remove(node) - queue_insert_tail(self.free_queue, node) - return true -end - - -function _M.set(self, key, value, ttl) - if type(key) ~= "string" then - key = tostring(key) - end - - local node_id = find_key(self, key) - local node - if not node_id then - local free_queue = self.free_queue - if queue_is_empty(free_queue) then - -- evict the least recently used key - -- assert(not queue_is_empty(self.cache_queue)) - node = queue_last(self.cache_queue) - remove_key(self, self.key_v[node.id]) - else - -- take a free queue node - node = queue_head(free_queue) - -- print(key, ": get a new free node: ", tostring(node)) - end - - -- insert the key - insert_key(self, key, value, node) - else - node = self.node_v + node_id - self.val_v[node_id] = value - end - - queue_remove(node) - queue_insert_head(self.cache_queue, node) - - if ttl then - node.expire = ngx_now() + ttl - else - node.expire = -1 - end -end - - -return _M From 50b58ebd1f8a9b34afbce25ca914909e04ccef8b Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sat, 3 Mar 2018 15:01:41 -0500 Subject: [PATCH 12/34] sync upstream --- images/nginx/Dockerfile | 34 ++-------------------------------- images/nginx/build.sh | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/images/nginx/Dockerfile b/images/nginx/Dockerfile index fd360590f4..4144ae3a72 100644 --- a/images/nginx/Dockerfile +++ b/images/nginx/Dockerfile @@ -17,40 +17,10 @@ FROM BASEIMAGE CROSS_BUILD_COPY qemu-ARCH-static /usr/bin/ -RUN clean-install bash +COPY build.sh / -RUN mkdir -p /etc/nginx - -# install required packages to build -RUN apt-get update && apt-get dist-upgrade -y && \ - clean-install \ - bash \ - build-essential \ - curl ca-certificates \ - libgeoip1 \ - libgeoip-dev \ - patch \ - libpcre3 \ - libpcre3-dev \ - libssl-dev \ - zlib1g \ - zlib1g-dev \ - libaio1 \ - libaio-dev \ - openssl \ - libperl-dev \ - cmake \ - util-linux \ - lmdb-utils \ - libjemalloc1 libjemalloc-dev \ - wget \ - libcurl4-openssl-dev \ - procps \ - git g++ pkgconf flex bison doxygen libyajl-dev liblmdb-dev libtool dh-autoreconf libxml2 libpcre++-dev libxml2-dev \ - lua-cjson \ - || exit 1 +RUN clean-install bash -COPY build.sh / RUN /build.sh # Create symlinks to redirect nginx logs to stdout and stderr docker log collector diff --git a/images/nginx/build.sh b/images/nginx/build.sh index f913699adf..b0c09d3250 100755 --- a/images/nginx/build.sh +++ b/images/nginx/build.sh @@ -56,6 +56,41 @@ if [[ ${ARCH} == "ppc64le" ]]; then clean-install software-properties-common fi +apt-get update && apt-get dist-upgrade -y + +# install required packages to build +clean-install \ + bash \ + build-essential \ + curl ca-certificates \ + libgeoip1 \ + libgeoip-dev \ + patch \ + libpcre3 \ + libpcre3-dev \ + libssl-dev \ + zlib1g \ + zlib1g-dev \ + libaio1 \ + libaio-dev \ + openssl \ + libperl-dev \ + cmake \ + util-linux \ + lua5.1 liblua5.1-0 liblua5.1-dev \ + lmdb-utils \ + libjemalloc1 libjemalloc-dev \ + wget \ + libcurl4-openssl-dev \ + procps \ + git g++ pkgconf flex bison doxygen libyajl-dev liblmdb-dev libtool dh-autoreconf libxml2 libpcre++-dev libxml2-dev \ + lua-cjson \ + || exit 1 + +ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so + +mkdir -p /etc/nginx + if [[ ${ARCH} == "s390x" ]]; then # avoid error: # git: ../nptl/pthread_mutex_lock.c:81: __pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed. From 502e4a4ce84a413f8e9d0c16dbc329ca436727c1 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sat, 3 Mar 2018 15:52:08 -0500 Subject: [PATCH 13/34] fix lua stuff in nginx image --- images/nginx/build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/images/nginx/build.sh b/images/nginx/build.sh index b0c09d3250..bb2258506a 100755 --- a/images/nginx/build.sh +++ b/images/nginx/build.sh @@ -32,7 +32,7 @@ export OPENTRACING_CPP_VERSION=1.2.0 export ZIPKIN_CPP_VERSION=0.2.0 export JAEGER_VERSION=0.2.0 export MODSECURITY_VERSION=1.0.0 -export LUA_VERSION=0.10.12rc2 +export LUA_NGX_VERSION=0.10.12rc2 export LUA_UPSTREAM_VERSION=0.07 export COOKIE_FLAG_VERSION=1.1.0 @@ -155,7 +155,7 @@ get_src 9915ad1cf0734cc5b357b0d9ea92fec94764b4bf22f4dce185cbd65feda30ec1 \ "https://github.com/AirisX/nginx_cookie_flag_module/archive/v$COOKIE_FLAG_VERSION.tar.gz" get_src 18edf2d18fa331265c36516a4a19ba75d26f46eafcc5e0c2d9aa6c237e8bc110 \ - "https://github.com/openresty/lua-nginx-module/archive/v$LUA_VERSION.tar.gz" + "https://github.com/openresty/lua-nginx-module/archive/v$LUA_NGX_VERSION.tar.gz" get_src 2a69815e4ae01aa8b170941a8e1a10b6f6a9aab699dee485d58f021dd933829a \ "https://github.com/openresty/lua-upstream-nginx-module/archive/v$LUA_UPSTREAM_VERSION.tar.gz" @@ -335,7 +335,7 @@ WITH_MODULES="--add-module=$BUILD_PATH/ngx_devel_kit-$NDK_VERSION \ --add-module=$BUILD_PATH/nginx-goodies-nginx-sticky-module-ng-$STICKY_SESSIONS_VERSION \ --add-module=$BUILD_PATH/nginx-http-auth-digest-$NGINX_DIGEST_AUTH \ --add-module=$BUILD_PATH/ngx_http_substitutions_filter_module-$NGINX_SUBSTITUTIONS \ - --add-module=$BUILD_PATH/lua-nginx-module-$LUA_VERSION \ + --add-module=$BUILD_PATH/lua-nginx-module-$LUA_NGX_VERSION \ --add-module=$BUILD_PATH/lua-upstream-nginx-module-$LUA_UPSTREAM_VERSION \ --add-module=$BUILD_PATH/nginx_cookie_flag_module-$COOKIE_FLAG_VERSION \ --add-dynamic-module=$BUILD_PATH/nginx-opentracing-$NGINX_OPENTRACING_VERSION/opentracing \ From ded0aeaf29b4f7824589e4772728f71d11b102d9 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sat, 3 Mar 2018 16:34:15 -0500 Subject: [PATCH 14/34] adjust lua package paths --- rootfs/etc/nginx/template/nginx.tmpl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index 5fa3b0d889..c3160ea44c 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -32,7 +32,8 @@ events { } http { - lua_package_path "/etc/nginx/lua/?.lua;/etc/nginx/lua/vendor/?.lua;;"; + lua_package_cpath "/usr/lib/x86_64-linux-gnu/lua/5.1/?.so;;"; + lua_package_path "/etc/nginx/lua/?.lua;/etc/nginx/lua/vendor/?.lua;/usr/local/lib/lua/?.lua;;"; lua_shared_dict dynamic_upstreams 1M; init_by_lua_block { require "resty.core" From 7bdc6ae33b8c062f038e9229f5b718d1bb1ab04e Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sat, 3 Mar 2018 19:33:08 -0500 Subject: [PATCH 15/34] implemented general Nginx configuration handler --- internal/ingress/controller/controller.go | 4 +- rootfs/etc/nginx/lua/configuration.lua | 72 +++++++++++++++++------ rootfs/etc/nginx/template/nginx.tmpl | 26 ++++++-- 3 files changed, 77 insertions(+), 25 deletions(-) diff --git a/internal/ingress/controller/controller.go b/internal/ingress/controller/controller.go index a69a24660e..3c08616acc 100644 --- a/internal/ingress/controller/controller.go +++ b/internal/ingress/controller/controller.go @@ -203,7 +203,7 @@ func (n *NGINXController) syncIngress(item interface{}) error { } if !found { // endpoints of this backend have been updated, needs to be posted to Nginx - buf, err := json.Marshal(backend.Endpoints) + buf, err := json.Marshal(backend) if err != nil { glog.Errorf("unexpected error when json encoding endpoints: \n%v", err) // TODO(elvinefendi) implement retry logic @@ -211,7 +211,7 @@ func (n *NGINXController) syncIngress(item interface{}) error { } // TODO(elvinefendi) set port dynamically - resp, err := http.Post("http://localhost:18080/configuration/backends/"+backend.Name+"/endpoints", "application/json", bytes.NewReader(buf)) + resp, err := http.Post("http://localhost:18080/configuration/backends/"+backend.Name, "application/json", bytes.NewReader(buf)) if err != nil { glog.Errorf("unexpected error when POSTing HTTP request: \n%v", err) // TODO(elvinefendi) implement retry logic diff --git a/rootfs/etc/nginx/lua/configuration.lua b/rootfs/etc/nginx/lua/configuration.lua index 999a8f6ab1..97bff151d4 100644 --- a/rootfs/etc/nginx/lua/configuration.lua +++ b/rootfs/etc/nginx/lua/configuration.lua @@ -1,38 +1,72 @@ -local router = require 'router' +local router = require("router") local json = require("cjson") -local dynamic_upstreams_dict = ngx.shared.dynamic_upstreams +-- key's are always going to be ngx.var.proxy_upstream_name, a uniqueue identifier of an app's Backend object +-- currently it is built our of namepsace, service name and service port +-- value is JSON encoded ingress.Backend object.Backend object, for more info refer to internal//ingress/types.go +local backends_data = ngx.shared.backends_data + +-- TODO(elvinefendi) this is for future iteration when/if we decide for example to dynamically configure certificates +-- similar to backends_data +-- local servers_data = ngx.shared.servers_data + +-- measured in seconds +-- for an Nginx worker to pick up the new list of upstream peers +-- it will take + BACKEND_PROCESSING_DELAY +local BACKEND_PROCESSING_DELAY = 1 local _M = {} ---curl -XPOST -d '{"key": "upstream-default-backend", "value": "172.17.0.4:8080 : 172.17.0.4:8081 : 172.17.0.5:8080", "ttl": 0}' localhost:18080/lua_dicts/dynamic_upstreams/keys -function _M.call() - ngx.log(ngx.WARN, "I'm the dicts handler") +local backends = {} + +function _M.get_backend(name) + return backends[name] +end + +-- this function will be periodically called in every worker to decode backends and store them in local backends variable +local function process_backends_data() + ngx.log(ngx.DEBUG, "processing backends_data") + + -- 0 here means get all the keys which can be slow if there are many keys + -- TODO(elvinefendi) think about storing comma separated backend names in another dictionary and using that to + -- fetch the list of them here insted of blocking the access to shared dictionary + backend_names = backends_data:get_keys(0) + + for _, backend_name in pairs(backend_names) do + backend_data = backends_data:get(backend_name) + + local ok, backend = pcall(json.decode, backend_data) + + if ok then + backends[backend_name] = backend + else + ngx.log(ngx.ERROR, "could not parse backend_json: " .. tostring(backend)) + end + end +end + +function _M.init_worker() + _, err = ngx.timer.every(BACKEND_PROCESSING_DELAY, process_backends_data) + if err then + ngx.log(ngx.ERROR, "error when setting up timer.every for process_backends_data: " .. tostring(err)) + end +end +function _M.call() local r = router.new() r:match({ POST = { - ["/configuration/backends/:name/endpoints"] = function(params) + ["/configuration/backends/:name"] = function(params) ngx.req.read_body() -- explicitly read the req body - local ok, endpoints = pcall(json.decode, ngx.req.get_body_data()) - if not ok then - return "could not parse request body: " .. tostring(endpoints) - end - - endpoints_with_ports = {} - for i, endpoint in pairs(endpoints) do - endpoints_with_ports[i] = endpoint.address .. ":" .. endpoint.port - end - endpoints_string = table.concat(endpoints_with_ports, " : ") - local success, err = dynamic_upstreams_dict:set(params.name, endpoints_string, 0) + local success, err = backends_data:set(params.name, ngx.req.get_body_data()) if not success then return err end ngx.status = 201 - ngx.print("endpoints for '" .. tostring(params.name) .. "' updated to '" .. endpoints_string .. "'") + ngx.log(ngx.INFO, "backend data was updated for " .. params.name .. ": " .. tostring(ngx.req.get_body_data())) end } }) @@ -44,7 +78,7 @@ function _M.call() ngx.print(tostring(errmsg)) end else - ngx.log(ngx.ERROR, errmsg) + ngx.log(ngx.ERROR, tostring(errmsg)) ngx.status = 404 ngx.print("Not found!") end diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index c3160ea44c..9a121dbc50 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -34,10 +34,30 @@ events { http { lua_package_cpath "/usr/lib/x86_64-linux-gnu/lua/5.1/?.so;;"; lua_package_path "/etc/nginx/lua/?.lua;/etc/nginx/lua/vendor/?.lua;/usr/local/lib/lua/?.lua;;"; - lua_shared_dict dynamic_upstreams 1M; + lua_shared_dict backends_data 5M; init_by_lua_block { - require "resty.core" + require("resty.core") collectgarbage("collect") + + -- init modules + local ok, res + + ok, res = pcall(require, "configuration") + if not ok then + error("require failed: " .. tostring(res)) + else + configuration = res + end + + ok, res = pcall(require, "balancer") + if not ok then + error("require failed: " .. tostring(res)) + else + balancer = res + end + } + init_worker_by_lua_block { + configuration.init_worker() } {{/* we use the value of the header X-Forwarded-For to be able to use the geo_ip module */}} @@ -350,7 +370,6 @@ http { server 0.0.0.1; # placeholder balancer_by_lua_block { - local balancer = require("balancer") balancer.call() } @@ -474,7 +493,6 @@ http { location /configuration { content_by_lua_block { - local configuration = require("configuration") configuration.call() } } From fac1d9a86938034ccbb374591db8a35bb5e12136 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sat, 3 Mar 2018 19:40:02 -0500 Subject: [PATCH 16/34] adjust placeholder balancer --- rootfs/etc/nginx/lua/balancer.lua | 60 ++++--------------------------- 1 file changed, 7 insertions(+), 53 deletions(-) diff --git a/rootfs/etc/nginx/lua/balancer.lua b/rootfs/etc/nginx/lua/balancer.lua index f8011388d0..7e55c75c53 100644 --- a/rootfs/etc/nginx/lua/balancer.lua +++ b/rootfs/etc/nginx/lua/balancer.lua @@ -2,68 +2,22 @@ local ngx_balancer = require("ngx.balancer") local ngx_upstream = require("ngx.upstream") local math = require("math") local json = require("cjson") - -local dynamic_upstreams_dict = ngx.shared.dynamic_upstreams +local configuration = require("configuration") local _M = {} --- http://nginx.org/en/docs/http/ngx_http_upstream_module.html#example --- CAVEAT: nginx is giving out : instead of , so the docs are wrong --- 127.0.0.1:26157 : 127.0.0.1:26157 , ngx.var.upstream_addr --- 200 : 200 , ngx.var.upstream_status --- 0.00 : 0.00, ngx.var.upstream_response_time -local function split_upstream_var(var) - if not var then - return nil, nil - end - local t = {} - for v in var:gmatch("[^%s|,]+") do - if v ~= ":" then - t[#t+1] = v - end - end - return t -end - -local function split_pair(pair, seperator) - local i = pair:find(seperator) - if i == nil then - return pair, nil - else - local name = pair:sub(1, i - 1) - local value = pair:sub(i + 1, -1) - return name, value - end -end - --- dynamic peers are stored per upstream name --- : " : : " -local function get_dynamic_peers(upstream_name) - local peers_string = dynamic_upstreams_dict:get(upstream_name) - if not peers_string then - return nil - end - - local raw_peers = split_upstream_var(peers_string) - local peers = {} - for i, p in pairs(raw_peers) do - peers[i] = { - name = p, - down = false - } - end - - return peers -end - local function get_peers(upstream_name) - return get_dynamic_peers(upstream_name) or ngx_upstream.get_primary_peers(upstream_name) + local backend = configuration.get_backend(upstream_name) + if backend then + return backend.endpoints + end + ngx_upstream.get_primary_peers(upstream_name) end local function balance(peers) local offset = math.random(1, #peers) local peer = peers[offset] - return split_pair(peer.name, ":") + return peer.address, peer.port end function _M.call() From 8ae88771b10f8df85c38372a2f9ac59249eaa00c Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sat, 3 Mar 2018 23:21:02 -0500 Subject: [PATCH 17/34] install lua-resty-balancer --- images/nginx/build.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/images/nginx/build.sh b/images/nginx/build.sh index bb2258506a..e66af14508 100755 --- a/images/nginx/build.sh +++ b/images/nginx/build.sh @@ -166,6 +166,9 @@ get_src d4a9ed0d2405f41eb0178462b398afde8599c5115dcc1ff8f60e2f34a41a4c21 \ get_src 92fd006d5ca3b3266847d33410eb280122a7f6c06334715f87acce064188a02e \ "https://github.com/openresty/lua-resty-core/archive/v0.1.14rc1.tar.gz" +get_src a77bf0d7cf6a9ba017d0dc973b1a58f13e48242dd3849c5e99c07d250667c44c \ + "https://github.com/openresty/lua-resty-balancer/archive/v0.02rc4.tar.gz" + get_src 1ad2e34b111c802f9d0cdf019e986909123237a28c746b21295b63c9e785d9c3 \ "http://luajit.org/download/LuaJIT-2.1.0-beta3.tar.gz" @@ -197,6 +200,10 @@ make install cd "$BUILD_PATH/lua-resty-lrucache-0.07" make install +cd "$BUILD_PATH/lua-resty-balancer-0.02rc4" +make +make install + # build opentracing lib cd "$BUILD_PATH/opentracing-cpp-$OPENTRACING_CPP_VERSION" mkdir .build From e31b12ede3ec5c12b87672be9b8d4adb17875254 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sat, 3 Mar 2018 23:21:55 -0500 Subject: [PATCH 18/34] proof of concept for per backend custom load balancing --- rootfs/etc/nginx/lua/balancer.lua | 44 ++++++++++++----------- rootfs/etc/nginx/lua/configuration.lua | 49 +++++++++++++++++++++++--- rootfs/etc/nginx/lua/util.lua | 35 ++++++++++++++++++ rootfs/etc/nginx/template/nginx.tmpl | 3 +- 4 files changed, 105 insertions(+), 26 deletions(-) create mode 100644 rootfs/etc/nginx/lua/util.lua diff --git a/rootfs/etc/nginx/lua/balancer.lua b/rootfs/etc/nginx/lua/balancer.lua index 7e55c75c53..182ede1104 100644 --- a/rootfs/etc/nginx/lua/balancer.lua +++ b/rootfs/etc/nginx/lua/balancer.lua @@ -2,40 +2,44 @@ local ngx_balancer = require("ngx.balancer") local ngx_upstream = require("ngx.upstream") local math = require("math") local json = require("cjson") +local resty_chash = require("resty.chash") +local resty_roundrobin = require("resty.roundrobin") local configuration = require("configuration") +local util = require("util") + +local DEFAULT_ALGORITHM = "round_robin" local _M = {} -local function get_peers(upstream_name) - local backend = configuration.get_backend(upstream_name) - if backend then - return backend.endpoints +local function balance_least_conn(endpoints) + local servers, nodes = {}, {} + local str_null = string.char(0) + + for _, endpoint in ipairs(endpoints) do + local id = endpoint.address .. str_null .. endpoint.port + servers[id] = endpoint + nodes[id] = 1 end - ngx_upstream.get_primary_peers(upstream_name) -end -local function balance(peers) - local offset = math.random(1, #peers) - local peer = peers[offset] - return peer.address, peer.port + -- TODO(elvinefendi) move this out of hot path and do it in process_backends_data function instead + local chash = resty_chash:new(nodes) + + local id = chash:find() + local endpoint = servers[id] + return endpoint.address, endpoint.port end function _M.call() - ngx.log(ngx.WARN, "I'm the balancer") - ngx_balancer.set_more_tries(1) - local peers = get_peers(ngx.var.proxy_upstream_name) - if not peers or #peers == 0 then - ngx.log(ngx.ERR, "no upstream peers available") - return - end - - local host, port = balance(peers) + local lb = configuration.get_lb(ngx.var.proxy_upstream_name) + local host_port_string = lb:find() + ngx.log(ngx.INFO, "selected host_port_string: " .. host_port_string) + local host, port = util.split_pair(host_port_string, ":") local ok, err = ngx_balancer.set_current_peer(host, port) if ok then - ngx.log(ngx.WARN, "current peer is set to " .. tostring(host) .. ":" .. tostring(port)) + ngx.log(ngx.INFO, "current peer is set to " .. host_port_string) else ngx.log(ngx.ERR, "error while setting current upstream peer to: " .. tostring(err)) end diff --git a/rootfs/etc/nginx/lua/configuration.lua b/rootfs/etc/nginx/lua/configuration.lua index 97bff151d4..51e71b99fd 100644 --- a/rootfs/etc/nginx/lua/configuration.lua +++ b/rootfs/etc/nginx/lua/configuration.lua @@ -1,5 +1,10 @@ local router = require("router") local json = require("cjson") +local util = require("util") + +-- key's are backend names +-- value's are respective load balancing algorithm name to use for the backend +local backend_lb_algorithms = ngx.shared.backend_lb_algorithms -- key's are always going to be ngx.var.proxy_upstream_name, a uniqueue identifier of an app's Backend object -- currently it is built our of namepsace, service name and service port @@ -17,16 +22,40 @@ local BACKEND_PROCESSING_DELAY = 1 local _M = {} +local lbs = {} local backends = {} -function _M.get_backend(name) - return backends[name] +function _M.get_lb(backend_name) + return lbs[backend_name] +end + +local resty_roundrobin = require("resty.roundrobin") + +-- TODO(elvinefendi) make this consider lb_alg instead of always using round robin +local function update_backend(backend) + ngx.log(ngx.INFO, "updating backend: " .. backend.name) + + local servers, nodes = {}, {} + + for _, endpoint in ipairs(backend.endpoints) do + id = endpoint.address .. ":" .. endpoint.port + servers[id] = endpoint + nodes[id] = 1 + end + + local rr = lbs[backend.name] + if rr then + rr:reinit(nodes) + else + rr = resty_roundrobin:new(nodes) + end + + lbs[backend.name] = rr + backends[backend.name] = backend end -- this function will be periodically called in every worker to decode backends and store them in local backends variable local function process_backends_data() - ngx.log(ngx.DEBUG, "processing backends_data") - -- 0 here means get all the keys which can be slow if there are many keys -- TODO(elvinefendi) think about storing comma separated backend names in another dictionary and using that to -- fetch the list of them here insted of blocking the access to shared dictionary @@ -38,7 +67,9 @@ local function process_backends_data() local ok, backend = pcall(json.decode, backend_data) if ok then - backends[backend_name] = backend + if not util.deep_compare(backends[backend_name], backend, true) then + update_backend(backend) + end else ngx.log(ngx.ERROR, "could not parse backend_json: " .. tostring(backend)) end @@ -65,6 +96,14 @@ function _M.call() return err end + -- TODO(elvinefendi) also check if it is a supported algorith + if params.lb_alg ~=nil and params.lb_alg ~= "" then + success, err = backend_lb_algorithms:set(params.name, params.lb_alg) + if not success then + return err + end + end + ngx.status = 201 ngx.log(ngx.INFO, "backend data was updated for " .. params.name .. ": " .. tostring(ngx.req.get_body_data())) end diff --git a/rootfs/etc/nginx/lua/util.lua b/rootfs/etc/nginx/lua/util.lua new file mode 100644 index 0000000000..e8fd553fa3 --- /dev/null +++ b/rootfs/etc/nginx/lua/util.lua @@ -0,0 +1,35 @@ +local _M = {} + +function _M.split_pair(pair, seperator) + local i = pair:find(seperator) + if i == nil then + return pair, nil + else + local name = pair:sub(1, i - 1) + local value = pair:sub(i + 1, -1) + return name, value + end +end + +local function deep_compare(t1, t2, ignore_mt) + local ty1 = type(t1) + local ty2 = type(t2) + if ty1 ~= ty2 then return false end + -- non-table types can be directly compared + if ty1 ~= 'table' and ty2 ~= 'table' then return t1 == t2 end + -- as well as tables which have the metamethod __eq + local mt = getmetatable(t1) + if not ignore_mt and mt and mt.__eq then return t1 == t2 end + for k1,v1 in pairs(t1) do + local v2 = t2[k1] + if v2 == nil or not deep_compare(v1,v2) then return false end + end + for k2,v2 in pairs(t2) do + local v1 = t1[k2] + if v1 == nil or not deep_compare(v1,v2) then return false end + end + return true +end +_M.deep_compare = deep_compare + +return _M diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index 9a121dbc50..7fd0a36f49 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -32,9 +32,10 @@ events { } http { - lua_package_cpath "/usr/lib/x86_64-linux-gnu/lua/5.1/?.so;;"; + lua_package_cpath "/usr/local/lib/lua/?.so;/usr/lib/x86_64-linux-gnu/lua/5.1/?.so;;"; lua_package_path "/etc/nginx/lua/?.lua;/etc/nginx/lua/vendor/?.lua;/usr/local/lib/lua/?.lua;;"; lua_shared_dict backends_data 5M; + lua_shared_dict backend_lb_algorithms 1M; init_by_lua_block { require("resty.core") collectgarbage("collect") From 5fe302e47ce2ac8ede9d148e5348b1d59e05ef03 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sun, 4 Mar 2018 13:55:47 -0500 Subject: [PATCH 19/34] dont use third party --- images/nginx/build.sh | 7 --- rootfs/etc/nginx/lua/balancer.lua | 81 +++++++++++++++++++------- rootfs/etc/nginx/lua/configuration.lua | 65 ++------------------- rootfs/etc/nginx/template/nginx.tmpl | 6 +- 4 files changed, 71 insertions(+), 88 deletions(-) diff --git a/images/nginx/build.sh b/images/nginx/build.sh index e66af14508..bb2258506a 100755 --- a/images/nginx/build.sh +++ b/images/nginx/build.sh @@ -166,9 +166,6 @@ get_src d4a9ed0d2405f41eb0178462b398afde8599c5115dcc1ff8f60e2f34a41a4c21 \ get_src 92fd006d5ca3b3266847d33410eb280122a7f6c06334715f87acce064188a02e \ "https://github.com/openresty/lua-resty-core/archive/v0.1.14rc1.tar.gz" -get_src a77bf0d7cf6a9ba017d0dc973b1a58f13e48242dd3849c5e99c07d250667c44c \ - "https://github.com/openresty/lua-resty-balancer/archive/v0.02rc4.tar.gz" - get_src 1ad2e34b111c802f9d0cdf019e986909123237a28c746b21295b63c9e785d9c3 \ "http://luajit.org/download/LuaJIT-2.1.0-beta3.tar.gz" @@ -200,10 +197,6 @@ make install cd "$BUILD_PATH/lua-resty-lrucache-0.07" make install -cd "$BUILD_PATH/lua-resty-balancer-0.02rc4" -make -make install - # build opentracing lib cd "$BUILD_PATH/opentracing-cpp-$OPENTRACING_CPP_VERSION" mkdir .build diff --git a/rootfs/etc/nginx/lua/balancer.lua b/rootfs/etc/nginx/lua/balancer.lua index 182ede1104..d8bfd1485f 100644 --- a/rootfs/etc/nginx/lua/balancer.lua +++ b/rootfs/etc/nginx/lua/balancer.lua @@ -1,45 +1,84 @@ local ngx_balancer = require("ngx.balancer") local ngx_upstream = require("ngx.upstream") -local math = require("math") local json = require("cjson") -local resty_chash = require("resty.chash") -local resty_roundrobin = require("resty.roundrobin") local configuration = require("configuration") local util = require("util") -local DEFAULT_ALGORITHM = "round_robin" +-- measured in seconds +-- for an Nginx worker to pick up the new list of upstream peers +-- it will take + BACKENDS_SYNC_INTERVAL +local BACKENDS_SYNC_INTERVAL = 1 + +local round_robin_state = ngx.shared.round_robin_state local _M = {} -local function balance_least_conn(endpoints) - local servers, nodes = {}, {} - local str_null = string.char(0) +local backends = {} - for _, endpoint in ipairs(endpoints) do - local id = endpoint.address .. str_null .. endpoint.port - servers[id] = endpoint - nodes[id] = 1 - end +local function balance() + local backend_name = ngx.var.proxy_upstream_name + local lb_alg = configuration.get_lb_alg(backend_name) + local backend = backends[backend_name] - -- TODO(elvinefendi) move this out of hot path and do it in process_backends_data function instead - local chash = resty_chash:new(nodes) + if lb_alg == "ip_hash" then + -- TODO(elvinefendi) implement me + return backends.endpoints[0].address, backends.endpoints[0].port + end - local id = chash:find() - local endpoint = servers[id] + -- Round-Robin + -- TODO(elvinefendi) use resty lock here, otherwise there can be race + local index = round_robin_state:get(backend_name) + local index, endpoint = next(backend.endpoints, index) + if not index then + index = 1 + endpoint = backend.endpoints[index] + end + round_robin_state:set(backend_name, index) return endpoint.address, endpoint.port end +local function sync_backend(backend) + backends[backend.name] = backend + + -- also reset the respective balancer state since backend has changed + round_robin_state:delete(backend.name) + + ngx.log(ngx.INFO, "syncronization completed for: " .. backend.name) +end + +local function sync_backends() + local backend_names = configuration.get_backend_names() + + for _, backend_name in pairs(backend_names) do + backend_data = configuration.get_backend_data(backend_name) + + local ok, backend = pcall(json.decode, backend_data) + + if ok then + if not util.deep_compare(backends[backend_name], backend, true) then + sync_backend(backend) + end + else + ngx.log(ngx.ERROR, "could not parse backend_json: " .. tostring(backend)) + end + end +end + +function _M.init_worker() + _, err = ngx.timer.every(BACKENDS_SYNC_INTERVAL, sync_backends) + if err then + ngx.log(ngx.ERROR, "error when setting up timer.every for sync_backends: " .. tostring(err)) + end +end + function _M.call() ngx_balancer.set_more_tries(1) - local lb = configuration.get_lb(ngx.var.proxy_upstream_name) - local host_port_string = lb:find() - ngx.log(ngx.INFO, "selected host_port_string: " .. host_port_string) - local host, port = util.split_pair(host_port_string, ":") + local host, port = balance() local ok, err = ngx_balancer.set_current_peer(host, port) if ok then - ngx.log(ngx.INFO, "current peer is set to " .. host_port_string) + ngx.log(ngx.INFO, "current peer is set to " .. host .. ":" .. port) else ngx.log(ngx.ERR, "error while setting current upstream peer to: " .. tostring(err)) end diff --git a/rootfs/etc/nginx/lua/configuration.lua b/rootfs/etc/nginx/lua/configuration.lua index 51e71b99fd..d47e220c2e 100644 --- a/rootfs/etc/nginx/lua/configuration.lua +++ b/rootfs/etc/nginx/lua/configuration.lua @@ -1,6 +1,4 @@ local router = require("router") -local json = require("cjson") -local util = require("util") -- key's are backend names -- value's are respective load balancing algorithm name to use for the backend @@ -15,72 +13,21 @@ local backends_data = ngx.shared.backends_data -- similar to backends_data -- local servers_data = ngx.shared.servers_data --- measured in seconds --- for an Nginx worker to pick up the new list of upstream peers --- it will take + BACKEND_PROCESSING_DELAY -local BACKEND_PROCESSING_DELAY = 1 - local _M = {} -local lbs = {} -local backends = {} - -function _M.get_lb(backend_name) - return lbs[backend_name] +function _M.get_lb_alg(backend_name) + return backend_lb_algorithms:get(backend_name) end -local resty_roundrobin = require("resty.roundrobin") - --- TODO(elvinefendi) make this consider lb_alg instead of always using round robin -local function update_backend(backend) - ngx.log(ngx.INFO, "updating backend: " .. backend.name) - - local servers, nodes = {}, {} - - for _, endpoint in ipairs(backend.endpoints) do - id = endpoint.address .. ":" .. endpoint.port - servers[id] = endpoint - nodes[id] = 1 - end - - local rr = lbs[backend.name] - if rr then - rr:reinit(nodes) - else - rr = resty_roundrobin:new(nodes) - end - - lbs[backend.name] = rr - backends[backend.name] = backend +function _M.get_backend_data(backend_name) + return backends_data:get(backend_name) end --- this function will be periodically called in every worker to decode backends and store them in local backends variable -local function process_backends_data() +function _M.get_backend_names() -- 0 here means get all the keys which can be slow if there are many keys -- TODO(elvinefendi) think about storing comma separated backend names in another dictionary and using that to -- fetch the list of them here insted of blocking the access to shared dictionary - backend_names = backends_data:get_keys(0) - - for _, backend_name in pairs(backend_names) do - backend_data = backends_data:get(backend_name) - - local ok, backend = pcall(json.decode, backend_data) - - if ok then - if not util.deep_compare(backends[backend_name], backend, true) then - update_backend(backend) - end - else - ngx.log(ngx.ERROR, "could not parse backend_json: " .. tostring(backend)) - end - end -end - -function _M.init_worker() - _, err = ngx.timer.every(BACKEND_PROCESSING_DELAY, process_backends_data) - if err then - ngx.log(ngx.ERROR, "error when setting up timer.every for process_backends_data: " .. tostring(err)) - end + return backends_data:get_keys(0) end function _M.call() diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index 7fd0a36f49..89f71f7180 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -34,8 +34,11 @@ events { http { lua_package_cpath "/usr/local/lib/lua/?.so;/usr/lib/x86_64-linux-gnu/lua/5.1/?.so;;"; lua_package_path "/etc/nginx/lua/?.lua;/etc/nginx/lua/vendor/?.lua;/usr/local/lib/lua/?.lua;;"; + lua_shared_dict backends_data 5M; lua_shared_dict backend_lb_algorithms 1M; + lua_shared_dict round_robin_state 1M; + init_by_lua_block { require("resty.core") collectgarbage("collect") @@ -57,8 +60,9 @@ http { balancer = res end } + init_worker_by_lua_block { - configuration.init_worker() + balancer.init_worker() } {{/* we use the value of the header X-Forwarded-For to be able to use the geo_ip module */}} From 1e86ac242ee737877a8bf0c0988187d04c39504a Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sun, 4 Mar 2018 19:57:01 -0500 Subject: [PATCH 20/34] refactor controller changes and make it clearer --- internal/ingress/controller/controller.go | 73 ++--------------------- internal/ingress/controller/nginx.go | 48 +++++++++++++++ 2 files changed, 54 insertions(+), 67 deletions(-) diff --git a/internal/ingress/controller/controller.go b/internal/ingress/controller/controller.go index 3c08616acc..dbf586226f 100644 --- a/internal/ingress/controller/controller.go +++ b/internal/ingress/controller/controller.go @@ -17,12 +17,9 @@ limitations under the License. package controller import ( - "bytes" - "encoding/json" "fmt" "math/rand" "net" - "net/http" "reflect" "sort" "strconv" @@ -170,74 +167,16 @@ func (n *NGINXController) syncIngress(item interface{}) error { if !n.isForceReload() && n.runningConfig.Equal(&pcfg) { glog.V(3).Infof("skipping backend reload (no changes detected)") return nil - } else if !n.isForceReload() && len(n.runningConfig.Backends) == len(pcfg.Backends) { - // check whether the configuration change is only about endpoints - - newBackends := make([]*ingress.Backend, 0, len(pcfg.Backends)) - runningBackends := make([]*ingress.Backend, 0, len(n.runningConfig.Backends)) - for i := 0; i < len(n.runningConfig.Backends); i++ { - newBackends = append(newBackends, pcfg.Backends[i].DeepCopy()) - runningBackends = append(runningBackends, n.runningConfig.Backends[i].DeepCopy()) - } - - for i := 0; i < len(n.runningConfig.Backends); i++ { - pcfg.Backends[i].Endpoints = []ingress.Endpoint{} - n.runningConfig.Backends[i].Endpoints = []ingress.Endpoint{} - } - if n.runningConfig.Equal(&pcfg) { - // so configuration change is only about endpoints and force reload is not set - // we can skip reload and dynamically update endpoints - glog.Infof("only endpoints have changed, skipping reload and posting them to Nginx via HTTP request") - - // reset backends - pcfg.Backends = newBackends - n.runningConfig.Backends = runningBackends - - for _, backend := range pcfg.Backends { - found := false - for _, runningBackend := range n.runningConfig.Backends { - if backend.Equal(runningBackend) { - found = true - break - } - } - if !found { - // endpoints of this backend have been updated, needs to be posted to Nginx - buf, err := json.Marshal(backend) - if err != nil { - glog.Errorf("unexpected error when json encoding endpoints: \n%v", err) - // TODO(elvinefendi) implement retry logic - continue - } - - // TODO(elvinefendi) set port dynamically - resp, err := http.Post("http://localhost:18080/configuration/backends/"+backend.Name, "application/json", bytes.NewReader(buf)) - if err != nil { - glog.Errorf("unexpected error when POSTing HTTP request: \n%v", err) - // TODO(elvinefendi) implement retry logic - continue - } - - defer func() { - if err := resp.Body.Close(); err != nil { - glog.Warningf("error while closing response body: \n%v", err) - } - }() - - if resp.StatusCode != http.StatusCreated { - glog.Errorf("Unexpected error code: %v", resp.StatusCode) - } else { - glog.Infof("endpoints for " + backend.Name + " have been updated") - } - } else { - glog.Infof(backend.Name + " is same as running config. number of endpoints: " + string(len(backend.Endpoints))) - } - } - + } else if !n.isForceReload() && n.IsDynamicallyConfigurable(&pcfg) { + err := n.ConfigureDynamically(&pcfg) + if err == nil { + glog.Infof("dynamic reconfiguration succeeded, skipping reload") n.OnUpdate(pcfg, true) n.runningConfig = &pcfg return nil } + + glog.Warningf("falling back to reload, could not dynamically reconfigure: %v", err) } glog.Infof("backend reload required") diff --git a/internal/ingress/controller/nginx.go b/internal/ingress/controller/nginx.go index f68cab7481..688f42d8be 100644 --- a/internal/ingress/controller/nginx.go +++ b/internal/ingress/controller/nginx.go @@ -18,10 +18,12 @@ package controller import ( "bytes" + "encoding/json" "errors" "fmt" "io/ioutil" "net" + "net/http" "os" "os/exec" "strconv" @@ -743,3 +745,49 @@ func (n *NGINXController) setupSSLProxy() { } }() } + +// decide if the new configuration can be dynamically configured without reloading +func (n *NGINXController) IsDynamicallyConfigurable(pcfg *ingress.Configuration) bool { + newBackends := make([]*ingress.Backend, 0, len(pcfg.Backends)) + runningBackends := make([]*ingress.Backend, 0, len(n.runningConfig.Backends)) + + for i := 0; i < len(n.runningConfig.Backends); i++ { + newBackends = append(newBackends, pcfg.Backends[i].DeepCopy()) + runningBackends = append(runningBackends, n.runningConfig.Backends[i].DeepCopy()) + } + + n.runningConfig.Backends = []*ingress.Backend{} + pcfg.Backends = []*ingress.Backend{} + + ret := n.runningConfig.Equal(pcfg) + + pcfg.Backends = newBackends + n.runningConfig.Backends = runningBackends + + return ret +} + +func (n *NGINXController) ConfigureDynamically(pcfg *ingress.Configuration) error { + buf, err := json.Marshal(pcfg.Backends) + if err != nil { + return err + } + + url := fmt.Sprintf("http://localhost:%d/configuration/backends", n.cfg.ListenPorts.Status) + resp, err := http.Post(url, "application/json", bytes.NewReader(buf)) + if err != nil { + return err + } + + defer func() { + if err := resp.Body.Close(); err != nil { + glog.Warningf("error while closing response body: \n%v", err) + } + }() + + if resp.StatusCode != http.StatusCreated { + return fmt.Errorf("Unexpected error code: %d", resp.StatusCode) + } + + return nil +} From 250680f6085e52479d42f7e6caa32c241e7a4622 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sun, 4 Mar 2018 20:39:29 -0500 Subject: [PATCH 21/34] simplify --- rootfs/etc/nginx/lua/balancer.lua | 36 ++++--- rootfs/etc/nginx/lua/configuration.lua | 66 +++--------- rootfs/etc/nginx/lua/vendor/router.lua | 135 ------------------------- rootfs/etc/nginx/template/nginx.tmpl | 3 +- 4 files changed, 40 insertions(+), 200 deletions(-) delete mode 100644 rootfs/etc/nginx/lua/vendor/router.lua diff --git a/rootfs/etc/nginx/lua/balancer.lua b/rootfs/etc/nginx/lua/balancer.lua index d8bfd1485f..48d1b5c5c3 100644 --- a/rootfs/etc/nginx/lua/balancer.lua +++ b/rootfs/etc/nginx/lua/balancer.lua @@ -1,5 +1,4 @@ local ngx_balancer = require("ngx.balancer") -local ngx_upstream = require("ngx.upstream") local json = require("cjson") local configuration = require("configuration") local util = require("util") @@ -17,8 +16,10 @@ local backends = {} local function balance() local backend_name = ngx.var.proxy_upstream_name - local lb_alg = configuration.get_lb_alg(backend_name) local backend = backends[backend_name] + -- lb_alg field does not exist for ingress.Backend struct for now, so lb_alg + -- will always be round_robin + local lb_alg = backend.lb_alg or "round_robin" if lb_alg == "ip_hash" then -- TODO(elvinefendi) implement me @@ -47,19 +48,28 @@ local function sync_backend(backend) end local function sync_backends() - local backend_names = configuration.get_backend_names() + local backends_data = configuration.get_backends_data() + if not backends_data then + return + end + + local ok, backends = pcall(json.decode, backends_data) + if not ok then + ngx.log(ngx.ERR, "could not parse backends data: " .. tostring(backends)) + return + end - for _, backend_name in pairs(backend_names) do - backend_data = configuration.get_backend_data(backend_name) + for _, backend in pairs(backends) do + local current_backend = backends[backend.name] + local backend_changed = true - local ok, backend = pcall(json.decode, backend_data) + if current_backend then + -- this might change in future but currently we react to only endpoints changes + backend_changed = util.deep_compare(current_backend.endpoints, backend.endpoints) + end - if ok then - if not util.deep_compare(backends[backend_name], backend, true) then - sync_backend(backend) - end - else - ngx.log(ngx.ERROR, "could not parse backend_json: " .. tostring(backend)) + if backend_changed then + sync_backend(backend) end end end @@ -67,7 +77,7 @@ end function _M.init_worker() _, err = ngx.timer.every(BACKENDS_SYNC_INTERVAL, sync_backends) if err then - ngx.log(ngx.ERROR, "error when setting up timer.every for sync_backends: " .. tostring(err)) + ngx.log(ngx.ERR, "error when setting up timer.every for sync_backends: " .. tostring(err)) end end diff --git a/rootfs/etc/nginx/lua/configuration.lua b/rootfs/etc/nginx/lua/configuration.lua index d47e220c2e..e49a821a3c 100644 --- a/rootfs/etc/nginx/lua/configuration.lua +++ b/rootfs/etc/nginx/lua/configuration.lua @@ -1,26 +1,12 @@ -local router = require("router") - --- key's are backend names --- value's are respective load balancing algorithm name to use for the backend -local backend_lb_algorithms = ngx.shared.backend_lb_algorithms - -- key's are always going to be ngx.var.proxy_upstream_name, a uniqueue identifier of an app's Backend object -- currently it is built our of namepsace, service name and service port -- value is JSON encoded ingress.Backend object.Backend object, for more info refer to internal//ingress/types.go -local backends_data = ngx.shared.backends_data - --- TODO(elvinefendi) this is for future iteration when/if we decide for example to dynamically configure certificates --- similar to backends_data --- local servers_data = ngx.shared.servers_data +local configuration_data = ngx.shared.configuration_data local _M = {} -function _M.get_lb_alg(backend_name) - return backend_lb_algorithms:get(backend_name) -end - -function _M.get_backend_data(backend_name) - return backends_data:get(backend_name) +function _M.get_backends_data() + return configuration_data:get("backends") end function _M.get_backend_names() @@ -31,43 +17,23 @@ function _M.get_backend_names() end function _M.call() - local r = router.new() - - r:match({ - POST = { - ["/configuration/backends/:name"] = function(params) - ngx.req.read_body() -- explicitly read the req body - - local success, err = backends_data:set(params.name, ngx.req.get_body_data()) - if not success then - return err - end + if ngx.var.request_method ~= "POST" or ngx.var.request_uri ~= "/configuration/backends" then + ngx.status = 404 + ngx.print("Not found!") - -- TODO(elvinefendi) also check if it is a supported algorith - if params.lb_alg ~=nil and params.lb_alg ~= "" then - success, err = backend_lb_algorithms:set(params.name, params.lb_alg) - if not success then - return err - end - end + return + end - ngx.status = 201 - ngx.log(ngx.INFO, "backend data was updated for " .. params.name .. ": " .. tostring(ngx.req.get_body_data())) - end - } - }) + ngx.req.read_body() - local ok, errmsg = r:execute(ngx.var.request_method, ngx.var.request_uri, ngx.req.get_uri_args()) - if ok then - if errmsg then - ngx.status = 400 - ngx.print(tostring(errmsg)) - end - else - ngx.log(ngx.ERROR, tostring(errmsg)) - ngx.status = 404 - ngx.print("Not found!") + local success, err = configuration_data:set("backends", ngx.req.get_body_data()) + if not success then + ngx.log(ngx.ERR, "error while saving configuration: " .. tostring(err)) + ngx.status = 400 + return end + + ngx.status = 201 end return _M diff --git a/rootfs/etc/nginx/lua/vendor/router.lua b/rootfs/etc/nginx/lua/vendor/router.lua deleted file mode 100644 index 56eff96bc8..0000000000 --- a/rootfs/etc/nginx/lua/vendor/router.lua +++ /dev/null @@ -1,135 +0,0 @@ -local router = { - _VERSION = 'router.lua v2.1.0', - _DESCRIPTION = 'A simple router for Lua', - _LICENSE = [[ - MIT LICENSE - - * Copyright (c) 2013 Enrique GarcĂ­a Cota - * Copyright (c) 2013 Raimon Grau - * Copyright (c) 2015 Lloyd Zhou - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ]] -} - -local COLON_BYTE = string.byte(':', 1) - -local function match_one_path(node, path, f) - for token in path:gmatch("[^/.]+") do - node[token] = node[token] or {} - node = node[token] - end - node["LEAF"] = f -end - -local function resolve(path, node, params) - local _, _, current_token, path = path:find("([^/.]+)(.*)") - if not current_token then return node["LEAF"], params end - - for child_token, child_node in pairs(node) do - if child_token == current_token then - local f, bindings = resolve(path, child_node, params) - if f then return f, bindings end - end - end - - for child_token, child_node in pairs(node) do - if child_token:byte(1) == COLON_BYTE then -- token begins with ':' - local param_name = child_token:sub(2) - local param_value = params[param_name] - params[param_name] = current_token or param_value -- store the value in params, resolve tail path - - local f, bindings = resolve(path, child_node, params) - if f then return f, bindings end - - params[param_name] = param_value -- reset the params table. - end - end - - return false -end - -local function merge(destination, origin, visited) - if type(origin) ~= 'table' then return origin end - if visited[origin] then return visited[origin] end - if destination == nil then destination = {} end - - for k,v in pairs(origin) do - k = merge(nil, k, visited) -- makes a copy of k - if destination[k] == nil then - destination[k] = merge(nil, v, visited) - end - end - - return destination -end - -local function merge_params(...) - local params_list = {...} - local result, visited = {}, {} - - for i=1, #params_list do - merge(result, params_list[i], visited) - end - - return result -end - ------------------------------- INSTANCE METHODS ------------------------------------ -local Router = {} - -function Router:resolve(method, path, ...) - local node = self._tree[method] - if not node then return nil, ("Unknown method: %s"):format(method) end - return resolve(path, node, merge_params(...)) -end - -function Router:execute(method, path, ...) - local f,params = self:resolve(method, path, ...) - if not f then return nil, ('Could not resolve %s %s - %s'):format(method, path, params) end - return true, f(params) -end - -function Router:match(method, path, f) - if type(method) == 'string' then -- always make the method to table. - method = {[method] = {[path] = f}} - end - for m, routes in pairs(method) do - for path, f in pairs(routes) do - if not self._tree[m] then self._tree[m] = {} end - match_one_path(self._tree[m], path, f) - end - end -end - -for method in ("get post put delete trace connect options head"):gmatch("%S+") do - Router[method] = function(self, path, f) -- Router.get = function(self, path, f) - return self:match(method:upper(), path, f) -- return self:match('GET', path, f) - end -- end -end - -local router_mt = { __index = Router } - ------------------------------- PUBLIC INTERFACE ------------------------------------ -router.new = function() - return setmetatable({ _tree = {} }, router_mt) -end - -return router diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index 89f71f7180..31bed3b5c2 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -35,8 +35,7 @@ http { lua_package_cpath "/usr/local/lib/lua/?.so;/usr/lib/x86_64-linux-gnu/lua/5.1/?.so;;"; lua_package_path "/etc/nginx/lua/?.lua;/etc/nginx/lua/vendor/?.lua;/usr/local/lib/lua/?.lua;;"; - lua_shared_dict backends_data 5M; - lua_shared_dict backend_lb_algorithms 1M; + lua_shared_dict configuration_data 5M; lua_shared_dict round_robin_state 1M; init_by_lua_block { From 922de0ec10e635070730bae9d27125d3b14a6f50 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sun, 4 Mar 2018 20:46:45 -0500 Subject: [PATCH 22/34] make sure first config generation dynamically applied as well on top of reload --- internal/ingress/controller/controller.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/internal/ingress/controller/controller.go b/internal/ingress/controller/controller.go index dbf586226f..ee7aab90b9 100644 --- a/internal/ingress/controller/controller.go +++ b/internal/ingress/controller/controller.go @@ -192,6 +192,19 @@ func (n *NGINXController) syncIngress(item interface{}) error { incReloadCount() setSSLExpireTime(servers) + if n.isForceReload() { + go func() { + // it takes time for Nginx to start listening on the port + time.Sleep(1 * time.Second) + err := n.ConfigureDynamically(&pcfg) + if err == nil { + glog.Infof("dynamic reconfiguration succeeded") + } else { + glog.Warningf("could not dynamically reconfigure: %v", err) + } + }() + } + n.runningConfig = &pcfg n.SetForceReload(false) From 90cde4604ab7c5a818c3b4b434c6e09e94615c87 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sun, 4 Mar 2018 21:46:00 -0500 Subject: [PATCH 23/34] add enable-dynamic-configuration cmd flag --- cmd/nginx/flags.go | 48 ++++++++++--------- internal/ingress/controller/config/config.go | 35 +++++++------- internal/ingress/controller/controller.go | 6 ++- internal/ingress/controller/nginx.go | 35 +++++++------- .../ingress/controller/template/template.go | 9 ++-- rootfs/etc/nginx/template/nginx.tmpl | 2 +- 6 files changed, 73 insertions(+), 62 deletions(-) diff --git a/cmd/nginx/flags.go b/cmd/nginx/flags.go index c732fe30ce..eb57e7bd29 100644 --- a/cmd/nginx/flags.go +++ b/cmd/nginx/flags.go @@ -131,6 +131,9 @@ func parseFlags() (bool, *controller.Configuration, error) { publishStatusAddress = flags.String("publish-status-address", "", `User customized address to be set in the status of ingress resources. The controller will set the endpoint records on the ingress using this address.`) + + dynamicConfigurationEnabled = flags.Bool("enable-dynamic-configuration", false, + `When enabled controller will try to avoid Nginx reloads as much as possible by using Lua. Disabled by default.`) ) flag.Set("logtostderr", "true") @@ -192,28 +195,29 @@ func parseFlags() (bool, *controller.Configuration, error) { } config := &controller.Configuration{ - APIServerHost: *apiserverHost, - KubeConfigFile: *kubeConfigFile, - UpdateStatus: *updateStatus, - ElectionID: *electionID, - EnableProfiling: *profiling, - EnableSSLPassthrough: *enableSSLPassthrough, - EnableSSLChainCompletion: *enableSSLChainCompletion, - ResyncPeriod: *resyncPeriod, - DefaultService: *defaultSvc, - Namespace: *watchNamespace, - ConfigMapName: *configMap, - TCPConfigMapName: *tcpConfigMapName, - UDPConfigMapName: *udpConfigMapName, - DefaultSSLCertificate: *defSSLCertificate, - DefaultHealthzURL: *defHealthzURL, - PublishService: *publishSvc, - PublishStatusAddress: *publishStatusAddress, - ForceNamespaceIsolation: *forceIsolation, - UpdateStatusOnShutdown: *updateStatusOnShutdown, - SortBackends: *sortBackends, - UseNodeInternalIP: *useNodeInternalIP, - SyncRateLimit: *syncRateLimit, + APIServerHost: *apiserverHost, + KubeConfigFile: *kubeConfigFile, + UpdateStatus: *updateStatus, + ElectionID: *electionID, + EnableProfiling: *profiling, + EnableSSLPassthrough: *enableSSLPassthrough, + EnableSSLChainCompletion: *enableSSLChainCompletion, + ResyncPeriod: *resyncPeriod, + DefaultService: *defaultSvc, + Namespace: *watchNamespace, + ConfigMapName: *configMap, + TCPConfigMapName: *tcpConfigMapName, + UDPConfigMapName: *udpConfigMapName, + DefaultSSLCertificate: *defSSLCertificate, + DefaultHealthzURL: *defHealthzURL, + PublishService: *publishSvc, + PublishStatusAddress: *publishStatusAddress, + ForceNamespaceIsolation: *forceIsolation, + UpdateStatusOnShutdown: *updateStatusOnShutdown, + SortBackends: *sortBackends, + UseNodeInternalIP: *useNodeInternalIP, + SyncRateLimit: *syncRateLimit, + DynamicConfigurationEnabled: *dynamicConfigurationEnabled, ListenPorts: &ngx_config.ListenPorts{ Default: *defServerPort, Health: *healthzPort, diff --git a/internal/ingress/controller/config/config.go b/internal/ingress/controller/config/config.go index f5615a9cb0..9885512da0 100644 --- a/internal/ingress/controller/config/config.go +++ b/internal/ingress/controller/config/config.go @@ -599,23 +599,24 @@ func (cfg Configuration) BuildLogFormatUpstream() string { // TemplateConfig contains the nginx configuration to render the file nginx.conf type TemplateConfig struct { - ProxySetHeaders map[string]string - AddHeaders map[string]string - MaxOpenFiles int - BacklogSize int - Backends []*ingress.Backend - PassthroughBackends []*ingress.SSLPassthroughBackend - Servers []*ingress.Server - TCPBackends []ingress.L4Service - UDPBackends []ingress.L4Service - HealthzURI string - CustomErrors bool - Cfg Configuration - IsIPV6Enabled bool - IsSSLPassthroughEnabled bool - RedirectServers map[string]string - ListenPorts *ListenPorts - PublishService *apiv1.Service + ProxySetHeaders map[string]string + AddHeaders map[string]string + MaxOpenFiles int + BacklogSize int + Backends []*ingress.Backend + PassthroughBackends []*ingress.SSLPassthroughBackend + Servers []*ingress.Server + TCPBackends []ingress.L4Service + UDPBackends []ingress.L4Service + HealthzURI string + CustomErrors bool + Cfg Configuration + IsIPV6Enabled bool + IsSSLPassthroughEnabled bool + RedirectServers map[string]string + ListenPorts *ListenPorts + PublishService *apiv1.Service + DynamicConfigurationEnabled bool } // ListenPorts describe the ports required to run the diff --git a/internal/ingress/controller/controller.go b/internal/ingress/controller/controller.go index ee7aab90b9..55482ce19a 100644 --- a/internal/ingress/controller/controller.go +++ b/internal/ingress/controller/controller.go @@ -95,6 +95,8 @@ type Configuration struct { FakeCertificateSHA string SyncRateLimit float32 + + DynamicConfigurationEnabled bool } // GetPublishService returns the configured service used to set ingress status @@ -167,7 +169,7 @@ func (n *NGINXController) syncIngress(item interface{}) error { if !n.isForceReload() && n.runningConfig.Equal(&pcfg) { glog.V(3).Infof("skipping backend reload (no changes detected)") return nil - } else if !n.isForceReload() && n.IsDynamicallyConfigurable(&pcfg) { + } else if !n.isForceReload() && n.cfg.DynamicConfigurationEnabled && n.IsDynamicallyConfigurable(&pcfg) { err := n.ConfigureDynamically(&pcfg) if err == nil { glog.Infof("dynamic reconfiguration succeeded, skipping reload") @@ -192,7 +194,7 @@ func (n *NGINXController) syncIngress(item interface{}) error { incReloadCount() setSSLExpireTime(servers) - if n.isForceReload() { + if n.isForceReload() && n.cfg.DynamicConfigurationEnabled { go func() { // it takes time for Nginx to start listening on the port time.Sleep(1 * time.Second) diff --git a/internal/ingress/controller/nginx.go b/internal/ingress/controller/nginx.go index 688f42d8be..497edb1958 100644 --- a/internal/ingress/controller/nginx.go +++ b/internal/ingress/controller/nginx.go @@ -604,23 +604,24 @@ func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration, skipReload cfg.SSLDHParam = sslDHParam tc := ngx_config.TemplateConfig{ - ProxySetHeaders: setHeaders, - AddHeaders: addHeaders, - MaxOpenFiles: maxOpenFiles, - BacklogSize: sysctlSomaxconn(), - Backends: ingressCfg.Backends, - PassthroughBackends: ingressCfg.PassthroughBackends, - Servers: ingressCfg.Servers, - TCPBackends: ingressCfg.TCPEndpoints, - UDPBackends: ingressCfg.UDPEndpoints, - HealthzURI: ngxHealthPath, - CustomErrors: len(cfg.CustomHTTPErrors) > 0, - Cfg: cfg, - IsIPV6Enabled: n.isIPV6Enabled && !cfg.DisableIpv6, - RedirectServers: redirectServers, - IsSSLPassthroughEnabled: n.cfg.EnableSSLPassthrough, - ListenPorts: n.cfg.ListenPorts, - PublishService: n.GetPublishService(), + ProxySetHeaders: setHeaders, + AddHeaders: addHeaders, + MaxOpenFiles: maxOpenFiles, + BacklogSize: sysctlSomaxconn(), + Backends: ingressCfg.Backends, + PassthroughBackends: ingressCfg.PassthroughBackends, + Servers: ingressCfg.Servers, + TCPBackends: ingressCfg.TCPEndpoints, + UDPBackends: ingressCfg.UDPEndpoints, + HealthzURI: ngxHealthPath, + CustomErrors: len(cfg.CustomHTTPErrors) > 0, + Cfg: cfg, + IsIPV6Enabled: n.isIPV6Enabled && !cfg.DisableIpv6, + RedirectServers: redirectServers, + IsSSLPassthroughEnabled: n.cfg.EnableSSLPassthrough, + ListenPorts: n.cfg.ListenPorts, + PublishService: n.GetPublishService(), + DynamicConfigurationEnabled: n.cfg.DynamicConfigurationEnabled, } content, err := n.t.Write(tc) diff --git a/internal/ingress/controller/template/template.go b/internal/ingress/controller/template/template.go index ec366cb828..1af66814e2 100644 --- a/internal/ingress/controller/template/template.go +++ b/internal/ingress/controller/template/template.go @@ -281,7 +281,7 @@ func buildLogFormatUpstream(input interface{}) string { // (specified through the nginx.ingress.kubernetes.io/rewrite-to annotation) // If the annotation nginx.ingress.kubernetes.io/add-base-url:"true" is specified it will // add a base tag in the head of the response from the service -func buildProxyPass(host string, b interface{}, loc interface{}) string { +func buildProxyPass(host string, b interface{}, loc interface{}, dynamicConfigurationEnabled bool) string { backends, ok := b.([]*ingress.Backend) if !ok { glog.Errorf("expected an '[]*ingress.Backend' type but %T was returned", b) @@ -313,8 +313,11 @@ func buildProxyPass(host string, b interface{}, loc interface{}) string { } // defProxyPass returns the default proxy_pass, just the name of the upstream - //defProxyPass := fmt.Sprintf("proxy_pass %s://%s;", proto, upstreamName) - defProxyPass := fmt.Sprintf("proxy_pass %s://upstream_balancer;", proto) + defProxyPass := fmt.Sprintf("proxy_pass %s://%s;", proto, upstreamName) + if dynamicConfigurationEnabled { + defProxyPass = fmt.Sprintf("proxy_pass %s://upstream_balancer;", proto) + } + // if the path in the ingress rule is equals to the target: no special rewrite if path == location.Rewrite.Target { return defProxyPass diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index 31bed3b5c2..caa93e46b4 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -936,7 +936,7 @@ stream { {{ end }} {{ if not (empty $location.Backend) }} - {{ buildProxyPass $server.Hostname $all.Backends $location }} + {{ buildProxyPass $server.Hostname $all.Backends $location $all.DynamicConfigurationEnabled }} {{ if (or (eq $location.Proxy.ProxyRedirectFrom "default") (eq $location.Proxy.ProxyRedirectFrom "off")) }} proxy_redirect {{ $location.Proxy.ProxyRedirectFrom }}; {{ else }} From 93861d85577bc8b0d0ebfe765787d983d3c79995 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sun, 4 Mar 2018 22:48:18 -0500 Subject: [PATCH 24/34] dont spam with periodic info messages --- rootfs/etc/nginx/lua/balancer.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootfs/etc/nginx/lua/balancer.lua b/rootfs/etc/nginx/lua/balancer.lua index 48d1b5c5c3..02017479c1 100644 --- a/rootfs/etc/nginx/lua/balancer.lua +++ b/rootfs/etc/nginx/lua/balancer.lua @@ -44,7 +44,7 @@ local function sync_backend(backend) -- also reset the respective balancer state since backend has changed round_robin_state:delete(backend.name) - ngx.log(ngx.INFO, "syncronization completed for: " .. backend.name) + ngx.log(ngx.DEBUG, "syncronization completed for: " .. backend.name) end local function sync_backends() From cf13265a4706dc0f5eb4be22f013757a707fa8d1 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sun, 4 Mar 2018 23:15:04 -0500 Subject: [PATCH 25/34] use lrucache --- rootfs/etc/nginx/lua/balancer.lua | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/rootfs/etc/nginx/lua/balancer.lua b/rootfs/etc/nginx/lua/balancer.lua index 02017479c1..f2817616c7 100644 --- a/rootfs/etc/nginx/lua/balancer.lua +++ b/rootfs/etc/nginx/lua/balancer.lua @@ -2,6 +2,7 @@ local ngx_balancer = require("ngx.balancer") local json = require("cjson") local configuration = require("configuration") local util = require("util") +local lrucache = require("resty.lrucache") -- measured in seconds -- for an Nginx worker to pick up the new list of upstream peers @@ -12,18 +13,21 @@ local round_robin_state = ngx.shared.round_robin_state local _M = {} -local backends = {} +local backends, err = lrucache.new(1024) +if not backends then + return error("failed to create the cache for backends: " .. (err or "unknown")) +end local function balance() local backend_name = ngx.var.proxy_upstream_name - local backend = backends[backend_name] + local backend = backends:get(backend_name) -- lb_alg field does not exist for ingress.Backend struct for now, so lb_alg -- will always be round_robin local lb_alg = backend.lb_alg or "round_robin" if lb_alg == "ip_hash" then -- TODO(elvinefendi) implement me - return backends.endpoints[0].address, backends.endpoints[0].port + return backend.endpoints[0].address, backend.endpoints[0].port end -- Round-Robin @@ -39,7 +43,7 @@ local function balance() end local function sync_backend(backend) - backends[backend.name] = backend + backends:set(backend.name, backend) -- also reset the respective balancer state since backend has changed round_robin_state:delete(backend.name) @@ -53,23 +57,22 @@ local function sync_backends() return end - local ok, backends = pcall(json.decode, backends_data) + local ok, new_backends = pcall(json.decode, backends_data) if not ok then ngx.log(ngx.ERR, "could not parse backends data: " .. tostring(backends)) return end - for _, backend in pairs(backends) do - local current_backend = backends[backend.name] + for _, new_backend in pairs(new_backends) do + local backend = backends:get(new_backend.name) local backend_changed = true - if current_backend then - -- this might change in future but currently we react to only endpoints changes - backend_changed = util.deep_compare(current_backend.endpoints, backend.endpoints) + if backend then + backend_changed = util.deep_compare(backend, new_backend) end if backend_changed then - sync_backend(backend) + sync_backend(new_backend) end end end From ad17d7846973741474a56bbce8c7f5276034862e Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sun, 4 Mar 2018 23:51:34 -0500 Subject: [PATCH 26/34] use resty lock to avoid potential race condition --- rootfs/etc/nginx/lua/balancer.lua | 15 +++++++++++---- rootfs/etc/nginx/template/nginx.tmpl | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/rootfs/etc/nginx/lua/balancer.lua b/rootfs/etc/nginx/lua/balancer.lua index f2817616c7..be07405e13 100644 --- a/rootfs/etc/nginx/lua/balancer.lua +++ b/rootfs/etc/nginx/lua/balancer.lua @@ -3,16 +3,21 @@ local json = require("cjson") local configuration = require("configuration") local util = require("util") local lrucache = require("resty.lrucache") +local resty_lock = require("resty.lock") -- measured in seconds -- for an Nginx worker to pick up the new list of upstream peers -- it will take + BACKENDS_SYNC_INTERVAL local BACKENDS_SYNC_INTERVAL = 1 +ROUND_ROBIN_LOCK_KEY = "round_robin" + local round_robin_state = ngx.shared.round_robin_state local _M = {} +local round_robin_lock = resty_lock:new("locks", {timeout = 0, exptime = 0.1}) + local backends, err = lrucache.new(1024) if not backends then return error("failed to create the cache for backends: " .. (err or "unknown")) @@ -31,7 +36,7 @@ local function balance() end -- Round-Robin - -- TODO(elvinefendi) use resty lock here, otherwise there can be race + round_robin_lock:lock(backend_name .. ROUND_ROBIN_LOCK_KEY) local index = round_robin_state:get(backend_name) local index, endpoint = next(backend.endpoints, index) if not index then @@ -39,6 +44,8 @@ local function balance() endpoint = backend.endpoints[index] end round_robin_state:set(backend_name, index) + round_robin_lock:unlock(backend_name .. ROUND_ROBIN_LOCK_KEY) + return endpoint.address, endpoint.port end @@ -48,7 +55,7 @@ local function sync_backend(backend) -- also reset the respective balancer state since backend has changed round_robin_state:delete(backend.name) - ngx.log(ngx.DEBUG, "syncronization completed for: " .. backend.name) + ngx.log(ngx.INFO, "syncronization completed for: " .. backend.name) end local function sync_backends() @@ -59,7 +66,7 @@ local function sync_backends() local ok, new_backends = pcall(json.decode, backends_data) if not ok then - ngx.log(ngx.ERR, "could not parse backends data: " .. tostring(backends)) + ngx.log(ngx.ERR, "could not parse backends data: " .. tostring(new_backends)) return end @@ -68,7 +75,7 @@ local function sync_backends() local backend_changed = true if backend then - backend_changed = util.deep_compare(backend, new_backend) + backend_changed = not util.deep_compare(backend, new_backend) end if backend_changed then diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index caa93e46b4..cadd023e77 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -37,6 +37,7 @@ http { lua_shared_dict configuration_data 5M; lua_shared_dict round_robin_state 1M; + lua_shared_dict locks 512k; init_by_lua_block { require("resty.core") From 9206972880bbeccbef5dc3b477b5030bbff8a208 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sun, 4 Mar 2018 23:57:07 -0500 Subject: [PATCH 27/34] include lua-resty-lock in nginx image --- images/nginx/build.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/images/nginx/build.sh b/images/nginx/build.sh index bb2258506a..687badc14a 100755 --- a/images/nginx/build.sh +++ b/images/nginx/build.sh @@ -166,6 +166,9 @@ get_src d4a9ed0d2405f41eb0178462b398afde8599c5115dcc1ff8f60e2f34a41a4c21 \ get_src 92fd006d5ca3b3266847d33410eb280122a7f6c06334715f87acce064188a02e \ "https://github.com/openresty/lua-resty-core/archive/v0.1.14rc1.tar.gz" +get_src eaf84f58b43289c1c3e0442ada9ed40406357f203adc96e2091638080cb8d361 \ + "https://github.com/openresty/lua-resty-lock/archive/v0.07.tar.gz" + get_src 1ad2e34b111c802f9d0cdf019e986909123237a28c746b21295b63c9e785d9c3 \ "http://luajit.org/download/LuaJIT-2.1.0-beta3.tar.gz" @@ -197,6 +200,9 @@ make install cd "$BUILD_PATH/lua-resty-lrucache-0.07" make install +cd "$BUILD_PATH/lua-resty-lock-0.07" +make install + # build opentracing lib cd "$BUILD_PATH/opentracing-cpp-$OPENTRACING_CPP_VERSION" mkdir .build From 6e9cfd09193ab42ed2195f3cd8f558a0f4abb89c Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Mon, 5 Mar 2018 01:36:43 -0500 Subject: [PATCH 28/34] do not assume same size of running and new backends --- internal/ingress/controller/nginx.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/internal/ingress/controller/nginx.go b/internal/ingress/controller/nginx.go index 497edb1958..a490ca10b9 100644 --- a/internal/ingress/controller/nginx.go +++ b/internal/ingress/controller/nginx.go @@ -749,21 +749,24 @@ func (n *NGINXController) setupSSLProxy() { // decide if the new configuration can be dynamically configured without reloading func (n *NGINXController) IsDynamicallyConfigurable(pcfg *ingress.Configuration) bool { - newBackends := make([]*ingress.Backend, 0, len(pcfg.Backends)) runningBackends := make([]*ingress.Backend, 0, len(n.runningConfig.Backends)) + newBackends := make([]*ingress.Backend, 0, len(pcfg.Backends)) for i := 0; i < len(n.runningConfig.Backends); i++ { - newBackends = append(newBackends, pcfg.Backends[i].DeepCopy()) runningBackends = append(runningBackends, n.runningConfig.Backends[i].DeepCopy()) } + for i := 0; i < len(pcfg.Backends); i++ { + newBackends = append(newBackends, pcfg.Backends[i].DeepCopy()) + } + n.runningConfig.Backends = []*ingress.Backend{} pcfg.Backends = []*ingress.Backend{} ret := n.runningConfig.Equal(pcfg) - pcfg.Backends = newBackends n.runningConfig.Backends = runningBackends + pcfg.Backends = newBackends return ret } From e347013959102e23daa9b4ae78c984dddfa219db Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Tue, 6 Mar 2018 21:42:12 -0500 Subject: [PATCH 29/34] remove redundant method and add attribution --- rootfs/etc/nginx/lua/util.lua | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/rootfs/etc/nginx/lua/util.lua b/rootfs/etc/nginx/lua/util.lua index e8fd553fa3..19e104f092 100644 --- a/rootfs/etc/nginx/lua/util.lua +++ b/rootfs/etc/nginx/lua/util.lua @@ -1,16 +1,8 @@ local _M = {} -function _M.split_pair(pair, seperator) - local i = pair:find(seperator) - if i == nil then - return pair, nil - else - local name = pair:sub(1, i - 1) - local value = pair:sub(i + 1, -1) - return name, value - end -end - +-- this implementation is taken from +-- https://web.archive.org/web/20131225070434/http://snippets.luacode.org/snippets/Deep_Comparison_of_Two_Values_3 +-- and modified for use in this project local function deep_compare(t1, t2, ignore_mt) local ty1 = type(t1) local ty2 = type(t2) From cd4ad96c2dfc5bd9bd5810fe4b9d903f4417894a Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Tue, 6 Mar 2018 23:26:19 -0500 Subject: [PATCH 30/34] add test case for new buildProxyPass logic --- .../ingress/controller/template/template.go | 27 +-- .../controller/template/template_test.go | 195 +++++++++++++++--- 2 files changed, 177 insertions(+), 45 deletions(-) diff --git a/internal/ingress/controller/template/template.go b/internal/ingress/controller/template/template.go index 1af66814e2..c80cd6b029 100644 --- a/internal/ingress/controller/template/template.go +++ b/internal/ingress/controller/template/template.go @@ -297,26 +297,27 @@ func buildProxyPass(host string, b interface{}, loc interface{}, dynamicConfigur path := location.Path proto := "http" - upstreamName := location.Backend - for _, backend := range backends { - if backend.Name == location.Backend { - if backend.Secure || backend.SSLPassthrough { - proto = "https" - } + upstreamName := "upstream_balancer" + + if !dynamicConfigurationEnabled { + upstreamName = location.Backend + for _, backend := range backends { + if backend.Name == location.Backend { + if backend.Secure || backend.SSLPassthrough { + proto = "https" + } - if isSticky(host, location, backend.SessionAffinity.CookieSessionAffinity.Locations) { - upstreamName = fmt.Sprintf("sticky-%v", upstreamName) - } + if isSticky(host, location, backend.SessionAffinity.CookieSessionAffinity.Locations) { + upstreamName = fmt.Sprintf("sticky-%v", upstreamName) + } - break + break + } } } // defProxyPass returns the default proxy_pass, just the name of the upstream defProxyPass := fmt.Sprintf("proxy_pass %s://%s;", proto, upstreamName) - if dynamicConfigurationEnabled { - defProxyPass = fmt.Sprintf("proxy_pass %s://upstream_balancer;", proto) - } // if the path in the ingress rule is equals to the target: no special rewrite if path == location.Rewrite.Target { diff --git a/internal/ingress/controller/template/template_test.go b/internal/ingress/controller/template/template_test.go index 6502999155..0813b97d30 100644 --- a/internal/ingress/controller/template/template_test.go +++ b/internal/ingress/controller/template/template_test.go @@ -39,70 +39,201 @@ import ( var ( // TODO: add tests for secure endpoints tmplFuncTestcases = map[string]struct { - Path string - Target string - Location string - ProxyPass string - AddBaseURL bool - BaseURLScheme string - Sticky bool - XForwardedPrefix bool + Path string + Target string + Location string + ProxyPass string + AddBaseURL bool + BaseURLScheme string + Sticky bool + XForwardedPrefix bool + DynamicConfigurationEnabled bool }{ - "invalid redirect / to /": {"/", "/", "/", "proxy_pass http://upstream-name;", false, "", false, false}, - "redirect / to /jenkins": {"/", "/jenkins", "~* /", + "invalid redirect / to / with dynamic config enabled": { + "/", + "/", + "/", + "proxy_pass http://upstream_balancer;", + false, + "", + false, + false, + true}, + "invalid redirect / to /": { + "/", + "/", + "/", + "proxy_pass http://upstream-name;", + false, + "", + false, + false, + false}, + "redirect / to /jenkins": { + "/", + "/jenkins", + "~* /", ` rewrite /(.*) /jenkins/$1 break; proxy_pass http://upstream-name; - `, false, "", false, false}, - "redirect /something to /": {"/something", "/", `~* ^/something\/?(?.*)`, ` + `, + false, + "", + false, + false, + false}, + "redirect /something to /": { + "/something", + "/", + `~* ^/something\/?(?.*)`, + ` rewrite /something/(.*) /$1 break; rewrite /something / break; proxy_pass http://upstream-name; - `, false, "", false, false}, - "redirect /end-with-slash/ to /not-root": {"/end-with-slash/", "/not-root", "~* ^/end-with-slash/(?.*)", ` + `, + false, + "", + false, + false, + false}, + "redirect /end-with-slash/ to /not-root": { + "/end-with-slash/", + "/not-root", + "~* ^/end-with-slash/(?.*)", + ` rewrite /end-with-slash/(.*) /not-root/$1 break; proxy_pass http://upstream-name; - `, false, "", false, false}, - "redirect /something-complex to /not-root": {"/something-complex", "/not-root", `~* ^/something-complex\/?(?.*)`, ` + `, + false, + "", + false, + false, + false}, + "redirect /something-complex to /not-root": { + "/something-complex", + "/not-root", + `~* ^/something-complex\/?(?.*)`, + ` rewrite /something-complex/(.*) /not-root/$1 break; proxy_pass http://upstream-name; - `, false, "", false, false}, - "redirect / to /jenkins and rewrite": {"/", "/jenkins", "~* /", ` + `, + false, + "", + false, + false, + false}, + "redirect / to /jenkins and rewrite": { + "/", + "/jenkins", + "~* /", + ` rewrite /(.*) /jenkins/$1 break; proxy_pass http://upstream-name; subs_filter '(<(?:H|h)(?:E|e)(?:A|a)(?:D|d)(?:[^">]|"[^"]*")*>)' '$1' ro; - `, true, "", false, false}, - "redirect /something to / and rewrite": {"/something", "/", `~* ^/something\/?(?.*)`, ` + `, + true, + "", + false, + false, + false}, + "redirect /something to / and rewrite": { + "/something", + "/", + `~* ^/something\/?(?.*)`, + ` rewrite /something/(.*) /$1 break; rewrite /something / break; proxy_pass http://upstream-name; subs_filter '(<(?:H|h)(?:E|e)(?:A|a)(?:D|d)(?:[^">]|"[^"]*")*>)' '$1' ro; - `, true, "", false, false}, - "redirect /end-with-slash/ to /not-root and rewrite": {"/end-with-slash/", "/not-root", `~* ^/end-with-slash/(?.*)`, ` + `, + true, + "", + false, + false, + false}, + "redirect /end-with-slash/ to /not-root and rewrite": { + "/end-with-slash/", + "/not-root", + `~* ^/end-with-slash/(?.*)`, + ` rewrite /end-with-slash/(.*) /not-root/$1 break; proxy_pass http://upstream-name; subs_filter '(<(?:H|h)(?:E|e)(?:A|a)(?:D|d)(?:[^">]|"[^"]*")*>)' '$1' ro; - `, true, "", false, false}, - "redirect /something-complex to /not-root and rewrite": {"/something-complex", "/not-root", `~* ^/something-complex\/?(?.*)`, ` + `, + true, + "", + false, + false, + false}, + "redirect /something-complex to /not-root and rewrite": { + "/something-complex", + "/not-root", + `~* ^/something-complex\/?(?.*)`, + ` rewrite /something-complex/(.*) /not-root/$1 break; proxy_pass http://upstream-name; subs_filter '(<(?:H|h)(?:E|e)(?:A|a)(?:D|d)(?:[^">]|"[^"]*")*>)' '$1' ro; - `, true, "", false, false}, - "redirect /something to / and rewrite with specific scheme": {"/something", "/", `~* ^/something\/?(?.*)`, ` + `, + true, + "", + false, + false, + false}, + "redirect /something to / and rewrite with specific scheme": { + "/something", + "/", + `~* ^/something\/?(?.*)`, + ` rewrite /something/(.*) /$1 break; rewrite /something / break; proxy_pass http://upstream-name; subs_filter '(<(?:H|h)(?:E|e)(?:A|a)(?:D|d)(?:[^">]|"[^"]*")*>)' '$1' ro; - `, true, "http", false, false}, - "redirect / to /something with sticky enabled": {"/", "/something", `~* /`, ` + `, + true, + "http", + false, + false, + false}, + "redirect / to /something with sticky enabled": { + "/", + "/something", + `~* /`, + ` rewrite /(.*) /something/$1 break; proxy_pass http://sticky-upstream-name; - `, false, "http", true, false}, - "add the X-Forwarded-Prefix header": {"/there", "/something", `~* ^/there\/?(?.*)`, ` + `, + false, + "http", + true, + false, + false}, + "redirect / to /something with sticky and dynamic config enabled": { + "/", + "/something", + `~* /`, + ` + rewrite /(.*) /something/$1 break; + proxy_pass http://upstream_balancer; + `, + false, + "http", + true, + false, + true}, + "add the X-Forwarded-Prefix header": { + "/there", + "/something", + `~* ^/there\/?(?.*)`, + ` rewrite /there/(.*) /something/$1 break; proxy_set_header X-Forwarded-Prefix "/there/"; proxy_pass http://sticky-upstream-name; - `, false, "http", true, true}, + `, + false, + "http", + true, + true, + false}, } ) @@ -168,7 +299,7 @@ func TestBuildProxyPass(t *testing.T) { } } - pp := buildProxyPass(defaultHost, backends, loc) + pp := buildProxyPass(defaultHost, backends, loc, tc.DynamicConfigurationEnabled) if !strings.EqualFold(tc.ProxyPass, pp) { t.Errorf("%s: expected \n'%v'\nbut returned \n'%v'", k, tc.ProxyPass, pp) } From 577e6b4a98c80c98ecc65a5a8546feba9e2205dd Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Tue, 6 Mar 2018 23:39:33 -0500 Subject: [PATCH 31/34] test IsDynamicallyConfigurable --- internal/ingress/controller/nginx_test.go | 62 ++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/internal/ingress/controller/nginx_test.go b/internal/ingress/controller/nginx_test.go index 4b85ed2fc8..3ea86e6338 100644 --- a/internal/ingress/controller/nginx_test.go +++ b/internal/ingress/controller/nginx_test.go @@ -16,7 +16,67 @@ limitations under the License. package controller -import "testing" +import ( + "testing" + + "k8s.io/ingress-nginx/internal/ingress" +) + +func TestIsDynamicallyConfigurable(t *testing.T) { + backends := []*ingress.Backend{&ingress.Backend{ + Name: "fakenamespace-myapp-80", + Endpoints: []ingress.Endpoint{ + ingress.Endpoint{ + Address: "10.0.0.1", + Port: "8080", + }, + ingress.Endpoint{ + Address: "10.0.0.2", + Port: "8080", + }, + }, + }} + + servers := []*ingress.Server{&ingress.Server{ + Hostname: "myapp.fake", + Locations: []*ingress.Location{ + &ingress.Location{ + Path: "/", + Backend: "fakenamespace-myapp-80", + }, + }, + }} + + commonConfig := &ingress.Configuration{ + Backends: backends, + Servers: servers, + } + + n := &NGINXController{ + runningConfig: commonConfig, + } + + newConfig := commonConfig + if !n.IsDynamicallyConfigurable(newConfig) { + t.Errorf("When new config is same as the running config it should be deemed as dynamically configurable") + } + + newConfig = &ingress.Configuration{ + Backends: []*ingress.Backend{&ingress.Backend{}}, + Servers: []*ingress.Server{&ingress.Server{}}, + } + if n.IsDynamicallyConfigurable(newConfig) { + t.Errorf("Expected to not be dynamically configurable when there's more than just backends change") + } + + newConfig = &ingress.Configuration{ + Backends: []*ingress.Backend{&ingress.Backend{}}, + Servers: servers, + } + if !n.IsDynamicallyConfigurable(newConfig) { + t.Errorf("Expected to be dynamically configurable when only backends change") + } +} func TestNginxHashBucketSize(t *testing.T) { tests := []struct { From aacd87038e03cc4b0e764114bc40a2efcaf21d75 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Wed, 7 Mar 2018 08:10:41 -0800 Subject: [PATCH 32/34] ran make code-generator --- internal/file/bindata.go | 79 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/internal/file/bindata.go b/internal/file/bindata.go index 6cff8ede2b..933bf46f71 100644 --- a/internal/file/bindata.go +++ b/internal/file/bindata.go @@ -1,5 +1,8 @@ // Code generated by go-bindata. // sources: +// rootfs/etc/nginx/lua/balancer.lua +// rootfs/etc/nginx/lua/configuration.lua +// rootfs/etc/nginx/lua/util.lua // rootfs/etc/nginx/nginx.conf // rootfs/etc/nginx/template/nginx.tmpl // rootfs/ingress-controller/clean-nginx-conf.sh @@ -70,6 +73,66 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } +var _etcNginxLuaBalancerLua = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x56\xdd\x8e\xdb\x36\x13\xbd\xd7\x53\x0c\x74\x25\xe1\xd3\x0a\xd9\x0f\xbd\x5a\xd4\x05\xf2\xb3\x05\x82\x24\x76\xe1\xa4\x05\x82\x22\x20\xb8\xd4\x58\x66\x4c\x93\x2a\x49\xad\xed\x06\x79\xf7\x62\x28\x89\x92\xbc\x4a\x17\xbd\x59\xaf\xc8\xe1\x99\x99\x33\x67\x86\x54\x46\x70\x05\xba\x3e\xb3\x07\xae\xb8\x16\x68\x61\x05\x16\xff\x6a\xa5\xc5\x2c\xd5\xf5\xb9\x1c\xd6\xd3\x3c\xe9\x8c\xbf\x3a\xa3\xa7\x46\x82\x16\xe2\xae\x30\x7a\x27\xeb\xd6\x72\x2f\xaf\xcc\xa6\x1b\xd1\xbc\xf5\x52\x4d\xad\xe8\x3b\x6e\x2a\xdb\x0a\x2e\xf6\x38\x35\xb0\xe8\xfc\xa5\x1c\x76\xa2\x69\x58\x66\xca\x88\xc3\x82\xb1\x11\x87\x34\x4f\x92\x9b\x1b\x38\x22\x77\xad\xc5\x0a\xa4\x06\x87\xc2\xe8\xca\xd1\xf2\xce\x58\xe0\x1a\xd6\xb5\xd4\x67\x38\x19\x7b\x40\x0b\xde\x40\x23\xc5\x01\xda\x06\xfc\x1e\x41\xe3\x09\x94\x74\x1e\xcc\x0e\xda\xc6\x79\x8b\xfc\x08\x0d\xa2\x75\x40\x08\xd2\xc3\x49\x2a\x05\x9e\x1f\x10\x7e\xa6\x03\x15\x2a\x7e\x81\x56\x53\x82\xc2\x68\x6f\x8d\x52\x68\xe1\xb7\xcd\xc7\x4f\x58\x05\xc8\x07\x2e\x0e\xa8\x2b\x30\x0f\x5f\x51\x78\x72\x48\xab\x5d\x10\xa8\xab\xc6\x48\xed\x7f\x81\xff\xc1\xab\x97\xaf\xdf\xdd\xaf\xdf\x7c\x64\x1f\x3f\xaf\x5f\xb3\xb7\xeb\x4f\xf7\xdb\x3f\x5e\xbe\xef\x13\x5f\xde\x84\x15\xdc\x26\xc9\x76\xf3\xfb\xfa\x0d\xdb\x6e\x5e\xbd\x5d\xb3\xf7\x9b\xd7\xef\xd8\xbb\xfb\xcf\xb0\x82\xd4\x9a\x56\x57\xcc\x9a\x07\xa9\xd3\x64\x20\x70\x5c\x63\xce\x73\x4f\xa4\x53\xf9\xdd\x9e\x5b\xac\xca\x27\xdb\xc3\x39\xf6\x01\x56\xf0\xed\xfb\x12\x4c\xac\xc6\x50\x9a\x3b\x8d\xa7\x2c\xa5\xff\x5c\x5a\xc0\x37\x2f\x8f\x68\x5a\x0f\x2b\x78\x51\x00\x9e\x1b\xfa\xa6\x8f\xf2\xf6\x7b\x3e\xe0\xf5\x1c\xb9\x02\xd0\x92\x34\x87\xc2\x97\x04\x75\xfb\xe2\xff\x3f\xe5\x89\xdc\x81\x36\x3e\x5a\x12\x89\x3a\x01\xb0\xe8\x5b\xab\xe9\x98\xb1\x59\xba\xe3\x52\x11\xed\x06\x84\x45\xca\x8e\xa8\xee\xc4\x45\xc5\x1f\x0e\xdf\x41\x0a\x65\x09\x19\x39\x33\x16\xd2\x56\x1f\xb4\x39\xe9\x34\xcf\x13\xd4\xd5\x10\xd4\xae\xd5\x22\xc8\xbb\xef\x8d\x2c\x4f\x00\x66\xf1\x32\xcd\x8f\x03\x83\x8f\xdc\x96\x8d\x35\xe7\x0b\x1b\x74\x13\x76\xaf\x8f\xc0\x6a\x8c\xa2\x46\x9f\x4d\x91\x08\xff\xe6\x06\xd4\x03\xe3\xaa\x86\x9d\x44\x55\x41\x65\xd0\x85\xc4\xf1\x4c\xb2\xa4\x2c\xa4\xae\x2d\x3a\x57\xbe\xea\x11\x9d\xb7\xad\xe8\xb6\xb4\x39\x15\xe0\x4c\x0f\xd1\xc1\x05\xc1\x72\x75\xe2\x17\x07\x0f\x38\x2d\x5d\x8c\xad\xf7\x18\x43\x2b\xfb\x05\xe2\x66\xae\x22\x00\xb9\x8b\xe6\x2b\x48\x65\xc3\xf6\xdc\xed\xd3\xa1\x1c\xc1\xe3\xa7\xcd\x9b\x4d\x86\xea\x51\x6a\xdc\xa1\xae\x64\x0e\xf2\xd8\x28\x3c\xa2\xf6\x10\x18\x89\x65\x1b\xfc\x0d\x7d\xe0\xfe\x7c\xf1\xa5\xe4\x55\x45\xf9\x15\xcb\xbb\x8d\xb1\x3e\x01\x08\x75\x0a\xde\xb6\x14\xe0\xcd\xb6\x4f\xe8\x5a\x99\x77\xf4\x67\xc6\x32\x55\x7e\xa9\x65\xc6\xea\x4a\x5d\xe1\x99\x24\x7d\xdd\x0d\x8b\x15\x9b\x9c\x29\x62\x43\x93\x28\xf0\x1c\x8d\xc7\x14\x8a\xce\x32\xef\x98\xa4\xc2\x76\xde\x22\x7f\x83\xf3\xdb\xf0\x35\xc1\x7b\xca\x46\x30\xfd\xd2\x93\x01\x0b\xe1\xba\xab\x70\x27\xce\x9f\xf0\xd4\xea\xff\xc0\xd4\xa4\xf1\xfa\x68\xc6\xaa\xc5\x95\x50\xa9\xa5\x7e\x72\x17\x2d\x58\xef\x68\x70\x48\x31\xc5\xc6\x98\xc4\x5d\x76\x71\x47\xab\xae\xe6\x5c\x39\x43\x13\x07\x7d\xe8\x70\x8b\xae\x41\xe1\xe5\x23\x42\xbc\xdf\xba\xe9\xe6\xa4\x16\xe3\x08\xde\x73\x07\x62\xcf\x75\x8d\xcb\x7c\x55\xa8\xd0\xe3\xcc\x75\xf0\x48\xfd\xad\x4c\x9d\xd1\xef\xdb\xf5\xaf\x9b\x02\x52\xca\xc1\x1a\x2d\xff\xee\x6e\x40\x61\x48\xe1\x1e\x2b\x6a\xc3\x7e\xbc\xcc\x61\x9e\x23\xc2\x3d\x1d\x2f\x8e\x55\xdc\x73\x58\xcd\x6f\xdb\xb2\x46\xcf\x66\x16\xd9\x44\x4d\xf3\xa3\x51\x55\x5d\xb5\xc6\xbe\xe9\xfc\x98\x43\x41\x37\x5e\x44\x83\x15\x34\x82\x2b\x95\xd1\x5d\x5f\x56\x28\x4c\x35\x72\xdf\x41\x4e\x5c\x99\xc3\x88\x3f\x65\xe8\x7e\xbb\x2d\x00\x52\x61\x5a\x55\x05\xc3\x86\x5b\x87\xe3\xe4\x26\x98\x9e\x22\x6f\x9c\xb7\x52\xd7\xd9\x34\x8a\x3c\x5f\x0c\x99\xe6\x1b\x9b\xc5\x4b\xd7\x7b\xc3\xa5\x75\xf3\xe3\x50\x99\x00\xf0\xaf\x73\x77\x72\xa2\x1c\x3a\xf9\x7a\xba\xf7\x52\x81\x15\x78\xdb\x62\xd2\xb5\xe7\x2e\x22\xc6\xe4\x61\xe1\x04\xe5\x4d\xaf\x9c\xb2\x42\x6c\x18\xc9\x83\xdb\xa8\xac\x59\x16\xf9\xd0\xe8\xd7\x0e\x22\xda\xc4\xd1\xac\x75\x16\x41\xba\xbf\x01\x2e\xea\x8c\x7d\x28\xa5\x96\x9e\x75\x6f\x9e\x20\x17\x36\x5c\xb5\x54\x31\xba\x92\x6d\x89\x8f\x68\x2f\xd9\xf2\x4b\xa3\x98\x6b\xb5\x57\x01\x21\xfc\x58\x02\x69\xb8\x94\xe1\xb4\x47\x7a\x85\x79\x2f\x75\x1d\x9e\x59\xa3\xb3\x50\xd3\x19\xf0\xb5\x2e\xd0\xda\x20\x87\xc5\x9c\x82\x54\xf3\xae\x3f\xe3\xc3\xb6\x74\xe8\xd9\xd1\x58\x64\xde\x4a\x74\xd9\x6d\x3e\xea\x7d\x6f\x9c\x2f\x80\xe6\x52\x90\xc3\x70\xab\xcf\xfa\x21\xb2\x32\x47\x14\xad\xb5\xa8\x3d\xa3\xb7\x60\x36\xe2\xf4\x44\xfc\xa8\x15\xfa\x61\xd1\x1f\x0e\x0f\x49\x90\x0e\xc2\xdc\x32\x5d\xaa\x84\x45\xbf\xe9\x5d\xf8\x1c\x40\x51\x39\x7c\x86\x56\xa9\x30\xf2\x3a\x78\x98\xbd\x59\xc1\x9b\x67\xf9\xec\xc7\x38\xfb\x90\xfc\x13\x00\x00\xff\xff\x07\x54\x62\xed\x24\x0c\x00\x00") + +func etcNginxLuaBalancerLuaBytes() ([]byte, error) { + return bindataRead( + _etcNginxLuaBalancerLua, + "etc/nginx/lua/balancer.lua", + ) +} + +func etcNginxLuaBalancerLua() (*asset, error) { + bytes, err := etcNginxLuaBalancerLuaBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "etc/nginx/lua/balancer.lua", size: 3108, mode: os.FileMode(420), modTime: time.Unix(1520364534, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _etcNginxLuaConfigurationLua = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x74\x53\xc1\x8e\xdb\x46\x0c\xbd\xeb\x2b\x5e\x7d\x89\x17\xb0\x65\xb7\xc8\x29\x80\x2f\x45\x7b\x29\xb0\xd9\x22\xc9\x5d\xa0\x25\x4a\x9a\xee\x78\xa8\xe5\x70\xbc\x11\x8a\xf6\xdb\x8b\x19\x79\xdd\x38\xbb\x39\x19\x1e\x92\xef\x91\xef\x3d\x6d\xb7\x78\xe4\xf9\x5d\x04\x29\x83\xfc\x33\xcd\x11\x83\xb8\x30\xc0\x04\x47\x46\x18\xbe\xd6\x67\xd2\x7a\x52\xf9\x3a\x37\x69\x8a\xa6\x4c\xa7\x26\xd0\x89\x37\x20\xa4\xe0\x9e\x12\x27\x86\xeb\x38\x98\xeb\x1d\x2b\xa4\x07\x05\xd0\x34\xbd\x8b\xf8\x95\xda\x47\x0e\x1d\xe4\xf8\x17\xb7\x56\x6d\xb7\x68\x93\x2a\x07\xf3\x33\x9c\xc1\x45\x1c\x93\xf3\x06\x49\x65\x2e\xc3\x4e\x91\x5a\xde\x20\xb2\x9e\x5d\xcb\xe5\x09\x14\xba\xeb\xc3\x24\x5a\x80\xce\xe4\x33\x6f\xc4\x1f\x9f\x1f\x3e\x82\x43\x2b\x1d\x77\x70\x61\x50\x8e\xb1\xbe\x25\xfe\xee\xef\x06\xbd\x28\x4e\xa2\x0c\x17\x7a\x81\x72\xcf\x9a\x0f\x76\xc1\x58\x03\xf9\xdd\xee\x82\xb3\xb3\x79\xe2\x58\x0f\x52\x79\x69\xc9\xa3\x95\xd0\xbb\x21\x29\x99\x93\xd0\x74\x64\x84\x43\xd1\x28\x8e\xa4\xdc\xd5\xaf\xeb\xd5\x65\xb2\xb9\xc7\x01\x7f\xff\x53\x55\x7d\x0a\x6d\xae\xa2\xb9\xaf\x07\xb6\xe6\xb8\xac\x16\x4b\xf7\xfa\xae\x02\x94\x2d\x69\x78\x83\xeb\xc3\xc0\xb6\x5e\xbd\x0c\xac\xee\x2a\x0e\xdd\x0f\x01\x8b\x47\xb1\x00\x6e\xb7\xd8\x63\x64\x65\x9c\x98\x42\xc4\xc0\x06\xf2\x1e\x36\x72\x76\x3f\xe2\x79\x74\xed\x88\x96\x42\xb6\x3c\x7a\x79\x86\xeb\x73\x35\x67\x22\x4f\x51\x98\x4b\xe3\x82\xf5\xe5\xe1\xb7\x87\x35\xfb\xb3\x0b\xdc\x73\xe8\xdc\x1d\x6c\x74\xe1\x11\x74\x94\x64\x88\x26\x9a\xf3\xd3\xca\xe9\x44\x88\x3c\x91\x92\x71\x87\xcb\x5a\xc5\xd0\x08\x17\x40\x41\x32\x05\x3a\x57\xd6\x27\x9d\x8b\xcf\x29\x96\xf4\x8d\x64\x30\x59\x08\x7b\xb6\x76\x2c\xdb\x7a\x17\x2d\x07\xc5\x46\x3e\x2d\x17\xb9\x10\x33\xba\xf4\x38\x7a\x69\x1f\x97\x59\x06\xb5\x2d\xc7\x98\x3d\x5d\x9c\xf9\x86\xe5\x7f\x85\x6f\xa4\xcf\xe2\x36\xf9\xc8\xf5\xfe\x0d\x61\x5b\xf2\xbe\x68\xe9\xfa\xeb\x37\xa1\xfc\x94\x38\x5a\x73\x62\x1b\xa5\xc3\xbf\x07\xac\xfe\x7c\xf8\xfc\x65\x05\xd1\x57\x3d\x49\x5d\x69\xd8\xdd\xb8\xba\xbb\x7a\x99\x97\x0e\x15\x80\x25\x4d\x46\x96\x22\x0e\x78\xbf\x7f\x7f\x7d\x9c\xd4\x05\x5b\xaf\x3e\x8a\xa1\x97\x14\xba\x9f\x56\x77\x55\x29\x2e\xd7\x54\x40\xd9\x7a\x69\x56\x7e\xaa\x95\xa9\x6b\x8e\xd2\xcd\xeb\xd2\xb8\xe4\x30\xa6\xa2\xcc\x06\xac\x8a\xc3\x5b\x21\x8b\x37\x21\xdb\x5c\xe1\x4a\xb6\xa4\x9b\x2f\x41\x7d\x11\x43\xec\x05\xf3\xf6\x06\x2f\xc3\x3a\xff\xfe\xfe\xe9\xd3\x06\x2b\x56\x15\xcd\x39\xf3\x8c\x48\xe7\x25\x20\xdf\x50\x7f\xc0\x0a\x75\x0d\x93\x68\x39\x3d\x6b\x56\x2d\x0c\xaf\xf4\xd8\xff\xf0\xe4\x6b\xd3\x2f\xfb\x9f\x17\x03\x2f\x36\x37\xf7\xd5\x7f\x01\x00\x00\xff\xff\xf6\x6d\xd4\xcd\xe7\x04\x00\x00") + +func etcNginxLuaConfigurationLuaBytes() ([]byte, error) { + return bindataRead( + _etcNginxLuaConfigurationLua, + "etc/nginx/lua/configuration.lua", + ) +} + +func etcNginxLuaConfigurationLua() (*asset, error) { + bytes, err := etcNginxLuaConfigurationLuaBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "etc/nginx/lua/configuration.lua", size: 1255, mode: os.FileMode(420), modTime: time.Unix(1520364534, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _etcNginxLuaUtilLua = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x91\x4f\x8f\xd3\x30\x10\xc5\xef\xf9\x14\xef\xb6\xac\xd4\x36\x6b\x77\x11\xd2\x4a\x39\xc1\xb5\x37\xc4\x65\x85\x2c\x37\x99\x34\xa6\x8e\x1d\xec\x49\xaa\x0a\xc1\x67\x47\x76\xda\x6d\x8a\x04\x17\x4e\x51\x9e\xdf\xbc\xdf\xfc\xb1\xbe\xd6\x16\x6a\x87\x0a\x3f\x7e\x16\xc5\x7a\x0d\xee\x4c\x84\xe9\x07\x4b\x3d\x39\xd6\x6c\xbc\x83\x89\x60\x7d\x24\x87\x36\xf8\x3e\x99\x3a\xe6\x21\xbe\x94\xe5\x89\xf6\x1b\x1d\xea\xce\x4c\xb4\xf1\xe1\x90\xfe\x4b\xf9\x24\xb6\x42\xca\xf7\x4f\x1f\x9e\x9e\xb7\xcf\x65\xb2\xbe\x94\x65\x74\x66\x18\x88\xe3\xc6\x8e\xba\xf6\xcd\x6c\xbf\x8a\xe5\x27\xa2\x41\x7d\xf4\xfd\xa0\x83\x89\xde\x29\xdf\xaa\xcf\x27\xaf\xbe\x68\x3b\x52\x54\xdb\x84\xd4\xae\x41\xef\x1b\xd3\x1a\x6a\xd0\xfa\x80\x31\x12\x8c\x9b\xfb\x1d\x82\xff\x46\x35\x17\xf3\x38\xed\xe8\xea\xdc\x77\x93\x62\xeb\x1c\x4b\xef\x58\xac\xc0\x72\x05\x73\x70\x3e\x90\xea\xf9\xb1\x00\xe6\x02\x3e\x0b\x54\xe0\xf3\x90\x5c\x4b\x59\xbe\xc9\x32\xc9\xa6\xcd\xd6\x5f\x55\x7e\xe2\x8e\x1c\x02\xf1\x18\x1c\x5a\x6d\x23\x81\x5c\x53\x00\xeb\x35\x9c\x77\x6b\xd6\x7b\x4b\xb9\x3a\xa2\xd6\x0e\x7b\x42\x63\x02\xd5\x6c\xcf\xb8\xf4\xd4\xdc\x65\x3e\xe4\x8a\x87\x3c\x69\xca\x5f\x48\x4b\x14\x0b\x54\x15\x58\xde\x68\x3a\xe2\x44\xd6\xa6\x6f\xf6\x47\x9c\x3a\x53\x77\xe8\xf4\x44\xa9\x14\x3d\xb1\xee\x89\x3b\xdf\x40\x29\xfa\xfe\x36\x60\xcf\xa8\x70\x20\x4e\xef\xb9\xf2\x32\xbe\x69\xe1\x3c\xdf\x36\x35\x2f\xff\xfa\xd9\xa4\x8c\x7f\xb5\x94\xae\x73\x14\xab\x49\xa4\xfb\x0c\xda\x84\x98\x72\xd1\xf8\x02\xb8\xa2\xa7\xbc\x5a\xf9\x7a\x14\x5f\xb3\x6a\xda\x2c\x55\x70\xc6\xc2\x87\xcc\xbf\x3b\xdf\x24\x56\x93\x7c\xfc\xeb\xd2\x17\x64\xb9\x9a\xe4\x82\x2c\xff\x24\xe7\x5b\x8b\xd7\xa3\xbc\x91\xc5\x7f\x93\xaf\x9b\x08\x23\x15\x49\x51\xbb\xcd\x32\x04\xd5\x5d\x66\x51\x5c\xfc\x6a\x57\xfc\x0e\x00\x00\xff\xff\xb9\x73\x37\x07\x83\x03\x00\x00") + +func etcNginxLuaUtilLuaBytes() ([]byte, error) { + return bindataRead( + _etcNginxLuaUtilLua, + "etc/nginx/lua/util.lua", + ) +} + +func etcNginxLuaUtilLua() (*asset, error) { + bytes, err := etcNginxLuaUtilLuaBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "etc/nginx/lua/util.lua", size: 899, mode: os.FileMode(420), modTime: time.Unix(1520390515, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + var _etcNginxNginxConf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xca\x41\x0a\x83\x40\x0c\x85\xe1\xfd\x9c\xe2\x41\xf7\x7a\x00\x57\x3d\xca\xa0\x89\x06\x34\x19\x32\x4f\x69\x29\xbd\x7b\x69\xe9\xea\x5f\xfc\xdf\x0d\x77\x5c\x92\x4f\x74\x3b\xda\x2e\xf0\xd5\xfc\x81\x39\x5c\x6d\x3d\xb3\xd2\xc2\xa1\xb6\x0b\xb8\x55\x42\x23\x67\xe9\x7f\xc4\x40\x67\x4d\x0e\xa5\xd9\x82\x31\x4f\x1f\x7f\x63\x68\xb6\x4c\xa5\xc8\x25\xce\x8e\xd7\xbb\x6c\x64\xfb\x76\xa9\x72\x84\x23\x54\xa7\x4f\x00\x00\x00\xff\xff\x75\xb5\xe6\xb8\x77\x00\x00\x00") func etcNginxNginxConfBytes() ([]byte, error) { @@ -85,12 +148,12 @@ func etcNginxNginxConf() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "etc/nginx/nginx.conf", size: 119, mode: os.FileMode(420), modTime: time.Unix(1516916602, 0)} + info := bindataFileInfo{name: "etc/nginx/nginx.conf", size: 119, mode: os.FileMode(420), modTime: time.Unix(1519920732, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _etcNginxTemplateNginxTmpl = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x7d\x6b\x73\xdb\x38\x12\xe0\xf7\xfc\x0a\x94\xec\x2b\xdb\xa9\x48\x76\x66\xb2\xb3\xbb\x76\xf9\xea\x1c\x3b\x59\x7b\xd7\x49\x5c\x96\x33\xb3\xb5\x57\x57\x2a\x88\x6c\x89\x58\x53\x04\x07\x00\x65\x6b\x72\xba\xdf\x7e\x85\x27\x01\x12\xa4\x64\x4f\xe6\xb1\x53\xcb\x0f\x2e\x8b\x6c\x34\x1a\x8d\x46\x03\xfd\x00\xf0\xe5\x0b\xda\xc5\x79\x8e\x8e\x4f\xd1\x08\xad\xd7\x2f\xe4\x6f\x0e\x6c\x09\x8c\xab\x77\x63\xf3\xbf\xf9\x94\xcc\xe6\xea\xf5\xf9\x6c\x6e\x5f\x5d\xf1\xab\x9b\xef\xbf\x7b\x57\xe0\x69\x0e\xa9\xfa\x18\xbe\x31\x60\x19\xe0\x5c\x64\x3f\x7d\xbe\xbd\x52\x30\x97\xf5\x4f\x03\x30\xc5\xc9\x3d\x14\xa9\xae\xf6\xad\xfd\x61\x3e\x96\x8c\x3e\xae\x2e\x01\xa7\x96\xae\x1b\xf9\x62\x0c\xc2\xbe\x33\x70\x38\x4d\x7d\xa8\xb3\xfa\xe7\x7a\xfd\x42\x42\x90\x99\x6a\xc4\x48\x53\xf7\x81\xa6\x1c\x92\x8a\x11\xb1\x92\x00\x39\xc5\xe9\x64\x41\xd3\x2a\x07\x74\x08\x22\x39\x2c\xe6\xa4\x78\x3c\xd4\x6f\xf8\x61\x31\x7f\x9c\x64\x42\x94\x12\xc4\x16\x33\xe0\x23\x4e\x4f\x24\x7a\x28\xd2\x78\x4d\x9f\x4a\x28\x04\xc3\x09\x29\xe6\x4f\xa9\x89\xd6\xc5\x7a\x6b\xda\xc7\x45\xda\x55\xdd\x7e\x01\xfa\xd3\xbf\x48\x79\x4f\x8a\x73\x9a\xe7\x90\x08\xca\x2e\x29\x17\x68\x30\x38\x38\x78\x0a\x41\x3f\x29\x1c\x3f\x9f\x96\xbf\x63\x98\x03\xfb\x79\xb4\xfc\x5b\xe1\xe8\xa0\x25\xc5\xb0\xa0\x05\xa2\xb3\xd9\xc9\x8b\x17\x0f\x94\xdd\x03\x9b\x94\x8c\x26\xc0\x39\x70\x64\x64\x79\xf4\x83\xfa\x70\xe3\xde\xaf\xd7\x27\x2f\x4a\x92\xa2\x43\x56\x15\xba\xda\x51\x49\xd2\x13\xd3\xb2\x02\xd0\xe8\x03\x7e\x94\x0d\x7a\x4f\x72\xe0\xe8\x48\x56\x65\x90\xb3\x9c\x2c\x88\x98\x14\x74\x46\x72\x90\x15\x84\xa0\x12\xb3\x26\x4f\x73\xea\xf0\x25\x92\x8d\x38\x3e\x34\xd5\x50\x36\x3f\x84\xe2\x30\xa5\x89\x6e\x61\x42\x19\xd8\xa6\x65\x62\x91\xef\x98\x6a\x78\x56\x89\x94\x3e\x14\x13\x41\x16\x40\x2b\x81\x5e\x1e\x2a\xd9\x3f\x7c\x89\xf0\x92\x92\x14\x3d\x60\x22\x24\xab\x05\xa5\x28\xa7\xc5\x1c\xa5\x15\x93\xbf\x31\x62\x20\x39\xab\x0b\x74\x61\x0b\x19\x33\x36\x9f\xef\xcc\xd7\xf5\x1a\x9d\xbc\x78\x01\x4b\x28\x04\x47\x5f\x5e\x20\x84\xd0\xa2\xca\x05\x99\xe0\x24\x81\x52\x20\xf3\xd0\xe2\x44\x7d\x33\x95\x24\xb4\x28\x20\x11\x84\x16\x1c\xb9\x0a\x3e\xe0\x47\x5d\xc7\xb9\xf7\x55\x32\x49\x16\xac\x38\xa0\xe6\x03\x25\xcd\xf3\x93\x17\xeb\x17\x2f\x24\xdf\x4c\xed\xaa\xdd\x0f\xa0\x0a\x88\x0c\xd0\x12\xe7\x15\x20\x3a\x53\x3f\x32\x35\xf4\xd1\x3f\x87\xef\x29\x7b\xc0\x2c\x85\x54\xfe\x87\x04\x45\x53\x40\x52\x32\xe5\xbf\xb6\xe4\x1c\xe8\x84\x94\xc8\x88\x9d\xe2\x91\xae\xc0\x0d\xe4\xcf\x1c\x94\xd6\xb9\x61\x54\xd0\x84\xe6\xc8\x80\x30\xc0\xf9\x84\x94\x13\x53\x9d\x7a\x94\xbe\x92\xf2\xa6\x20\x4f\x2c\x2a\xc8\x39\xf4\x15\xb3\xcc\x71\x04\xbf\xa7\x4c\x2b\x30\xc7\x1a\x4f\xc4\x7d\x2c\x4c\xea\x23\x4e\x96\xe0\xb1\xff\xcb\x17\xc4\x70\x31\x07\xb4\x2b\x58\xc5\x05\xa4\xb2\x81\xc7\xa7\xba\x0a\xd5\x94\x5b\xc0\xf9\xd5\xcd\xf9\xd5\xc5\xad\xa5\x8a\x83\x98\x58\x9c\x33\x46\x17\x96\x2a\x0f\x43\x07\x25\xaa\x2b\x52\x2c\xf0\x14\xcb\x91\x54\x71\x48\x25\x7f\x53\x10\xc0\x16\xa4\xd0\x5c\x4e\x68\x55\x08\xb6\x42\x29\x94\x50\xa4\x52\x2c\x69\xa1\x3f\xe4\x04\x0a\x81\xae\x6e\x10\x4e\x53\x06\x9c\xfb\x5d\xd0\x37\x56\xe4\x87\x5a\x25\xcc\x81\x92\xd2\x1f\x36\x0d\x34\x22\x23\x1c\x11\x8e\x18\xfc\x58\x11\xa6\x04\x20\xc1\x79\x52\xe5\x58\x00\x12\x0c\xcf\x66\x24\x41\x33\xca\x10\x29\x52\xb2\x24\x69\x85\x73\x47\x73\xc5\x25\xbd\x7f\x03\x7a\x75\x83\x88\xa6\x9a\x0b\x2c\x2a\x8e\x4a\x3c\xf7\x44\x46\xd3\x60\x4b\xe9\xc7\x53\x63\x0a\xc1\x28\xc5\xe2\xc4\x87\x96\x33\x90\x7b\x42\xe8\x6b\x22\xe0\x9c\x88\x55\xb3\x8c\x96\xb1\xba\xe3\x65\xb7\x37\x65\x56\x6b\xe0\xef\x05\x1f\x6b\x4a\x0d\x89\xcb\x8c\x72\x31\x31\xed\x9d\xe8\x56\x4c\x7e\xa2\x05\x20\x9e\x61\x06\xe9\x71\x0c\xe0\xd8\x4a\xa7\x43\xf7\x2f\x5a\xc0\x98\xfc\x04\x4e\x24\xa2\x78\x67\x24\x17\xc0\x26\xd3\xd5\x44\x0a\xd7\x3d\xac\x90\x87\xe8\x02\x66\xb8\xca\xc5\x7b\x05\xf3\x0f\x58\x75\x49\x17\x26\xb4\xa5\x11\x44\xc6\x00\xa7\xfc\xc4\x02\x4c\x1e\x18\x11\xbe\xe2\x70\x1c\x11\x49\x39\x29\x68\x59\xf1\x2c\xfc\x58\x7f\x4b\x21\xc7\xab\x76\xc1\x9c\xce\x27\xbc\x9a\x4a\x71\x01\x2e\x1a\x1f\x19\xc8\x06\x49\xcd\x99\xd2\x4a\x78\x6a\xae\x06\xb9\x07\x28\x71\x4e\x96\xe0\x14\xac\x6b\xfc\x3f\x00\xca\x33\xf9\x09\xad\xd7\xa6\x0d\x35\xb4\xa9\x90\xb7\xa1\x6f\xed\x17\xc9\x28\x55\x4a\x0f\x1d\xa3\x47\x26\xd3\x6a\x36\x93\x8a\x5d\x76\x4b\xa8\x54\xce\x15\x9c\x56\x27\x6f\x15\x54\xd0\x77\x21\x1a\x47\xae\x7b\x62\x68\xea\x79\xc1\xb4\x20\xc7\x6c\x0e\x93\x18\x45\x3c\x40\x72\x2d\xe1\xda\x04\xf1\x26\x35\x53\x9a\xae\x22\x4d\x6a\x52\xf3\x96\xa6\xab\xee\x26\x29\x24\xed\x06\xc5\x90\x04\x0d\x52\x38\xa4\x5a\xf9\x66\xb2\xc0\x8f\x93\x19\x81\x3c\x0d\xa9\xf0\x70\x5c\xde\xdd\xdd\x7c\xf3\x01\x3f\xbe\x97\x50\x01\x15\x35\x06\xc3\x90\x06\x8a\x26\x06\xcd\x10\x87\x42\x0b\xe9\xaa\x04\x3e\xc9\x30\xcf\x14\xa2\x26\x11\xe8\x9b\xa3\x37\x7f\x39\x31\x0a\x5c\x2e\xd8\x27\x05\x5e\xc4\x0b\xd8\xda\xf4\xc2\xfe\x23\x5e\xc0\x25\xe6\xd9\x07\xfc\x18\xd0\xdc\xc6\x32\xad\x92\x7b\x10\x16\x51\x1c\xcb\x5b\x05\x13\x20\x5a\xe0\x32\x56\xbe\xd5\xf8\x0f\xb8\x8c\x60\x50\x28\xb4\x9e\xd3\xbc\x8b\x35\xc9\xa2\xb8\xf1\x6c\x84\x58\x9b\x22\x78\x02\xa2\xba\xf0\xc4\x68\x5a\x62\x46\xa4\x66\x8d\x32\xc7\xa3\xe9\x7b\x0b\xd7\xc1\x9e\x06\x9e\x56\xdf\x46\xf1\xf8\x0d\xd3\xcb\xa5\x42\xd2\x2a\x57\x8c\x7c\x42\x0a\xdb\xc4\x80\xc9\xe1\x84\xf0\xb9\x2e\x70\x55\xd4\x16\x12\x2d\xea\x35\x0a\x9d\xcd\x9c\x0a\xd6\xb4\x92\x79\x21\xd7\xa4\xa4\x58\xe2\x9c\xa4\xbd\xb5\x5c\x29\xd0\x2b\x0d\xb9\x0d\x7e\xad\x3c\xd4\x02\x9a\xc1\x8f\x66\xe6\x40\x8d\xc7\x29\x0f\x09\x77\x0b\x3f\xea\x49\xe8\x9c\xa6\x1e\x2b\x36\x19\x5e\x12\xc6\x33\xaa\xfc\xb5\x52\xb8\x98\xf9\x2a\x56\x95\x44\x65\x2c\xa6\xc4\x02\x4c\xe4\x1c\xd9\x6c\x9a\xd7\xba\x18\x3e\xdb\x05\x2d\x5c\x25\x65\x4f\xc0\x75\x23\xa1\x1b\xb8\xe4\x48\x27\x09\xa8\xa1\x1e\xc1\xd4\xc4\x35\xd6\xe0\x72\xc4\x07\x53\xb5\xec\xd4\xaf\x61\xfb\x49\x7c\xc6\xae\x63\x20\x5b\x07\x6c\x92\xd3\x04\xe7\x13\x3c\x57\x73\x8a\x5c\x60\x98\x56\x5b\xca\x62\xf8\xd6\xeb\xe3\x8e\xcf\x01\x13\x4c\x55\x5b\x33\x41\xe3\x8a\x31\xc1\x62\xc2\x8b\x32\x97\xf3\xe7\xaa\xdc\x0a\x93\x06\xbf\x93\xd0\x1d\x98\x4a\xcc\xf0\x62\x6b\x4c\x37\x0a\xba\x63\x11\x45\x8a\x24\xaf\xd2\xd0\xa8\x26\x0b\x18\xa9\xd9\x45\x97\x48\xf5\x7a\x4c\xd3\x2f\xe0\x51\x1c\xca\x55\x74\xd7\xe0\x7a\xcb\xa8\xc8\x89\xed\xb7\xa9\xfe\x65\x87\x94\xfe\x39\x49\xe8\xa2\x9c\xe4\xb0\x84\xdc\x51\xac\x8b\x5d\xab\x77\x96\x54\x03\xad\x48\x69\x00\xde\xa9\x77\x9d\x66\x87\x6f\xa0\xfd\xed\x27\x65\xa0\xe8\x55\xb2\xfc\xdf\x12\x23\x7f\xf8\xa4\xfc\xc9\x7b\xad\x2c\x87\x25\x30\x2e\x97\x6e\xaf\x47\xaf\xbd\x4f\x0b\x52\x4c\x72\x28\xe6\x22\x43\xdf\xfc\xe9\x3b\xef\x43\x48\xa7\xac\x36\xa4\x52\x01\xc9\x19\x87\x40\x8a\x70\xb1\xf2\xde\x2e\x31\x5b\x75\xe9\x9d\x1d\x74\x5e\x71\x41\x17\xc8\x6a\x57\x69\x8b\x30\xe0\x25\x2d\x38\x34\x8c\xba\xfb\x57\x68\x77\xa9\xec\x39\x1c\xb8\xb9\x24\x14\x4e\xad\x82\x56\x34\xde\x4b\xcb\xdd\x7b\x06\xf2\xe5\x12\xad\xd7\x83\x28\x15\x66\xf6\x17\xf4\x1e\x0a\xee\x73\x78\x9c\xd1\x07\x3d\xe5\xdf\xe9\x6f\x9b\xe6\x0c\xe3\x37\xa1\xa2\xb3\xbc\x5e\x25\xc8\x89\x45\x2e\xa6\x6d\xb3\x07\x1a\xea\x18\xc5\x09\xdc\x41\x29\xe1\xca\x82\x7f\xc0\xac\x20\xc5\x9c\x9b\x79\x90\x14\x44\x10\x9c\x93\x9f\x20\x9d\xd8\xb9\x75\x22\x61\x8c\x23\x48\x17\x3e\x4b\x53\x22\xd7\xe9\x38\x47\x78\x89\x49\xae\x30\xb9\xa9\xf8\xd8\x40\xed\xaa\xd5\x4f\x89\x13\xb0\x2f\x48\x31\x97\xa6\xa9\x52\x13\xf6\x9d\xaf\x3a\x9c\xc9\x30\xa3\x6c\x81\x05\xaa\x4a\x2e\x18\xe0\x05\x29\x66\xd4\x67\xe3\x35\x9d\xbf\x57\x10\xef\x78\x82\x4b\xf8\xfb\xf8\xd3\x47\xb4\x5e\x83\xfa\x71\xfa\x6f\x4e\x8b\xba\xbd\x7b\x5f\xbe\xa0\x69\x45\xf2\xd4\x95\xf9\x6c\x90\x6a\x67\xec\x7a\xbd\x77\xe2\xd9\xdf\x0b\x5c\xa2\x8a\xe5\x1c\x89\x0c\x0b\xc4\x33\x5a\xe5\xa9\x62\x3f\x2e\x4b\xc0\xd2\xac\x45\x38\x49\x80\xf3\x51\x4e\xe7\xcf\x33\xb1\x65\xfb\x7c\xbf\x94\xc6\x37\x09\xf0\x49\x32\x76\x8d\x0d\x33\xa9\x18\x41\xbb\x39\x9d\xcf\x15\x9b\xb5\xdf\x26\x94\x64\x06\x3f\x7e\x66\xc4\xb9\x26\xc6\xf7\xa4\x3c\x53\x58\xaf\xe9\xfc\xf3\xed\xb5\x13\x13\xab\xf5\x0c\xfc\x7a\x8d\x8e\x4e\x6a\xc9\xb0\x10\x46\x85\x21\x33\x8e\xdb\x7a\xe2\x42\xcb\x8e\xab\xc2\x0d\x9a\xba\x25\x4a\x5a\x50\xdb\x69\xe3\x81\xd8\xb1\xef\xd0\xdc\x60\x91\x49\x9a\x82\x5e\x27\xb3\x53\xd7\xf6\xa6\x28\xcb\x5f\xc0\x18\x65\x0a\x9f\x43\xf8\x4e\xbe\xf2\xf0\x35\xdf\xd7\x7a\xd3\xe2\x53\x02\x72\x0b\x9c\xe6\xca\x57\xaf\xa0\xed\xcf\xa0\xc9\x57\xe5\xf2\xbb\x8b\x8f\xe3\xd0\x67\xf3\x43\x06\x05\x48\x48\xd5\xf3\x48\x2b\x2d\xae\xfc\x85\xda\xea\x7d\x20\x22\x93\x46\x11\x46\x83\xda\x59\x37\x30\x2a\xea\x95\x72\x84\x44\x3e\x20\xc2\x11\x07\x81\x04\x45\x83\x24\xa7\x1c\x06\x0d\x79\x7b\xc8\xa0\x40\x0b\x7c\xaf\x9c\x95\x19\x20\x21\x6d\x42\x61\x6b\x1d\x21\x74\x97\x11\x8e\x16\x80\x0b\x23\xce\x2b\x5a\xa1\x04\x17\x52\x9c\x39\x59\x94\xf9\x4a\x39\xef\x42\xa4\x03\xbd\xca\xaf\x75\x09\xaa\x29\x43\xbb\x4a\x80\x13\x8f\x54\xa9\x5e\x7f\x80\xe9\x98\xca\x95\x39\xe2\x55\xa9\x96\x16\x53\x48\xb0\x44\xad\xbc\x3c\x84\xa3\x04\x73\xd0\xed\x6c\x54\x16\x69\xf5\x83\x1a\x72\x53\x70\x6d\x1f\xa8\x86\x2a\x06\x4b\x0c\x94\x91\x39\x91\x9a\xc7\x72\x37\x25\x7a\x84\x66\x78\x09\x5d\x2c\x6e\x32\x8e\x24\x99\xa9\x48\xb2\x07\x15\xb4\x9f\x14\xe3\xad\x6a\x31\x78\x4c\x8a\x04\x74\x13\x35\x6c\x0a\x4b\x82\x05\x20\xe5\xf9\x0b\x2b\x2d\xa4\xf2\xc9\x8d\x8c\x4c\x21\xc3\x4b\x42\x19\x7a\x00\x4d\xb7\x73\xa4\x12\x2e\x55\x0d\xa3\x38\xc9\x46\x35\x86\x1d\x74\x0b\x02\x1b\x32\xec\xf8\xd4\xa8\x32\x5c\xa4\xb9\x5a\x89\xcf\x90\xf3\x7a\xf4\x4a\x5c\xad\x61\x54\x77\x56\xe5\x9c\xe1\x54\x2e\x2d\x1d\xa4\x7b\xf7\xa5\xa5\x14\xdc\x63\x40\x4e\x1c\xc4\xde\x5e\x63\x7d\xa5\x84\x36\xd0\x21\xb2\x52\x3b\xdc\x7c\x17\x6d\x8f\xd3\x16\xed\x8a\x0c\xac\x47\xd5\x39\xad\x37\xfa\x94\x35\xd3\xfe\x06\x81\x47\x54\xf5\x8a\x02\x47\x16\xbe\xbb\x7d\xbb\xa1\x0b\x7a\x22\x91\x44\x55\x5a\xbc\x34\x83\x05\x15\xd0\x28\x55\xab\x2d\x37\x0f\x2b\xbf\xb0\x9a\x3a\x26\x8f\x72\xda\xd3\x1c\xd0\xd5\xba\x45\x4c\x42\x19\x83\x44\xe4\x2b\xe5\x56\x4d\xa4\x84\x71\x9e\x4b\x25\x9b\x53\x9c\x92\x62\xde\xe8\xd2\x36\xa6\xdd\x12\x73\x3e\x31\xda\x97\x27\x19\x2c\x7a\x3b\xb7\x03\x4d\x4f\x67\xef\x6a\xa4\x27\x61\xeb\x94\xfd\x2a\xc9\x8d\xd5\xaf\x4c\x1d\xfb\x3f\x03\xc5\x04\x39\x10\x66\x94\x25\xa0\xd4\x67\x4a\x64\xb3\x5d\xe3\x06\x06\xfa\x38\x82\x6d\x20\x59\xae\xe1\x27\x82\xaa\x99\x96\xf7\xb5\xf0\xa8\x6e\xcb\x40\x4d\xdc\xf2\xcf\x40\xbf\x78\xdd\xf8\xc6\xbd\x8f\xaf\x5b\x02\x1d\xe1\x95\xd4\x81\x9a\x46\xb3\x12\x54\x6f\x7a\xa8\xe9\x40\xd2\xc3\x6f\x1b\x65\xf6\xe0\xc2\x89\x1a\xe7\xf9\xe8\x8a\x8f\xc7\xd7\x37\x98\x73\x91\x31\x5a\xcd\x33\x2f\xa4\xac\xfb\x47\xd2\xaf\x69\xd3\x61\xec\xd1\x35\xe1\x02\x0a\x69\xe2\xf1\x91\x2c\xab\x06\xcb\x7a\x2d\xbb\xe5\xcd\x9b\x6f\x95\xba\x8f\x44\x85\x24\x7c\xcd\x8f\x56\xc3\xf5\x9b\x06\x0f\x36\xd5\x18\x3c\x6f\xde\x7c\x7b\xd2\x37\x54\x1b\x35\x5a\x7e\xa0\xf6\x68\xfd\x99\x14\x5e\xde\xdd\xdd\x8c\xbf\x36\x79\x71\x6b\xec\x9c\x2e\xca\x4a\xc0\xfb\x2a\xcf\x03\x5d\xe9\x3a\xef\x07\x90\xb3\xf9\x9e\x50\x33\x87\x51\x57\xd2\x6e\xf1\xa5\x48\x76\x98\x9d\x8d\xe5\xdc\x21\x15\xa9\x8b\xd2\x19\x3c\x0c\xca\x1c\x27\xc0\x0d\x80\xd3\x5b\x2a\x02\xca\x29\x2d\x7a\x44\x5d\xe2\xdf\x9d\x55\x79\xde\x7a\x1b\xf0\xd1\x0a\xe4\xf9\x06\x95\xdd\xe2\xdd\x20\x5a\xe5\xab\xa8\x76\x1e\xf4\x0c\x97\xc1\x86\x02\xdb\xe8\xf4\x4e\x5a\x34\x53\x27\x1e\xeb\xfa\x49\xe9\x85\x77\x31\xee\x4e\x19\xf1\x7c\xcb\x13\x52\x4c\xac\xda\xab\xd7\xdc\x52\xc6\x82\x2f\xe6\xa9\x4d\x38\x06\x2a\xd4\xa3\xd7\xcd\xde\xe3\xe2\x2e\x9c\xe7\x8e\x57\xb5\x99\xae\xc7\xa7\x79\xe9\x16\xd0\x3b\x48\x54\xd2\x40\x2c\x10\x07\xae\x7c\x00\x09\x4e\x32\x1d\x42\x47\x29\xc3\x5c\x90\x04\xe7\x72\xf2\x5a\x94\x8c\x2e\x01\x95\xc0\x94\x81\x57\x24\xd0\x14\xfa\xf1\xf8\x7a\xac\x91\x9c\xe3\x24\x73\xfd\x21\xc9\x31\xc8\x27\x89\xfa\x20\xd7\x10\x82\x14\xc7\xaf\x8f\x8e\x8e\x6c\xd0\x6d\x3c\xbe\x3e\xf6\x48\xf5\x11\x85\xce\x79\x0f\x5b\x33\x6e\x5f\x97\xab\x43\x19\x1d\x26\x34\xce\x73\xfa\x80\x12\x5a\xcc\xc8\x5c\xa7\x08\xc8\x49\xd9\xf2\x40\x10\xb9\x24\xe6\x91\x0a\xd5\xfb\x78\xa3\xef\xcc\xc7\x8d\xae\xde\xda\x2f\xb0\x0f\x8b\x52\xac\xe2\x88\xfe\x01\x2b\x74\x10\xe3\xa1\x26\x42\xc5\x12\x3d\x5f\x96\x21\x6d\x74\x0f\xab\x8e\x26\xf3\x9c\xcc\x33\xb9\x0e\x61\x90\x56\x89\x56\x29\x92\x83\x43\x41\x87\x33\xc2\xb8\x18\x4e\x57\x02\x5c\x75\x7e\xe0\xc9\x63\x70\x23\xd2\xd4\xdf\xa0\x73\x52\x66\xc0\xf8\x41\xad\xf7\xda\x7c\x4f\xb4\xcf\x47\xb2\x3f\xd1\xe0\x8e\x04\xf3\x1b\xed\x79\xf5\x1b\x94\xda\xf6\xaf\xa5\x1d\x66\xc6\x93\x09\xcc\x15\xeb\x75\x6f\x47\xa8\xbd\xb8\x54\x0e\xc4\x36\xb5\x9a\xc2\x8b\x4b\xa4\xb2\x5b\xb6\x74\x15\x48\xba\x7c\x57\x81\xfc\x9d\x66\xca\xa1\xe9\xe8\x36\xbf\x7d\xfe\x1a\x22\xfa\x3d\x7e\xce\xa7\xa4\x17\x05\x17\xab\x02\x2f\x48\x72\x77\x3d\xbe\x85\x84\xb2\x94\xfb\x62\x93\xae\xa4\x32\x49\x54\x47\x4e\x72\x6a\x17\x4f\x4d\xbd\xc4\xf3\x09\x24\x69\x36\x49\x2a\xb6\x0c\x3a\xfc\xdd\xf9\xc5\xe5\xb9\x7a\xd9\xe8\xef\x91\xf6\xd6\x29\xcb\x9c\xd7\x3c\x33\x3e\x3c\x65\xdb\xab\xe4\x00\xdd\x9f\x5a\x85\x93\x42\x00\x4b\xa0\x14\x13\xd0\xc5\xba\xfb\xc8\xb8\x47\x80\x31\x15\xe4\xb0\xfe\x11\x8d\x5e\x4e\xe5\x61\xc5\xda\x97\xa0\x92\x11\x24\xf1\xb6\xd8\x7a\x8d\x4e\xd1\xff\xd2\x3d\x38\x09\x3f\x9c\x34\xea\x34\xc6\xb3\x37\xd2\x18\xc8\xa9\x37\x96\x5a\x70\x26\x05\xc3\xe4\xe9\x69\x6f\x9d\x33\x7a\x3c\x5c\x6a\xed\x60\x96\x5c\x1a\x6a\x43\x63\x0d\xac\x6d\xeb\x25\x49\xa1\xf6\x6d\x9a\x10\x1e\x49\xc1\xf7\x6e\x66\xbd\x19\x32\x71\x59\x57\x0b\xa1\x82\x94\x25\x88\x83\x56\xc7\x25\x92\x3b\x5c\x7f\x75\x03\x15\x52\x6b\x47\xdb\x37\x58\x39\x15\xf4\xaf\x05\x2e\x6d\x6d\x4d\xfc\x68\xdd\xb5\x54\x32\x4d\x96\x33\xe1\x2b\xb4\x6b\xfd\x46\xaa\xed\x53\x2f\x01\xb2\x6e\x05\xfc\x58\x83\x8d\x8c\xaa\x3c\x9b\xcd\x48\x41\xc4\x6a\x64\xff\x51\xc1\x84\x41\x42\xe9\x3d\x81\x81\x2d\xef\x90\xcb\xd9\xec\x7e\x35\x94\x74\x3a\x4c\x26\x90\xe1\xad\x79\x34\x14\xca\x30\xcf\x4e\x03\xd0\x66\xa5\xe7\xaa\x9a\xe6\xdb\x4b\xcc\x95\xeb\x4a\xb6\xec\x39\xe5\x2d\x41\x4a\xd1\xd0\x22\x5f\x19\xf1\xab\x39\xb1\x3f\x37\xc3\xdf\xba\x43\xff\x61\x73\x27\xfc\x7c\xb2\xa3\x03\x7f\x45\xe4\xd2\x2b\x5c\x2f\xf5\x16\xb6\xf2\x14\xe9\xbb\xb0\xff\xb4\xce\x55\xdd\xe6\xda\xf9\xae\x48\x4b\x4a\x0a\x35\x17\x9a\xef\x75\x6a\xed\xe8\xcc\x58\xf4\xff\x17\x69\x4f\xf1\xd5\x8d\x0d\x58\x19\x00\x13\xa4\x42\x2a\xef\x00\x93\x9c\x9f\x7a\x1f\x3f\xe0\xc7\xf7\xf2\x9d\x04\x90\x1f\xed\x22\xc0\x87\x91\x00\xcd\x15\x40\xa4\x21\xb5\x2c\xfa\x6f\x9d\xb0\x6c\x90\x12\xa3\x0d\x1c\x84\x65\xa7\x0a\x76\xaf\x7c\xd6\x4b\x41\x0a\xb1\xb5\x60\xe5\x40\xe2\xca\x54\x11\xbd\xeb\xda\x1d\x74\x4d\x71\x8a\xa6\x38\x97\x0b\x30\x84\xf3\x39\x65\x44\x64\x8b\x13\xa4\x87\xb7\x8a\x98\xd0\xaa\x48\x11\xa3\x53\x52\xbc\x32\xee\x32\xc2\x7d\xe7\x53\xa3\x09\x36\x32\x29\x31\xbf\xd5\x88\xcf\x2c\x5e\x34\x50\xd8\x26\x0a\x9b\x1c\x4f\x2e\x0c\x1d\x03\x0e\x74\x6a\xbf\xf4\xfc\x57\x8a\xbf\x82\x14\x77\x0b\xb1\xf2\x5a\x2a\x57\x9d\xea\xf8\x05\x2e\x8d\x1b\xf9\x81\xe4\x39\x9a\x9a\x9c\x51\x5a\xfb\x78\x24\xd4\x0f\x19\x11\x90\x13\x2e\x82\x0c\x50\xc3\x21\x52\xa4\xf0\xf8\x2a\xe0\x14\xaf\xd3\xe3\x43\xd8\x9c\x26\x7a\x7a\xa8\xa1\x46\xd7\xe6\x9d\x0f\xbe\x5b\x62\x91\x49\x20\x13\xe4\x31\xa5\xea\xf2\xe1\x34\x46\xb8\x05\x51\xd3\x2f\xa4\x21\x64\x0d\x38\x17\x68\x3f\x07\x0f\xd1\xc8\x35\x6d\x74\x7e\x75\x71\x7b\xa0\x73\x97\xcd\xbc\x77\x01\x85\x1e\x38\x5f\xbe\xa0\x92\x91\x42\x38\x9a\x2f\x29\x17\x3a\x2a\xae\x29\xad\x73\x1c\x1b\x9e\x4d\xe3\x16\x95\x98\x6c\xb2\x0a\xda\xef\xc0\x35\x98\x0c\x0c\xbe\x83\x50\xa1\x78\xa1\x9b\x88\x84\x9a\xec\xd5\x8e\x16\x35\x83\x44\x2a\x10\xdc\x0a\x10\x35\xa7\xe2\xed\x7f\x35\x3a\x98\xa9\x3d\x13\xfb\x3a\xb9\xf1\x16\x0b\x50\x59\x29\xbc\x16\x09\x6f\x59\x21\x3f\xab\xe4\x16\x1d\xbd\xca\xad\x2a\x8d\xb3\x72\xf7\xc1\xb6\x6b\x62\xc0\xaf\x2e\xe2\x6c\x3a\x3a\xe9\xe6\x12\xcb\x6b\xfe\xc4\x59\xf3\xba\xc5\x9a\x6d\xc8\x55\x7e\x94\x0e\x0a\x77\x75\x06\x4f\x07\xd5\x47\x61\x02\x8f\x54\x52\xff\xa2\x05\x38\x69\xf1\x07\xf8\x6b\x34\x18\xf4\xba\x99\xdc\xd8\xc6\x79\x6e\x1c\x3f\x2a\xa3\x37\x45\x4c\x8e\x65\x4d\xfe\x4f\xb4\x00\x3e\x42\xef\x70\x92\x21\x15\x37\xd2\x03\xc5\x80\x72\x84\x51\x0a\xda\x1f\x9d\x2a\xd8\x46\xc8\xe3\xf5\x87\xb7\x68\xf8\x3f\xd1\xeb\xef\x90\xc8\x68\xc5\x71\x91\xa2\xef\xde\x28\x0b\x51\x25\xfe\x02\x47\x94\x21\x3c\x95\xca\xe9\x2f\x35\xc8\xeb\x6f\xfe\x12\xc0\x44\x14\x89\xaa\x4b\x4a\x8f\x0e\xdc\x59\xe1\x91\xdc\xa8\x05\xe8\xc0\xd7\x12\xaa\x44\x97\x48\x1e\xbe\x44\x6f\x15\x2f\x8c\x62\xb2\x7e\x13\x8e\xf6\x67\x8c\x2e\x0e\x05\x45\x0f\x0f\x0f\x07\x31\x4a\x32\x33\x24\x5f\xa1\x5d\x41\xd5\x96\x99\x5b\x53\x78\x1c\x6a\x36\xab\xfd\x23\x02\x67\xc3\x13\x2a\x13\xc1\x38\xc9\xde\x92\x22\x35\xd3\xc3\x55\xb9\x7c\xe3\x0b\x60\xae\xe6\x78\x64\x76\xeb\xa8\x92\x66\xd6\x88\x39\x2b\xf5\x7c\xbb\xc1\xff\xd6\x48\xb7\x6f\xe4\x20\xf4\x56\xba\xd9\xd5\xbc\xc9\xd1\xdb\xae\x5b\x2f\x58\xfa\xdc\xaf\xcf\x6f\x92\xfb\x47\x9a\xab\xbd\xeb\x24\xbf\xc9\xbf\x06\x63\xff\x40\x9c\x6c\xad\xde\x64\x15\xad\x5d\x6d\xcf\x19\x09\xdf\xfd\x77\x24\x7c\xf5\xfe\xdb\x66\x14\xfc\xef\xe3\xe3\xff\xf3\x2b\x71\xd6\x56\xf5\x07\xe1\x67\x97\x25\x63\xdf\x78\xde\x7c\xed\x8c\xb1\x8b\x3c\xe7\x2a\x43\x81\x99\x15\x27\xfc\xcd\x9b\x6f\xdb\x49\x3e\x26\x1c\xaa\xc2\x5a\x72\xb6\x54\xab\xc9\x19\x1a\x1c\xff\x8f\xe5\xa0\x03\x51\x60\x29\x31\x50\x8e\x7d\xcb\xae\x73\xe3\x96\xb1\x33\x9c\x75\x8e\xd9\xa8\xec\xe1\xa1\xda\xe8\x44\x0d\x87\xc3\xfa\xd7\x6b\x3f\x9f\xa9\x57\xe4\x9e\x5f\x6d\x77\x15\xdd\x0b\xd8\x27\xd9\x28\x7a\x81\xb7\x23\x97\x26\x4c\xa0\xb6\x45\x77\x59\x77\x5e\x7c\xd6\x6f\xf6\x76\xbb\x5c\x60\x20\xe6\x04\xb7\x2c\x50\x01\x8b\x52\x6d\xb7\x1a\x8c\xdf\xdd\x7e\xff\xee\x76\x60\x90\x9e\x2b\x3f\x9a\xde\x8d\x6c\xc9\x6f\x5b\xcc\x2d\x9f\xb5\x02\x6c\x7a\xf2\xd0\x57\xf2\xe6\x21\xcf\xa3\x17\xd4\xb4\xd9\xba\xaf\x9b\x79\xfe\x79\x7c\xf7\xe9\xc3\xe4\xdd\xed\xed\xa7\xdb\xb1\x16\xdc\xb0\x33\x77\x76\x14\x82\xfe\xee\x88\x75\xfb\x8e\xb3\x04\x74\x81\x57\x7a\xd7\x9d\x34\xe4\x3e\xfe\xed\xea\xe3\x3f\x91\xde\x74\x9d\x64\x90\xdc\xab\x74\x05\x9d\x72\x20\xad\x5e\x9d\x7c\x23\x97\xa8\x3c\xde\xd3\x3b\xe8\xb3\x89\xb9\x76\x07\xd8\xed\x9e\x32\xb4\xcf\x70\x91\xd2\x85\xd9\x7e\xf9\xef\x8a\xab\xd4\x27\xbd\x1f\xf5\xbe\xa0\x0f\x85\x42\xc2\x0f\x10\xe6\x8e\x64\x85\x56\x92\xaa\xa3\x08\x7e\xbf\x65\x58\xbe\x9b\xeb\x74\x22\x8d\xd3\x5b\xb3\x27\x99\x12\x75\x52\x1c\x7b\x65\x74\x9e\xc3\xe1\xe1\x9c\x88\xac\x9a\x8e\x12\xba\x38\xbc\xaf\xa6\xc0\x0a\x10\xc0\x0f\x4d\xe2\xe6\x50\xc7\x89\xa6\x39\x9d\x1e\x2e\x30\x17\xc0\x0e\x13\x5a\x08\x46\xf3\x1c\x18\x37\x51\xa4\xf2\x7e\x7e\x98\x2c\x52\xef\x8b\x89\x73\xcc\xe9\x36\x6b\xab\x9a\x29\x36\x95\xba\xee\x57\x5f\x33\xdf\x42\xc5\xc1\x38\x48\x94\x93\x5d\xf2\xa3\x5e\x93\x4c\x71\x72\x9f\xd3\xf9\xa9\xad\xe2\xad\xfe\x1d\xc4\x01\x51\xf7\xe2\x64\xd3\xb4\xf7\xeb\x50\x19\x9b\x2d\x84\x8d\x7d\x5b\x27\x93\x56\x26\x83\xe1\xc0\x9b\x2e\x9c\x4f\xa3\x71\x72\x40\x60\x4f\xa2\x8e\x94\xcd\x86\x1e\xfe\xe6\xc8\x33\x93\xd7\x91\x3a\x74\xf7\xda\x3d\x27\x21\xfe\x6e\x7a\x55\x18\xa7\xc0\xb9\x4f\x36\x8a\xe5\xc8\xb7\x36\x5f\xda\x27\xba\x59\x32\x25\xbc\xcc\xf1\xea\x64\x6b\x48\x9b\x6b\xac\xd3\xf4\x1b\x94\x34\xa7\xa6\x4d\x2c\xe3\xa2\x9a\x5a\x46\xd8\xb0\x94\x8f\x2e\xec\xcc\x28\x33\x1b\x0c\xec\x89\x93\xd9\xa7\x95\xb1\x89\x10\xfa\xe7\x50\x4d\x93\x6f\x8e\xde\x6c\x22\xa2\xbf\x97\xec\xcf\xa1\x11\xf3\xa1\x89\xab\x0c\x4e\x22\x24\x94\x98\x7b\x7b\x8e\x4c\x8c\xb3\x0b\x43\x54\xa6\xb6\xd7\xfb\xeb\x17\x2f\xac\x8f\xfd\x05\x0a\xb3\xc6\xd5\x9e\xd3\xda\xff\x1e\x24\x8c\x8f\xf5\xfb\xd8\x76\xa7\x5f\x38\xab\xb9\xa6\x2a\x1a\x65\xdb\x9c\xc7\xec\xb2\x2d\xee\xce\x6f\x90\xc9\x9a\xe7\xcd\xd5\xcb\x2b\xb4\x2b\x92\x72\xec\x16\x2f\xa3\xbb\xf3\x9b\xb7\x8d\x50\x98\x8b\x4e\x88\xa4\x54\x71\x2c\x57\xc2\x3a\x9c\x1b\x6f\x0d\x02\xe5\xc6\x52\xf9\xfc\xfd\x20\xdd\x5f\xad\x3f\xfb\x4b\x83\xec\x7f\xbf\x42\xbb\x60\x5c\xe5\x6a\xc9\x55\x17\xf5\x3d\xe8\x8d\x55\x14\x6a\x3d\x2a\x38\x6b\x0a\x38\xef\xba\x31\x09\xdd\xfb\x60\xff\x52\x6c\x6d\xf8\xd5\x5d\x35\x51\x3a\x1b\x16\x6b\xab\x0f\x8c\x64\x46\x98\xe8\xdb\x23\xa3\x0b\x48\xcc\x7a\x78\xa3\x7d\xd5\x6d\xdd\x45\x09\xfc\x95\x28\xfa\x75\x7d\x05\xff\x79\x5d\xe1\x96\x20\xbf\x55\x7f\x34\xde\x68\x24\xdd\xdb\xdb\xf5\xc1\x42\x4a\xc1\xc4\x22\x4f\xb1\x99\x02\xe9\x53\x04\x7e\x13\x5d\xd4\x5a\x09\x6e\x62\xe7\xbb\xc2\xb0\xb3\xd9\x24\xeb\x21\x70\x8f\xbf\x00\xd8\x26\xe0\xb6\x83\x3e\x5f\xf4\x6a\xf6\x2a\xf5\x35\xfb\xe7\x8b\x6e\xcd\x5e\xa5\x9a\x9b\xae\x44\xc0\xcd\xfa\x6d\x27\x37\xe3\x20\xdd\x5f\xb7\xd6\xec\x75\xd1\x5f\x59\xb3\xff\x76\xaa\xbd\xd5\x09\xb2\x7b\x9e\xad\x96\xb7\xc0\xf6\xfb\x53\xa9\x5f\x8f\x05\x4e\x1d\x3e\x87\x0f\x51\x55\x66\x77\x87\xf2\xa0\x01\x0d\x55\x76\xeb\x80\xda\xca\xec\xab\xeb\xc2\xdf\x6a\xf4\x36\xb7\x11\x18\x76\xd9\xe3\xb6\x52\x50\xd9\x45\xea\x7c\x96\x99\x5b\xa7\xf3\xda\x53\xc1\xa0\x04\x41\x74\x84\xde\x9c\xaa\xa5\x0b\xb5\x17\xf3\x0d\x5f\x65\xd9\x38\x8d\xae\xe3\x84\xba\xb6\xc8\x7a\xa9\x7d\x4a\x5c\xbb\x52\xfb\x90\x6f\x63\xc5\x73\xf9\x1a\x86\x97\xb5\x4f\x1b\xe6\x69\x57\x0e\xa2\x4b\xad\x0e\x01\x43\xab\xac\x36\xcc\x50\x43\x5a\xbc\x94\xc2\xed\xb0\x68\x73\xc6\x83\xd4\xc9\xe9\xfa\x1c\xb1\x2d\x71\x7c\x32\x5b\xe9\x86\x9f\x6f\xaf\x34\x8e\xa8\xff\xb4\x17\x47\x2d\x7b\x96\x0e\xb7\xeb\x77\x4b\x0c\x57\xc6\xb7\xf4\xd1\x9e\x1d\x10\x6c\x13\xde\x12\x89\x39\x51\xc0\x43\xe2\xef\x2b\x6e\x74\x8d\xc9\x7e\x47\x8d\x67\x7f\xf4\xf2\x00\x1d\xa2\x29\x03\x7c\xbf\xd9\xbc\x7d\x9a\x85\x6b\xff\xab\x47\x55\x70\xec\xdf\xe1\x4b\x74\xfe\xe9\x76\xec\x36\x50\xaa\x9d\x6a\xd6\x25\xb7\x20\x49\x46\x20\xbf\xc7\xf9\xfd\x02\x17\xca\x35\x67\xbc\xb1\xc6\xe5\x36\x4c\x28\xe3\x43\x5a\x42\x31\x0c\x9c\xb1\xde\x01\x5e\xfe\x48\x0c\x06\xa0\x52\x55\xd4\x0c\xb9\x73\xca\xb8\x71\x23\xdb\xef\x3b\x48\xbe\x44\x37\x0c\x66\x2a\xf7\x1b\x2d\x40\x64\x34\xe5\xa8\x00\x48\x39\xc2\xf5\x4e\x70\x5a\xea\x91\x8f\x8b\x14\xa5\x64\x36\x03\x06\x85\x40\xb7\xda\x89\x24\x85\x5b\x23\x24\x33\xb4\xef\xe4\x4c\x23\x43\xa7\x68\xef\xd3\xcd\xdd\xd5\xa7\x8f\xe3\xbd\x03\x6f\x18\x7a\x9b\xf0\xf7\xb4\x3d\x3d\x3c\xd7\x4e\xc5\xa1\xca\xde\x31\x02\xbc\x67\x92\xbb\x29\xe3\xaa\x05\xea\x9b\xfe\x84\xd6\xeb\x3d\x84\xf3\x07\xbc\xe2\xad\x85\x5e\x08\x7f\xce\x20\x85\x42\x10\xac\x13\xaa\x36\x56\xed\xc1\x47\xeb\x0f\xf1\x39\x22\x22\xb3\xd0\xc6\xaa\x3e\x68\x8e\x47\xab\x31\xdf\xa2\xed\xdc\x88\xd8\x68\xd6\x28\xe2\x5a\xeb\x3e\x09\xf1\x07\xfc\x38\x3c\x9b\xc3\x1e\x0a\x30\x7e\xc0\x8f\x67\xf3\x50\xb9\xf9\x38\x64\x61\x28\xc4\xf0\x6e\x55\xc2\x1e\xda\x53\xa7\x66\x94\x39\x26\x05\x4a\x32\xcc\x38\x88\xd3\xcf\x77\xef\x87\x7f\xd9\xeb\x2f\x7d\xad\x8e\x99\xd8\xf3\x93\x7a\x9c\x07\xd3\x7a\xc1\x3c\x57\xd3\x7f\x85\xeb\xf7\x25\x5c\x2d\x85\x18\x2e\x37\xf4\xca\x7d\xe8\xbc\x83\xd1\x45\xc7\x03\x11\x99\x85\xc4\x2a\x76\xd6\x54\x7e\x36\x64\xd6\x58\x7f\xd8\x13\x7c\xdf\x13\xd6\xce\xf6\xaa\x43\x81\xa3\x31\x24\xb4\xb5\xaa\xfc\xdd\xa7\xf1\xd4\xb9\xef\x91\x44\xc2\x5f\x36\x84\xf1\xe5\x8b\xda\xcc\xf6\x9b\x25\xda\xfc\xde\x9a\x1e\x35\xcd\x74\x96\xc3\x7f\x70\x76\xcc\x6f\xca\xe5\xdf\x45\x16\xcb\xef\x8f\x03\x9b\xf3\x4e\xb6\x8a\x24\x2a\x55\xac\x59\x85\x68\x47\xc4\xd6\x4b\xb9\xb1\x7b\x8d\x3b\x63\xde\x6e\x03\x35\x31\x47\xdc\x9a\x2c\x82\xbb\xeb\x31\xe2\x05\xb1\x1e\x1a\x97\x6a\xe9\x68\x50\x87\x99\xe8\x7e\x04\x86\x16\x15\x17\x66\xea\xd0\x07\x68\x34\x9c\x70\xa0\x07\xd2\xab\x60\xf3\xf3\xf8\xe3\x55\x8d\xc1\x6c\xe2\xe5\x6a\xdf\x2a\xad\x58\x02\x48\x9d\x4b\x3b\xa3\x92\x24\x22\x46\x4d\x1a\x9a\xd9\x13\xa6\xa3\xc7\xe3\xeb\x73\x60\x82\xcc\x54\x1e\xec\xc1\x2f\x3b\x37\x7c\xed\x9c\x28\xf4\xeb\x25\x09\xfe\xf6\x9a\x58\xed\x0f\x6d\x37\x45\x1d\x1b\x8a\xd6\x6b\x75\xcc\xe8\x93\xd4\xc9\x7f\x3b\xe4\x37\xeb\x90\x5f\x71\x1e\x7d\xc2\xc8\xff\xe3\xe5\x86\xfe\x41\xc4\xa5\x31\x7e\x9f\xde\xa5\xff\xf1\x49\xa9\x7f\x90\x8e\xdc\xb4\xaa\x51\x4b\x85\x84\x2e\x16\x50\x08\x74\xf3\xee\x03\xe2\x19\xf6\xce\xab\x77\x27\xea\x27\xc2\xa4\xc1\x71\xbb\x00\x99\xcb\x55\x81\xda\xc9\x12\x26\x34\xe2\x22\xf5\x4e\x24\xaa\x2f\x80\xb0\x35\xee\xd8\x6a\x8e\xfd\xcc\x43\xd9\xe3\xb0\x38\xcf\x20\xb9\xe7\xd5\x22\x58\x77\xf1\x7c\x92\xd4\x32\x86\xba\x9e\x10\x99\x27\x95\x01\x4f\x1a\xd8\xd4\x89\x0e\xcf\xc7\xd6\x37\x2e\xde\x57\x79\x7e\x9e\x61\x52\xf8\x03\xa4\xd1\x2e\x7b\xc9\x41\x5f\xfb\x42\x4a\x62\x58\x5b\x0d\xe4\x02\x97\xea\x88\xb3\x9e\xc7\x0f\xb6\xfa\x65\x26\x4b\x60\x64\x16\x67\x4a\x77\x80\x16\x75\xa6\xa5\xda\x33\x7a\xf7\x37\x6b\x8f\x03\x2f\x7f\x79\x7c\x17\xa6\x56\xb7\x0e\xec\xec\x78\x06\x63\xc1\x48\x22\x86\x77\x0c\x17\x5c\x0e\xb5\xe1\xd8\x5c\x9c\x73\x8c\x16\xf8\x71\x88\xe7\x70\x1a\x24\x4a\x8f\xef\xc6\xce\xdb\xd6\x18\x62\xf2\xdb\x95\x3e\xc1\x76\x5c\x4d\x53\xba\xc0\x44\xef\x6f\xb5\xe7\xda\x8e\xab\xe9\x85\x7e\x5b\x8f\xbe\x08\x8e\x1b\x33\x0c\x94\xd6\x51\xff\x3a\xf0\xd6\x39\x36\x1b\x32\x90\x0d\xe3\x3c\xae\x9d\x55\x22\x1b\x9d\x9f\xbd\x27\xb9\x3a\x1e\xb8\x91\x91\x1c\x1b\x6a\xcd\xc2\x37\xb0\x18\x5f\x9e\xb5\x86\x9c\x3e\xca\xbe\x77\xe4\xf5\x20\xad\x29\x6a\x49\xa7\x16\x30\x53\x41\x47\x37\xf6\x60\xfe\x5e\x15\xd7\x27\xe8\x77\xe1\x4e\xa1\x14\x59\x97\x88\xf4\xe1\xd6\x5b\x73\x09\x2d\x2e\x14\x86\xad\xc6\x7a\x13\x89\x0a\xa4\xdd\xe0\x79\x30\xda\xbd\xa3\x32\xde\xfc\xf5\x4f\xe8\xcd\x5f\xbf\x43\xa7\x7d\x94\x38\x24\x5b\x6b\xf4\xed\x26\xeb\xc6\xe1\x30\xa8\x71\xea\x4b\xdf\xd3\x50\x89\xee\x4c\x98\xe7\x89\x70\x77\x1e\xbd\x5f\xcf\xd3\x52\xe0\x9f\xb2\x15\xda\xd6\xb4\xc5\x76\x68\x1f\x1c\x57\x22\xbb\xf1\x8b\xc8\xde\xea\xd9\x45\x1d\xe7\x81\xdb\x51\x7c\xab\x23\x6b\xa3\xb3\xb2\xbc\xa5\x54\xf8\x12\xa3\xe2\x3e\x15\x23\xe8\x14\x1d\x1e\x34\x62\xad\xc6\x4f\xff\xed\xd1\x37\x8a\xa8\x2e\x74\x41\xe7\x6c\x21\x33\x75\xeb\x62\x51\xe0\xd3\x90\x01\x3d\x01\x60\xff\x6d\xb7\xdb\x04\x1e\x35\xfc\x50\xa2\x84\x42\x10\x5d\x4f\x33\xbf\xd9\x3b\xd6\xc5\x46\xc1\xa6\x34\xd5\x13\x54\x2b\x9f\xb8\x23\xde\xa9\x9e\x30\xee\xa1\xf6\xfb\x06\x65\x0d\x0f\x1c\x33\xdf\x19\xfa\xd4\x78\xd4\xae\xfd\x78\x26\xb1\x09\xca\x35\x9e\xa0\x63\xe2\xb8\xb6\xa7\x3d\x12\x7b\x56\xcf\x93\x03\xd0\x06\xdb\x58\x9f\x22\xd9\x78\x22\xc7\x44\x76\x65\x43\x6f\x5d\xd7\x65\xfc\xf2\x81\x1e\xf6\x04\x17\x10\x3c\x99\x39\xd7\x5e\x73\xdc\x86\x27\x1d\xeb\xcf\x28\x17\xcf\x65\x98\xab\xe1\x83\xdf\xd9\x8d\xb8\xec\x93\x7a\x40\x8a\xe2\x7b\x73\xe1\x95\x7b\x06\x3a\x3e\x6d\xb7\x8f\xd4\x5b\x42\x9e\x24\xac\xe6\xca\x1e\xbb\x01\x6c\x9b\xfc\xf7\x9a\x30\x89\x61\x68\x30\x0c\x1d\x8a\xee\xee\x6a\x57\xb6\xd5\xae\x80\xe7\x10\xd1\xdd\x79\xbd\x82\x19\x1c\xb7\xef\x1e\x77\xee\x7e\x83\x22\x75\x16\x55\xbd\xe9\x4c\x3f\xcd\xbd\x09\x11\xa5\xe4\x16\xa6\x4d\x58\xb3\x92\x5a\xe0\x47\x7d\x31\x90\x7f\xdf\xca\x20\xe0\xab\x32\x52\x47\x6f\x69\xba\x32\xf6\xdf\xa0\xd5\x4a\x75\x24\x87\x5a\xa6\x44\x2f\x22\xaa\x71\x75\xdc\x53\x14\xa3\x2c\x7a\xe7\x51\x40\x58\xef\xa5\x47\x1b\xfa\x40\x4d\x00\xe6\x24\xe8\x6e\x29\x92\x03\x37\x3e\xe6\x55\x16\x89\x41\xb0\xe5\x6c\x16\xec\xe6\x29\xa3\x93\x55\xeb\xc8\xc7\xe6\x80\xfa\xac\xad\xf6\xab\xe2\xd6\x1d\x6e\xb0\xf1\x90\xc1\xb0\x9f\x9c\x0d\xd0\xde\x96\xd3\xac\xec\x7b\xc1\xfd\x0b\xc9\x9e\x72\xad\x59\x17\x8e\x93\xb6\x27\x23\xd2\x2f\xd1\x89\xd9\x1e\xad\x62\x8f\xf9\x51\xab\xf8\x96\xf3\xc3\xb9\x2b\x54\x42\xad\xbf\xf2\x89\xe8\xaa\x5d\x69\x8d\x1e\x9f\xa2\xfd\x39\x08\x93\xbf\x74\x55\xe8\xed\x27\xc1\xba\x69\x64\x3e\xd6\x87\xb5\x34\x30\x1d\xbe\x54\xb8\xe4\x1c\x8a\x53\x2c\x30\x92\x2a\x52\xd9\x65\x22\x03\x64\x4b\x2f\xec\xd7\xc0\xf3\xe0\x5a\x5d\x84\x39\x58\x03\x43\x60\x90\x17\x38\x88\x2c\x63\xfc\x3c\x2b\xbf\xdc\x6d\x95\x77\x15\x69\x5c\xf4\xe2\x8a\x98\xfc\xab\x28\xb7\x0e\x5f\xba\x13\x35\x90\xa0\x48\x3b\xb5\x12\x5c\xa8\x5b\x24\x93\x8c\xc0\x52\xef\xb9\x4c\xec\x41\xf6\xf5\x89\xa6\x0c\x65\x78\xa9\x2f\xdf\x1c\x8f\xaf\x91\xef\x24\xf0\x36\xa2\xce\xa8\x3e\x1a\x3e\x16\x3b\xaa\xe5\x77\x9f\xb2\xc8\xd2\xf2\x3d\x65\x09\x8c\xc7\xd7\x4e\x29\x3f\xc1\xba\x6f\x21\xf3\xf0\x1c\xb4\x3a\x7b\x07\x41\xa1\x1d\x49\xea\xec\xee\xc2\x92\xcb\x89\x4d\x8d\x32\x8f\xc9\x90\x6a\x1c\x66\xdd\x5c\x33\xa3\xc8\xac\x19\x1d\xe4\xad\x52\x3b\xe6\x26\x46\x73\x26\xa5\xda\x59\xea\x2e\x74\xc4\x5e\xee\x96\xcd\x93\xd3\xb8\xc8\x12\x62\x04\x7c\x85\x7d\xe6\xf6\x09\x8c\xca\x3f\xa3\xd3\x4d\x3b\xc0\x6d\x82\x9c\xda\x33\xbf\x79\xcb\x79\xab\x3e\x63\x76\xbc\xf9\xeb\x9f\x4f\x62\x2d\x8b\x4d\xf3\x68\xfb\xfd\xe9\x01\x75\xdd\x53\x3d\xea\xdc\x95\xd7\x12\xe2\x98\xda\x8b\xea\xe6\xc6\xb5\xcc\x3e\xbc\x77\xf5\x72\x7d\x2a\x65\xe4\xe3\x84\x55\x39\x28\x25\xdd\xbc\x43\xd8\x42\xf8\xff\x8f\xe4\x68\x8c\x4d\xee\x0d\xc2\x3e\xfd\x70\x36\xbe\x39\xa7\x0c\xa4\x8a\x69\x09\xe7\xe6\xea\xe9\x03\xe6\xe5\xd0\x83\x1b\x26\x76\xdf\xf1\x70\x23\x39\x11\x16\xf7\x32\x75\x8b\xb3\xc2\xc2\x02\x5b\x9e\x19\xe6\x17\x94\x63\xfd\x67\x1c\xfd\x15\x53\x0a\x56\xaa\x8f\xbe\x3d\x79\xbe\x38\x45\x0c\x67\xa4\x8f\x7a\x56\x61\x78\xcb\x86\x7a\x57\x79\x60\xf3\x06\x65\xe4\xa7\x49\x70\x01\x28\x6a\x5a\xde\x27\x9d\x05\xe4\xda\x40\xbe\x53\xd0\x13\x7d\x26\x67\x7d\xbe\x9e\x39\x25\x17\x84\xf9\xd2\xc0\x53\xa7\xa8\xb9\x67\x0c\x62\x78\x6e\xb0\x78\x28\x9b\xb2\x32\x74\xdb\x6e\xd2\xc7\x57\x68\x37\x27\xfa\xbc\x29\xe7\x21\xb1\xdb\x01\x6c\x22\x5b\x9f\x60\xe8\xd2\xad\xf7\xc3\x27\xcb\x63\xc7\x52\x73\x4c\xe6\x05\x29\xf4\x82\x33\x28\xe5\xab\xd3\xa3\xd7\xda\xdf\xe1\x5a\x20\x4b\xc9\x32\x5b\x20\xdd\x6a\x59\xac\xa6\x79\xa2\xef\x8d\x76\xcc\x70\x8b\x19\xec\x9f\x2a\x56\x9f\x24\xf6\x0a\x25\x0c\xe4\x87\xe0\xec\xb0\x90\x77\xea\x50\x38\xcb\x7b\x77\xd4\x57\x2f\xc7\xad\xdf\x4c\x01\xaa\x13\xef\x34\x96\x2e\xfc\xdd\x8b\xca\x26\xe3\xdf\x62\x4e\x92\x0b\x32\x07\x2e\x34\x9b\xa4\xc2\x81\x58\x37\x9a\x10\x5b\x67\x49\x7d\xc8\xec\x54\xbe\x1d\xb4\x76\x98\x4b\xc1\x54\x9f\x1a\x06\x55\x13\xc9\x2d\xe0\x7c\xd1\x5e\xa9\xd5\xe5\x27\x15\x07\x36\xb1\x17\xaa\x77\x23\x7a\x4f\xf2\xb8\x01\x14\xdb\xff\x2e\xb1\xa7\xaa\xec\xcf\x20\x4f\x23\xf8\xd9\xf4\xb5\x87\x50\xcb\x10\x97\x08\x28\x23\x3f\x69\x69\x19\xb4\x6d\xd0\x6d\x3a\xbe\xce\x8c\x57\xff\x46\xf2\x0b\x4c\x29\x6f\xfb\xba\xde\xb5\xde\x23\xa7\xdd\x15\x77\x38\x57\xf5\x02\x43\x1a\x97\xad\xf5\x93\x73\xaf\xfe\xbf\x97\xbe\x99\xd8\x33\x41\x34\x3c\xad\x06\xb7\xdb\x0c\x13\xfd\x1a\x53\x08\x5b\x35\xab\xcf\x69\xe0\x3f\xbf\x5f\x07\x42\xa3\xde\xaf\xe3\x4c\xd0\x67\x0f\xae\xdc\x99\x2e\x15\x07\x6d\x2c\x23\xcc\xb5\xab\x51\x50\xb7\xab\xf3\x15\x9a\x56\xc2\x9c\x27\x4f\x97\xc0\x18\x49\xfd\xe3\x11\xb7\x90\x20\x6b\x01\x7f\x2f\xab\x68\x89\x50\x6b\xe4\x74\xf8\x3a\xc3\x3e\x0a\x70\x46\xbb\x68\x2b\x77\x59\x47\x5d\x6a\xf1\xbc\x15\x2b\x77\xd0\x0d\xe6\xda\x6c\x86\x47\xc1\x70\xa2\x42\xf9\x3a\xac\xe6\x47\xfd\x04\x55\x30\x66\x8f\xce\x06\xce\x3d\x2d\x3e\x59\xe3\xe8\x8c\x4d\x62\xce\xe5\xbb\x3b\xea\x6e\x21\xdc\xc4\x18\xce\xf3\xa1\x6e\xc6\x50\x36\xc3\x31\xc6\x0b\x6a\xea\x8b\x0f\x75\xd8\xfd\x79\xdc\xef\xa8\xa4\x5b\x59\x6e\x8b\xcd\x8f\xbe\xfb\x24\xeb\xf7\x1b\x1c\xcc\x1e\x9e\xd4\xf3\x74\xfa\x78\xf8\x24\x8d\x1c\xb3\xf2\x15\x9b\xbc\x6d\xe3\x9e\x52\xce\x6f\xcc\x96\xf3\xd1\x0e\x52\x36\x08\x7a\x80\x29\xd7\x77\xed\xd5\xb7\xb5\xf1\xad\x1d\xd1\xfe\xf3\xd9\x5c\xf1\xe6\xf1\xd5\xbf\x0e\x2e\x6a\xcc\x79\xd3\xa1\xad\xdc\x18\x76\xe9\x13\xdc\xe1\xfe\xe3\x5d\x2e\x58\x57\x15\xad\xe7\x32\xbc\xa4\xc0\xe7\xd7\x13\xdd\xf1\xfd\xf5\x47\xae\xc1\x7b\x5e\xd0\xe8\x9f\x43\xb9\xfe\x19\x5e\xdd\x84\x35\xfa\x47\x15\xf7\x5a\xcc\x1b\xee\x7f\xea\xa9\xb7\xbe\x98\x4b\xc2\xdb\x7a\x63\xb7\x34\x3d\x8f\x97\x5d\x35\xf4\xb5\x6c\x1b\xbd\xe1\xe3\xf5\xe6\x83\xc8\x1c\xd0\x5b\xf4\xa6\xbe\xd3\xbb\xbe\xd7\xeb\x29\xe5\xd5\x8d\x79\x5e\xf9\x9e\x08\x62\x04\x51\x34\xb2\xf9\x84\x38\x5d\x47\x34\x33\x4a\x4a\xd7\x0c\xe8\x2e\xc9\x6c\x74\xd5\xd6\xb4\x87\x1d\x1c\xbf\xb3\xd1\x0a\x6a\xf4\xde\xc6\x16\x6d\x0b\x22\xc8\x5c\x4e\xc0\x97\x77\x77\x37\xf4\x71\x85\xbe\xaf\xf2\x02\x18\x9e\x92\x9c\x88\x55\x03\xd8\xfa\xce\x1e\x1e\x1e\x46\xfa\xf0\xb8\x84\x2e\x0e\xa7\x39\x9d\x1f\x1a\x3c\xa4\x98\x0f\x45\x06\x43\x75\xc1\xc5\xe3\x6a\xb8\xf4\xb1\x0d\x1f\x88\xc8\xcc\x61\x75\xfd\x4d\xd6\x69\x99\xad\xa7\x15\x4c\x6f\xdd\x2b\x2d\x28\xb2\xb7\x53\xeb\xb9\xbe\xc3\x08\xf5\x2e\x99\xce\xf3\xbe\x3d\xed\x51\xf2\xbe\x44\xee\x9e\x76\x34\x7e\x09\xef\xa0\xf6\xea\xee\xd6\x4f\x46\xb9\x45\xce\x2c\xf0\x8a\x37\x17\xe0\x46\x49\xd6\x47\x18\xf0\xb8\x08\x17\x69\x0f\xde\x38\xea\x31\x14\xe9\x06\xbc\x0c\xf0\xd3\xf1\xde\x02\x0e\xf1\x46\x10\xeb\x15\x7e\x5f\x5e\x61\xcc\x1a\x51\x7f\xdf\xba\xa2\x2d\xf6\xfb\xb8\x3b\xcd\x9c\x2e\x4b\xc7\x37\x20\x7a\xf0\xf6\x25\x36\xbd\x79\x26\x66\x97\x8c\xd2\xc9\x95\x18\x5e\x13\xd3\x6e\xf0\x23\x82\x3e\x1e\xb4\xf6\x1f\x15\xc0\x8e\x8a\x2c\xbd\x27\x30\xd1\xf9\x8a\xd1\x92\x51\x91\x95\x85\x74\x36\x63\x47\x20\xd6\xe0\x55\x86\x72\xfc\xe9\xc4\x1b\x9e\xc8\x66\x9f\x1d\x74\x55\xa8\xab\x8e\x11\x9d\x21\x73\x2e\x84\x60\x2b\xa5\x90\x0b\x78\x14\xde\x1d\x42\x3a\xf2\x33\x85\x19\x65\x60\xec\x71\x15\xe5\x2a\x74\xb9\x08\xb5\x12\x81\x0b\x6c\x76\x51\xab\x94\xf4\x47\x78\xf4\xee\x38\x6f\xd0\x1f\x7e\xac\x93\xba\x05\x5b\x7d\xa4\xc5\x55\x0a\x8b\x92\x0a\x9b\x89\x18\x8b\xe3\xe9\x88\x10\x2d\xf2\x15\x7a\xa0\xec\x9e\x5b\x9f\x5f\xa2\xb3\x91\x10\xe1\xca\x80\x4a\xe8\xa2\x64\xc0\x39\xa4\x5d\x06\x6a\x24\xcb\x2b\x4d\xdf\x62\x0e\x11\x4f\xe6\xb6\xab\xb9\x33\x75\xfa\xc5\x50\x1d\xd1\x64\x25\x78\x6b\x87\xcf\xe1\x4b\x74\x96\xa6\x08\x17\x2b\xff\x54\x83\x30\x19\x5c\x6f\x23\x8e\xb7\x29\x58\xb5\xd6\x65\xbc\x6c\xbf\x0d\xc6\xa6\xed\x0d\x1b\x75\x88\x25\x13\xa2\xaf\x78\x30\xaf\xa5\xbb\xa3\xde\xad\x1d\x56\xda\xf1\xfb\xa0\x2f\xf1\x95\xb3\x40\x1d\xc7\xd5\x4e\x7f\x41\x11\xb6\xd1\x46\xeb\xe9\x30\xf6\xf7\x2b\x55\x2e\x4d\xc3\x2b\x28\xec\x24\xdb\x15\xc9\xcd\x30\xbf\x61\x30\x23\x8f\x81\xcb\x50\x21\x44\x03\x5d\x51\xf3\x30\x8e\xe1\x60\xb3\xbf\x43\x3f\x91\x13\x5a\xfe\xd4\x8c\xa5\xfc\xa2\xc7\xb2\xfc\x87\x1c\xa9\xb2\x95\x6c\x74\xba\xa2\x4c\x77\xc5\xfc\x27\x4a\x8b\xe9\x0d\x2e\x2a\x57\x66\xfb\x4c\x8d\x98\xac\x50\x86\xf6\x03\x4f\xbc\x37\x8d\x5b\xbf\xa6\xca\x5b\x1b\x18\x89\x19\x1c\x6c\x5b\x80\xce\x66\x83\x76\x9c\xdf\x4e\xa7\xe1\xdd\xab\xed\xa7\x6b\x6d\x11\xd4\xf1\x24\x73\xf7\xab\xd5\xb9\x11\xee\x8e\x6e\xe9\x8d\xef\xa0\x77\x07\x7d\xa4\x08\xdc\x01\x70\x78\x89\x49\xae\xc2\x9e\x36\x95\xc3\xa8\x8e\xa0\x90\xf1\x5b\xb7\x06\xe3\x13\x6b\x76\xd9\xcd\x29\x14\x04\xd2\x11\xba\x05\xcc\x69\x71\x1c\x36\xfa\x42\x7d\x6c\x96\xde\x9e\x84\x30\x19\x39\x9e\x9f\xdc\xb1\x07\x2b\xdc\xf2\xa0\x4f\x6f\x46\xea\x0c\x72\xb5\x59\x29\xc9\x69\x95\xca\x1e\x5f\x12\xa5\x24\x6d\xe6\x86\x64\x5b\xa5\x17\x1f\xbd\xbb\xaf\xa3\xc9\xd0\x16\xf8\xf2\x97\x39\x2b\xda\xc4\x8d\x1b\x1b\xb1\xf4\x01\x1e\xfa\x96\x4f\xa9\x27\xd4\x91\xea\x84\xa3\x29\xc8\x19\x64\x41\x0b\x22\x28\x83\xd4\xc3\xa2\x0e\xf8\x90\xab\x24\x13\xab\x44\x9c\xce\xc4\x83\x9c\x77\xf6\x73\x72\x0f\x88\xaf\x78\x4a\xe6\x07\xed\xf6\xf5\x9d\x51\xad\x3d\xea\xaf\xbf\xf9\xf3\xe8\x68\x74\xd4\xcc\xa2\xec\xd9\x5a\xaa\xcb\x1d\x1f\x37\xef\x81\xb2\x4f\x0a\x72\x29\x91\x37\x4f\x10\x7b\xce\xf9\xd1\x71\x69\xaa\xff\xfd\xff\x01\x00\x00\xff\xff\xb5\xac\x2a\x30\x86\x9c\x00\x00") +var _etcNginxTemplateNginxTmpl = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x7d\xff\x73\xdb\xb6\xf2\xe0\xef\xfe\x2b\x30\xb2\x6f\x62\x67\x2c\xc9\x49\xd3\xbc\x3e\x7b\x7c\x77\x8e\x9d\x3c\xfb\x9e\x93\x78\x2c\xa7\x7d\xf3\xb9\xb9\xd1\x40\xe4\x4a\xc4\x33\x45\xb0\x00\x68\x5b\xcd\xf9\xfe\xf6\x1b\x7c\x25\x40\x82\x94\x9c\xa6\x69\x5f\xa7\xec\x4c\x6a\x91\xc0\x62\xb1\x58\x2c\x16\xbb\x8b\xc5\xe7\xcf\x68\x07\xe7\x39\x3a\x3c\x46\x23\xf4\xf8\xb8\x25\x7f\x73\x60\x77\xc0\xb8\x7a\x37\x31\x7f\x9b\x4f\xc9\x7c\xa1\x5e\x9f\xce\x17\xf6\xd5\x05\xbf\xb8\xfa\xf1\xf5\xdb\x02\xcf\x72\x48\xd5\xc7\xf0\x8d\x29\x96\x01\xce\x45\xf6\xcb\xa7\xeb\x0b\x55\xe6\xbc\xfe\x69\x0a\xcc\x70\x72\x0b\x45\xaa\x9b\x7d\x63\x7f\x98\x8f\x25\xa3\x0f\xab\x73\xc0\xa9\xc5\xeb\x4a\xbe\x98\x80\xb0\xef\x4c\x39\x9c\xa6\x7e\xa9\x93\xfa\xe7\xe3\xe3\x96\x2c\x41\xe6\xaa\x13\x23\x8d\xdd\x7b\x9a\x72\x48\x2a\x46\xc4\x4a\x16\xc8\x29\x4e\xa7\x4b\x9a\x56\x39\xa0\x31\x88\x64\x5c\x2c\x48\xf1\x30\xd6\x6f\xf8\xb8\x58\x3c\x4c\x33\x21\x4a\x59\xc4\x56\x33\xc5\x47\x9c\x1e\x49\xf0\x50\xa4\xb6\xa5\x59\x45\xf2\xf4\x63\x09\x85\x60\x38\x21\xc5\xe2\x92\xe2\x54\x13\x50\x16\x48\x31\x2c\x69\x81\xe8\x7c\x7e\xb4\xb5\x75\x4f\xd9\x2d\xb0\x69\xc9\x68\x02\x9c\x03\x47\x86\xd4\xa3\x9f\xd4\x87\x2b\xf7\xfe\xf1\xf1\x68\xab\x24\x29\x1a\xb3\xaa\xd0\xc8\x8d\x4a\x92\x1e\x99\x8e\x15\x80\x46\xef\xf1\x83\x6c\xf3\x1d\xc9\x81\xa3\x03\xd9\x94\x01\xce\x72\xb2\x24\x62\x5a\xd0\x39\xc9\x41\x36\x10\x16\x95\x90\x35\xfe\x1a\xfd\xf1\x73\x24\xbb\x7a\x38\x36\xcd\x50\xb6\x18\x43\x31\x4e\x69\xa2\xe9\x90\x50\x06\xb6\xef\x99\x58\xe6\xdb\xa6\x19\x9e\x55\x22\xa5\xf7\xc5\x54\x90\x25\xd0\x4a\xa0\xe7\x63\x35\x34\xe3\xe7\x08\xdf\x51\x92\xa2\x7b\x4c\x04\x29\x16\x48\x50\x8a\x72\x5a\x2c\x50\x5a\x31\xf9\x1b\x23\x06\x92\xfe\xba\x42\x17\xb4\x90\x30\x13\xf3\xf9\xc6\x7c\x7d\x7c\x44\x47\x5b\x5b\x70\x07\x85\xe0\xe8\xf3\x16\x42\x08\x2d\xab\x5c\x90\x29\x4e\x12\x28\x05\x32\x0f\x2d\x8e\xd4\x37\xd3\x48\x42\x8b\x02\x12\x41\x68\xc1\x91\x6b\xe0\x3d\x7e\xd0\x6d\x9c\x7a\x5f\x25\x91\x64\xc5\x8a\x03\x6a\x3e\x50\xd2\x3c\x3f\xda\x7a\xdc\xda\x92\x74\x33\xad\xe7\x15\x9e\x96\x38\xb9\xc5\x0b\x98\x26\x25\x16\x19\x1a\x8c\x2b\xce\xc6\x39\x4d\x70\x3e\xce\xc9\x6c\x9c\x57\x78\xfc\x3f\x24\xf7\xe8\xf7\x64\x36\x7e\xf8\xe1\xf5\xf4\xf5\xab\x61\x4e\x8a\xea\x61\xb8\x28\x2a\x55\xe4\xfb\xd1\x0b\x5d\xec\x68\x70\xd4\x82\x6c\x00\xd7\x0c\xab\x81\xe6\x15\x3e\x6a\xbc\xbc\x83\x22\xa5\xcc\x7e\x8b\x61\x22\x3f\xc8\x36\x5c\x23\x3c\xc3\x0c\xd2\x69\x4a\x12\x81\x12\x5a\xcc\xc9\xa2\x62\x58\x92\x63\x9a\x62\x81\xd1\xf7\xef\x8f\xa2\x45\x19\xad\x8a\x74\xca\xe8\x8c\x14\x53\x2e\xb0\x00\xf4\xa2\xa3\x64\x4e\x93\x5b\x8e\xbe\x7f\xf1\xf2\xd6\xb4\x4a\x0a\x22\xa6\xb3\xd5\x54\x16\x9c\xc9\xaf\x86\x98\xf2\x61\xf0\x73\x45\x18\xec\x0e\x18\x70\xb1\x1a\x49\x2e\x1c\xec\xb9\xaf\x09\xcd\x73\x48\xc4\x02\xb3\x19\x5e\xc0\xee\xc0\xfc\x1e\xec\x6d\xb9\x22\xc3\xa1\x82\x8f\xcc\x9c\x76\xef\x15\x1d\x10\xbd\xdd\x47\x0c\x78\x5d\xdc\xbc\x40\xc7\xa8\x4c\x70\x9e\xef\x9a\xf6\xf7\xd1\x20\xa0\x85\x87\x83\x9c\x87\x54\x20\x7a\x8b\x44\x06\xc5\x96\xc7\x20\x8c\x51\x26\x11\x57\x10\xd0\x1c\x93\x1c\xd2\x43\x34\x40\xa3\x11\x12\x94\x0b\x39\x0b\x76\x19\xf0\xbd\x1a\x16\xe4\x1c\x3c\x08\x41\x93\xe8\x58\x61\xea\x8a\x16\xe9\x26\x58\xcf\x70\x8e\x8b\x04\xd8\xb7\x41\xd8\xb6\x16\xc1\x55\xfe\xff\xd1\x1b\x6f\x33\x17\x3b\x86\xdd\x02\x1a\x79\x65\x77\xf7\x7c\x20\x4a\xc2\xdc\x83\x9a\x9a\x22\x03\x74\x87\xf3\x0a\x10\x9d\xab\x1f\x99\x5a\x03\xd0\xbf\x86\xef\x28\xbb\xc7\x2c\x85\x54\xfe\x85\x04\x45\x33\x40\x72\x1d\x90\x7f\xda\x9a\x0b\xa0\x53\x52\x1a\x06\xd1\xd2\x48\x37\xe0\xd6\x8e\x4f\x1c\xd4\xf2\x73\xc5\xa8\xa0\x09\xcd\x91\x29\xc2\x00\xe7\x53\x52\x4e\x4d\x73\xea\x51\x0b\x97\x94\xec\xaa\xe4\x91\x05\x25\x09\xd5\x57\xcd\x8a\x21\x87\xf0\x3b\xca\xf4\x4a\xe6\x84\x90\xb7\xda\xf8\x50\x98\x5c\x98\x38\xb9\x03\x4f\xd0\x7d\xfe\x8c\x18\x2e\x16\x80\x76\x04\xab\xb8\x80\x54\x76\xf0\xf0\x58\x37\xa1\xba\x72\x0d\x38\xbf\xb8\x3a\xbd\x38\xbb\xb6\x58\x71\x10\x53\x0b\x73\xce\xe8\xd2\x62\xe5\x41\xe8\xc0\x44\x0d\x85\x14\x0e\x33\x2c\xd7\xac\x8a\x43\x2a\xe9\x9b\x82\x00\xb6\x24\x85\xa6\x72\x42\xab\x42\xb0\x15\x4a\xa1\x84\x22\x95\x0b\x00\x2d\xf4\x87\x9c\x40\x21\xd0\xc5\x15\xc2\x69\xca\x80\x73\x7f\x08\xfa\x56\x25\xf9\xa1\x5e\xa2\x17\x40\x49\xe9\x2f\x50\x0d\x30\x22\x23\x1c\x11\x6e\x05\x8a\x44\x30\xc1\x79\x52\xe5\x52\x54\x09\x86\xe7\x73\x92\xa0\x39\x65\x88\x14\x29\xb9\x23\x69\x85\x73\x87\x73\xc5\x25\xbe\xff\x00\x7a\x71\x85\x88\xc6\x5a\x8a\xb8\x8a\xa3\x12\x2f\x3c\x96\xd1\x38\xd8\x5a\xfa\xf1\x04\xb2\xfa\x3c\x56\x60\x46\x29\x16\x47\x7e\x1d\xa9\x90\xb8\x27\x56\xe7\x92\x08\x38\x25\x62\xd5\xac\x49\xd9\x02\xf5\xd7\xbc\xb8\x3a\x99\x7c\xa8\x96\xcd\x8a\x9a\x51\x6b\xee\x91\xbc\xd3\x64\x7c\xad\x34\xfd\x28\xf8\x44\x77\xd7\xf4\xf3\x2e\xa3\x5c\x4c\x0d\xd1\xa6\x9a\x14\xd3\x5f\x68\x01\x48\xcb\xf9\xc3\x58\x81\x43\xcb\xe2\x0e\xdc\x7f\xd1\x02\x26\xe4\x17\x70\x7c\x15\x85\x3b\x27\xb9\xd0\x82\x42\x72\xe8\x2d\xac\x90\x07\xe8\x0c\xe6\xb8\xca\xc5\x3b\x55\xe6\x9f\xb0\xea\x62\x51\x4c\x28\x6a\x3e\x22\x63\x80\x53\x7e\x64\x0b\x4c\xef\x19\x11\xfe\x3a\xef\x28\x22\x92\x72\x5a\xd0\xb2\xe2\x59\xf8\xb1\xfe\x96\x42\x8e\x57\xed\x8a\x39\x5d\x4c\x79\x35\x93\x3c\x07\x5c\x34\x3e\x32\x90\x1d\x92\x8a\x4e\x4a\x2b\xe1\x69\x25\x75\x91\x5b\x80\x12\xe7\xe4\x0e\x9c\x3e\xe4\x3a\xff\x4f\x80\xf2\x44\x7e\x42\x8f\x8f\xa6\x0f\x75\x69\xd3\x20\x6f\x97\xbe\xb6\x5f\x24\xa1\x54\x2d\x3d\xff\x8c\x30\x9a\xce\xaa\xf9\x5c\xea\x61\x72\x58\x42\xc9\x74\xaa\xca\x69\x99\xf4\x46\x95\x0a\xc6\x2e\x04\xe3\xd0\x75\x4f\x0c\x4c\xad\xc6\x99\x1e\xe4\x98\x49\xc5\x29\x82\x11\x0f\x80\x5c\xca\x72\x6d\x84\x78\x13\x9b\x19\x4d\x57\x91\x2e\x35\xb1\x79\x43\xd3\x55\x77\x97\x14\x90\x76\x87\x62\x40\x82\x0e\x29\x18\x52\x36\xbd\x9c\x2e\xf1\xc3\x74\x4e\x20\x4f\x43\x2c\x3c\x18\xe7\x37\x37\x57\x2f\xdf\xe3\x87\x77\xb2\x54\x80\x45\x0d\xc1\x10\xa4\x01\xa2\x09\x41\x13\xc4\x81\xd0\x4c\xba\x2a\x81\x4f\x33\xcc\x33\x05\xa8\x89\x04\x7a\x79\xf0\xea\x87\x23\xb3\x0a\xc8\xed\xdf\xb4\xc0\xcb\x78\x05\xdb\x9a\xde\x26\x7e\xc0\x4b\x38\xc7\x3c\x7b\x8f\x1f\x02\x9c\xdb\x50\x66\x55\x72\x0b\xc2\x02\x8a\x43\x79\xa3\xca\x04\x80\x96\xb8\x8c\xd5\x6f\x75\xfe\x3d\x2e\x23\x10\x14\x08\x2d\xe7\x34\xed\x62\x5d\xb2\x20\xae\xbc\x1d\x67\xac\x4f\x11\x38\x01\x52\x5d\x70\x62\x38\xdd\x61\x46\xa4\x64\x8d\x12\xc7\xc3\xe9\x47\x5b\xae\x83\x3c\x0d\x38\xad\xb1\x8d\xc2\xf1\x3b\xa6\x77\x37\x85\xc4\x55\xaa\xd6\x7c\x4a\x0a\xdb\xc5\x80\xc8\xe1\x82\xf0\xa9\xae\x70\x51\xd4\xfb\x6d\x5a\xd4\x8a\x0e\x9d\xcf\x9d\x08\xd6\xb8\x92\x45\x21\xb7\x90\xa4\xb8\xc3\x39\x49\x7b\x5b\xb9\x50\x45\x2f\x74\xc9\x4d\xe0\x6b\xe1\xa1\xf6\xbb\x0c\x7e\x36\x2b\x07\x6a\x3c\x4e\x78\xc8\x72\xd7\xf0\xb3\x5e\x84\x4e\x69\xea\x91\xa2\xd5\x55\x6f\x3f\x6f\x57\x3f\xea\xbd\xf2\x14\x2e\xb3\xdc\xc8\x5f\xf6\x55\xd3\x22\x50\x5b\x03\x14\x41\x8a\x24\xaf\xd2\xd0\xf0\x40\x96\x30\x52\x93\x55\x83\x4d\xf5\xf2\x36\x95\xaf\x90\x80\x07\x31\x96\x9a\x4d\x17\xae\x6f\x18\x15\x39\xb1\x48\xcc\xf4\x2f\x8b\xa1\xfe\x39\x4d\xe8\xb2\x9c\xe6\x70\x07\xb9\xa3\x87\xae\x76\xa9\xde\xd9\xc1\x32\xa5\x15\x2a\x8d\x82\x37\xea\x5d\xa7\x2a\xe8\x2b\xcd\xff\xf8\x45\x29\x8d\x5a\xe9\x90\x7f\x5b\x64\xe4\x0f\x1f\x95\xef\xbd\xd7\x4a\x9b\xbb\x03\xc6\xe5\x4a\xf8\x62\xf4\xc2\xfb\xb4\x24\xc5\x34\x87\x62\x21\x32\xf4\xf2\xfb\xd7\xde\x87\x10\x4f\xd9\x6c\x88\xa5\x2a\x24\x27\x30\x81\x14\xe1\x62\xe5\xbd\xbd\xc3\x6c\x15\x19\x46\xf5\x73\x1b\x9d\x56\x5c\xd0\x25\xb2\xcc\x2a\xf5\x43\x06\xbc\xa4\x85\xd9\xf6\xd4\x8a\xf6\xed\x3e\xda\xb9\x53\x3a\x36\x0e\x6c\x50\xb2\x14\x4e\x2d\xbf\x2b\x1c\x6f\xd1\xe3\xa3\xcf\x98\x03\xf9\xf2\x0e\x3d\x3e\x0e\xa2\x58\x18\x61\x2a\xe8\x2d\x14\xdc\xa7\xf0\x24\xa3\xf7\x5a\x82\xde\xe8\x6f\xeb\xa6\xa0\xb1\x1a\x51\xd1\x59\x5f\x0b\x5d\x39\x4f\xa5\x6e\x62\xbb\x3d\xd0\xa5\x0e\x51\x1c\xc1\x6d\x94\x12\xae\x76\x55\xf7\x98\x15\xa4\x58\x70\x23\x56\xe4\xe6\x8d\xe0\x9c\xfc\x02\xe9\xd4\x8a\xaa\xa9\x2c\x63\xcc\x60\xba\xf2\x49\x9a\x12\xa9\xf6\xe0\x1c\xe1\x3b\x4c\x72\x05\xc9\x49\xb6\x43\x53\x6a\x47\x2d\x26\x25\x4e\xc0\xbe\x20\xc5\x42\x6e\x17\xd4\x2a\x63\xdf\x49\x5a\x91\x04\xea\x77\x52\x03\x9b\x53\xb6\xc4\x02\x55\x25\x17\x0c\xf0\x92\x14\x73\xea\x93\xf1\x92\x2e\xde\xa9\x12\x6f\x79\x82\x4b\xf8\x5f\x93\x8f\x1f\xd0\xe3\x23\xa8\x1f\xc7\xff\xe6\xb4\xa8\xfb\xfb\xcc\x4e\x6a\x57\xe7\x93\x01\x6a\xa7\xf6\xb3\x23\x6f\x4f\xb4\xc4\x25\xaa\x58\xce\x91\xc8\xb0\x40\x3c\xa3\x55\x9e\x2a\xf2\xe3\xb2\x04\x2c\xb7\x1a\x08\x27\x09\x70\x3e\xca\xe9\xe2\xcb\xb6\x3d\xb2\x7f\xbe\x55\x4e\xc3\x9b\x06\xf0\x24\x1a\x3b\x46\x25\x9c\x56\x8c\xa0\x9d\x9c\x2e\x16\x8a\xcc\xf5\x8e\xbb\xe6\x64\x06\x3f\x7f\x62\xc4\x6d\x17\x27\xb7\xa4\x3c\x51\x50\x2f\xe9\xe2\xd3\xf5\xa5\x63\x13\x2b\x53\x4d\xf9\xc7\x47\x74\x70\x14\xca\x41\x4f\x84\x21\x33\x8f\xdb\x72\xe2\x4c\xf3\x8e\x6b\xc2\x4d\x9a\xba\x27\x8a\x5b\x50\x7b\x23\xdd\x92\x80\x93\x15\xcf\xa3\x10\xb8\xfa\x70\xa8\xa7\xd2\xb1\x53\x3f\xd4\xdb\x73\xca\xa5\xc6\x76\x18\xbe\xbd\xa2\x4c\xd9\x17\x03\xae\x21\xf3\x63\x47\xbb\x28\x46\x5e\x93\x16\x9c\xeb\xd8\x15\x16\xd9\x86\x10\x6b\x12\x76\xcb\xd7\x58\x8f\x95\x05\xe7\x57\x76\xd8\xbe\x7d\x2b\x61\x5d\xd2\x45\xb8\x30\x34\xfa\x5b\x37\xd8\xaa\x67\xbb\xbb\x1e\x5e\xd8\x3f\x35\xbf\xae\x81\xd3\x5c\xf9\x21\x54\x5d\xfb\x33\xe0\x98\x8b\xf2\xee\xf5\xd9\x87\x49\x68\x86\xf8\x29\x83\x02\x64\x49\x35\x71\x90\x96\xf9\x5c\x19\x9b\xf5\x1e\xec\x9e\x88\x4c\xaa\xe8\x18\x0d\x6a\x4b\xef\xc0\x48\xf8\x7d\xb5\xb7\x8f\x7c\x40\x84\x23\x0e\x02\x09\x8a\x06\x49\x4e\x39\x0c\x1a\xd3\xf5\x3e\x83\x02\x2d\xf1\xad\xb2\x74\x67\x80\x84\xdc\xa1\x08\xdb\xea\x08\xa1\x9b\x8c\x70\xb4\x04\x5c\x18\x69\xb0\xa2\x15\x4a\x70\x21\xa5\x01\x27\xcb\x32\x5f\x29\x7b\x54\x08\x74\xa0\x75\xce\x5a\x14\xa3\x1a\x33\xb4\xa3\xe6\x7f\xe2\xa1\x2a\x57\xa7\x9f\x60\x36\xa1\x52\x4f\x44\xbc\x2a\x4b\x39\xa4\x33\x48\xb0\x04\xad\x0c\x17\x84\xa3\x04\x73\xd0\xfd\x6c\x34\x16\xe9\xf5\xbd\x92\x58\x33\x70\x7d\x1f\xa8\x8e\x2a\x02\x4b\x08\x94\x91\x05\x91\x82\xdb\x52\x37\x25\x5a\xc0\x65\xf8\x0e\xba\x48\xdc\x24\x1c\x49\x32\xd3\x90\x24\x0f\x2a\x68\x3f\x2a\xc6\x00\xd3\x22\xf0\x84\x14\x09\xe8\x2e\xea\xb2\x29\xdc\x11\x2c\x00\x29\x63\x56\xd8\x68\x21\x65\x77\x6e\x78\x64\x06\x19\xbe\x23\x94\xa1\x7b\xd0\x78\x3b\xdb\x20\xe1\x52\x52\x33\x8a\x93\x6c\x54\x43\xd8\x46\xd7\x20\xb0\x41\xc3\x8a\x37\x0d\x2a\xc3\x45\x9a\x2b\xbd\x70\x8e\xdc\x1e\xbc\x97\xe3\x6a\x01\xad\x86\xb3\x2a\x17\x0c\xa7\x80\x76\xea\x71\x75\xef\x3e\xb7\x64\xaa\x7b\x4c\x91\x23\x57\xe2\xd9\xb3\x86\xf2\xab\x98\x36\x10\xc1\xb2\x51\x3b\xdd\x7c\xab\x63\x8f\x1d\x12\xed\x88\x0c\xac\x91\xd0\xe0\xb3\x81\x99\x54\x13\xed\x1f\x10\x18\xf9\xd4\xa8\xa8\xe2\xc8\x96\xef\xee\xdf\x4e\x68\x55\x9d\x4a\x20\x51\x79\x14\xaf\xcd\x60\x49\x05\x34\x6a\xd5\x32\xd6\xa9\x31\xca\xd4\xa9\x56\xde\xe9\x83\xd4\x1a\x34\x05\x74\xb3\x4e\x07\x4c\x28\x63\x90\x88\x7c\xa5\x2c\x85\x89\xe4\x30\xce\x73\xb9\x46\xe5\x14\xa7\xa4\x58\x34\x86\xb4\x0d\x69\xa7\xc4\x9c\x4f\xcd\x52\xc1\x93\x0c\x96\xbd\x83\xdb\x01\xa6\x67\xb0\x77\x34\xd0\xa3\xb0\x77\x6a\x37\x25\xd1\x8d\xb5\x8f\x8b\xd4\x56\x43\x98\x81\x22\x82\x9c\x08\x73\xca\x12\x50\xe2\x33\x25\xb2\xdb\xae\x73\x03\x53\xfa\x30\x02\x6d\x20\x49\xae\xcb\x4f\x05\x55\x8a\x0a\xef\xeb\xe1\x41\xdd\x97\x81\xd2\x7b\xe4\x3f\x03\xfd\xe2\x45\xe3\x1b\xf7\x3e\xbe\x68\x31\x74\x84\x56\x52\x06\x6a\x1c\x8d\x22\xad\xde\xf4\x60\xd3\x01\xa4\x87\xde\xd6\x83\xee\x95\x0b\xd7\x6b\x9c\xe7\xa3\x0b\x3e\x99\x5c\x5e\x61\xce\x45\xc6\x68\xb5\xc8\x3c\x77\xb9\x1e\x1f\x89\xbf\xc6\x4d\xbb\xe8\x47\x97\x84\x0b\x28\xe4\xba\xcc\x47\xb2\xae\x9a\x2c\x8f\x8f\x72\x58\x5e\xbd\xfa\x4e\x89\xfb\x88\xa3\x43\x96\xaf\xe9\xd1\xea\xb8\x7e\xd3\xa0\xc1\xba\x16\x83\xe7\xd5\xab\xef\x8e\xfa\xa6\x6a\xa3\x45\x4b\x0f\xd4\x9e\xad\xbf\x12\xc3\xf3\x9b\x9b\xab\xc9\xd7\x46\x2f\xd8\xd7\x7c\x9c\x29\x41\x3f\x03\x23\x16\x50\x46\xb9\x68\x30\x9b\x7c\x25\x05\x23\xe1\xfa\xcf\xb5\x33\x59\x96\xea\x9b\xbc\xf5\xf7\x5e\xc6\xd6\xed\x4a\xd4\xa6\x35\x1e\x4f\x12\x23\xeb\x10\x71\x7d\xea\x52\xdd\x4f\xe9\xb2\xac\x04\xbc\xab\xf2\x3c\x58\x41\x1c\x4b\xff\x04\x52\xc7\x79\x26\xd4\x7a\x6a\x84\xb8\xdc\x0c\xfb\x58\x48\x36\xb6\x3a\x8a\x5c\x51\xe5\xf2\xe2\xdc\x71\x06\x0e\x83\x32\xc7\x09\x70\x53\xc0\x49\x73\x15\x54\xc0\x29\x2d\x7a\xe8\x24\xe1\xef\xcc\xab\x3c\x6f\xbd\x0d\xb8\xcb\x4e\xd3\xd3\x35\x0b\x59\x8b\xae\x83\x68\x93\xfb\xd1\x35\x6b\xd0\x43\xee\xc1\x9a\x0a\x9b\xac\x74\x9d\xb8\x68\xa2\x4e\x3d\xd2\xf5\xa3\xd2\x5b\xde\x85\x8d\xa0\xae\x99\xe3\xd9\x7f\xa7\xa4\x98\xda\xc5\xa0\xde\xc8\xc9\x99\x17\x7c\x31\x4f\x6d\x17\x60\xa0\xdc\x31\x7a\x6f\xe1\x3d\xce\x37\xc2\x79\xee\x68\x55\xdb\x7e\xb4\xd4\x32\x2f\x9d\x59\x6f\x1b\x89\x8a\x15\x88\x16\x88\x03\x57\x86\xa5\x04\x27\x99\x8e\x4a\x41\x29\xc3\x5c\x90\x04\xe7\x72\x49\x5f\x96\x8c\xde\x01\x2a\x81\x29\xab\x41\x91\x40\x93\xe9\x27\x93\xcb\x89\x06\x72\x8a\x93\xcc\x8d\x87\x44\xc7\x00\x9f\x26\xea\x83\xd4\xac\x04\x29\x0e\x5f\x1c\x1c\x1c\x58\xc7\xd8\x64\x72\x79\xe8\xa1\xea\x03\x0a\x0d\xe8\x1e\xb4\x66\x28\x4c\x5d\xaf\x76\x37\x74\xd8\x65\x70\x9e\xd3\x7b\x17\x46\x20\xfb\x2b\x55\x15\x4b\x03\x41\xe4\x46\x81\x47\x1a\x54\xef\xe3\x9d\xbe\x31\x1f\xd7\x9a\x63\x6b\x63\xd3\x2e\x2c\x4b\xb1\x8a\x03\xfa\x27\xac\xd0\x5e\x8c\x86\x1a\x09\xe5\xef\xf3\x0c\xa4\x06\xb5\xd1\x2d\xac\x3a\xba\xcc\x73\xb2\xc8\xa4\x76\xc6\x20\xad\x12\x2d\x52\x24\x05\x87\x82\x0e\xe7\x84\x71\x31\x9c\xad\x04\xb8\xe6\x7c\xe7\x90\x47\xe0\x86\x37\xa8\xbf\x43\xa7\xa4\xcc\x80\xf1\xbd\x5a\xee\xb5\xe9\x9e\x68\x43\xa2\x24\x7f\xa2\x8b\x3b\x14\xcc\x6f\xf4\xcc\x6b\xdf\x80\xd4\x06\xa5\x9a\xdb\x41\xe1\xaa\x27\x97\xad\xd6\x61\xbb\xec\xc4\xf6\xec\xfc\x0a\x33\xbc\x6c\x63\xab\x31\x3c\x3b\x47\x2a\x60\x6c\x43\xfb\x93\xc4\xcb\xb7\x3f\xc9\xdf\x69\x56\xca\x16\x1c\xde\xe6\xb7\x4f\x5f\x83\x44\xbf\x19\xd9\x19\x2a\xb5\xaa\x74\xb6\x2a\xf0\x92\x24\x37\x97\x93\x6b\x48\x28\x4b\xb9\xcf\x36\xe9\x4a\x0a\x93\x44\x0d\xe4\x34\xa7\x56\xa5\x6c\xca\x25\x9e\x4f\x21\x49\xb3\x69\x52\xb1\xbb\x60\xc0\xdf\x9e\x9e\x9d\x9f\xaa\x97\x8d\xf1\x1e\x69\x13\xb0\xb2\x5e\xf0\x9a\x66\xc6\x30\xac\xec\x1f\x2a\x0a\x40\x8f\xa7\x16\xe1\xa4\x10\xc0\x12\x28\xc5\x14\x74\xb5\xee\x31\x32\x36\x37\x60\x4c\x39\x22\xac\xd1\x4d\x83\x97\x0a\x4e\xd8\xb0\xb6\xb7\xa8\xa8\x03\x89\xbc\xad\xf6\xf8\x88\x8e\xd1\xff\xd4\x23\x38\x0d\x3f\x1c\x35\xda\x34\x26\x05\x6f\xa6\x31\x90\x4b\x6f\xcc\xfd\x7f\x22\x19\xc3\x44\x66\x6a\x13\xb0\xdb\x0a\x7a\xb0\x94\x46\x65\x14\x51\x5d\x6a\x4d\x67\x4d\x59\xdb\xd7\x73\x92\x42\x6d\x30\x37\x6e\x36\x92\x82\x6f\x32\xcf\x7a\x43\x61\xe2\xbc\xae\xd4\xc3\x82\x94\x25\x88\xbd\xd6\xc0\x25\x92\x3a\x5c\x7f\x75\x13\x15\x52\x6b\x5d\x08\x23\xaf\xf4\xaf\x25\x2e\x6d\x6b\x4d\xf8\xdd\xd6\x3a\xd3\x65\xb9\x12\xee\xa3\x1d\x6b\xfa\x53\x7d\x9f\x79\x21\xaf\x75\x2f\xe0\xe7\xba\xd8\xc8\x88\xca\x93\xf9\x9c\x14\x44\xac\x46\xf6\x8f\x9b\x55\x09\x68\x90\x50\x7a\x4b\x60\x60\xeb\x3b\xe0\x72\x35\xbb\x5d\x0d\x25\x9e\x0e\xd2\x07\xbc\x54\x6c\x52\xeb\x3c\xba\x14\xca\x30\xcf\x8e\x83\xa2\xcd\x46\x4f\x55\x33\xcd\xb7\xe7\x98\x2b\xf3\x9e\xec\xd9\x97\xd4\xb7\x08\x29\x41\x43\x8b\x7c\x75\xb4\xd5\x50\xc7\x76\x17\x66\xfa\x5b\x1b\xfb\x3f\x6d\x7c\x83\x1f\xa2\x79\xb0\xe7\x6b\x44\x2e\x04\xc2\x8d\x52\x6f\x65\xcb\x4f\x91\xb1\x0b\xc7\x4f\xcb\x5c\x35\x6c\xae\x9f\x6f\x8b\xb4\xa4\xa4\x50\x6b\xa1\xf9\x5e\x07\x53\x8f\x4e\x8c\x9d\xe3\xff\x22\xed\x7e\xb8\xb8\xb2\x26\x57\x53\xc0\xda\x5b\x55\x6c\x00\x26\x39\x3f\xf6\x3e\xbe\xc7\x0f\xef\xe4\x3b\x59\x40\x7e\xb4\x4a\x80\x5f\x46\x16\x68\x6a\x00\x91\x8e\xd4\xbc\xe8\xbf\x75\xcc\xb2\x86\x4b\x8c\x34\x70\x25\x2c\x39\x95\x43\x7a\xe5\x93\x5e\x32\x52\x08\xad\x55\x56\x4e\x24\xae\x36\x70\xa2\x57\xaf\xdd\x46\x2a\x76\xda\x04\x01\x22\x9c\x2f\x28\x23\x22\x5b\x1e\x21\x3d\xbd\x95\x1b\x8e\x56\x45\x8a\x54\xbc\xe9\xbe\x31\x22\x12\xee\x9b\xe4\x1a\x5d\x28\xc0\x7a\x7b\x70\xfa\x46\x03\x3e\xb1\x70\xd1\xc0\x8b\x5e\x95\xf3\xc9\xb9\x8a\x63\x85\x03\x99\xda\xcf\x3d\x7f\x71\xf1\x57\xe0\xe2\x0d\x98\xd8\xfe\x31\x75\x01\xa8\x9e\x9c\xd3\x9d\x3a\x18\xc9\xff\x5e\x1c\xa1\x6d\xa4\xf6\x92\x19\xcd\x53\x60\x35\x95\x6c\xcd\xae\x88\x54\x2f\x26\x55\x85\xd8\xd6\x31\xb0\x1e\xa9\xeb\x81\x93\x4a\x7f\x63\xdb\x3c\x7e\xae\x8d\xad\x8a\x49\x97\xb8\x34\x8e\x80\x7b\x92\xe7\x68\x66\x02\x59\x69\x6d\xa5\x93\xa5\x7e\xca\x88\x80\x9c\x70\x11\x84\xa5\x9a\xd1\x24\x45\x0a\x0f\xfb\xc1\xa8\xf2\xfa\xf0\x46\x58\x36\xa7\x89\x5e\xca\xea\x52\xa3\x4b\xf3\xce\x2f\xbe\xa3\x42\xcb\x0f\x8f\xad\x97\xd3\xd4\xaa\xeb\x87\x4b\x2e\xe1\xb6\x88\x52\x15\x20\x0d\x4b\xd6\x05\x17\x02\xed\xe6\xe0\x01\x1a\xb9\xae\x8d\x4e\x2f\xce\xae\xf7\xf4\xd1\x05\xb3\x46\x9f\x41\xa1\x27\xf9\xe7\xcf\xa8\x64\xa4\x10\x0e\xe7\x73\xca\x85\x5c\x71\x90\xc1\xb4\x0e\xbc\x6c\xd8\xa6\x8d\x61\x5b\x42\xb2\xc1\x2f\x68\xb7\x03\xd6\x60\x3a\x30\xf0\xf6\x42\xe1\xe7\xf9\x2e\x23\xb3\xc9\x84\xd4\x76\xf4\xa8\xe9\x25\x55\x91\x10\x2d\x0f\x69\x53\x6d\xd8\xfc\x57\x63\x80\x99\x3a\xd1\xb3\xab\x83\x25\xaf\xb1\x00\x15\xe5\xc2\x6b\x96\xf0\x54\x20\xf9\x59\x05\xcb\x68\xf7\x6d\x6e\xc5\x7e\x9c\x94\x3b\xf7\xb6\x5f\x53\x53\xfc\xe2\x2c\x4e\xa6\x83\xa3\x6e\x2a\xb1\xbc\xa6\x4f\x9c\x34\x2f\x5a\xa4\xd9\x04\x5d\x65\xf3\xe9\xc0\x70\x47\x47\x04\x75\x60\x7d\x10\x06\x04\x49\x81\xfa\x5f\xb4\x00\xc7\x2d\xbe\x30\x7a\x81\x06\x83\x1e\x43\xa1\x37\xb7\x71\x9e\x1b\x23\x95\x0a\x33\x4e\x11\x93\x73\x59\xa3\xff\x0b\x2d\x80\x8f\xd0\x5b\x9c\x64\x48\x79\xfe\xf4\x44\x31\x45\x39\xc2\x28\x05\xed\x51\x48\x55\xd9\x86\xd3\xea\xc5\xfb\x37\x68\xf8\xdf\xd1\x8b\xd7\x48\x64\xb4\xe2\xb8\x48\xd1\xeb\x57\x6a\x37\xab\xa2\x91\x81\x23\xca\x10\x9e\x49\x41\xfa\x43\x5d\xe4\xc5\xcb\x1f\x82\x32\x11\x41\xa2\xda\x92\xdc\xa3\x5d\xaf\x96\x79\x24\x35\x6a\x06\xda\xf3\xa5\x84\xaa\xd1\xc5\x92\xe3\xe7\xe8\x8d\xa2\x85\x11\x4c\xd6\xc6\xc3\xd1\xee\x9c\xd1\xe5\x58\x50\x74\x7f\x7f\xbf\x17\xc3\x24\x33\x53\x72\x1f\xed\x08\xaa\x0e\x74\x5d\x9b\xca\x93\x50\xb2\xd9\x95\x2a\xc2\x70\xd6\xc1\xa4\x42\x71\x8c\x41\xef\x0d\x29\x52\xb3\x94\x5d\x94\x77\xaf\x7c\x06\xcc\x95\x3e\x82\xcc\x59\x32\x55\xd3\xac\x70\x31\x73\xb3\xd6\x0d\xd6\xd8\x0a\x1b\x67\x00\x1a\x41\x38\xbd\x8d\xae\x77\x16\xac\x33\xd5\xb7\xdb\xd6\xca\x55\x9f\x01\xfd\xcb\xbb\xe4\xfe\x90\x5b\xeb\x5e\x9d\xce\xef\xf2\xb7\x20\xec\x9f\x88\x92\x2d\x4d\x53\x36\xd1\x3a\x73\xf9\x25\x33\xe1\xf5\x5f\x33\xe1\xab\x8f\xdf\x26\xb3\xe0\x7f\x1f\x1e\xfe\x9f\x6f\x44\x59\xdb\xd4\x9f\x84\x9e\x5d\xbb\x2e\xfb\xc6\xf3\x3c\x68\xc3\x91\x55\xf2\x9c\x59\x0f\x05\x5b\xc2\x38\xe2\xaf\x5e\x7d\xd7\x8e\x72\x33\x0e\x6d\xe5\x98\x94\xab\xa5\xd2\x26\xe7\x68\x70\xf8\xdf\xee\x06\x1d\x80\x82\x5d\x1d\x03\xe5\x84\xb0\xe4\x3a\x35\x26\x24\xbb\xc2\x59\x43\x9e\xf5\xab\x8f\xc7\xea\xf4\x15\x35\x14\x0e\xdb\x7f\x7c\xf4\x03\xfa\x7a\x59\xee\xcb\x9b\xed\x6e\xa2\x5b\x81\x7d\xd2\x1e\x45\x2b\x78\xdb\x52\x35\x61\x02\xb5\x77\x9f\xe7\xf5\xe0\xc5\x57\xfd\xe6\x68\xb7\xeb\x05\x9b\xd9\x9c\xe0\xd6\x6e\x59\xc0\xb2\x54\x67\xc0\x06\x93\xb7\xd7\x3f\xbe\xbd\x1e\x18\xa0\xa7\xca\xe6\xa7\xcf\xca\x5b\xf4\xdb\xbb\xfb\x96\x7d\x5d\x15\x6c\x5a\x1d\xd1\x57\xb2\x3c\xa2\xd6\xd1\x89\x86\xfd\x31\x32\x16\xad\x6e\x9e\x7e\x9a\xdc\x7c\x7c\x3f\x7d\x7b\x7d\xfd\xf1\x7a\xa2\x19\x37\x1c\xcc\xed\x6d\x05\xa0\x7f\x38\x62\xc3\xbe\xed\x76\x02\xba\xc2\xbe\x3e\x0a\x28\x37\x72\x1f\xfe\x71\xf1\xe1\x5f\x48\xa7\x04\x48\x32\x48\x6e\x55\xc0\x89\x0e\x1a\x91\xbb\x5e\x1d\x3e\x25\x55\x54\x1e\x1f\xe9\x6d\xf4\xc9\xf8\x87\xbb\x43\x24\xec\x19\x35\xb4\xcb\x70\x91\xd2\xa5\x39\x13\xfa\xef\x8a\xab\xe0\x35\x7d\x1c\xfd\xb6\xa0\xf7\x85\x02\xc2\xf7\x10\xe6\x0e\x65\x05\x56\xa2\xaa\x3d\x1e\xfe\xb8\x65\x58\xbe\x5b\xe8\x80\x30\x0d\xd3\xd3\xd9\x93\x4c\xb1\x3a\x29\x0e\xbd\x3a\x3a\x52\x65\x3c\x5e\x10\x91\x55\xb3\x51\x42\x97\xe3\xdb\x6a\x06\xac\x00\x01\x7c\x6c\x22\x97\x87\xda\xa7\x35\xcb\xe9\x6c\xbc\xc4\x5c\x00\x1b\x27\xb4\x10\x8c\xe6\x39\x30\x6e\x3c\x5e\xe5\xed\x62\x9c\x2c\x53\xef\x8b\xf1\xc9\x2c\xe8\x26\xba\x55\x4d\x14\x7b\x96\xa0\x1e\x57\x5f\x32\x5f\x43\xc5\xc1\x18\x73\x94\x43\x40\xd2\xa3\xd6\x49\x66\x38\xb9\xcd\xe9\xe2\xd8\x36\xf1\x46\xff\x0e\x7c\x96\xa8\x5b\x39\x59\xb7\xec\x7d\x1b\x2c\x63\xab\x85\xb0\x7e\x7a\x67\x42\xd2\x26\x81\xe1\xc0\x5b\x2e\x9c\x4d\xa3\x91\xd7\x22\xd8\x4f\xa2\x8e\x98\xe5\x86\x1c\x7e\x79\xe0\x6d\x93\x1f\x23\x6d\xe8\xe1\xb5\x67\x58\x42\xf8\xdd\xf8\x2a\x97\x53\x81\x73\x1f\x6d\x14\x0b\x18\x6e\x1d\xe6\xb4\x4f\xf4\xf0\x65\x4a\x78\x99\xe3\xd5\xd1\xc6\x25\x6d\xb0\xbd\x3e\xa7\xd2\xc0\xa4\xb9\x34\xad\x23\x19\x17\xd5\xcc\x12\xc2\xba\xd0\x7c\x70\xe1\x60\x46\x89\x19\x8a\xd3\x90\x9a\x72\x4a\xa9\x03\x7e\x5d\x16\x3f\xd4\x3c\x83\xdf\x34\xfd\x21\x27\x34\x3b\x11\x68\x00\xec\x71\x2a\xda\xa7\x15\xf4\x8b\x10\xfa\xd7\x50\xad\xd3\xaf\x0e\x5e\xad\xa3\x02\xea\x65\x13\xfb\x73\x68\xe6\xd9\xd0\x38\xa1\x06\x47\x11\x14\x4a\xcc\xbd\x43\x54\xc6\x21\xdc\x05\x21\xca\xd4\x9b\x2f\x3c\x8f\x5b\x5b\xd6\x21\xb1\x85\xc2\x73\x1b\xea\x10\x6d\xed\xac\x08\x8e\x6c\x4c\xf4\xfb\xd8\xf9\xad\x5f\x71\xae\x60\x93\x28\xfe\x1a\xab\xa8\x4b\x72\x7d\x60\xbc\x0b\x4d\xb9\x39\xbd\x42\xe6\xdc\x0a\x6f\xaa\x4f\xfb\x68\x47\x24\xe5\xc4\x69\x4f\xa3\x9b\xd3\xab\x37\x0d\xbf\xa1\xb3\x82\x8b\xa4\x54\x4e\x3f\x57\xc3\x5a\xe7\x1b\x6f\x0d\x00\x65\x47\x53\x27\x6a\xfa\x8b\x74\x7f\x75\x47\x06\x1a\x68\xff\x7b\x1f\xed\x80\xf1\x2b\x28\x9d\xaf\xae\xea\xbb\x1b\x9a\x26\xfa\xd6\xa3\x3c\xd9\xa6\x82\x73\x45\x98\x3d\xa9\x7b\x6f\x90\x88\x07\xf6\xa2\xdf\xc2\x56\x14\xc5\xb3\xb1\x65\x6e\x8d\x81\xe1\xcc\x08\x11\xfd\x0d\xd1\xe8\x0c\x12\xa3\x90\xaf\xdd\xe0\x75\x6f\x2f\xa3\x08\x7e\x23\x8c\xbe\xad\xb1\xe2\x3f\x6f\x28\x9c\x0e\xf4\x7b\x8d\x47\xe3\x8d\x06\xd2\x7d\x5e\x5f\xe7\xdd\x52\x02\x26\xe6\xa6\x8b\xad\x14\x48\xa7\x45\xf8\x5d\x64\x51\x4b\x15\x5d\x47\xce\xb7\x85\x21\x67\xb3\x4b\xd6\x44\xe1\x1e\x5f\x03\xd9\xc4\x3b\xb9\x8d\x3e\x9d\xf5\x4a\xf6\x2a\xf5\x25\xfb\xa7\xb3\x6e\xc9\x5e\xa5\x9a\x9a\xae\x46\x40\xcd\xfa\x6d\x27\x35\xe3\x45\xba\xbf\x6e\x2c\xd9\xeb\xaa\xdf\x58\xb2\xff\x7e\xa2\xbd\x35\x08\x72\x78\xbe\x58\x2c\x6f\x00\xed\x8f\x27\x52\xbf\x1e\x09\x9c\x38\xfc\x12\x3a\x44\x45\x99\x3d\x9f\xcd\x83\x0e\x34\x44\xd9\xb5\x2b\xd4\x16\x66\x5f\x5d\x16\xfe\x5e\xb3\xb7\x19\xb6\x6f\xc8\x65\xd3\xfd\xa5\xa0\x42\xb1\x54\xc2\x99\xb9\xd3\xd3\x79\x6d\x2a\x61\x50\x82\x20\x3a\x44\xc0\x64\xf5\xd3\x95\xda\xca\x7c\xc3\x58\x5a\x36\x92\x35\x76\x24\x70\x6c\xb3\xac\x17\x07\xa9\xd8\xb5\x2b\x0e\x12\xf9\x7b\xac\x78\xe0\x63\x63\xe3\x65\x37\xc8\x8d\xfd\x71\x57\xc0\xa6\x8b\x43\x0f\x0b\x86\xbb\xb2\x7a\x63\x86\x1a\xdc\xe2\xc5\x5f\x6e\x06\x45\x6f\x67\xbc\x92\x3a\x92\x5f\xe7\x31\xdc\x10\xc6\x47\x73\x1a\x73\xf8\xe9\xfa\x42\xc3\x88\x1a\x70\x7b\x61\xd4\xbc\x67\xf1\x70\xe7\xee\x37\x84\x70\x61\x8c\x5b\x8a\x45\x15\x04\xff\xa0\xfe\x86\x40\x26\x7a\xd5\xf4\x80\xf8\x27\xfb\x1b\x43\x63\x8e\x0a\xa0\xc6\xb3\x3b\x7a\xbe\x87\xc6\x68\xc6\x00\xdf\xae\xdf\xde\x3e\x6d\x87\x6b\xff\xaa\x67\x55\x90\x0b\x74\xfc\x1c\x9d\x7e\xbc\x9e\xb8\x33\xb8\xea\xb0\xa3\xb5\x09\x2e\x49\x92\x11\xc8\x6f\x71\x7e\xbb\xc4\x85\xb2\x0d\x1a\x73\xb0\xb1\xf9\x0d\x13\xca\xf8\x90\x96\x50\x0c\x43\xeb\x43\x9d\xd6\xcc\x9f\x89\xc1\x04\x54\xa2\x8a\x9a\x29\x77\x4a\x19\x37\x76\x6c\xfb\x7d\x1b\xc9\x97\xe8\x8a\xc1\x5c\x05\xca\xa3\x25\x88\x8c\xa6\x1c\x15\x00\x29\x47\xb8\xce\xc5\x40\x4b\x3d\xf3\x71\x91\xa2\x94\xcc\xe7\xc0\xa0\x10\xe8\x5a\x5b\xb1\x24\x73\x6b\x80\x64\x8e\x76\x1d\x9f\x69\x60\xe8\x18\x3d\xfb\x78\x75\x73\xf1\xf1\xc3\xe4\xd9\x9e\x37\x0d\x5b\x79\x25\x9e\xe9\x5d\xf5\xf0\x54\xdb\x36\x87\x2a\x88\xc8\xb0\xf1\xa1\xeb\x8a\xea\x86\xfa\xa4\xbf\xd4\x41\xf1\xc8\xdb\xf1\x07\x05\x4f\x19\xa4\x50\x08\x82\x75\xec\xd9\x86\x0d\x7b\xb5\x62\xad\x87\x40\x9f\x1d\x45\x56\xa0\x0d\x1b\x7a\xaf\x69\x1e\x6b\xc4\x7c\x0a\xfb\xb8\x21\x58\x23\x59\x63\x60\x6b\xa1\xfb\x14\xb0\xef\xf1\xc3\xf0\x64\x01\x0d\x80\xef\xf1\xc3\xc9\x02\xd6\x81\x3a\xd5\xc6\xb5\xe1\xcd\xaa\x84\x43\x9d\xbb\xa6\xcc\x31\x29\x50\x92\x61\xc6\x41\x1c\x7f\xba\x79\x37\xfc\x61\x23\x10\x97\x2a\xe5\xcb\x21\x3a\xf0\x4a\x3b\x6b\xaa\x35\x88\x79\x56\xa7\xbf\xf8\xec\x8f\xc1\x67\x2d\x99\x18\x6a\x1c\x5a\x79\x1f\x3a\x03\x61\x54\xef\xb8\x27\x22\xb3\x25\xb1\xf2\xdf\x35\xe5\x9f\x75\xdb\x35\x54\x10\x9b\xe3\xfa\x1d\x61\xed\x88\xb3\xda\x1d\x39\x9a\x40\x42\x5b\x8a\xe5\x1f\x3e\x94\xa8\x3e\x2b\x10\x09\x66\xfc\x6d\xdd\x28\x9f\x3f\xab\xc3\x7f\xbf\x5b\xb0\xcf\x1f\xad\xeb\xd1\xdd\x99\x8e\xb4\xf8\x0f\x8e\xd0\xf9\x5d\xa9\xfc\x87\x88\xa4\xf9\xe3\x51\x60\x7d\xec\xcb\x46\xde\x4c\x25\x8a\x35\xa9\x10\xed\xf0\x1a\x7b\x61\x3f\xf6\x6c\x76\xa7\xdf\xdd\x1d\xc3\x27\x26\xf7\xaf\x89\x64\xb8\xb9\x9c\x20\x5e\x10\x6b\xa4\x71\xe1\x9e\x0e\x07\x95\x12\x47\x8f\x23\x30\xb4\xac\xb8\x40\x38\xbf\xc7\x2b\xae\xd3\xb0\x34\xec\x70\xa0\x27\xd2\x7e\x70\x58\x7c\xf2\xe1\xa2\x86\x60\x0e\x3d\x73\x75\xce\x97\x56\x2c\x01\xa4\x12\xf6\xce\xa9\x44\x89\x88\x51\x13\x87\x66\x04\x87\x19\xe8\xc9\xe4\xf2\x14\x98\x20\x73\x15\x8b\xbb\xf7\xdb\xae\x0d\x5f\x3b\x2e\x0b\x7d\xbb\x40\xc5\xdf\x5f\x12\xab\xf3\xb4\xed\xae\xa8\x54\xa8\xe8\xf1\x51\xa5\x4e\x7d\x92\x38\xf9\x6b\x40\x7e\xb7\x01\xf9\x86\xeb\xe8\x13\x66\xfe\x9f\x2f\x3e\xf5\x4f\xc2\x2e\x8d\xf9\xfb\xf4\x21\xfd\x8f\x0f\x8c\xfd\x93\x0c\xe4\x3a\xad\x46\xa9\x0a\x09\x5d\x2e\xa1\x10\xe8\xea\xed\x7b\xc4\x33\xec\x25\xf2\x77\x57\x0d\x24\xc2\x84\xe2\x71\xab\x80\x2c\xa4\x56\xa0\x4e\xd3\x84\x51\x40\xb8\x48\xbd\xbc\x56\xf5\x1d\x34\xb6\xc5\x6d\xdb\xcc\xa1\x1f\xfd\x28\x47\x1c\x96\xa7\x19\x24\xb7\xbc\x5a\x06\x7a\x17\xcf\xa7\x49\xcd\x63\xa8\xeb\x09\x81\x79\x5c\x19\xd0\xa4\x01\x4d\x65\xc0\xf8\x72\x68\x7d\xf3\xe2\x5d\x95\xe7\xa7\x19\x26\x85\x3f\x41\x1a\xfd\xb2\xb7\x3f\xf4\xf5\x2f\xc4\x24\x06\xb5\xd5\x41\x2e\x70\xa9\x12\xe5\xf5\x3c\xbe\xbf\xd5\xaf\x33\xbd\x03\x46\xe6\x71\xa2\x74\xfb\x68\x51\x67\x68\x6c\x9c\x3e\x27\x95\xc8\x6e\x2e\x27\xca\xed\xd0\x08\xe4\xf5\x43\x8a\xbd\x52\x91\xa0\xeb\x57\x07\xdf\x45\xa5\xd6\xfa\xe6\x3d\xe2\xc9\x36\x46\xa7\x27\xef\x48\x0e\x1f\xf0\x12\x1a\xc8\xc4\x58\xb5\x59\xf9\x0a\x96\x93\xf3\x93\x16\xcb\xea\xf4\xf6\xbd\x9c\xdb\x03\xb4\xc6\xa8\x35\xba\x7a\x80\x4c\x03\x1d\xa3\xdb\x03\xf9\x47\x55\x5d\x67\xd5\xef\x82\x9d\x42\x29\xb2\x0e\xd0\xbd\xb0\xf5\xf1\x5a\x42\x8b\x33\x05\x61\xa3\xb9\xd2\x04\xa2\x86\xfb\x0a\x2f\x82\xd9\xe2\xa5\xe6\x78\xf5\xf7\xef\xd1\xab\xbf\xbf\x46\xc7\x7d\x98\x38\x20\x1b\x4b\xc4\xcd\x16\xbb\x46\x32\x1a\xd4\xc8\x32\xd3\xf7\x34\x44\x8a\xcb\x41\xb3\xee\x78\x79\x07\x32\x9d\xb1\xf0\x7e\x3b\x4f\x0b\x63\x7f\xca\x71\x66\xdb\xd2\x06\x47\x9a\xfd\xe2\xb8\x12\xd9\x95\x5f\x45\x8e\x56\xcf\x49\xe8\x38\x0d\xdc\xa9\xe0\x6b\xed\x9c\x1a\x9d\x94\xe5\x35\xa5\xc2\xe7\x18\xe5\x3a\xa9\x18\x41\xc7\x68\xbc\xd7\x70\x57\x1a\x01\xf2\xdd\xc1\x4b\x85\x54\x17\xb8\x60\x70\x36\xe0\x99\xba\x77\x31\x47\xea\x71\x48\x80\x1e\x1f\xaa\xff\xb6\xdb\xec\x00\x0f\xba\xfc\x50\x82\x84\x42\x10\xdd\x4e\x33\x46\xd9\x4b\x23\x63\x1d\x49\x33\x9a\x6a\x01\xdf\x8a\x09\xee\x70\x19\xaa\x27\x74\x18\xa8\x33\xbb\x41\x5d\x43\x03\x47\xcc\xb7\x06\x3f\x35\x1f\xb5\x45\x3c\x1e\x8c\x6b\xfc\x5a\x8d\x27\x18\x98\x38\xac\xcd\x71\x8f\xb8\x6f\xd5\xf3\x64\x1f\xae\x81\x36\xd1\xb9\x3c\x1b\x4f\x24\x59\x67\x57\x40\xf1\xc6\x6d\xa9\x74\xd2\x91\xa7\x9b\x3c\x26\x01\xf5\x17\x12\xe7\xd2\xeb\x8e\x3b\xb4\x54\xa7\x56\xfc\x52\x82\xb9\x16\xde\xfb\x83\xdd\x70\x6d\x3e\x69\x04\x24\x2b\xbe\x33\x37\x69\xb9\x67\xa0\x5d\xbc\xf6\x08\x48\x7d\xac\xe3\x49\xcc\x6a\xae\xf1\xb1\x87\xb8\x36\x09\x21\xaf\x11\x93\x10\x86\x06\xc2\xd0\x81\xe8\x1e\xae\x76\x63\x1b\x45\xf6\x7f\x09\x12\xdd\x83\xd7\xcb\x98\xc1\x9d\x11\xee\x71\x97\x47\x34\x30\x52\xb9\xaf\xea\x83\x63\xfa\x69\x9e\x2f\x88\x08\x25\x77\x65\x49\xb3\xac\xd1\xa4\x96\xf8\x41\x5f\x16\xe4\xdf\xc1\x32\x08\xe8\xaa\x36\x79\xa3\x37\x34\x5d\x99\xfd\xd3\xa0\xd5\x4b\x95\x56\x43\xa9\x29\xd1\xcb\x89\x6a\x58\x1d\x77\x17\xc5\x30\x8b\xde\x83\x14\x20\xd6\x7b\x11\xd2\x9a\x31\x50\x0b\x80\xc9\xc7\xdd\xcd\x45\x72\xe2\xc6\xe7\xbc\x0a\xc4\x30\x00\x36\x5c\xcd\x82\x13\x39\x65\x74\xb1\x32\xe9\x77\xe4\x66\x6f\x77\xbd\x5d\x60\xcf\x3b\x1d\x39\xb9\x09\x0f\x6e\x22\xbb\x56\x9b\xfc\xc8\xc7\x3a\x94\xa3\xb9\x64\xb7\xbc\xa7\x1d\xcf\x60\x22\x18\x49\xc4\xf0\x86\xe1\x82\xcb\xbd\xf6\x70\x62\xee\x96\x3d\x44\x4b\xfc\x30\xc4\x0b\x38\x0e\x4e\x6b\x4e\x6e\x26\xce\xe7\xde\xd8\x63\xcb\x6f\x17\xfa\x1e\x99\x49\x35\x4b\xe9\x12\x13\x9d\x10\xc8\xde\x2e\x33\xa9\x66\x67\xfa\x6d\xbd\xfd\x8e\xc0\xb8\x32\xfb\x60\x65\x76\x50\x7f\xba\xe2\x0d\x0e\x7d\xec\xe2\x88\x08\xf1\x55\x02\x3f\xc7\x0d\x97\x74\xc1\xcd\x39\x8a\xa7\x1c\x02\xea\x9a\xf8\xcd\x0c\xa2\x4d\x79\xf9\x49\x1b\x35\x2e\x8a\x6b\x97\x7f\x62\x6d\xce\xca\x10\x7d\x47\xa1\xf6\xc9\xa9\x66\x63\x3f\x0a\xee\xdf\x41\xf7\x94\x9b\xec\xba\x60\x1c\xb5\x0d\x3d\x91\x69\x17\xd5\xbb\x6c\xf6\x1b\x9b\x35\x4a\x6d\xd2\x5a\xb6\x21\x67\xcd\x51\x21\xc7\xbe\x62\x1b\x59\x8a\x76\xe4\x66\xfd\xf0\x18\xed\x2e\x40\x98\x08\xaf\x8b\x42\x1f\xd0\x09\xd4\xe2\x91\xf9\x58\xe7\xd3\x69\x40\x1a\x3f\x57\xb0\xa4\x8a\x84\xd5\x85\xb2\x72\x05\x54\x5c\x2b\x32\x40\xb6\xf6\xd2\x7e\x0d\x0c\x33\xae\xd7\x45\x18\xa5\x36\x30\x08\x06\x91\x93\x83\x88\x96\xea\x47\xa2\xf9\xf5\xae\xab\xbc\xab\x8a\x1f\x77\xe6\x57\x31\x11\x6a\x51\x6a\x8d\x9f\xbb\xa4\x27\x48\x50\xa4\x6d\x7e\x09\x2e\xd4\xed\xa3\x49\x46\xe0\x4e\x1f\x8b\x4d\xec\x6d\x11\x75\x82\x5c\x86\x32\x7c\xa7\xaf\x47\x9e\x4c\x2e\x91\x6f\x43\xf1\xce\x0a\xcf\xa9\xbe\x7f\x21\xe6\x5a\xab\xf9\x77\x97\xb2\xc8\xce\xe1\x1d\x65\x09\x4c\x26\x97\x6e\xcd\x7d\x82\x88\x6c\x01\xf3\xe0\xec\xb5\x06\x7b\x1b\x41\xa1\xed\x6c\x2a\x41\x7e\x61\xd1\xe5\x24\x85\xb6\x70\x6d\x65\x8c\x6f\xca\x57\x14\x51\x8a\xa2\x93\xbc\x55\x6b\xdb\xdc\xe0\x69\x52\x9c\xaa\xc3\xbf\xee\x22\x50\xec\x45\xb7\xd9\x48\x42\x0d\x8b\xdc\x41\x0c\x81\xaf\x90\x0a\xc0\x3e\x81\xcd\xe0\x6f\xe8\x78\xdd\x21\x7d\x1b\x42\xa8\xd2\x1a\xac\xcf\x0a\xd0\x6a\xcf\x9a\xa5\xfe\xfe\xb7\xa3\x58\xcf\x62\x5a\x1c\xda\x3c\x85\x80\xc3\x2e\x4c\x4a\xde\xad\xd3\xa1\xce\x13\x8c\x9d\xab\x4c\x84\x19\x42\x29\xdd\xb8\xe1\xdd\x2f\xef\xdd\xe2\x5e\xa7\x3b\x8d\x7c\x9c\xb2\x2a\x07\x25\xae\x9b\xb7\xc2\xdb\x12\xfe\xdf\x23\x39\x2f\x63\x5a\x5c\x03\xb1\x8f\x3f\x9d\x4c\xae\x4e\x29\x03\x29\x6c\x5a\x6c\xba\xbe\x79\x7a\x8f\x79\x39\xf4\xca\x0d\x13\x7b\x48\x7c\xb8\x16\x9d\x08\x89\x7b\x89\xba\x41\x62\xb7\xb0\xc2\x86\x09\xde\xfc\x8a\x72\xd6\xff\x8a\x3c\x6d\x31\xf1\x10\x33\xbb\x3e\x99\x9d\x22\x16\x12\xa4\x73\x88\xab\x78\x05\x4b\x86\x3a\x05\x40\x60\xdc\x08\xf5\x9a\x4a\x64\xd3\xe0\xf6\x57\xd4\x34\xb1\x1c\x75\x56\x90\x5a\x82\x7c\xa7\x4a\x4f\x75\xb2\xd7\x3a\x71\xa3\x49\xbf\x0c\xc2\x7c\x69\xc0\xa9\x6f\x9c\x73\xcf\x04\xc4\xf0\xd4\x40\xf1\x40\x36\x79\x65\xe8\x8e\x28\xa5\x0f\xfb\x68\x27\x27\x3a\x39\x98\x33\x85\xd9\xa3\x13\x36\xd4\xaf\x8f\x31\x74\xed\xd6\xfb\xe1\x93\xf9\xb1\x63\x4f\x31\x21\x8b\x82\x14\x7a\x67\x11\xd4\xf2\x05\xeb\xc1\x0b\x6d\xd8\x72\x3d\x90\xb5\x64\x9d\x0d\x80\x6e\xa4\x8a\xaa\x05\x9f\xe8\x9b\xc7\x1d\x31\x9c\x5a\x83\xfd\x14\x70\x75\xda\xb7\x7d\x94\x30\x90\x1f\x82\x44\x6f\x21\xed\x54\x06\x3f\x4b\x7b\x97\x97\xad\x97\xe2\xd6\x40\xaa\x0a\xaa\xf4\x84\x1a\x4a\x17\xfc\x6e\xf5\xb2\x49\xf8\x37\x98\x93\xe4\x8c\x2c\x80\x0b\x4d\x26\x29\x70\x20\x36\x8c\xc6\x17\xd9\x59\x53\x67\x2f\x9e\xc9\xb7\x83\xd6\x4e\x40\x32\xa6\xfa\xd4\xd8\x39\x37\x81\x5c\x03\xce\x97\x6d\x9d\xad\xae\x3f\xad\x38\x30\x2d\x45\x7b\x01\xbd\x23\x79\x7c\xa7\x1b\x4b\x56\x20\xa1\xa7\xaa\xee\xaf\x40\x4f\x03\xf8\xd5\xf8\xb5\xa7\x50\xcb\xe2\x22\x01\x50\x46\x7e\xd1\xdc\x32\x68\x1b\x1b\x36\x19\xf8\xfa\x14\x81\xfa\x33\x12\x88\x61\x6a\x79\x47\xfd\xf5\x09\xff\x1e\x3e\xed\x6e\xb8\xc3\x8a\xae\x55\x8d\xd1\xa7\xeb\xcb\xf8\xde\xbc\x62\x04\xfd\xbf\xe7\xbe\x3d\xa0\x67\x81\x68\x98\xd4\x0d\x6c\x77\x70\x28\xfa\x35\x26\x10\x36\xea\x56\x9f\x75\xc8\x7f\xfe\xb8\x96\xa2\x46\xbb\x5f\xc7\x6a\xa4\x13\x45\xae\x5c\x02\x9e\x8a\x83\xde\x36\x23\xcc\xb5\x4d\x59\x50\x77\x02\x76\x1f\xcd\x2a\x61\x2e\x2a\xa0\x77\xc0\x18\x49\xfd\x5c\x96\x1b\x70\x90\xdd\x0b\xff\x28\x9b\x68\xb1\x50\x6b\xe6\x74\x18\xb5\xc3\x31\x0a\x60\x46\x87\x68\x23\xbb\x68\x47\x5b\x0d\x35\x7a\x23\xa2\x6e\xa3\x2b\xcc\xf5\x56\x1a\x1e\x04\xc3\x89\x8a\x7e\xd0\x9e\x54\xdf\xd1\x2b\xa8\x2a\x63\x4e\x36\xad\xa1\xe1\xd3\x5c\xd2\x35\x8c\x4e\x77\x34\xe6\x5c\xbe\xbb\xa1\xee\xf6\xd4\x75\x24\xe2\x3c\x1f\xea\x6e\x0c\x65\x37\x1c\x89\x3c\x3f\xb6\xbe\xb0\x55\x47\x2a\x7c\xd9\x38\x74\x34\xd2\x2d\x36\x37\x85\xe6\x07\x2c\xf8\x28\xeb\xf7\x6b\x7c\x0a\x1e\x9c\xd4\x33\x6e\xfb\x70\xf8\x34\x8d\x64\xc7\xf9\x8a\x5d\xde\xb4\x73\x4f\xa9\xe7\x77\x66\xc3\x95\x69\x1b\xa9\xdd\x08\xba\x87\x19\xd7\x97\x5c\xd6\xd7\x24\xf2\x8d\x7d\x0f\xfe\xf3\xc9\xdc\xad\xe8\xd1\xd5\xbf\x87\x31\xba\xad\xf3\x16\x46\xdb\xb8\xd9\xe2\xa5\x4f\xf0\x80\xf8\x8f\x77\xab\x67\xdd\x54\xb4\x9d\xf3\xf0\x1e\x0c\x9f\x5e\x4f\xf4\xc0\xf4\xb7\x1f\xb9\x7f\xf2\xcb\xfc\x84\xff\x1a\x4a\x4d\x68\x78\x71\x15\xb6\xe8\x67\x98\xee\xdd\x3b\xaf\xb9\x62\xac\xa7\xdd\xfa\x46\x3c\x59\xde\xb6\x1b\xbb\x08\xec\xcb\x68\xd9\xd5\x42\x5f\xcf\x36\x91\x1b\x3e\x5c\x6f\x65\xe8\x5d\x0d\x7a\x81\xa8\xd0\x3e\x03\xc4\x5d\xad\xf7\x94\xfa\xea\xd2\x4a\xaf\x7e\x8f\xfb\x38\x02\x28\xea\xd6\x7e\x82\x93\xb6\xc3\x95\x1d\x45\xa5\x6b\x2d\x74\xf7\xd4\x36\x06\x6d\x63\xdc\xc3\xa1\x8e\x5f\x9b\x6a\x59\x36\x7a\x75\x6a\x0b\xb7\x25\x11\x64\x21\x97\xe2\xf3\x9b\x9b\x2b\xfa\xb0\x42\x3f\x56\x79\x01\x0c\xcf\x48\x4e\xc4\xaa\x51\xd8\x5a\xd6\xee\xef\xef\x47\x3a\xfb\x5f\x42\x97\xe3\x59\x4e\x17\x63\x03\x87\x14\x8b\xa1\xc8\x60\xa8\x6e\x53\x79\x58\x0d\xef\x7c\x68\xc3\x7b\x22\x32\x93\x6d\xb0\xbf\xcb\x3a\xa6\xb5\xf5\xb4\x22\x29\x5a\x37\xe3\x0b\x8a\xec\xfd\xfa\x7a\xd5\xef\xd8\x98\x7a\xd7\xe4\xe7\x79\x5f\x4e\x80\x28\x7a\x9f\x23\xb7\xe7\x3b\x1c\x3f\x87\xb7\xe8\x7b\x6d\x77\x4b\x2a\x23\xe6\x22\x39\x1f\xbc\xea\x4d\xa5\xdc\x88\xcb\x3a\x05\x04\x8f\xb3\x70\x91\xf6\xc0\x8d\x83\x9e\x40\x91\xae\x81\xcb\x00\x3f\x1d\xee\x35\xe0\x10\x6e\x04\xb0\xd6\xfa\xfb\x82\x32\x63\x3b\x14\xf5\xef\x1b\x57\xb5\x45\x7e\x1f\x76\xe7\xd6\xa7\x6b\xf7\xe3\x6f\x2a\x7a\xe0\xf6\x45\xb5\xbd\xfa\x42\xc8\x2e\x12\xa9\x93\x2a\x31\xb8\x26\xa0\xa1\x41\x8f\x08\xf8\x78\xc4\x82\xff\xa8\xe8\x85\x28\xcb\xd2\x5b\x02\x53\xed\xeb\x8d\xd6\x8c\xb2\xac\xac\xa4\x3d\xc1\x1d\x5e\x78\x03\x57\x6d\x9e\xe3\x4f\x27\xdc\x30\xa3\x9d\x7d\xb6\xd1\x45\xa1\x6e\x1b\x47\x74\x8e\x4c\x5e\x0d\xc1\x56\x4a\x20\x17\xf0\x20\xbc\x0b\xab\xb4\x5f\x68\x06\x73\xca\xc0\xec\xd1\x95\x0f\xac\xd0\xf5\x22\xd8\x4a\x00\xce\xed\xd9\x85\xad\x12\xd2\x1f\xe0\x41\xb8\x7d\x46\x13\xff\xf0\x63\x1d\x11\x2f\xd8\xea\x03\x2d\x2e\x52\x58\x96\x54\xd8\x30\xd4\x98\x97\x4f\xfb\x8b\x68\x91\xaf\xd0\x3d\x65\xb7\xdc\xda\x01\x4d\x6e\x49\x44\xb8\xda\x4a\x25\x74\x59\x32\xe0\x1c\xd2\xae\x4d\x6b\x24\xc4\x2f\x4d\xdf\x60\x0e\x11\xeb\xe6\xa6\x7a\xdd\x89\xca\x1e\x32\x54\x29\xae\x2c\x07\x6f\x6c\x04\x1a\x3f\x47\x27\x69\x8a\x70\xb1\xf2\xb3\x42\x84\x91\xf4\xfa\x0c\x76\xbc\x4f\x81\xfe\x5a\xd7\xf1\x42\x3d\xd7\x6c\x3b\xed\x68\x58\x4f\x44\x2c\x92\x14\x7d\xc5\xcc\xca\x16\xef\x8e\x76\x37\x36\x62\x69\x63\xf0\xbd\xbe\x47\x5b\xae\x02\xb5\x97\x57\x3b\x02\x04\x45\xd8\xfa\x22\xad\xf5\xc3\xec\xc4\xf7\x55\xbd\x34\x0d\xef\x10\xb1\x8b\x6c\x97\x9f\x37\xc3\xfc\x8a\xc1\x9c\x3c\x04\x66\x44\x05\x10\x0d\x74\x43\xcd\x64\x26\xc3\xc1\x7a\x1b\x88\x7e\x22\x19\x6e\xbe\x6f\xfa\x57\x7e\xd3\xb4\x36\xff\x21\x29\x69\x36\xe2\x8d\x4e\xf3\x94\x19\xae\x98\x25\x45\x49\x31\x7d\x3a\x48\x05\x4a\x6d\x1a\xc7\xa1\xde\x9b\x4b\x33\x83\x29\xd8\x6d\xc1\x35\x41\x03\xbb\x81\xf9\xde\x5b\xe7\xad\x31\x54\x45\x35\x0e\x0c\x4b\x0d\xf6\x36\xad\x40\xe7\xf3\x41\x3b\x4c\xc0\xae\xb7\xe1\x4d\xc0\xed\xa7\x4b\xf9\x08\xda\x78\xd2\xce\xf8\xab\xb5\xb9\xb6\xdc\x0d\xdd\xd0\x84\xdf\x81\xef\x36\xfa\x40\x11\xb8\x0c\x7b\xf8\x0e\x93\x5c\xf9\x4a\x6d\x24\x88\x91\x2d\x41\x25\x63\xec\x6e\xcd\xd6\x27\xb6\xec\x62\xdf\x53\x28\x08\xa4\x23\x74\x0d\x98\x53\x93\x38\xc5\x75\xfa\x4c\x7d\x6c\xd6\xde\x1c\x85\xfe\x23\x60\x1d\xe1\xec\x1d\x47\xde\xc2\x13\x32\x3a\x61\x37\x52\x69\xe7\xd5\xd9\xb0\x24\xa7\x55\x2a\x59\xe0\x8e\x28\xb1\x6a\x23\x41\x24\x1d\x2b\xad\xae\xf4\x1e\x76\x8f\xc6\xce\xdb\xc2\xe7\xbf\x4d\x7a\x70\xe3\x7d\x6e\x9c\x7b\xd3\xf9\x52\xf4\x25\xb4\x52\xb2\xa8\x2c\xfa\x84\xa3\x19\xc8\x35\x67\x49\x0b\x22\x28\x83\xd4\x83\xa2\xf2\xa9\x48\xbd\xca\x78\x3c\x11\xa7\x73\x71\x2f\x57\xaa\xdd\x9c\xdc\x02\xe2\x2b\x9e\x92\xc5\x5e\xbb\x7f\x7d\x69\xc9\xb5\x5d\xfe\xc5\xcb\xbf\x99\x3b\xf6\xba\x0c\x3a\xcd\x93\xbc\xba\xde\xe1\x61\xf3\xea\x2f\xfb\xa4\x20\x95\x8f\xbc\x99\xb3\xed\x4b\x52\x86\x87\xac\x53\x67\xa5\xb1\x7f\xfe\xff\x00\x00\x00\xff\xff\xdd\xe6\xaf\x37\x17\xa1\x00\x00") func etcNginxTemplateNginxTmplBytes() ([]byte, error) { return bindataRead( @@ -105,7 +168,7 @@ func etcNginxTemplateNginxTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "etc/nginx/template/nginx.tmpl", size: 40070, mode: os.FileMode(420), modTime: time.Unix(1517597409, 0)} + info := bindataFileInfo{name: "etc/nginx/template/nginx.tmpl", size: 41239, mode: os.FileMode(420), modTime: time.Unix(1520400310, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -125,7 +188,7 @@ func ingressControllerCleanNginxConfSh() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "ingress-controller/clean-nginx-conf.sh", size: 901, mode: os.FileMode(493), modTime: time.Unix(1516916602, 0)} + info := bindataFileInfo{name: "ingress-controller/clean-nginx-conf.sh", size: 901, mode: os.FileMode(493), modTime: time.Unix(1519920732, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -182,6 +245,9 @@ func AssetNames() []string { // _bindata is a table, holding each asset generator, mapped to its name. var _bindata = map[string]func() (*asset, error){ + "etc/nginx/lua/balancer.lua": etcNginxLuaBalancerLua, + "etc/nginx/lua/configuration.lua": etcNginxLuaConfigurationLua, + "etc/nginx/lua/util.lua": etcNginxLuaUtilLua, "etc/nginx/nginx.conf": etcNginxNginxConf, "etc/nginx/template/nginx.tmpl": etcNginxTemplateNginxTmpl, "ingress-controller/clean-nginx-conf.sh": ingressControllerCleanNginxConfSh, @@ -229,6 +295,11 @@ type bintree struct { var _bintree = &bintree{nil, map[string]*bintree{ "etc": &bintree{nil, map[string]*bintree{ "nginx": &bintree{nil, map[string]*bintree{ + "lua": &bintree{nil, map[string]*bintree{ + "balancer.lua": &bintree{etcNginxLuaBalancerLua, map[string]*bintree{}}, + "configuration.lua": &bintree{etcNginxLuaConfigurationLua, map[string]*bintree{}}, + "util.lua": &bintree{etcNginxLuaUtilLua, map[string]*bintree{}}, + }}, "nginx.conf": &bintree{etcNginxNginxConf, map[string]*bintree{}}, "template": &bintree{nil, map[string]*bintree{ "nginx.tmpl": &bintree{etcNginxTemplateNginxTmpl, map[string]*bintree{}}, From cba2f46ea4c8abea574741f1520f0e36ba44c5f3 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Wed, 7 Mar 2018 08:29:27 -0800 Subject: [PATCH 33/34] fix linting issues --- internal/ingress/controller/nginx.go | 4 +++- internal/ingress/controller/nginx_test.go | 16 ++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/internal/ingress/controller/nginx.go b/internal/ingress/controller/nginx.go index a490ca10b9..068b78dabd 100644 --- a/internal/ingress/controller/nginx.go +++ b/internal/ingress/controller/nginx.go @@ -747,7 +747,7 @@ func (n *NGINXController) setupSSLProxy() { }() } -// decide if the new configuration can be dynamically configured without reloading +// IsDynamicallyConfigurable decides if the new configuration can be dynamically configured without reloading func (n *NGINXController) IsDynamicallyConfigurable(pcfg *ingress.Configuration) bool { runningBackends := make([]*ingress.Backend, 0, len(n.runningConfig.Backends)) newBackends := make([]*ingress.Backend, 0, len(pcfg.Backends)) @@ -771,6 +771,8 @@ func (n *NGINXController) IsDynamicallyConfigurable(pcfg *ingress.Configuration) return ret } +// ConfigureDynamically JSON encodes new Backends and POSTs it to an internal HTTP endpoint +// that is handled by Lua func (n *NGINXController) ConfigureDynamically(pcfg *ingress.Configuration) error { buf, err := json.Marshal(pcfg.Backends) if err != nil { diff --git a/internal/ingress/controller/nginx_test.go b/internal/ingress/controller/nginx_test.go index 3ea86e6338..cd0eaa266e 100644 --- a/internal/ingress/controller/nginx_test.go +++ b/internal/ingress/controller/nginx_test.go @@ -23,24 +23,24 @@ import ( ) func TestIsDynamicallyConfigurable(t *testing.T) { - backends := []*ingress.Backend{&ingress.Backend{ + backends := []*ingress.Backend{{ Name: "fakenamespace-myapp-80", Endpoints: []ingress.Endpoint{ - ingress.Endpoint{ + { Address: "10.0.0.1", Port: "8080", }, - ingress.Endpoint{ + { Address: "10.0.0.2", Port: "8080", }, }, }} - servers := []*ingress.Server{&ingress.Server{ + servers := []*ingress.Server{{ Hostname: "myapp.fake", Locations: []*ingress.Location{ - &ingress.Location{ + { Path: "/", Backend: "fakenamespace-myapp-80", }, @@ -62,15 +62,15 @@ func TestIsDynamicallyConfigurable(t *testing.T) { } newConfig = &ingress.Configuration{ - Backends: []*ingress.Backend{&ingress.Backend{}}, - Servers: []*ingress.Server{&ingress.Server{}}, + Backends: []*ingress.Backend{{}}, + Servers: []*ingress.Server{{}}, } if n.IsDynamicallyConfigurable(newConfig) { t.Errorf("Expected to not be dynamically configurable when there's more than just backends change") } newConfig = &ingress.Configuration{ - Backends: []*ingress.Backend{&ingress.Backend{}}, + Backends: []*ingress.Backend{{}}, Servers: servers, } if !n.IsDynamicallyConfigurable(newConfig) { From 8b550d002e820324153276bd02d078507db98de4 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Wed, 7 Mar 2018 09:10:18 -0800 Subject: [PATCH 34/34] update the nginx image --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a052b79416..9451c49ce3 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ IMAGE = $(REGISTRY)/$(IMGNAME) MULTI_ARCH_IMG = $(IMAGE)-$(ARCH) # Set default base image dynamically for each arch -BASEIMAGE?=quay.io/kubernetes-ingress-controller/nginx-$(ARCH):0.34 +BASEIMAGE?=quay.io/kubernetes-ingress-controller/nginx-$(ARCH):0.37 ifeq ($(ARCH),arm) QEMUARCH=arm