├── .gitignore ├── nginx ├── html │ └── ourl │ │ ├── favicon.ico │ │ ├── css │ │ └── app.css │ │ ├── js │ │ └── index.js │ │ └── index.html └── conf │ ├── nginx.conf │ ├── vhosts │ └── ourl.conf │ └── mime.types ├── dist.ini ├── lualib └── ourl │ ├── urls.sql │ ├── config.sample.lua │ ├── idna.lua │ └── init.lua └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | *.o 3 | lualib/ourl/config.lua 4 | -------------------------------------------------------------------------------- /nginx/html/ourl/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaooloong/ourls-resty/HEAD/nginx/html/ourl/favicon.ico -------------------------------------------------------------------------------- /nginx/html/ourl/css/app.css: -------------------------------------------------------------------------------- 1 | .header { 2 | text-align: center; 3 | } 4 | 5 | .header h1 { 6 | font-size: 200%; 7 | color: #333; 8 | margin-top: 30px; 9 | } -------------------------------------------------------------------------------- /nginx/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes auto; 2 | user apache; 3 | events { 4 | worker_connections 1024; 5 | } 6 | http { 7 | include mime.types; 8 | default_type application/octet-stream; 9 | sendfile on; 10 | keepalive_timeout 65; 11 | 12 | include vhosts/*.conf; 13 | } 14 | -------------------------------------------------------------------------------- /dist.ini: -------------------------------------------------------------------------------- 1 | name = ourls-resty 2 | abstract = 一个网址短链接应用,Ourls(PHP) 的 OpenResty 移植 3 | author = xiaooloong 4 | is_original = no 5 | license = mit 6 | lib_dir = lualib 7 | doc_dir = lualib 8 | repo_link = https://github.com/xiaooloong/ourls-resty 9 | main_module = lualib/ourl/init.lua 10 | requires = nginx, hamishforbes/lua-resty-iputils, openresty/lua-resty-string, openresty/lua-resty-mysql -------------------------------------------------------------------------------- /nginx/conf/vhosts/ourl.conf: -------------------------------------------------------------------------------- 1 | lua_shared_dict ourls 10m; 2 | server { 3 | listen 80; 4 | server_name t.sicaudm.com; 5 | root html/ourl; 6 | index index.html; 7 | 8 | location / { 9 | try_files $uri $uri/ @app; 10 | } 11 | location @app { 12 | internal; 13 | default_type text/html; 14 | content_by_lua_block { 15 | local t = require 'ourl' 16 | t.run() 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lualib/ourl/urls.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `urls` ( 2 | `id` INT (11) NOT NULL AUTO_INCREMENT, 3 | `sha1` CHAR (40) NOT NULL, 4 | `url` VARCHAR (255) NOT NULL, 5 | `create_at` INT (11) NOT NULL, 6 | `creator` INT (11) unsigned NOT NULL DEFAULT '0', 7 | `count` INT (11) NOT NULL DEFAULT '0', 8 | `status` TINYINT(1) NOT NULL DEFAULT '1', 9 | PRIMARY KEY (`id`), 10 | INDEX (`sha1`), 11 | INDEX (`create_at`), 12 | INDEX (`creator`), 13 | INDEX (`count`), 14 | INDEX (`status`) 15 | ) ENGINE = INNODB CHARACTER 16 | SET utf8 COLLATE utf8_unicode_ci; -------------------------------------------------------------------------------- /lualib/ourl/config.sample.lua: -------------------------------------------------------------------------------- 1 | local ok, new_tab = pcall(require, "table.new") 2 | if not ok or type(new_tab) ~= "function" then 3 | new_tab = function (narr, nrec) return {} end 4 | end 5 | local _M = new_tab(0, 8) 6 | _M.db = new_tab(0, 4) 7 | _M.db_rw = new_tab(0, 8) 8 | _M.db_ro = new_tab(0, 8) 9 | _M.hash = new_tab(0, 4) 10 | 11 | _M.db_rw.host = '127.0.0.1' 12 | _M.db_rw.port = 3306 13 | --_M.db_rw.path = '/var/lib/mysql/mysql.sock' 14 | _M.db_rw.database = 'ourl' 15 | _M.db_rw.user = 'ourl' 16 | _M.db_rw.password = '' 17 | 18 | _M.db_ro.host = '127.0.0.1' 19 | _M.db_ro.port = 3306 20 | --_M.db_ro.path = '/var/lib/mysql/mysql.sock' 21 | _M.db_ro.database = 'ourl' 22 | _M.db_ro.user = 'ourl' 23 | _M.db_ro.password = '' 24 | 25 | _M.hash.salt = 'ourl' 26 | _M.hash.length = 5 27 | _M.hash.alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' 28 | 29 | _M.proxies = { 30 | '127.0.0.0/8', 31 | '10.0.0.0/8', 32 | '172.16.0.0/12', 33 | '192.168.0.0/16', 34 | } 35 | 36 | _M.db.timeout = 1000 37 | _M.db.keepalive = 10000 38 | _M.db.poolsize = 10 39 | 40 | _M.log_level = ngx.ALERT 41 | _M.debug = false 42 | return _M -------------------------------------------------------------------------------- /nginx/html/ourl/js/index.js: -------------------------------------------------------------------------------- 1 | $('#shorten').click(function() { 2 | var raw_url = $('#url').val(); 3 | if (validator.isURL(raw_url)) { 4 | var url = encodeURIComponent(raw_url); 5 | $.getJSON( 6 | 'shorten?url=' + url, 7 | function (data) { 8 | if (data.status == 1) { 9 | $('#url').val(data.s_url); 10 | var qrcode = $('#qrcode'); 11 | qrcode.qrcode({ 12 | width: 200, 13 | height: 200, 14 | text: data.s_url 15 | }); 16 | qrcode.removeClass('am-hide') 17 | } else { 18 | alert(data.msg); 19 | } 20 | } 21 | ) 22 | } else { 23 | alert('请输入正确的url'); 24 | } 25 | }); 26 | 27 | $('#expand').click(function() { 28 | var s_url = $('#url').val(); 29 | $.getJSON( 30 | 'expand?s_url=' + encodeURIComponent(s_url), 31 | function(data) { 32 | if (data.status == 1) { 33 | $('#url').val(data.url); 34 | var qrcode = $('#qrcode'); 35 | qrcode.addClass('am-hide'); 36 | qrcode.html(''); 37 | } else { 38 | alert(data.msg); 39 | } 40 | } 41 | ) 42 | }); 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ourls-Resty 2 | 3 | [Ourls][1] 是由 [takashiki][2] 实现的一个基于发号和 hashid 的短网址服务。 4 | 受这个项目的启发,将此项目移植到 [OpenResty][3] 。 5 | 6 | 移植了原项目的功能和特性,并加入了内存缓存支持。 7 | 8 | ### 使用方法 9 | 10 | #### 环境 11 | - 安装 openresty [预编译包][9] (或 [手动编译教程][10]) 12 | - 安装 libidn : `yum install libidn` 13 | 14 | #### 安装 15 | - 使用 opm 包管理安装本库: `opm install xiaooloong/ourls-resty` 16 | - 安装 lua 库依赖: `luarocks install net-url && luarocks install router` 17 | - 参考 [hashids.lua][4] 的说明安装 hashids 18 | 19 | #### 配置 20 | - 进入工程目录 `/usr/local/openresty/site/lualib/ourl` 21 | - 复制 `config.sample.lua` 为 `config.lua` 22 | - 修改 `config.lua` 中的数据库配置、hashids 参数、可信代理服务器的 cidr 23 | - 恢复 `urls.sql` 至 `mysql` 或 `mariadb` 数据库 24 | - 进入 `/usr/local/openresty/nginx/conf` 目录 25 | - 根据自己的实际情况,配置静态文件,合并配置 26 | 27 | #### 完成 28 | - 启动 openresty (service openresty start) 29 | 30 | ### 使用到的其他项目 31 | 32 | - [leihog/hashids.lua][4] 33 | - [APItools/router.lua][5] 34 | - [golgote/neturl][6] 35 | - [hamishforbes/lua-resty-iputils][8] 36 | 37 | [1]: https://github.com/takashiki/Ourls 38 | [2]: https://github.com/takashiki 39 | [3]: http://openresty.org/ 40 | [4]: https://github.com/leihog/hashids.lua 41 | [5]: https://github.com/APItools/router.lua 42 | [6]: https://github.com/golgote/neturl 43 | [8]: https://github.com/hamishforbes/lua-resty-iputils 44 | [9]: http://openresty.org/cn/rpm-packages.html 45 | [10]: https://moonbingbing.gitbooks.io/openresty-best-practices/content/openresty/install_on_centos.html -------------------------------------------------------------------------------- /lualib/ourl/idna.lua: -------------------------------------------------------------------------------- 1 | local ffi = require 'ffi' 2 | local ffi_new = ffi.new 3 | local ffi_string = ffi.string 4 | local ffi_typeof = ffi.typeof 5 | local ffi_c = ffi.C 6 | local type = type 7 | local char = string.char 8 | ffi.cdef[[ 9 | void free (void *__ptr); 10 | int idna_to_ascii_8z (const char *input, char **output, int flags); 11 | int idna_to_unicode_8z8z (const char *input, char **output, int flags); 12 | ]] 13 | local idna = ffi.load('idn') 14 | local buff_ptr_type = ffi_typeof('char *[1]') 15 | 16 | local ok, new_tab = pcall(require, "table.new") 17 | if not ok or type(new_tab) ~= "function" then 18 | new_tab = function (narr, nrec) return {} end 19 | end 20 | 21 | local _M = new_tab(0, 4) 22 | 23 | _M._VERSION = '0.0.1' 24 | 25 | function _M.encode(text) 26 | if not text or 'string' ~= type(text) or 1 > #text then 27 | return nil, 'empty string' 28 | end 29 | text = text .. char(0) 30 | local buff_out = ffi_new(buff_ptr_type) 31 | local ok = idna.idna_to_ascii_8z(text, buff_out, 0) 32 | if 0 == ok then 33 | local str = ffi_string(buff_out[0]) 34 | ffi_c.free(buff_out[0]) 35 | return str 36 | else 37 | ffi_c.free(buff_out[0]) 38 | return nil, 'failed to encode' 39 | end 40 | end 41 | 42 | function _M.decode(text) 43 | if not text or 'string' ~= type(text) or 1 > #text then 44 | return nil, 'empty string' 45 | end 46 | text = text .. char(0) 47 | local buff_out = ffi_new(buff_ptr_type) 48 | local ok = idna.idna_to_unicode_8z8z(text, buff_out, 0) 49 | if 0 == ok then 50 | local str = ffi_string(buff_out[0]) 51 | ffi_c.free(buff_out[0]) 52 | return str 53 | else 54 | ffi_c.free(buff_out[0]) 55 | return nil, 'failed to encode' 56 | end 57 | end 58 | 59 | return _M -------------------------------------------------------------------------------- /nginx/html/ourl/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | Ourls 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Fork me on GitHub 34 | 35 | 36 |
37 |
38 |

Ourls

39 |

Url Shorten Service
基于发号加hash id的短网址服务

40 |
41 |
42 |
43 | 44 |
45 |
46 |
47 | 48 |
49 |
50 | 51 | 52 |
53 |
54 |
55 |
56 |

© 2016 Ourls . Licensed under MIT license.

57 |
58 |
59 | 60 | 61 | 62 | 63 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /nginx/conf/mime.types: -------------------------------------------------------------------------------- 1 | 2 | types { 3 | text/html html htm shtml; 4 | text/css css; 5 | text/xml xml; 6 | image/gif gif; 7 | image/jpeg jpeg jpg; 8 | application/javascript js; 9 | application/atom+xml atom; 10 | application/rss+xml rss; 11 | 12 | text/mathml mml; 13 | text/plain txt; 14 | text/vnd.sun.j2me.app-descriptor jad; 15 | text/vnd.wap.wml wml; 16 | text/x-component htc; 17 | 18 | image/png png; 19 | image/tiff tif tiff; 20 | image/vnd.wap.wbmp wbmp; 21 | image/x-icon ico; 22 | image/x-jng jng; 23 | image/x-ms-bmp bmp; 24 | image/svg+xml svg svgz; 25 | image/webp webp; 26 | 27 | application/font-woff woff; 28 | application/java-archive jar war ear; 29 | application/json json; 30 | application/mac-binhex40 hqx; 31 | application/msword doc; 32 | application/pdf pdf; 33 | application/postscript ps eps ai; 34 | application/rtf rtf; 35 | application/vnd.apple.mpegurl m3u8; 36 | application/vnd.ms-excel xls; 37 | application/vnd.ms-fontobject eot; 38 | application/vnd.ms-powerpoint ppt; 39 | application/vnd.wap.wmlc wmlc; 40 | application/vnd.google-earth.kml+xml kml; 41 | application/vnd.google-earth.kmz kmz; 42 | application/x-7z-compressed 7z; 43 | application/x-cocoa cco; 44 | application/x-java-archive-diff jardiff; 45 | application/x-java-jnlp-file jnlp; 46 | application/x-makeself run; 47 | application/x-perl pl pm; 48 | application/x-pilot prc pdb; 49 | application/x-rar-compressed rar; 50 | application/x-redhat-package-manager rpm; 51 | application/x-sea sea; 52 | application/x-shockwave-flash swf; 53 | application/x-stuffit sit; 54 | application/x-tcl tcl tk; 55 | application/x-x509-ca-cert der pem crt; 56 | application/x-xpinstall xpi; 57 | application/xhtml+xml xhtml; 58 | application/xspf+xml xspf; 59 | application/zip zip; 60 | 61 | application/octet-stream bin exe dll; 62 | application/octet-stream deb; 63 | application/octet-stream dmg; 64 | application/octet-stream iso img; 65 | application/octet-stream msi msp msm; 66 | 67 | application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; 68 | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx; 69 | application/vnd.openxmlformats-officedocument.presentationml.presentation pptx; 70 | 71 | audio/midi mid midi kar; 72 | audio/mpeg mp3; 73 | audio/ogg ogg; 74 | audio/x-m4a m4a; 75 | audio/x-realaudio ra; 76 | 77 | video/3gpp 3gpp 3gp; 78 | video/mp2t ts; 79 | video/mp4 mp4; 80 | video/mpeg mpeg mpg; 81 | video/quicktime mov; 82 | video/webm webm; 83 | video/x-flv flv; 84 | video/x-m4v m4v; 85 | video/x-mng mng; 86 | video/x-ms-asf asx asf; 87 | video/x-ms-wmv wmv; 88 | video/x-msvideo avi; 89 | } 90 | -------------------------------------------------------------------------------- /lualib/ourl/init.lua: -------------------------------------------------------------------------------- 1 | local config = require 'ourl.config' 2 | local router = require 'router' 3 | local hashid = require 'hashids' 4 | local neturl = require 'net.url' 5 | local idna = require 'ourl.idna' 6 | local iputil = require 'resty.iputils' 7 | local json = require 'cjson' 8 | local mysql = require 'resty.mysql' 9 | local r_sha1 = require 'resty.sha1' 10 | local r_str = require 'resty.string' 11 | local cache = ngx.shared.ourls 12 | 13 | local ok, new_tab = pcall(require, "table.new") 14 | if not ok or type(new_tab) ~= "function" then 15 | new_tab = function (narr, nrec) return {} end 16 | end 17 | 18 | local STATUS_ERR = 0 19 | local STATUS_OK = 1 20 | local r, h, db_rw, db_ro, base, proxy_whitelist 21 | 22 | local function log(...) 23 | ngx.log(config.log_level, json.encode({...})) 24 | end 25 | 26 | local function finish() 27 | for _, db in ipairs({db_rw, db_ro}) do 28 | db:set_keepalive(config.db.keepalive, config.db.poolsize) 29 | end 30 | end 31 | 32 | local function json_api(t) 33 | finish() 34 | if 'table' ~= type(t) then 35 | t = {t} 36 | end 37 | ngx.status = ngx.HTTP_OK 38 | ngx.header['Content-Type'] = 'application/json' 39 | ngx.print(json.encode(t)) 40 | return ngx.exit(ngx.status) 41 | end 42 | 43 | local function die(msg, code) 44 | code = code or STATUS_ERR 45 | msg = msg or '' 46 | json_api({ 47 | status = code, 48 | msg = msg 49 | }) 50 | end 51 | 52 | local function db_query(db, query) 53 | local ok, err = db:send_query(query) 54 | if not ok then 55 | log('failed to send query', query, err) 56 | die('数据库错误') 57 | end 58 | 59 | local res, err, errcode, sqlstate = db:read_result() 60 | if not res then 61 | log('failed to read result of query', query, errcode, err, sqlstate) 62 | die('数据库错误') 63 | elseif config.debug then 64 | log('[DEBUG]', query, res, errcode, err, sqlstate) 65 | end 66 | 67 | return res, err, errcode, sqlstate 68 | end 69 | 70 | local function ip2long(ip) 71 | local l = 0 72 | for v in ngx.re.gmatch(ip, [=[[^\.]+]=], 'o') do 73 | l = l * 256 + tonumber(v[0]) 74 | end 75 | return l 76 | end 77 | 78 | local function real_remote_addr() 79 | local ip = ngx.var.remote_addr 80 | local proxy = ngx.req.get_headers()['X-Forwarded-For'] 81 | if proxy then 82 | if 'table' == type(proxy) then 83 | proxy = proxy[1] 84 | end 85 | local pattern = [=[([0-9]{1,3}\.){3}[0-9]{1,3}]=] 86 | local m = ngx.re.match(proxy, pattern, 'o') 87 | if m then 88 | proxy = m[0] 89 | if iputil.ip_in_cidrs(ip, proxy_whitelist) then 90 | ip = proxy 91 | end 92 | end 93 | end 94 | return ip2long(ip) 95 | end 96 | 97 | local function url_modify(url, scheme) 98 | scheme = scheme or 'http' 99 | if not ngx.re.match(url, [[^https?://]], 'io') then 100 | url = scheme .. '://' .. url 101 | end 102 | url = neturl.parse(url) 103 | if not url.host then 104 | return nil 105 | end 106 | local ok, err = idna.encode(url.host) 107 | if ok then 108 | url.host = ok 109 | else 110 | if config.debug then 111 | log('[DEBUG]', url.host, err) 112 | end 113 | die('非法域名') 114 | end 115 | return tostring(url:normalize()) 116 | end 117 | 118 | local function shorten(params) 119 | local url = params.url 120 | if not url then 121 | die('请输入正确的 url') 122 | end 123 | if 'table' == type(url) then 124 | url = url[1] 125 | end 126 | url = url_modify(url) 127 | if not url then 128 | die('请输入正确的 url') 129 | end 130 | local pattern = ("^https?://%s/"):format(ngx.var.host) 131 | if ngx.re.match(url, pattern, 'o') then 132 | die('该地址不能被缩短') 133 | end 134 | local sha1 = r_sha1:new() 135 | sha1:update(url) 136 | local digest = r_str.to_hex(sha1:final()) 137 | local id = cache:get(digest) 138 | if not id then 139 | local query = "SELECT `id` FROM `urls` WHERE `sha1`=" .. ngx.quote_sql_str(digest) 140 | local res = db_query(db_ro, query) 141 | id = 0 142 | if #res > 0 then 143 | id = res[1]['id'] 144 | cache:set(digest, id) 145 | else 146 | local ip = real_remote_addr() 147 | local query = ("INSERT INTO `urls` (`sha1`, `url`, `create_at`, `creator`) VALUES (%s, %s, %s, %s)"):format( 148 | ngx.quote_sql_str(digest), 149 | ngx.quote_sql_str(url), 150 | ngx.quote_sql_str(ngx.time()), 151 | ngx.quote_sql_str(ip) 152 | ) 153 | local res = db_query(db_rw, query) 154 | id = res['insert_id'] 155 | cache:set(digest, id) 156 | end 157 | end 158 | id = tonumber(id) 159 | if not id then 160 | die('服务器错误') 161 | end 162 | local s = h:encode(id) 163 | json_api({ 164 | status = STATUS_OK, 165 | s_url = base .. s 166 | }) 167 | end 168 | 169 | local function expand(params) 170 | local s = params.s_url 171 | if not s then 172 | die('请传入短链接') 173 | end 174 | if 'table' == type(s) then 175 | s = s[1] 176 | end 177 | local pattern = ("^https?://%s/([%s]+)$"):format( 178 | ngx.var.host, 179 | config.hash.alphabet 180 | ) 181 | local m = ngx.re.match(s, pattern, 'o') 182 | if m then 183 | s = m[1] 184 | local id = h:decode(s) 185 | if not id or not id[1] then 186 | die('短地址无法解析') 187 | end 188 | local url = cache:get(id[1]) 189 | if not url then 190 | local query = "SELECT `url` FROM `urls` WHERE `id`=" .. ngx.quote_sql_str(id[1]) 191 | local res = db_query(db_ro, query) 192 | if #res > 0 then 193 | url = res[1]['url'] 194 | cache:set(id[1], url) 195 | else 196 | die('地址不存在') 197 | end 198 | end 199 | json_api({ 200 | status = STATUS_OK, 201 | url = url 202 | }) 203 | else 204 | die('请传入正确的短链接') 205 | end 206 | end 207 | 208 | local function redirect(params) 209 | local hash = params.hash 210 | if not hash then 211 | die('请传入短地址') 212 | end 213 | if 'table' == type(hash) then 214 | hash = hash[1] 215 | end 216 | local id = h:decode(hash) 217 | if not id or not id[1] then 218 | die('请传入正确的短地址') 219 | end 220 | local url = cache:get(id[1]) 221 | if not url then 222 | local query = "SELECT `url` FROM `urls` WHERE `id`=" .. ngx.quote_sql_str(id[1]) 223 | local res = db_query(db_ro, query) 224 | if #res > 0 then 225 | url = res[1]['url'] 226 | cache:set(id[1], url) 227 | else 228 | die('地址不存在') 229 | end 230 | end 231 | local query = "UPDATE `urls` SET `count`=`count`+1 WHERE `id`=" .. ngx.quote_sql_str(id[1]) 232 | db_query(db_rw, query) 233 | finish() 234 | ngx.redirect(url, ngx.HTTP_MOVED_TEMPORARILY) 235 | end 236 | local _M = new_tab(0, 8) 237 | 238 | _M._VERSION = '0.3.2' 239 | 240 | local function prepare() 241 | local err 242 | db_rw, err = mysql:new() 243 | if not db_rw then 244 | log('failed to init mysql master', err) 245 | die('数据库错误') 246 | end 247 | db_ro, err = mysql:new() 248 | if not db_ro then 249 | log('failed to init mysql slave', err) 250 | die('数据库错误') 251 | end 252 | for name, db in pairs({db_rw = db_rw, db_ro = db_ro}) do 253 | db:set_timeout(config.db.timeout) 254 | local ok, err, errcode, sqlstate = db:connect(config[name]) 255 | if not ok then 256 | log('failed to connect to mysql', name, errcode, err, sqlstate) 257 | die('数据库错误') 258 | end 259 | local count 260 | count, err = db:get_reused_times() 261 | if 0 == count then 262 | db_query(db, [[SET NAMES 'utf8';]]) 263 | elseif err then 264 | log('failed to get reused times', name, err) 265 | die('数据库错误') 266 | end 267 | end 268 | 269 | if not r then 270 | r = router.new() 271 | r:get('/shorten', shorten) 272 | r:get('/expand', expand) 273 | r:get('/:hash', redirect) 274 | end 275 | if not h then 276 | h = hashid.new(config.hash.salt, config.hash.length, config.hash.alphabet) 277 | end 278 | if not base then 279 | base = ("%s://%s/"):format(ngx.var.scheme, ngx.var.host) 280 | end 281 | if not proxy_whitelist then 282 | proxy_whitelist = iputil.parse_cidrs(config.proxies) 283 | end 284 | ngx.req.read_body() 285 | end 286 | 287 | function _M.run() 288 | prepare() 289 | local ok, err = r:execute( 290 | ngx.var.request_method, 291 | ngx.var.uri, 292 | ngx.req.get_uri_args(), 293 | ngx.req.get_post_args() 294 | ) 295 | if not ok then 296 | if config.debug then 297 | die('服务器错误: ' .. err) 298 | else 299 | finish() 300 | ngx.status = ngx.HTTP_NOT_FOUND 301 | return ngx.exit(ngx.status) 302 | end 303 | end 304 | end 305 | 306 | return _M --------------------------------------------------------------------------------