From 4d43fb0c644d7b8485360805dae2f6919474a4e5 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Tue, 7 Apr 2015 09:42:46 -0500 Subject: [PATCH] Updating modules --- debian/changelog | 10 +- debian/modules/README.Modules-versions | 27 +- debian/modules/nginx-auth-pam/ChangeLog | 6 + debian/modules/nginx-auth-pam/LICENSE | 2 +- .../nginx-auth-pam/{README => README.md} | 71 +- .../nginx-auth-pam/ngx_http_auth_pam_module.c | 31 +- debian/modules/nginx-cache-purge/CHANGES | 10 + debian/modules/nginx-cache-purge/LICENSE | 4 +- debian/modules/nginx-cache-purge/README.md | 15 +- .../ngx_cache_purge_module.c | 624 +++- .../nginx-cache-purge/t/{proxy.t => proxy1.t} | 26 +- .../modules/nginx-cache-purge/t/proxy1_vars.t | 138 + debian/modules/nginx-cache-purge/t/proxy2.t | 56 +- .../modules/nginx-cache-purge/t/proxy2_vars.t | 353 +++ debian/modules/nginx-echo/.gitignore | 65 + debian/modules/nginx-echo/LICENSE | 7 +- debian/modules/nginx-echo/README.markdown | 14 +- .../nginx-echo/doc/HttpEchoModule.wiki | 14 +- .../src/ngx_http_echo_request_info.c | 49 +- debian/modules/nginx-echo/t/request-info.t | 98 +- debian/modules/nginx-echo/util/build.sh | 2 +- debian/modules/nginx-echo/util/releng | 8 - debian/modules/nginx-lua/.gitignore | 164 + debian/modules/nginx-lua/README.markdown | 2795 +++++++++-------- .../modules/nginx-lua/doc/HttpLuaModule.wiki | 96 +- .../nginx-lua/misc/recv-until-pm/Makefile | 3 - .../nginx-lua/src/api/ngx_http_lua_api.h | 2 +- .../nginx-lua/src/ngx_http_lua_common.h | 10 +- .../nginx-lua/src/ngx_http_lua_control.c | 26 +- .../src/ngx_http_lua_headerfilterby.c | 18 +- .../nginx-lua/src/ngx_http_lua_headers_out.c | 30 +- .../nginx-lua/src/ngx_http_lua_regex.c | 9 +- .../nginx-lua/src/ngx_http_lua_shdict.c | 8 +- .../nginx-lua/src/ngx_http_lua_socket_tcp.c | 11 +- .../nginx-lua/src/ngx_http_lua_string.c | 4 +- .../nginx-lua/src/ngx_http_lua_timer.c | 41 +- .../modules/nginx-lua/src/ngx_http_lua_util.c | 11 +- .../modules/nginx-lua/src/ngx_http_lua_util.h | 1 + debian/modules/nginx-lua/t/014-bugs.t | 2 +- debian/modules/nginx-lua/t/016-resp-header.t | 40 +- debian/modules/nginx-lua/t/022-redirect.t | 2 +- .../nginx-lua/t/023-rewrite/redirect.t | 2 +- debian/modules/nginx-lua/t/024-access/auth.t | 2 +- .../modules/nginx-lua/t/024-access/redirect.t | 2 +- debian/modules/nginx-lua/t/036-sub.t | 84 +- debian/modules/nginx-lua/t/037-gsub.t | 104 +- .../modules/nginx-lua/t/041-header-filter.t | 27 +- debian/modules/nginx-lua/t/058-tcp-socket.t | 46 +- .../modules/nginx-lua/t/115-quote-sql-str.t | 4 +- .../nginx-lua/t/128-duplex-tcp-socket.t | 2 +- debian/modules/nginx-lua/t/130-internal-api.t | 50 + debian/modules/nginx-lua/util/reindex | 64 - debian/modules/nginx-lua/util/releng | 8 - debian/modules/ngx-fancyindex/.gitignore | 1 + debian/modules/ngx-fancyindex/.todo | 42 - debian/modules/ngx-fancyindex/CHANGELOG.md | 37 + debian/modules/ngx-fancyindex/HACKING.md | 24 + debian/modules/ngx-fancyindex/HACKING.rst | 33 - debian/modules/ngx-fancyindex/NEWS.rst | 25 - debian/modules/ngx-fancyindex/README.rst | 29 + .../ngx_http_fancyindex_module.c | 97 +- 61 files changed, 3700 insertions(+), 1886 deletions(-) rename debian/modules/nginx-auth-pam/{README => README.md} (61%) rename debian/modules/nginx-cache-purge/t/{proxy.t => proxy1.t} (81%) create mode 100644 debian/modules/nginx-cache-purge/t/proxy1_vars.t create mode 100644 debian/modules/nginx-cache-purge/t/proxy2_vars.t create mode 100644 debian/modules/nginx-echo/.gitignore delete mode 100755 debian/modules/nginx-echo/util/releng create mode 100644 debian/modules/nginx-lua/.gitignore delete mode 100644 debian/modules/nginx-lua/misc/recv-until-pm/Makefile create mode 100644 debian/modules/nginx-lua/t/130-internal-api.t delete mode 100755 debian/modules/nginx-lua/util/reindex delete mode 100755 debian/modules/nginx-lua/util/releng create mode 100644 debian/modules/ngx-fancyindex/.gitignore delete mode 100644 debian/modules/ngx-fancyindex/.todo create mode 100644 debian/modules/ngx-fancyindex/CHANGELOG.md create mode 100644 debian/modules/ngx-fancyindex/HACKING.md delete mode 100644 debian/modules/ngx-fancyindex/HACKING.rst delete mode 100644 debian/modules/ngx-fancyindex/NEWS.rst diff --git a/debian/changelog b/debian/changelog index 5d3b367..6fb9f11 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.6.2-8) UNRELEASED; urgency=medium +nginx (1.6.2-9) UNRELEASED; urgency=medium [ Michael Lustfield ] * debian/conf/nginx.conf: @@ -6,6 +6,12 @@ nginx (1.6.2-8) UNRELEASED; urgency=medium * debian/conf/sites-available/default: + Add comment about disabling gzip in HTTPS. (Closes: #773332) + Add comment about checking ssl_ciphers. (Closes: #765782) + * debian/modules/*: + + Updated nginx-auth-pam 1.3 -> 1.4. (Closes: #777120) + + Updated nginx-echo v0.56 -> v0.57. + + Updated nginx-lua v0.9.13 -> v0.9.15. + + Updated nginx-cache-purge 2.1 -> 2.3. + + Updated ngx-fancyindex v0.3.4 -> v0.3.5. * debian/nginx-common.{dirs,install}, debian/vim/*: + Installing vim syntax highlighting from package. (Closes: #771609) Thanks Emmanuel Bouthenot for building this patch. @@ -26,7 +32,7 @@ nginx (1.6.2-8) UNRELEASED; urgency=medium * debian/nginx-common.manpages: + Replaced man page with upstream maintained version. (Closes: #781345) - -- Michael Lustfield Tue, 07 Apr 2015 08:23:00 -0500 + -- Michael Lustfield Tue, 07 Apr 2015 09:39:52 -0500 nginx (1.6.2-5) unstable; urgency=medium diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index d4bd95c..c95c897 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -5,44 +5,41 @@ README for Modules versions version. headers-more-nginx-module - https://github.com/agentzh/headers-more-nginx-module + Homepage: https://github.com/agentzh/headers-more-nginx-module Version: v0.25 nginx-development-kit - https://github.com/simpl/ngx_devel_kit/ + Homepage: https://github.com/simpl/ngx_devel_kit/ Version: v0.2.19 nginx-auth-pam - http://web.iti.upv.es/~sto/nginx/ - Version: 1.3 + Homepage: https://github.com/stogh/ngx_http_auth_pam_module + Version: 1.4 nginx-echo - https://github.com/agentzh/echo-nginx-module - Version: v0.56 + Homepage: https://github.com/agentzh/echo-nginx-module + Version: v0.57 nginx-lua Homepage: https://github.com/openresty/lua-nginx-module - https://github.com/openresty/lua-nginx-module.git - Version: v0.9.13 + Version: v0.9.15 nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair Version: a18b409 nginx-push - Homepage: http://pushmodule.slact.net/#download - https://github.com/slact/nginx_http_push_module/archive/v0.711.tar.gz + Homepage: https://github.com/slact/nginx_http_push_module Version: 0.73 nginx-upload-progress Homepage: https://github.com/masterzen/nginx-upload-progress-module - https://nodeload.github.com/masterzen/nginx-upload-progress-module/tarball/master - rm -r debian/nginx-upload-progress/test + rm -r debian/nginx-upload-progress/test Version: v0.9.1 nginx-cache-purge - Homepage: http://labs.frickle.com/nginx_ngx_cache_purge/ - Version: 2.1 + Homepage: https://github.com/FRiCKLE/ngx_cache_purge/ + Version: 2.3 nginx-dav-ext-module Homepage: https://github.com/arut/nginx-dav-ext-module @@ -50,7 +47,7 @@ README for Modules versions ngx-fancyindex Homepage: https://github.com/aperezdc/ngx-fancyindex - Version: v0.3.4 + Version: v0.3.5 ngx_http_substitutions_filter_module Homepage: https://github.com/yaoweibin/ngx_http_substitutions_filter_module diff --git a/debian/modules/nginx-auth-pam/ChangeLog b/debian/modules/nginx-auth-pam/ChangeLog index 5c49312..466bd9c 100644 --- a/debian/modules/nginx-auth-pam/ChangeLog +++ b/debian/modules/nginx-auth-pam/ChangeLog @@ -1,3 +1,9 @@ +2015-02-04 sto@iti.es + + * Version 1.4. + * Cleanup PAM responses on error, the module was not doing it, causing + memory leaks (thanks to Michael Koziarski for the report). + 2013-09-17 sto@iti.es * Version 1.3. diff --git a/debian/modules/nginx-auth-pam/LICENSE b/debian/modules/nginx-auth-pam/LICENSE index fd15a67..f5be528 100644 --- a/debian/modules/nginx-auth-pam/LICENSE +++ b/debian/modules/nginx-auth-pam/LICENSE @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 Sergio Talens Oliag + * Copyright (C) 2008-2015 Sergio Talens Oliag * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/debian/modules/nginx-auth-pam/README b/debian/modules/nginx-auth-pam/README.md similarity index 61% rename from debian/modules/nginx-auth-pam/README rename to debian/modules/nginx-auth-pam/README.md index b47f167..c6d58f0 100644 --- a/debian/modules/nginx-auth-pam/README +++ b/debian/modules/nginx-auth-pam/README.md @@ -1,15 +1,12 @@ -Nginx module to use PAM for simple http authentication -====================================================== +# ngx_http_auth_pam_module -:Date: $Date: 2013-09-17 12:00:49 +0200 (dt 17 de set de 2013) $ -:Revision: $Rev: 7626 $ +## Nginx module to use PAM for simple http authentication -Compilation ------------ +### Compilation -When compiling from source build as usual adding the -add-module option:: +When compiling from source build as usual adding the -add-module option: - ./configure --add-module=$PATH_TO_MODULE + ./configure --add-module=$PATH_TO_MODULE If you are using a Debian GNU/Linux distribution install the nginx-full package; the module has been included in the nginx debian package since version 1.1.6-1 @@ -17,8 +14,7 @@ and there are newer packages on the stable distribution (wheezy) and the wheezy version is also available from the oldstable backports repository (squeeze-backports). -Configuration -------------- +### Configuration The module only has two directives: @@ -29,16 +25,15 @@ The module only has two directives: - ``auth_pam_service_name``: this is the PAM service name and by default it is set to ``nginx``. -Examples --------- +### Examples To protect everything under ``/secure`` you will add the following to the -``nginx.conf`` file:: +``nginx.conf`` file: - location /secure { - auth_pam "Secure Zone"; - auth_pam_service_name "nginx"; - } + location /secure { + auth_pam "Secure Zone"; + auth_pam_service_name "nginx"; + } Note that the module runs as the web server user, so the PAM modules used must be able to authenticate the users without being root; that means that if you @@ -47,33 +42,32 @@ web server user to read the ``/etc/shadow`` file if that does not scare you (on Debian like systems you can add the ``www-data`` user to the ``shadow`` group). As an example, to authenticate users against an LDAP server (using the -``pam_ldap.so`` module) you will use an ``/etc/pam.d/nginx`` like the following:: +``pam_ldap.so`` module) you will use an ``/etc/pam.d/nginx`` like the +following: - auth required /lib/security/pam_ldap.so - account required /lib/security/pam_ldap.so + auth required /lib/security/pam_ldap.so + account required /lib/security/pam_ldap.so If you also want to limit the users from LDAP that can authenticate you can use the ``pam_listfile.so`` module; to limit who can access resources under -``/restricted`` add the following to the ``nginx.conf`` file:: +``/restricted`` add the following to the ``nginx.conf`` file: - location /restricted { - auth_pam "Restricted Zone"; - auth_pam_service_name "nginx_restricted"; - } + location /restricted { + auth_pam "Restricted Zone"; + auth_pam_service_name "nginx_restricted"; + } -Use the following ``/etc/pam.d/nginx_restricted`` file:: +Use the following ``/etc/pam.d/nginx_restricted`` file: - auth required /lib/security/pam_listfile.so onerr=fail item=user \ - sense=allow file=/etc/nginx/restricted_users - auth required /lib/security/pam_ldap.so - account required /lib/security/pam_ldap.so + auth required /lib/security/pam_listfile.so onerr=fail item=user \ + sense=allow file=/etc/nginx/restricted_users + auth required /lib/security/pam_ldap.so + account required /lib/security/pam_ldap.so And add the users allowed to authenticate to the ``/etc/nginx/restricted_users`` (remember that the web server user has to be able to read this file). - -PAM Environment ---------------- +### PAM Environment If you want use the ``pam_exec.so`` plugin for request based authentication the module can add to the PAM environment the ``HOST`` and ``REQUEST`` variables if @@ -87,16 +81,13 @@ you set the ``auth_pam_set_pam_env`` flag:: With this configuration if you access an URL like: - http://localhost:8000/pam_exec_protected/page?foo=yes&bar=too + http://localhost:8000/pam_exec_protected/page?foo=yes&bar=too -the PAM environment will include the following variables:: +the PAM environment will include the following variables: - HOST=localhost:8000 - REQUEST=GET /pam_exec_protected/page?foo=yes&bar=too HTTP/1.1 + HOST=localhost:8000 + REQUEST=GET /pam_exec_protected/page?foo=yes&bar=too HTTP/1.1 You may use this information for request based authentication. You need a recent pam release (>= version 1.0.90) to expose environment variables to pam_exec. - -.. ...... -.. SVN Id: $Id: README 7626 2013-09-17 10:00:49Z sto $ diff --git a/debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c b/debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c index 08fe1f6..a49d7a6 100644 --- a/debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c +++ b/debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c @@ -1,10 +1,10 @@ /* - * Copyright (C) 2008-2013 Sergio Talens-Oliag + * Copyright (C) 2008-2015 Sergio Talens-Oliag * * Based on nginx's 'ngx_http_auth_basic_module.c' by Igor Sysoev and apache's * 'mod_auth_pam.c' by Ingo Luetkebolhe. * - * SVN Id: $Id: ngx_http_auth_pam_module.c 7626 2013-09-17 10:00:49Z sto $ + * File: ngx_http_auth_pam_module.c */ #include @@ -118,6 +118,27 @@ ngx_module_t ngx_http_auth_pam_module = { NGX_MODULE_V1_PADDING }; + +/* + * Function to free PAM_CONV responses if an error is returned. + */ +static void +free_resp(int num_msg, struct pam_response *response) +{ + int i; + if (response == NULL) + return; + for (i = 0; i < num_msg; i++) { + if (response[i].resp) { + /* clear before freeing -- may be a password */ + bzero(response[i].resp, strlen(response[i].resp)); + free(response[i].resp); + response[i].resp = NULL; + } + } + free(response); +} + /* * ngx_auth_pam_talker: supply authentication information to PAM when asked * @@ -161,9 +182,7 @@ ngx_auth_pam_talker(int num_msg, const struct pam_message ** msg, response[i].resp = strdup((const char *)uinfo->password.data); break; default: - if (response) { - free(response); - } + free_resp(i, response); return PAM_CONV_ERR; } } @@ -440,4 +459,4 @@ ngx_http_auth_pam(ngx_conf_t *cf, void *post, void *data) return NGX_CONF_OK; } -/* SVN Id: $Id: ngx_http_auth_pam_module.c 7626 2013-09-17 10:00:49Z sto $ */ +/* File: ngx_http_auth_pam_module.c */ diff --git a/debian/modules/nginx-cache-purge/CHANGES b/debian/modules/nginx-cache-purge/CHANGES index 4dea592..ead3cdf 100644 --- a/debian/modules/nginx-cache-purge/CHANGES +++ b/debian/modules/nginx-cache-purge/CHANGES @@ -1,3 +1,13 @@ +2014-12-23 VERSION 2.3 + * Fix compatibility with nginx-1.7.9+. + +2014-12-02 VERSION 2.2 + * Fix compatibility with nginx-1.7.8+. + +2014-05-19 + * Fix build on Solaris with SunCC (Solaris Studio). + Reported by Jussi Sallinen. + 2013-03-19 VERSION 2.1 * When enabled, cache purge will now catch all requests with PURGE (or specified) method, even if cache isn't configured. diff --git a/debian/modules/nginx-cache-purge/LICENSE b/debian/modules/nginx-cache-purge/LICENSE index a9bd6ee..0047538 100644 --- a/debian/modules/nginx-cache-purge/LICENSE +++ b/debian/modules/nginx-cache-purge/LICENSE @@ -1,5 +1,5 @@ -Copyright (c) 2009-2012, FRiCKLE -Copyright (c) 2009-2012, Piotr Sikora +Copyright (c) 2009-2014, FRiCKLE +Copyright (c) 2009-2014, Piotr Sikora All rights reserved. This project was fully funded by yo.se. diff --git a/debian/modules/nginx-cache-purge/README.md b/debian/modules/nginx-cache-purge/README.md index 89d84e0..3b42e32 100644 --- a/debian/modules/nginx-cache-purge/README.md +++ b/debian/modules/nginx-cache-purge/README.md @@ -11,16 +11,7 @@ Work on the original patch was fully funded by [yo.se](http://yo.se). Status ====== -This module is production-ready and it's compatible with following nginx -releases: - -- 0.7.x (tested with 0.7.60 to 0.7.69), -- 0.8.x (tested with 0.8.0 to 0.8.55), -- 0.9.x (tested with 0.9.0 to 0.9.7), -- 1.0.x (tested with 1.0.0 to 1.0.15), -- 1.1.x (tested with 1.1.0 to 1.1.19), -- 1.2.x (tested with 1.2.0 to 1.2.7), -- 1.3.x (tested with 1.3.0 to 1.3.14). +This module is production-ready. Configuration directives (same location syntax) @@ -147,8 +138,8 @@ You can test it by running: License ======= - Copyright (c) 2009-2012, FRiCKLE - Copyright (c) 2009-2012, Piotr Sikora + Copyright (c) 2009-2014, FRiCKLE + Copyright (c) 2009-2014, Piotr Sikora All rights reserved. This project was fully funded by yo.se. diff --git a/debian/modules/nginx-cache-purge/ngx_cache_purge_module.c b/debian/modules/nginx-cache-purge/ngx_cache_purge_module.c index be51a7d..62d3818 100644 --- a/debian/modules/nginx-cache-purge/ngx_cache_purge_module.c +++ b/debian/modules/nginx-cache-purge/ngx_cache_purge_module.c @@ -1,6 +1,6 @@ /* - * Copyright (c) 2009-2012, FRiCKLE - * Copyright (c) 2009-2012, Piotr Sikora + * Copyright (c) 2009-2014, FRiCKLE + * Copyright (c) 2009-2014, Piotr Sikora * All rights reserved. * * This project was fully funded by yo.se. @@ -33,6 +33,11 @@ #include +#ifndef nginx_version +#error This module cannot be build against an unknown nginx version. +#endif + + #if (NGX_HTTP_CACHE) typedef struct { @@ -90,6 +95,10 @@ ngx_int_t ngx_http_cache_purge_access(ngx_array_t *a, ngx_array_t *a6, struct sockaddr *s); ngx_int_t ngx_http_cache_purge_send_response(ngx_http_request_t *r); +# if (nginx_version >= 1007009) +ngx_int_t ngx_http_cache_purge_cache_get(ngx_http_request_t *r, + ngx_http_upstream_t *u, ngx_http_file_cache_t **cache); +# endif /* nginx_version >= 1007009 */ ngx_int_t ngx_http_cache_purge_init(ngx_http_request_t *r, ngx_http_file_cache_t *cache, ngx_http_complex_value_t *cache_key); void ngx_http_cache_purge_handler(ngx_http_request_t *r); @@ -190,26 +199,52 @@ CRLF "" CRLF # if (NGX_HTTP_FASTCGI) extern ngx_module_t ngx_http_fastcgi_module; +# if (nginx_version >= 1007009) + +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_fastcgi_main_conf_t; + +# endif /* nginx_version >= 1007009 */ + +# if (nginx_version >= 1007008) + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_uint_t number; + ngx_hash_t hash; +} ngx_http_fastcgi_params_t; + +# endif /* nginx_version >= 1007008 */ + typedef struct { ngx_http_upstream_conf_t upstream; ngx_str_t index; +# if (nginx_version >= 1007008) + ngx_http_fastcgi_params_t params; + ngx_http_fastcgi_params_t params_cache; +# else ngx_array_t *flushes; ngx_array_t *params_len; ngx_array_t *params; +# endif /* nginx_version >= 1007008 */ + ngx_array_t *params_source; ngx_array_t *catch_stderr; ngx_array_t *fastcgi_lengths; ngx_array_t *fastcgi_values; -# if defined(nginx_version) && (nginx_version >= 8040) +# if (nginx_version >= 8040) && (nginx_version < 1007008) ngx_hash_t headers_hash; ngx_uint_t header_params; -# endif /* nginx_version >= 8040 */ +# endif /* nginx_version >= 8040 && nginx_version < 1007008 */ -# if defined(nginx_version) && (nginx_version >= 1001004) +# if (nginx_version >= 1001004) ngx_flag_t keep_conn; # endif /* nginx_version >= 1001004 */ @@ -230,6 +265,9 @@ ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, ngx_http_core_loc_conf_t *clcf; ngx_http_fastcgi_loc_conf_t *flcf; ngx_str_t *value; +# if (nginx_version >= 1007009) + ngx_http_complex_value_t cv; +# endif /* nginx_version >= 1007009 */ cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); @@ -248,8 +286,12 @@ ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, flcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_fastcgi_module); +# if (nginx_version >= 1007009) + if (flcf->upstream.cache > 0) +# else if (flcf->upstream.cache != NGX_CONF_UNSET_PTR && flcf->upstream.cache != NULL) +# endif /* nginx_version >= 1007009 */ { return "is incompatible with \"fastcgi_cache\""; } @@ -258,19 +300,61 @@ ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, return "is incompatible with \"fastcgi_pass\""; } - if (flcf->upstream.store > 0 || flcf->upstream.store_lengths) { + if (flcf->upstream.store > 0 +# if (nginx_version < 1007009) + || flcf->upstream.store_lengths +# endif /* nginx_version >= 1007009 */ + ) + { return "is incompatible with \"fastcgi_store\""; } value = cf->args->elts; /* set fastcgi_cache part */ +# if (nginx_version >= 1007009) + + flcf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + flcf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (flcf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *flcf->upstream.cache_value = cv; + + } else { + + flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_fastcgi_module); + if (flcf->upstream.cache_zone == NULL) { + return NGX_CONF_ERROR; + } + } + +# else + flcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, &ngx_http_fastcgi_module); if (flcf->upstream.cache == NULL) { return NGX_CONF_ERROR; } +# endif /* nginx_version >= 1007009 */ + /* set fastcgi_cache_key part */ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); @@ -294,18 +378,43 @@ ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, ngx_int_t ngx_http_fastcgi_cache_purge_handler(ngx_http_request_t *r) { - ngx_http_fastcgi_loc_conf_t *flcf; + ngx_http_file_cache_t *cache; + ngx_http_fastcgi_loc_conf_t *flcf; +# if (nginx_version >= 1007009) + ngx_http_fastcgi_main_conf_t *fmcf; + ngx_int_t rc; +# endif /* nginx_version >= 1007009 */ - flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); - - if (ngx_http_cache_purge_init(r, flcf->upstream.cache->data, - &flcf->cache_key) - != NGX_OK) - { + if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } -# if defined(nginx_version) && (nginx_version >= 8011) + flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); + + r->upstream->conf = &flcf->upstream; + +# if (nginx_version >= 1007009) + + fmcf = ngx_http_get_module_main_conf(r, ngx_http_fastcgi_module); + + r->upstream->caches = &fmcf->caches; + + rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); + if (rc != NGX_OK) { + return rc; + } + +# else + + cache = flcf->upstream.cache->data; + +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_cache_purge_init(r, cache, &flcf->cache_key) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + +# if (nginx_version >= 8011) r->main->count++; # endif @@ -326,18 +435,47 @@ typedef struct { ngx_str_t uri; } ngx_http_proxy_vars_t; +# if (nginx_version >= 1007009) + +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_proxy_main_conf_t; + +# endif /* nginx_version >= 1007009 */ + +# if (nginx_version >= 1007008) + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_hash_t hash; +} ngx_http_proxy_headers_t; + +# endif /* nginx_version >= 1007008 */ + typedef struct { ngx_http_upstream_conf_t upstream; +# if (nginx_version >= 1007008) + ngx_array_t *body_flushes; + ngx_array_t *body_lengths; + ngx_array_t *body_values; + ngx_str_t body_source; + + ngx_http_proxy_headers_t headers; + ngx_http_proxy_headers_t headers_cache; +# else ngx_array_t *flushes; ngx_array_t *body_set_len; ngx_array_t *body_set; ngx_array_t *headers_set_len; ngx_array_t *headers_set; ngx_hash_t headers_set_hash; +# endif /* nginx_version >= 1007008 */ ngx_array_t *headers_source; -# if defined(nginx_version) && (nginx_version < 8040) +# if (nginx_version < 8040) ngx_array_t *headers_names; # endif /* nginx_version < 8040 */ @@ -345,12 +483,14 @@ typedef struct { ngx_array_t *proxy_values; ngx_array_t *redirects; -# if defined(nginx_version) && (nginx_version >= 1001015) +# if (nginx_version >= 1001015) ngx_array_t *cookie_domains; ngx_array_t *cookie_paths; # endif /* nginx_version >= 1001015 */ +# if (nginx_version < 1007008) ngx_str_t body_source; +# endif /* nginx_version < 1007008 */ ngx_str_t method; ngx_str_t location; @@ -362,12 +502,30 @@ typedef struct { ngx_flag_t redirect; -# if defined(nginx_version) && (nginx_version >= 1001004) +# if (nginx_version >= 1001004) ngx_uint_t http_version; # endif /* nginx_version >= 1001004 */ ngx_uint_t headers_hash_max_size; ngx_uint_t headers_hash_bucket_size; + +# if (NGX_HTTP_SSL) +# if (nginx_version >= 1005006) + ngx_uint_t ssl; + ngx_uint_t ssl_protocols; + ngx_str_t ssl_ciphers; +# endif /* nginx_version >= 1005006 */ +# if (nginx_version >= 1007000) + ngx_uint_t ssl_verify_depth; + ngx_str_t ssl_trusted_certificate; + ngx_str_t ssl_crl; +# endif /* nginx_version >= 1007000 */ +# if (nginx_version >= 1007008) + ngx_str_t ssl_certificate; + ngx_str_t ssl_certificate_key; + ngx_array_t *ssl_passwords; +# endif /* nginx_version >= 1007008 */ +# endif } ngx_http_proxy_loc_conf_t; char * @@ -378,6 +536,9 @@ ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_http_core_loc_conf_t *clcf; ngx_http_proxy_loc_conf_t *plcf; ngx_str_t *value; +# if (nginx_version >= 1007009) + ngx_http_complex_value_t cv; +# endif /* nginx_version >= 1007009 */ cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); @@ -396,8 +557,12 @@ ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) plcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_proxy_module); +# if (nginx_version >= 1007009) + if (plcf->upstream.cache > 0) +# else if (plcf->upstream.cache != NGX_CONF_UNSET_PTR && plcf->upstream.cache != NULL) +# endif /* nginx_version >= 1007009 */ { return "is incompatible with \"proxy_cache\""; } @@ -406,19 +571,61 @@ ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return "is incompatible with \"proxy_pass\""; } - if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) { + if (plcf->upstream.store > 0 +# if (nginx_version < 1007009) + || plcf->upstream.store_lengths +# endif /* nginx_version >= 1007009 */ + ) + { return "is incompatible with \"proxy_store\""; } value = cf->args->elts; /* set proxy_cache part */ +# if (nginx_version >= 1007009) + + plcf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + plcf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (plcf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *plcf->upstream.cache_value = cv; + + } else { + + plcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_proxy_module); + if (plcf->upstream.cache_zone == NULL) { + return NGX_CONF_ERROR; + } + } + +# else + plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, &ngx_http_proxy_module); if (plcf->upstream.cache == NULL) { return NGX_CONF_ERROR; } +# endif /* nginx_version >= 1007009 */ + /* set proxy_cache_key part */ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); @@ -442,18 +649,43 @@ ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_int_t ngx_http_proxy_cache_purge_handler(ngx_http_request_t *r) { - ngx_http_proxy_loc_conf_t *plcf; + ngx_http_file_cache_t *cache; + ngx_http_proxy_loc_conf_t *plcf; +# if (nginx_version >= 1007009) + ngx_http_proxy_main_conf_t *pmcf; + ngx_int_t rc; +# endif /* nginx_version >= 1007009 */ - plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); - - if (ngx_http_cache_purge_init(r, plcf->upstream.cache->data, - &plcf->cache_key) - != NGX_OK) - { + if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } -# if defined(nginx_version) && (nginx_version >= 8011) + plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + + r->upstream->conf = &plcf->upstream; + +# if (nginx_version >= 1007009) + + pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module); + + r->upstream->caches = &pmcf->caches; + + rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); + if (rc != NGX_OK) { + return rc; + } + +# else + + cache = plcf->upstream.cache->data; + +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_cache_purge_init(r, cache, &plcf->cache_key) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + +# if (nginx_version >= 8011) r->main->count++; # endif @@ -466,9 +698,34 @@ ngx_http_proxy_cache_purge_handler(ngx_http_request_t *r) # if (NGX_HTTP_SCGI) extern ngx_module_t ngx_http_scgi_module; +# if (nginx_version >= 1007009) + +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_scgi_main_conf_t; + +# endif /* nginx_version >= 1007009 */ + +# if (nginx_version >= 1007008) + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_uint_t number; + ngx_hash_t hash; +} ngx_http_scgi_params_t; + +# endif /* nginx_version >= 1007008 */ + typedef struct { ngx_http_upstream_conf_t upstream; +# if (nginx_version >= 1007008) + ngx_http_scgi_params_t params; + ngx_http_scgi_params_t params_cache; + ngx_array_t *params_source; +# else ngx_array_t *flushes; ngx_array_t *params_len; ngx_array_t *params; @@ -476,6 +733,7 @@ typedef struct { ngx_hash_t headers_hash; ngx_uint_t header_params; +# endif /* nginx_version >= 1007008 */ ngx_array_t *scgi_lengths; ngx_array_t *scgi_values; @@ -491,6 +749,9 @@ ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_http_core_loc_conf_t *clcf; ngx_http_scgi_loc_conf_t *slcf; ngx_str_t *value; +# if (nginx_version >= 1007009) + ngx_http_complex_value_t cv; +# endif /* nginx_version >= 1007009 */ cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); @@ -509,8 +770,12 @@ ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) slcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_scgi_module); +# if (nginx_version >= 1007009) + if (slcf->upstream.cache > 0) +# else if (slcf->upstream.cache != NGX_CONF_UNSET_PTR && slcf->upstream.cache != NULL) +# endif /* nginx_version >= 1007009 */ { return "is incompatible with \"scgi_cache\""; } @@ -519,19 +784,61 @@ ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return "is incompatible with \"scgi_pass\""; } - if (slcf->upstream.store > 0 || slcf->upstream.store_lengths) { + if (slcf->upstream.store > 0 +# if (nginx_version < 1007009) + || slcf->upstream.store_lengths +# endif /* nginx_version >= 1007009 */ + ) + { return "is incompatible with \"scgi_store\""; } value = cf->args->elts; /* set scgi_cache part */ +# if (nginx_version >= 1007009) + + slcf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + slcf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (slcf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *slcf->upstream.cache_value = cv; + + } else { + + slcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_scgi_module); + if (slcf->upstream.cache_zone == NULL) { + return NGX_CONF_ERROR; + } + } + +# else + slcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, &ngx_http_scgi_module); if (slcf->upstream.cache == NULL) { return NGX_CONF_ERROR; } +# endif /* nginx_version >= 1007009 */ + /* set scgi_cache_key part */ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); @@ -555,18 +862,43 @@ ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_int_t ngx_http_scgi_cache_purge_handler(ngx_http_request_t *r) { - ngx_http_scgi_loc_conf_t *slcf; + ngx_http_file_cache_t *cache; + ngx_http_scgi_loc_conf_t *slcf; +# if (nginx_version >= 1007009) + ngx_http_scgi_main_conf_t *smcf; + ngx_int_t rc; +# endif /* nginx_version >= 1007009 */ - slcf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module); - - if (ngx_http_cache_purge_init(r, slcf->upstream.cache->data, - &slcf->cache_key) - != NGX_OK) - { + if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } -# if defined(nginx_version) && (nginx_version >= 8011) + slcf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module); + + r->upstream->conf = &slcf->upstream; + +# if (nginx_version >= 1007009) + + smcf = ngx_http_get_module_main_conf(r, ngx_http_scgi_module); + + r->upstream->caches = &smcf->caches; + + rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); + if (rc != NGX_OK) { + return rc; + } + +# else + + cache = slcf->upstream.cache->data; + +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_cache_purge_init(r, cache, &slcf->cache_key) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + +# if (nginx_version >= 8011) r->main->count++; # endif @@ -579,9 +911,34 @@ ngx_http_scgi_cache_purge_handler(ngx_http_request_t *r) # if (NGX_HTTP_UWSGI) extern ngx_module_t ngx_http_uwsgi_module; +# if (nginx_version >= 1007009) + +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_uwsgi_main_conf_t; + +# endif /* nginx_version >= 1007009 */ + +# if (nginx_version >= 1007008) + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_uint_t number; + ngx_hash_t hash; +} ngx_http_uwsgi_params_t; + +# endif /* nginx_version >= 1007008 */ + typedef struct { ngx_http_upstream_conf_t upstream; +# if (nginx_version >= 1007008) + ngx_http_uwsgi_params_t params; + ngx_http_uwsgi_params_t params_cache; + ngx_array_t *params_source; +# else ngx_array_t *flushes; ngx_array_t *params_len; ngx_array_t *params; @@ -589,6 +946,7 @@ typedef struct { ngx_hash_t headers_hash; ngx_uint_t header_params; +# endif /* nginx_version >= 1007008 */ ngx_array_t *uwsgi_lengths; ngx_array_t *uwsgi_values; @@ -599,6 +957,24 @@ typedef struct { ngx_uint_t modifier1; ngx_uint_t modifier2; + +# if (NGX_HTTP_SSL) +# if (nginx_version >= 1005008) + ngx_uint_t ssl; + ngx_uint_t ssl_protocols; + ngx_str_t ssl_ciphers; +# endif /* nginx_version >= 1005008 */ +# if (nginx_version >= 1007000) + ngx_uint_t ssl_verify_depth; + ngx_str_t ssl_trusted_certificate; + ngx_str_t ssl_crl; +# endif /* nginx_version >= 1007000 */ +# if (nginx_version >= 1007008) + ngx_str_t ssl_certificate; + ngx_str_t ssl_certificate_key; + ngx_array_t *ssl_passwords; +# endif /* nginx_version >= 1007008 */ +# endif } ngx_http_uwsgi_loc_conf_t; char * @@ -609,6 +985,9 @@ ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_http_core_loc_conf_t *clcf; ngx_http_uwsgi_loc_conf_t *ulcf; ngx_str_t *value; +# if (nginx_version >= 1007009) + ngx_http_complex_value_t cv; +# endif /* nginx_version >= 1007009 */ cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); @@ -627,8 +1006,12 @@ ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ulcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_uwsgi_module); +# if (nginx_version >= 1007009) + if (ulcf->upstream.cache > 0) +# else if (ulcf->upstream.cache != NGX_CONF_UNSET_PTR && ulcf->upstream.cache != NULL) +# endif /* nginx_version >= 1007009 */ { return "is incompatible with \"uwsgi_cache\""; } @@ -637,19 +1020,61 @@ ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return "is incompatible with \"uwsgi_pass\""; } - if (ulcf->upstream.store > 0 || ulcf->upstream.store_lengths) { + if (ulcf->upstream.store > 0 +# if (nginx_version < 1007009) + || ulcf->upstream.store_lengths +# endif /* nginx_version >= 1007009 */ + ) + { return "is incompatible with \"uwsgi_store\""; } value = cf->args->elts; /* set uwsgi_cache part */ +# if (nginx_version >= 1007009) + + ulcf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + ulcf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (ulcf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *ulcf->upstream.cache_value = cv; + + } else { + + ulcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_uwsgi_module); + if (ulcf->upstream.cache_zone == NULL) { + return NGX_CONF_ERROR; + } + } + +# else + ulcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, &ngx_http_uwsgi_module); if (ulcf->upstream.cache == NULL) { return NGX_CONF_ERROR; } +# endif /* nginx_version >= 1007009 */ + /* set uwsgi_cache_key part */ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); @@ -673,18 +1098,43 @@ ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_int_t ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r) { - ngx_http_uwsgi_loc_conf_t *ulcf; + ngx_http_file_cache_t *cache; + ngx_http_uwsgi_loc_conf_t *ulcf; +# if (nginx_version >= 1007009) + ngx_http_uwsgi_main_conf_t *umcf; + ngx_int_t rc; +# endif /* nginx_version >= 1007009 */ - ulcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module); - - if (ngx_http_cache_purge_init(r, ulcf->upstream.cache->data, - &ulcf->cache_key) - != NGX_OK) - { + if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } -# if defined(nginx_version) && (nginx_version >= 8011) + ulcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module); + + r->upstream->conf = &ulcf->upstream; + +# if (nginx_version >= 1007009) + + umcf = ngx_http_get_module_main_conf(r, ngx_http_uwsgi_module); + + r->upstream->caches = &umcf->caches; + + rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); + if (rc != NGX_OK) { + return rc; + } + +# else + + cache = ulcf->upstream.cache->data; + +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_cache_purge_init(r, cache, &ulcf->cache_key) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + +# if (nginx_version >= 8011) r->main->count++; # endif @@ -854,6 +1304,57 @@ ngx_http_cache_purge_send_response(ngx_http_request_t *r) return ngx_http_output_filter(r, &out); } +# if (nginx_version >= 1007009) + +/* + * Based on: ngx_http_upstream.c/ngx_http_upstream_cache_get + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ +ngx_int_t +ngx_http_cache_purge_cache_get(ngx_http_request_t *r, ngx_http_upstream_t *u, + ngx_http_file_cache_t **cache) +{ + ngx_str_t *name, val; + ngx_uint_t i; + ngx_http_file_cache_t **caches; + + if (u->conf->cache_zone) { + *cache = u->conf->cache_zone->data; + return NGX_OK; + } + + if (ngx_http_complex_value(r, u->conf->cache_value, &val) != NGX_OK) { + return NGX_ERROR; + } + + if (val.len == 0 + || (val.len == 3 && ngx_strncmp(val.data, "off", 3) == 0)) + { + return NGX_DECLINED; + } + + caches = u->caches->elts; + + for (i = 0; i < u->caches->nelts; i++) { + name = &caches[i]->shm_zone->shm.name; + + if (name->len == val.len + && ngx_strncmp(name->data, val.data, val.len) == 0) + { + *cache = caches[i]; + return NGX_OK; + } + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "cache \"%V\" not found", &val); + + return NGX_ERROR; +} + +# endif /* nginx_version >= 1007009 */ + ngx_int_t ngx_http_cache_purge_init(ngx_http_request_t *r, ngx_http_file_cache_t *cache, ngx_http_complex_value_t *cache_key) @@ -941,9 +1442,8 @@ ngx_http_file_cache_purge(ngx_http_request_t *r) switch (ngx_http_file_cache_open(r)) { case NGX_OK: case NGX_HTTP_CACHE_STALE: -# if defined(nginx_version) \ - && ((nginx_version >= 8001) \ - || ((nginx_version < 8000) && (nginx_version >= 7060))) +# if (nginx_version >= 8001) \ + || ((nginx_version < 8000) && (nginx_version >= 7060)) case NGX_HTTP_CACHE_UPDATING: # endif break; @@ -973,7 +1473,7 @@ ngx_http_file_cache_purge(ngx_http_request_t *r) return NGX_DECLINED; } -# if defined(nginx_version) && (nginx_version >= 1000001) +# if (nginx_version >= 1000001) cache->sh->size -= c->node->fs_size; c->node->fs_size = 0; # else @@ -982,9 +1482,8 @@ ngx_http_file_cache_purge(ngx_http_request_t *r) # endif c->node->exists = 0; -# if defined(nginx_version) \ - && ((nginx_version >= 8001) \ - || ((nginx_version < 8000) && (nginx_version >= 7060))) +# if (nginx_version >= 8001) \ + || ((nginx_version < 8000) && (nginx_version >= 7060)) c->node->updating = 0; # endif @@ -1014,11 +1513,11 @@ ngx_http_cache_purge_conf(ngx_conf_t *cf, ngx_http_cache_purge_conf_t *cpcf) value = cf->args->elts; - if (ngx_strcmp(value[1].data, (u_char *) "off") == 0) { + if (ngx_strcmp(value[1].data, "off") == 0) { cpcf->enable = 0; return NGX_CONF_OK; - } else if (ngx_strcmp(value[1].data, (u_char *) "on") == 0) { + } else if (ngx_strcmp(value[1].data, "on") == 0) { ngx_str_set(&cpcf->method, "PURGE"); } else { @@ -1031,14 +1530,14 @@ ngx_http_cache_purge_conf(ngx_conf_t *cf, ngx_http_cache_purge_conf_t *cpcf) } /* sanity check */ - if (ngx_strcmp(value[2].data, (u_char *) "from") != 0) { + if (ngx_strcmp(value[2].data, "from") != 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\", expected" " \"from\" keyword", &value[2]); return NGX_CONF_ERROR; } - if (ngx_strcmp(value[3].data, (u_char *) "all") == 0) { + if (ngx_strcmp(value[3].data, "all") == 0) { cpcf->enable = 1; return NGX_CONF_OK; } @@ -1139,6 +1638,8 @@ ngx_http_cache_purge_create_loc_conf(ngx_conf_t *cf) * conf->*.method = { 0, NULL } * conf->*.access = NULL * conf->*.access6 = NULL + * conf->handler = NULL + * conf->original_handler = NULL */ # if (NGX_HTTP_FASTCGI) @@ -1155,8 +1656,6 @@ ngx_http_cache_purge_create_loc_conf(ngx_conf_t *cf) # endif /* NGX_HTTP_UWSGI */ conf->conf = NGX_CONF_UNSET_PTR; - conf->handler = NGX_CONF_UNSET_PTR; - conf->original_handler = NGX_CONF_UNSET_PTR; return conf; } @@ -1258,9 +1757,14 @@ ngx_http_cache_purge_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) # endif /* NGX_HTTP_UWSGI */ ngx_conf_merge_ptr_value(conf->conf, prev->conf, NULL); - ngx_conf_merge_ptr_value(conf->handler, prev->handler, NULL); - ngx_conf_merge_ptr_value(conf->original_handler, prev->original_handler, - NULL); + + if (conf->handler == NULL) { + conf->handler = prev->handler; + } + + if (conf->original_handler == NULL) { + conf->original_handler = prev->original_handler; + } return NGX_CONF_OK; } diff --git a/debian/modules/nginx-cache-purge/t/proxy.t b/debian/modules/nginx-cache-purge/t/proxy1.t similarity index 81% rename from debian/modules/nginx-cache-purge/t/proxy.t rename to debian/modules/nginx-cache-purge/t/proxy1.t index d2d3b8a..e5c0054 100644 --- a/debian/modules/nginx-cache-purge/t/proxy.t +++ b/debian/modules/nginx-cache-purge/t/proxy1.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket; repeat_each(1); -plan tests => repeat_each() * (blocks() * 3 + 3 * 1); +plan tests => repeat_each() * (blocks() * 4 + 3 * 1); our $http_config = <<'_EOC_'; proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; @@ -48,7 +48,9 @@ GET /proxy/passwd Content-Type: text/plain --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -63,7 +65,9 @@ Content-Type: text/plain X-Cache-Status: HIT --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -77,7 +81,9 @@ PURGE /purge/proxy/passwd Content-Type: text/html --- response_body_like: Successful purge --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -91,7 +97,9 @@ PURGE /purge/proxy/passwd Content-Type: text/html --- response_body_like: 404 Not Found --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -106,7 +114,9 @@ Content-Type: text/plain X-Cache-Status: MISS --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -121,4 +131,6 @@ Content-Type: text/plain X-Cache-Status: HIT --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 diff --git a/debian/modules/nginx-cache-purge/t/proxy1_vars.t b/debian/modules/nginx-cache-purge/t/proxy1_vars.t new file mode 100644 index 0000000..af3553d --- /dev/null +++ b/debian/modules/nginx-cache-purge/t/proxy1_vars.t @@ -0,0 +1,138 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(1); + +plan tests => repeat_each() * (blocks() * 4 + 3 * 1); + +our $http_config = <<'_EOC_'; + proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; + proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; +_EOC_ + +our $config = <<'_EOC_'; + set $cache test_cache; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache $cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + } + + location ~ /purge(/.*) { + proxy_cache_purge $cache $1$is_args$args; + } + + location = /etc/passwd { + root /; + } +_EOC_ + +worker_connections(128); +no_shuffle(); +run_tests(); + +no_diff(); + +__DATA__ + +=== TEST 1: prepare +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 2: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 3: purge from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /purge/proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 4: purge from empty cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /purge/proxy/passwd +--- error_code: 404 +--- response_headers +Content-Type: text/html +--- response_body_like: 404 Not Found +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 5: get from source +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 6: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 diff --git a/debian/modules/nginx-cache-purge/t/proxy2.t b/debian/modules/nginx-cache-purge/t/proxy2.t index ad78d62..c07b042 100644 --- a/debian/modules/nginx-cache-purge/t/proxy2.t +++ b/debian/modules/nginx-cache-purge/t/proxy2.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket; repeat_each(1); -plan tests => repeat_each() * (blocks() * 3 + 6 * 1); +plan tests => repeat_each() * (blocks() * 4 + 6 * 1); our $http_config = <<'_EOC_'; proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; @@ -80,7 +80,9 @@ GET /proxy/passwd Content-Type: text/plain --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -95,7 +97,9 @@ Content-Type: text/plain X-Cache-Status: HIT --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -109,7 +113,9 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: Successful purge --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -123,7 +129,9 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: 404 Not Found --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -138,7 +146,9 @@ Content-Type: text/plain X-Cache-Status: MISS --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -153,7 +163,9 @@ Content-Type: text/plain X-Cache-Status: HIT --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -167,7 +179,9 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: Successful purge --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -181,7 +195,9 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: 404 Not Found --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -196,7 +212,9 @@ Content-Type: text/plain X-Cache-Status: MISS --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -211,7 +229,9 @@ Content-Type: text/plain X-Cache-Status: HIT --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -225,7 +245,9 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: 403 Forbidden --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -240,7 +262,9 @@ Content-Type: text/plain X-Cache-Status: HIT --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -263,6 +287,8 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: 404 Not Found --- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -286,6 +312,8 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: 403 Forbidden --- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -316,4 +344,6 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: Successful purge --- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 diff --git a/debian/modules/nginx-cache-purge/t/proxy2_vars.t b/debian/modules/nginx-cache-purge/t/proxy2_vars.t new file mode 100644 index 0000000..d09c08e --- /dev/null +++ b/debian/modules/nginx-cache-purge/t/proxy2_vars.t @@ -0,0 +1,353 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(1); + +plan tests => repeat_each() * (blocks() * 4 + 6 * 1); + +our $http_config = <<'_EOC_'; + proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; + proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; +_EOC_ + +our $config = <<'_EOC_'; + proxy_cache_purge on; + set $cache test_cache; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache $cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + + if ($uri) { } + } + + location = /etc/passwd { + root /; + } +_EOC_ + +our $config_allowed = <<'_EOC_'; + proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; + set $cache test_cache; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache $cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + } + + location = /etc/passwd { + root /; + } +_EOC_ + +our $config_forbidden = <<'_EOC_'; + proxy_cache_purge PURGE from 1.0.0.0/8; + set $cache test_cache; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache $cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + } + + location = /etc/passwd { + root /; + } +_EOC_ + +worker_connections(128); +no_shuffle(); +run_tests(); + +no_diff(); + +__DATA__ + +=== TEST 1: prepare +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 2: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 3: purge from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 4: purge from empty cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /proxy/passwd +--- error_code: 404 +--- response_headers +Content-Type: text/html +--- response_body_like: 404 Not Found +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 5: get from source +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 6: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 7: purge from cache (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +PURGE /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 8: purge from empty cache (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +PURGE /proxy/passwd +--- error_code: 404 +--- response_headers +Content-Type: text/html +--- response_body_like: 404 Not Found +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 9: get from source (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 10: get from cache (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 11: purge from cache (PURGE not allowed) +--- http_config eval: $::http_config +--- config eval: $::config_forbidden +--- request +PURGE /proxy/passwd +--- error_code: 403 +--- response_headers +Content-Type: text/html +--- response_body_like: 403 Forbidden +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 12: get from cache (PURGE not allowed) +--- http_config eval: $::http_config +--- config eval: $::config_forbidden +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 13: no cache (PURGE allowed) +--- http_config eval: $::http_config +--- config + proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + } + + location = /etc/passwd { + root /; + } +--- request +PURGE /proxy/passwd +--- error_code: 404 +--- response_headers +Content-Type: text/html +--- response_body_like: 404 Not Found +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 14: no cache (PURGE not allowed) +--- http_config eval: $::http_config +--- config + proxy_cache_purge PURGE from 1.0.0.0/8; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + } + + location = /etc/passwd { + root /; + } +--- request +PURGE /proxy/passwd +--- error_code: 403 +--- response_headers +Content-Type: text/html +--- response_body_like: 403 Forbidden +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 15: multiple cache purge directives +--- http_config eval: $::http_config +--- config + fastcgi_cache_purge on; + proxy_cache_purge on; + set $cache test_cache; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache $cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + + if ($uri) { } + } + + location = /etc/passwd { + root /; + } +--- request +PURGE /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 diff --git a/debian/modules/nginx-echo/.gitignore b/debian/modules/nginx-echo/.gitignore new file mode 100644 index 0000000..a9948e4 --- /dev/null +++ b/debian/modules/nginx-echo/.gitignore @@ -0,0 +1,65 @@ +.libs +*.swp +*.slo +*.la +*.swo +*.lo +*.mobi +genmobi.sh +*~ +*.o +print.txt +.rsync +*.tar.gz +dist +build[789] +build +tags +update-readme +*.tmp +test/Makefile +test/blib +test.sh +t.sh +t/t.sh +test/t/servroot/ +releng +reset +*.t_ +reindex +src/location.h +src/filter.c +src/subrequest.h +src/sleep.h +src/util.c +src/echo.c +src/info.c +src/util.h +src/var.h +src/filter.h +src/sleep.c +src/var.c +src/timer.c +src/module.h +src/echo.h +src/info.h +src/foreach.c +src/location.c +src/timer.h +src/module.c +src/subrequest.c +src/handler.h +src/foreach.h +src/handler.c +nginx +*.html +ctags +t/servroot +all +buildroot/ +go +Changes +build1[0-9] +analyze +Makefile +*.plist diff --git a/debian/modules/nginx-echo/LICENSE b/debian/modules/nginx-echo/LICENSE index 0403cb3..6feffbf 100644 --- a/debian/modules/nginx-echo/LICENSE +++ b/debian/modules/nginx-echo/LICENSE @@ -1,5 +1,4 @@ -Copyright (c) 2009, Taobao Inc., Alibaba Group ( http://www.taobao.com ). -Copyright (c) 2009, agentzh . +Copyright (C) 2009-2014, Yichun "agentzh" Zhang . All rights reserved. Redistribution and use in source and binary forms, with or without @@ -13,10 +12,6 @@ are met: notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the Taobao Inc. nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - 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 diff --git a/debian/modules/nginx-echo/README.markdown b/debian/modules/nginx-echo/README.markdown index d94fae6..c9768c2 100644 --- a/debian/modules/nginx-echo/README.markdown +++ b/debian/modules/nginx-echo/README.markdown @@ -73,7 +73,7 @@ This module is production ready. Version ======= -This document describes ngx_echo [v0.56](https://github.com/agentzh/echo-nginx-module/tags) released on 2 September 2014. +This document describes ngx_echo [v0.57](https://github.com/agentzh/echo-nginx-module/tags) released on 21 November 2014. Synopsis ======== @@ -1575,13 +1575,13 @@ You're recommended to install this module (as well as the Nginx core and many ot Alternatively, you can install this module manually with the Nginx source: Grab the nginx source code from [nginx.org](http://nginx.org/), for example, -the version 1.7.4 (see [nginx compatibility](#compatibility)), and then build the source with this module: +the version 1.7.7 (see [nginx compatibility](#compatibility)), and then build the source with this module: ```bash -$ wget 'http://nginx.org/download/nginx-1.7.4.tar.gz' -$ tar -xzvf nginx-1.7.4.tar.gz -$ cd nginx-1.7.4/ +$ wget 'http://nginx.org/download/nginx-1.7.7.tar.gz' +$ tar -xzvf nginx-1.7.7.tar.gz +$ cd nginx-1.7.7/ # Here we assume you would install you nginx under /opt/nginx/. $ ./configure --prefix=/opt/nginx \ @@ -1602,7 +1602,7 @@ Compatibility The following versions of Nginx should work with this module: -* **1.7.x** (last tested: 1.7.4) +* **1.7.x** (last tested: 1.7.7) * **1.6.x** * **1.5.x** (last tested: 1.5.12) * **1.4.x** (last tested: 1.4.4) @@ -1629,7 +1629,7 @@ If you find that any particular version of Nginx above 0.7.21 does not work with Known Issues ============ -Due to an unknown bug in Nginx (it still exists in Nginx 1.7.4), the [standard SSI module](http://nginx.org/en/docs/http/ngx_http_ssi_module.html) is required to ensure that the contents of the subrequests issued by [echo_locatoin_async](#echo_location_async) and [echo_subrequest_async](#echo_subrequest_async) are correctly merged into the output chains of the main one. Fortunately, the SSI module is enabled by default during Nginx's `configure` process. +Due to an unknown bug in Nginx (it still exists in Nginx 1.7.7), the [standard SSI module](http://nginx.org/en/docs/http/ngx_http_ssi_module.html) is required to ensure that the contents of the subrequests issued by [echo_locatoin_async](#echo_location_async) and [echo_subrequest_async](#echo_subrequest_async) are correctly merged into the output chains of the main one. Fortunately, the SSI module is enabled by default during Nginx's `configure` process. If calling this directive without SSI module enabled, you'll get truncated response without contents of any subrequests and get an alert message in your Nginx's `error.log`, like this: diff --git a/debian/modules/nginx-echo/doc/HttpEchoModule.wiki b/debian/modules/nginx-echo/doc/HttpEchoModule.wiki index 0f03b10..59c7f47 100644 --- a/debian/modules/nginx-echo/doc/HttpEchoModule.wiki +++ b/debian/modules/nginx-echo/doc/HttpEchoModule.wiki @@ -10,7 +10,7 @@ This module is production ready. = Version = -This document describes ngx_echo [https://github.com/agentzh/echo-nginx-module/tags v0.56] released on 2 September 2014. +This document describes ngx_echo [https://github.com/agentzh/echo-nginx-module/tags v0.57] released on 21 November 2014. = Synopsis = @@ -1338,12 +1338,12 @@ You're recommended to install this module (as well as the Nginx core and many ot Alternatively, you can install this module manually with the Nginx source: Grab the nginx source code from [http://nginx.org/ nginx.org], for example, -the version 1.7.4 (see [[#Compatibility|nginx compatibility]]), and then build the source with this module: +the version 1.7.7 (see [[#Compatibility|nginx compatibility]]), and then build the source with this module: - $ wget 'http://nginx.org/download/nginx-1.7.4.tar.gz' - $ tar -xzvf nginx-1.7.4.tar.gz - $ cd nginx-1.7.4/ + $ wget 'http://nginx.org/download/nginx-1.7.7.tar.gz' + $ tar -xzvf nginx-1.7.7.tar.gz + $ cd nginx-1.7.7/ # Here we assume you would install you nginx under /opt/nginx/. $ ./configure --prefix=/opt/nginx \ @@ -1361,7 +1361,7 @@ Also, this module is included and enabled by default in the [http://openresty.or The following versions of Nginx should work with this module: -* '''1.7.x''' (last tested: 1.7.4) +* '''1.7.x''' (last tested: 1.7.7) * '''1.6.x''' * '''1.5.x''' (last tested: 1.5.12) * '''1.4.x''' (last tested: 1.4.4) @@ -1385,7 +1385,7 @@ If you find that any particular version of Nginx above 0.7.21 does not work with = Known Issues = -Due to an unknown bug in Nginx (it still exists in Nginx 1.7.4), the [[HttpSsiModule|standard SSI module]] is required to ensure that the contents of the subrequests issued by [[#echo_location_async|echo_locatoin_async]] and [[#echo_subrequest_async|echo_subrequest_async]] are correctly merged into the output chains of the main one. Fortunately, the SSI module is enabled by default during Nginx's configure process. +Due to an unknown bug in Nginx (it still exists in Nginx 1.7.7), the [[HttpSsiModule|standard SSI module]] is required to ensure that the contents of the subrequests issued by [[#echo_location_async|echo_locatoin_async]] and [[#echo_subrequest_async|echo_subrequest_async]] are correctly merged into the output chains of the main one. Fortunately, the SSI module is enabled by default during Nginx's configure process. If calling this directive without SSI module enabled, you'll get truncated response without contents of any subrequests and get an alert message in your Nginx's error.log, like this: diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_request_info.c b/debian/modules/nginx-echo/src/ngx_http_echo_request_info.c index 9e75ac2..6e00ab1 100644 --- a/debian/modules/nginx-echo/src/ngx_http_echo_request_info.c +++ b/debian/modules/nginx-echo/src/ngx_http_echo_request_info.c @@ -202,24 +202,7 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, <= b->pos) { first = b; - - if (mr->header_in == b) { - size += mr->header_in->pos - mr->request_line.data; - - } else { - /* the subsequent part of the header is in the large header - * buffers */ -#if 1 - p = b->pos; - size += p - mr->request_line.data; - - /* skip truncated header entries (if any) */ - while (b->pos > b->start && b->pos[-1] != LF) { - b->pos--; - size--; - } -#endif - } + size += b->pos - mr->request_line.data; } if (hc->nbusy) { @@ -239,11 +222,6 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, first = b; } - if (b == mr->header_in) { - size += mr->header_in->pos - b->start; - break; - } - size += b->pos - b->start; } } @@ -260,17 +238,22 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, last = v->data; b = c->buffer; - if (first == b) { - if (mr->header_in == b) { - pos = mr->header_in->pos; + found = 0; - } else { - pos = b->pos; - } + if (first == b) { + found = 1; + pos = b->pos; last = ngx_copy(v->data, mr->request_line.data, pos - mr->request_line.data); + if (b != mr->header_in) { + /* skip truncated header entries (if any) */ + while (last > v->data && last[-1] != LF) { + last--; + } + } + i = 0; for (p = v->data; p != last; p++) { if (*p == '\0') { @@ -289,7 +272,6 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, } if (hc->nbusy) { - found = (b == c->buffer); for (i = 0; i < hc->nbusy; i++) { b = hc->busy[i]; @@ -304,12 +286,7 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, p = last; - if (b == mr->header_in) { - pos = mr->header_in->pos; - - } else { - pos = b->pos; - } + pos = b->pos; if (b == first) { dd("request line: %.*s", (int) mr->request_line.len, diff --git a/debian/modules/nginx-echo/t/request-info.t b/debian/modules/nginx-echo/t/request-info.t index 77e01a9..8fd015e 100644 --- a/debian/modules/nginx-echo/t/request-info.t +++ b/debian/modules/nginx-echo/t/request-info.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (3 * blocks() + 6); +plan tests => repeat_each() * (3 * blocks() + 15); run_tests(); @@ -743,3 +743,99 @@ Content-Length: 5 --- no_error_log [error] + + +=== TEST 31: two pipelined requests with large headers +--- config + client_header_buffer_size 10; + large_client_header_buffers 3 5610; + location /t { + echo -n $echo_client_request_headers; + } +--- pipelined_requests eval +["GET /t", "GET /t"] +--- more_headers eval +CORE::join "\n", map { "Header$_: value-$_" } 1..585 + +--- response_body eval +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..585) . "\r\n\r\n", +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..585) . "\r\n\r\n", +, +] + +--- no_error_log +[error] +--- timeout: 5 + + + +=== TEST 32: a request with large header and a smaller pipelined request following +--- config + client_header_buffer_size 10; + large_client_header_buffers 2 1921; + location /t { + echo -n $echo_client_request_headers; + } +--- pipelined_requests eval +["GET /t", "GET /t"] +--- more_headers eval +[CORE::join("\n", map { "Header$_: value-$_" } 1..170), "Foo: bar\n"] + +--- response_body eval +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..170) . "\r\n\r\n", +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +Foo: bar\r +\r +}, +] + +--- no_error_log +[error] +--- timeout: 5 + + + +=== TEST 33: a request with large header and a smaller pipelined request following +--- config + client_header_buffer_size 10; + large_client_header_buffers 2 1921; + location /t { + echo -n $echo_client_request_headers; + } +--- pipelined_requests eval +["GET /t", "GET /t" . ("a" x 512)] +--- more_headers eval +[CORE::join("\n", map { "Header$_: value-$_" } 1..170), "Foo: bar\n"] + +--- response_body eval +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..170) . "\r\n\r\n", +qq{GET /t} . ("a" x 512) . qq{ HTTP/1.1\r +Host: localhost\r +Connection: close\r +Foo: bar\r +\r +}, +] + +--- no_error_log +[error] +--- timeout: 5 + diff --git a/debian/modules/nginx-echo/util/build.sh b/debian/modules/nginx-echo/util/build.sh index d96527c..09a3914 100755 --- a/debian/modules/nginx-echo/util/build.sh +++ b/debian/modules/nginx-echo/util/build.sh @@ -11,7 +11,7 @@ home=~ #--with-cc=gcc46 \ ngx-build $force $version \ - --with-ld-opt="-L$PCRE_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB:$LUAJIT_LIB:/usr/local/lib" \ + --with-ld-opt="-L$PCRE_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB:/usr/local/lib" \ --with-cc-opt="-DDEBUG_MALLOC" \ --with-http_stub_status_module \ --without-mail_pop3_module \ diff --git a/debian/modules/nginx-echo/util/releng b/debian/modules/nginx-echo/util/releng deleted file mode 100755 index b3ad9f2..0000000 --- a/debian/modules/nginx-echo/util/releng +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -./update-readme -ack '.{81}' src/ngx_http_*.[ch] -ack '(?<=\#define)\s*DDEBUG\s*[12]' src -echo ======================================= -ack '(?<=This document describes echo-nginx-module v)\d+\.\d+' README - diff --git a/debian/modules/nginx-lua/.gitignore b/debian/modules/nginx-lua/.gitignore new file mode 100644 index 0000000..61613b2 --- /dev/null +++ b/debian/modules/nginx-lua/.gitignore @@ -0,0 +1,164 @@ +build/ +work/ +tags +cscope.* +*.mobi +genmobi.sh +.libs +*.swp +*.slo +*.la +*.swo +*.lo +*~ +*.o +print.txt +.rsync +*.tar.gz +dist +build[789] +build +tags +update-readme +*.tmp +test/Makefile +test/blib +test.sh +t.sh +t/t.sh +test/t/servroot/ +releng +reset +*.t_ +src/handler.h +src/util.c +src/module.h +src/module.c +src/drizzle.c +src/processor.h +src/handler.c +src/util.h +src/drizzle.h +src/processor.c +src/output.c +src/output.h +libdrizzle +ctags +src/stream.h +nginx +keepalive +reindex +src/keepalive.c +src/keepalive.h +src/checker.h +src/checker.c +src/quoting.h +src/quoting.c +src/module.h +src/module.c +src/util.h +src/util.c +src/processor.h +src/processor.c +src/rds.h +src/utils.h +src/handler.c +src/handler.h +util/bench +*.html +trace.out* +try.sh +src/cache.c +src/cache.h +src/common.h +src/directive.c +src/directive.h +src/consts.[ch] +src/contentby.[ch] +src/pcrefix.[ch] +src/util.c +src/clfactory.c +src/directive.c +src/conf.h +src/setby.h +src/cache.h +src/hook.c +src/util.h +src/hook.h +src/common.h +src/directive.h +src/conf.c +src/setby.c +src/cache.c +src/module.c +src/clfactory.h +src/capturefilter.[ch] +src/contentby.c +pack +b.sh +src/in.[ch] +src/out.[ch] +go +all.sh +src/accessby.[ch] +src/rewriteby.[ch] +src/patch.[ch] +src/ndk.[ch] +src/control.[ch] +src/output.[ch] +src/variable.[ch] +src/string.[ch] +src/misc.[ch] +src/log.[ch] +src/exception.[ch] +src/subrequest.[ch] +src/time.[ch] +src/regex.[ch] +src/ctx.[ch] +src/args.[ch] +src/headers.[ch] +src/script.[ch] +src/filter.[ch] +src/shdict.[ch] +src/body.[ch] +src/uri.[ch] +src/api.[ch] +src/coroutine.[ch] +src/logby.[ch] +src/sleep.[ch] +a.patch +all +build1[0-9] +g +buildroot/ +src/headerfilterby.[ch] +*.patch +analyze +tsock +a.c +test.lua +build12 +ERRORS +src/bodyfilterby.[ch] +src/tcp.[ch] +src/initby.[ch] +src/initworkerby.[ch] +src/socket.[ch] +src/udp.[ch] +src/method.[ch] +tre +src/phase.[ch] +src/probe.h +src/uthread.[ch] +src/timer.[ch] +src/config.[ch] +src/worker.[ch] +*.plist +lua +ttimer +Makefile +tsubreq +tthread +addr2line +hup +theaders diff --git a/debian/modules/nginx-lua/README.markdown b/debian/modules/nginx-lua/README.markdown index d620ec4..70c60dd 100644 --- a/debian/modules/nginx-lua/README.markdown +++ b/debian/modules/nginx-lua/README.markdown @@ -37,13 +37,11 @@ Table of Contents * [Lua Coroutine Yielding/Resuming](#lua-coroutine-yieldingresuming) * [Lua Variable Scope](#lua-variable-scope) * [Locations Configured by Subrequest Directives of Other Modules](#locations-configured-by-subrequest-directives-of-other-modules) - * [Cocockets Not Available Everywhere](#cocockets-not-available-everywhere) + * [Cosockets Not Available Everywhere](#cosockets-not-available-everywhere) * [Special PCRE Sequences](#special-pcre-sequences) * [Mixing with SSI Not Supported](#mixing-with-ssi-not-supported) * [SPDY Mode Not Fully Supported](#spdy-mode-not-fully-supported) * [TODO](#todo) - * [Short Term](#short-term) - * [Longer Term](#longer-term) * [Changes](#changes) * [Test Suite](#test-suite) * [Copyright and License](#copyright-and-license) @@ -59,177 +57,178 @@ Production ready. Version ======= -This document describes ngx_lua [v0.9.13](https://github.com/openresty/lua-nginx-module/tags) released on 21 November 2014. +This document describes ngx_lua [v0.9.15](https://github.com/openresty/lua-nginx-module/tags) released on 18 February 2015. Synopsis ======== ```nginx -# set search paths for pure Lua external libraries (';;' is the default path): -lua_package_path '/foo/bar/?.lua;/blah/?.lua;;'; - -# set search paths for Lua external libraries written in C (can also use ';;'): -lua_package_cpath '/bar/baz/?.so;/blah/blah/?.so;;'; - -server { - location /inline_concat { - # MIME type determined by default_type: - default_type 'text/plain'; - - set $a "hello"; - set $b "world"; - # inline Lua script - set_by_lua $res "return ngx.arg[1]..ngx.arg[2]" $a $b; - echo $res; - } - - location /rel_file_concat { - set $a "foo"; - set $b "bar"; - # script path relative to nginx prefix - # $ngx_prefix/conf/concat.lua contents: - # - # return ngx.arg[1]..ngx.arg[2] - # - set_by_lua_file $res conf/concat.lua $a $b; - echo $res; - } - - location /abs_file_concat { - set $a "fee"; - set $b "baz"; - # absolute script path not modified - set_by_lua_file $res /usr/nginx/conf/concat.lua $a $b; - echo $res; - } - - location /lua_content { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua "ngx.say('Hello,world!')"; - } - - location /nginx_var { - # MIME type determined by default_type: - default_type 'text/plain'; - - # try access /nginx_var?a=hello,world - content_by_lua "ngx.print(ngx.var['arg_a'], '\\n')"; - } - - location /request_body { - # force reading request body (default off) - lua_need_request_body on; - client_max_body_size 50k; - client_body_buffer_size 50k; - - content_by_lua 'ngx.print(ngx.var.request_body)'; - } - - # transparent non-blocking I/O in Lua via subrequests - location /lua { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua ' - local res = ngx.location.capture("/some_other_location") - if res.status == 200 then - ngx.print(res.body) - end'; - } - - # GET /recur?num=5 - location /recur { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua ' - local num = tonumber(ngx.var.arg_num) or 0 + # set search paths for pure Lua external libraries (';;' is the default path): + lua_package_path '/foo/bar/?.lua;/blah/?.lua;;'; - if num > 50 then - ngx.say("num too big") - return - end + # set search paths for Lua external libraries written in C (can also use ';;'): + lua_package_cpath '/bar/baz/?.so;/blah/blah/?.so;;'; - ngx.say("num is: ", num) - - if num > 0 then - res = ngx.location.capture("/recur?num=" .. tostring(num - 1)) - ngx.print("status=", res.status, " ") - ngx.print("body=", res.body) - else - ngx.say("end") - end - '; - } - - location /foo { - rewrite_by_lua ' - res = ngx.location.capture("/memc", - { args = { cmd = "incr", key = ngx.var.uri } } - ) - '; - - proxy_pass http://blah.blah.com; - } - - location /blah { - access_by_lua ' - local res = ngx.location.capture("/auth") - - if res.status == ngx.HTTP_OK then + server { + location /inline_concat { + # MIME type determined by default_type: + default_type 'text/plain'; + + set $a "hello"; + set $b "world"; + # inline Lua script + set_by_lua $res "return ngx.arg[1]..ngx.arg[2]" $a $b; + echo $res; + } + + location /rel_file_concat { + set $a "foo"; + set $b "bar"; + # script path relative to nginx prefix + # $ngx_prefix/conf/concat.lua contents: + # + # return ngx.arg[1]..ngx.arg[2] + # + set_by_lua_file $res conf/concat.lua $a $b; + echo $res; + } + + location /abs_file_concat { + set $a "fee"; + set $b "baz"; + # absolute script path not modified + set_by_lua_file $res /usr/nginx/conf/concat.lua $a $b; + echo $res; + } + + location /lua_content { + # MIME type determined by default_type: + default_type 'text/plain'; + + content_by_lua "ngx.say('Hello,world!')"; + } + + location /nginx_var { + # MIME type determined by default_type: + default_type 'text/plain'; + + # try access /nginx_var?a=hello,world + content_by_lua "ngx.print(ngx.var['arg_a'], '\\n')"; + } + + location /request_body { + # force reading request body (default off) + lua_need_request_body on; + client_max_body_size 50k; + client_body_buffer_size 50k; + + content_by_lua 'ngx.print(ngx.var.request_body)'; + } + + # transparent non-blocking I/O in Lua via subrequests + location /lua { + # MIME type determined by default_type: + default_type 'text/plain'; + + content_by_lua ' + local res = ngx.location.capture("/some_other_location") + if res.status == 200 then + ngx.print(res.body) + end'; + } + + # GET /recur?num=5 + location /recur { + # MIME type determined by default_type: + default_type 'text/plain'; + + content_by_lua ' + local num = tonumber(ngx.var.arg_num) or 0 + + if num > 50 then + ngx.say("num too big") return end - - if res.status == ngx.HTTP_FORBIDDEN then - ngx.exit(res.status) + + ngx.say("num is: ", num) + + if num > 0 then + res = ngx.location.capture("/recur?num=" .. tostring(num - 1)) + ngx.print("status=", res.status, " ") + ngx.print("body=", res.body) + else + ngx.say("end") end - - ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) + '; + } + + location /foo { + rewrite_by_lua ' + res = ngx.location.capture("/memc", + { args = { cmd = "incr", key = ngx.var.uri } } + ) + '; + + proxy_pass http://blah.blah.com; + } + + location /blah { + access_by_lua ' + local res = ngx.location.capture("/auth") + + if res.status == ngx.HTTP_OK then + return + end + + if res.status == ngx.HTTP_FORBIDDEN then + ngx.exit(res.status) + end + + ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) + '; + + # proxy_pass/fastcgi_pass/postgres_pass/... + } + + location /mixed { + rewrite_by_lua_file /path/to/rewrite.lua; + access_by_lua_file /path/to/access.lua; + content_by_lua_file /path/to/content.lua; + } + + # use nginx var in code path + # WARNING: contents in nginx var must be carefully filtered, + # otherwise there'll be great security risk! + location ~ ^/app/([-_a-zA-Z0-9/]+) { + set $path $1; + content_by_lua_file /path/to/lua/app/root/$path.lua; + } + + location / { + lua_need_request_body on; + + client_max_body_size 100k; + client_body_buffer_size 100k; + + access_by_lua ' + -- check the client IP address is in our black list + if ngx.var.remote_addr == "132.5.72.3" then + ngx.exit(ngx.HTTP_FORBIDDEN) + end + + -- check if the request body contains bad words + if ngx.var.request_body and + string.match(ngx.var.request_body, "fsck") + then + return ngx.redirect("/terms_of_use.html") + end + + -- tests passed '; - - # proxy_pass/fastcgi_pass/postgres_pass/... - } - - location /mixed { - rewrite_by_lua_file /path/to/rewrite.lua; - access_by_lua_file /path/to/access.lua; - content_by_lua_file /path/to/content.lua; - } - - # use nginx var in code path - # WARN: contents in nginx var must be carefully filtered, - # otherwise there'll be great security risk! - location ~ ^/app/(.+) { - content_by_lua_file /path/to/lua/app/root/$1.lua; - } - - location / { - lua_need_request_body on; - - client_max_body_size 100k; - client_body_buffer_size 100k; - - access_by_lua ' - -- check the client IP address is in our black list - if ngx.var.remote_addr == "132.5.72.3" then - ngx.exit(ngx.HTTP_FORBIDDEN) - end - - -- check if the request body contains bad words - if ngx.var.request_body and - string.match(ngx.var.request_body, "fsck") - then - return ngx.redirect("/terms_of_use.html") - end - - -- tests passed - '; - - # proxy_pass/fastcgi_pass/etc settings - } -} + + # proxy_pass/fastcgi_pass/etc settings + } + } ``` [Back to TOC](#table-of-contents) @@ -292,7 +291,7 @@ Nginx Compatibility =================== The latest module is compatible with the following versions of Nginx: -* 1.7.x (last tested: 1.7.7) +* 1.7.x (last tested: 1.7.10) * 1.6.x * 1.5.x (last tested: 1.5.12) * 1.4.x (last tested: 1.4.4) @@ -308,7 +307,7 @@ The latest module is compatible with the following versions of Nginx: Installation ============ -The [ngx_openresty bundle](http://openresty.org) can be used to install Nginx, ngx_lua, either one of the standard Lua 5.1 interpreter or LuaJIT 2.0/2.1, as well as a package of powerful companion Nginx modules. The basic installation step is a simple `./configure --with-luajit && make && make install`. +It is highly recommended to use the [ngx_openresty bundle](http://openresty.org) that bundles Nginx, ngx_lua, LuaJIT 2.0/2.1 (or the optional standard Lua 5.1 interpreter), as well as a package of powerful companion Nginx modules. The basic installation step is a simple command: `./configure --with-luajit && make && make install`. Alternatively, ngx_lua can be manually compiled into Nginx: @@ -321,29 +320,30 @@ Build the source with this module: ```bash -wget 'http://nginx.org/download/nginx-1.7.7.tar.gz' -tar -xzvf nginx-1.7.7.tar.gz -cd nginx-1.7.7/ + wget 'http://nginx.org/download/nginx-1.7.10.tar.gz' + tar -xzvf nginx-1.7.10.tar.gz + cd nginx-1.7.10/ -# tell nginx's build system where to find LuaJIT 2.0: -export LUAJIT_LIB=/path/to/luajit/lib -export LUAJIT_INC=/path/to/luajit/include/luajit-2.0 + # tell nginx's build system where to find LuaJIT 2.0: + export LUAJIT_LIB=/path/to/luajit/lib + export LUAJIT_INC=/path/to/luajit/include/luajit-2.0 -# tell nginx's build system where to find LuaJIT 2.1: -export LUAJIT_LIB=/path/to/luajit/lib -export LUAJIT_INC=/path/to/luajit/include/luajit-2.1 - -# or tell where to find Lua if using Lua instead: -#export LUA_LIB=/path/to/lua/lib -#export LUA_INC=/path/to/lua/include - -# Here we assume Nginx is to be installed under /opt/nginx/. -./configure --prefix=/opt/nginx \ - --add-module=/path/to/ngx_devel_kit \ - --add-module=/path/to/lua-nginx-module - -make -j2 -make install + # tell nginx's build system where to find LuaJIT 2.1: + export LUAJIT_LIB=/path/to/luajit/lib + export LUAJIT_INC=/path/to/luajit/include/luajit-2.1 + + # or tell where to find Lua if using Lua instead: + #export LUA_LIB=/path/to/lua/lib + #export LUA_INC=/path/to/lua/include + + # Here we assume Nginx is to be installed under /opt/nginx/. + ./configure --prefix=/opt/nginx \ + --with-ld-opt='-Wl,-rpath,/path/to/luajit-or-lua/lib" \ + --add-module=/path/to/ngx_devel_kit \ + --add-module=/path/to/lua-nginx-module + + make -j2 + make install ``` [Back to TOC](#table-of-contents) @@ -377,7 +377,7 @@ If the standard Lua 5.1 interpreter is required however, run the following comma ```bash -apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev + apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev ``` Everything should be installed correctly, except for one small tweak. @@ -386,7 +386,7 @@ Library name `liblua.so` has been changed in liblua5.1 package, it only comes wi ```bash -ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so + ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so ``` [Back to TOC](#table-of-contents) @@ -436,14 +436,14 @@ Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible wi ```bash -/path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.luac + /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.luac ``` The `-bg` option can be used to include debug information in the LuaJIT bytecode file: ```bash -/path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.luac + /path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.luac ``` Please refer to the official LuaJIT documentation on the `-b` option for more details: @@ -456,14 +456,14 @@ Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatibl ```bash -luac -o /path/to/output_file.luac /path/to/input_file.lua + luac -o /path/to/output_file.luac /path/to/input_file.lua ``` Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the `-s` option as shown: ```bash -luac -s -o /path/to/output_file.luac /path/to/input_file.lua + luac -s -o /path/to/output_file.luac /path/to/input_file.lua ``` Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx `error.log` file: @@ -483,7 +483,7 @@ If you want to access the system environment variable, say, `foo`, in Lua via th ```nginx -env foo; + env foo; ``` [Back to TOC](#table-of-contents) @@ -515,14 +515,14 @@ Below is a trivial example to demonstrate this. Consider that we have the follow ```lua --- foo.lua -local _M = {} + -- foo.lua + local _M = {} -function _M.go() - print("Hello from foo") -end + function _M.go() + print("Hello from foo") + end -return _M + return _M ``` And then we compile this `.lua` file to `foo.o` file: @@ -535,15 +535,15 @@ Then when building Nginx or OpenResty, pass the `--with-ld-opt="foo.o"` option t ```bash -./configure --with-ld-opt="/path/to/foo.o" ... + ./configure --with-ld-opt="/path/to/foo.o" ... ``` Finally, you can just do the following in any Lua code run by ngx_lua: ```lua -local foo = require "foo" -foo.go() + local foo = require "foo" + foo.go() ``` And this piece of code no longer depends on the external `foo.lua` file any more because it has already been compiled into the `nginx` executable. @@ -552,7 +552,7 @@ If you want to use dot in the Lua module name when calling `require`, as in ```lua -local foo = require "resty.foo" + local foo = require "resty.foo" ``` then you need to rename the `foo.lua` file to `resty_foo.lua` before compiling it down to a `.o` file with the `luajit` command-line utility. @@ -563,22 +563,22 @@ When you have multiple `.lua` files to compile and link, then just specify their ```bash -./configure --with-ld-opt="/path/to/foo.o /path/to/bar.o" ... + ./configure --with-ld-opt="/path/to/foo.o /path/to/bar.o" ... ``` If you have just too many `.o` files, then it might not be feasible to name them all in a single command. In this case, you can build a static library (or archive) for your `.o` files, as in ```bash -ar rcus libmyluafiles.a *.o + ar rcus libmyluafiles.a *.o ``` then you can link the `myluafiles` archive as a whole to your nginx executable: ```bash -./configure \ - --with-ld-opt="-L/path/to/lib -Wl,--whole-archive -lmyluafiles -Wl,--no-whole-archive" + ./configure \ + --with-ld-opt="-L/path/to/lib -Wl,--whole-archive -lmyluafiles -Wl,--no-whole-archive" ``` where `/path/to/lib` is the path of the directory containing the `libmyluafiles.a` file. It should be noted that the linker option `--whole-archive` is required here because otherwise our archive will be skipped because no symbols in our archive are mentioned in the main parts of the nginx executable. @@ -594,32 +594,32 @@ Here is a complete small example: ```lua --- mydata.lua -local _M = {} + -- mydata.lua + local _M = {} -local data = { - dog = 3, - cat = 4, - pig = 5, -} - -function _M.get_age(name) - return data[name] -end + local data = { + dog = 3, + cat = 4, + pig = 5, + } -return _M + function _M.get_age(name) + return data[name] + end + + return _M ``` and then accessing it from `nginx.conf`: ```nginx -location /lua { - content_by_lua ' - local mydata = require "mydata" - ngx.say(mydata.get_age("dog")) - '; -} + location /lua { + content_by_lua ' + local mydata = require "mydata" + ngx.say(mydata.get_age("dog")) + '; + } ``` The `mydata` module in this example will only be loaded and run on the first request to the location `/lua`, @@ -674,14 +674,14 @@ Care must be taken when importing modules and this form should be used: ```lua -local xxx = require('xxx') + local xxx = require('xxx') ``` instead of the old deprecated form: ```lua -require('xxx') + require('xxx') ``` Here is the reason: by design, the global environment has exactly the same lifetime as the Nginx request handler associated with it. Each request handler has its own set of Lua global variables and that is the idea of request isolation. The Lua module is actually loaded by the first Nginx request handler and is cached by the `require()` built-in in the `package.loaded` table for later reference, and the `module()` builtin used by some Lua modules has the side effect of setting a global variable to the loaded module table. But this global variable will be cleared at the end of the request handler, and every subsequent request handler all has its own (clean) global environment. So one will get Lua exception for accessing the `nil` value. @@ -714,29 +714,29 @@ The [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi] ```nginx -location /foo { - content_by_lua ' - res = ngx.location.capture("/bar") - '; -} -location /bar { - echo_location /blah; -} -location /blah { - echo "Success!"; -} + location /foo { + content_by_lua ' + res = ngx.location.capture("/bar") + '; + } + location /bar { + echo_location /blah; + } + location /blah { + echo "Success!"; + } ``` ```nginx -$ curl -i http://example.com/foo + $ curl -i http://example.com/foo ``` will not work as expected. [Back to TOC](#table-of-contents) -Cocockets Not Available Everywhere +Cosockets Not Available Everywhere ---------------------------------- Due the internal limitations in the nginx core, the cosocket API are disabled in the following contexts: [set_by_lua*](#set_by_lua), [log_by_lua*](#log_by_lua), [header_filter_by_lua*](#header_filter_by_lua), and [body_filter_by_lua](#body_filter_by_lua). @@ -753,30 +753,30 @@ PCRE sequences such as `\d`, `\s`, or `\w`, require special attention because in ```nginx -# nginx.conf -? location /test { -? content_by_lua ' -? local regex = "\d+" -- THIS IS WRONG!! -? local m = ngx.re.match("hello, 1234", regex) -? if m then ngx.say(m[0]) else ngx.say("not matched!") end -? '; -? } -# evaluates to "not matched!" + # nginx.conf + ? location /test { + ? content_by_lua ' + ? local regex = "\d+" -- THIS IS WRONG!! + ? local m = ngx.re.match("hello, 1234", regex) + ? if m then ngx.say(m[0]) else ngx.say("not matched!") end + ? '; + ? } + # evaluates to "not matched!" ``` To avoid this, *double* escape the backslash: ```nginx -# nginx.conf -location /test { - content_by_lua ' - local regex = "\\\\d+" - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - '; -} -# evaluates to "1234" + # nginx.conf + location /test { + content_by_lua ' + local regex = "\\\\d+" + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + '; + } + # evaluates to "1234" ``` Here, `\\\\d+` is stripped down to `\\d+` by the Nginx config file parser and this is further stripped down to `\d+` by the Lua language parser before running. @@ -785,15 +785,15 @@ Alternatively, the regex pattern can be presented as a long-bracketed Lua string ```nginx -# nginx.conf -location /test { - content_by_lua ' - local regex = [[\\d+]] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - '; -} -# evaluates to "1234" + # nginx.conf + location /test { + content_by_lua ' + local regex = [[\\d+]] + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + '; + } + # evaluates to "1234" ``` Here, `[[\\d+]]` is stripped down to `[[\d+]]` by the Nginx config file parser and this is processed correctly. @@ -803,15 +803,15 @@ The `[=[...]=]` form may be used as the default form if desired. ```nginx -# nginx.conf -location /test { - content_by_lua ' - local regex = [=[[0-9]+]=] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - '; -} -# evaluates to "1234" + # nginx.conf + location /test { + content_by_lua ' + local regex = [=[[0-9]+]=] + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + '; + } + # evaluates to "1234" ``` An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various `*_by_lua_file` directives. @@ -819,22 +819,22 @@ With this approach, the backslashes are only stripped by the Lua language parser ```lua --- test.lua -local regex = "\\d+" -local m = ngx.re.match("hello, 1234", regex) -if m then ngx.say(m[0]) else ngx.say("not matched!") end --- evaluates to "1234" + -- test.lua + local regex = "\\d+" + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + -- evaluates to "1234" ``` Within external script files, PCRE sequences presented as long-bracketed Lua string literals do not require modification. ```lua --- test.lua -local regex = [[\d+]] -local m = ngx.re.match("hello, 1234", regex) -if m then ngx.say(m[0]) else ngx.say("not matched!") end --- evaluates to "1234" + -- test.lua + local regex = [[\d+]] + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + -- evaluates to "1234" ``` [Back to TOC](#table-of-contents) @@ -856,21 +856,60 @@ Certain Lua APIs provided by ngx_lua do not work in Nginx's SPDY mode yet: [ngx. TODO ==== -[Back to TOC](#table-of-contents) +* add `*_by_lua_block` directives for existing `*_by_lua` directives so that we put literal Lua code directly in curly braces instead of an nginx literal string. For example, +```nginx -Short Term ----------- + content_by_lua_block { + ngx.say("hello, world\r\n") + } +``` + which is equivalent to +```nginx + + content_by_lua ' + ngx.say("hello, world\\r\\n") + '; +``` + but the former is much cleaner and nicer. +* cosocket: implement LuaSocket's unconnected UDP API. +* add support for implementing general TCP servers instead of HTTP servers in Lua. For example, +```lua + + tcp { + server { + listen 11212; + handler_by_lua ' + -- custom Lua code implementing the special TCP server... + '; + } + } +``` +* add support for implementing general UDP servers instead of HTTP servers in Lua. For example, +```lua + + udp { + server { + listen 1953; + handler_by_lua ' + -- custom Lua code implementing the special UDP server... + '; + } + } +``` +* ssl: implement directives `ssl_certificate_by_lua` and `ssl_certificate_by_lua_file` to allow using Lua to dynamically serve SSL certificates and keys for downstream SSL handshake. (already done in CloudFlare's private branch and powering CloudFlare's SSL gateway of its global network. expected to be opensourced in March 2015.) +* shm: implement a "shared queue API" to complement the existing [shared dict](#lua_shared_dict) API. +* cosocket: add support in the context of [init_by_lua*](#init_by_lua). +* cosocket: implement the `bind()` method for stream-typed cosockets. +* cosocket: pool-based backend concurrency level control: implement automatic `connect` queueing when the backend concurrency exceeds its connection pool limit. +* cosocket: review and merge aviramc's [patch](https://github.com/openresty/lua-nginx-module/pull/290) for adding the `bsdrecv` method. +* add new API function `ngx.resp.add_header` to emulate the standard `add_header` config directive. +* [ngx.re](#ngxrematch) API: use `false` instead of `nil` in the resulting match table to indicate non-existent submatch captures, such that we can avoid "holes" in the array table. * review and apply Jader H. Silva's patch for `ngx.re.split()`. * review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option * use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), [ngx.header.HEADER](#ngxheaderheader), and etc. * add configure options for different strategies of handling the cosocket connection exceeding in the pools. * add directives to run Lua codes when nginx stops. * add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side. - -[Back to TOC](#table-of-contents) - -Longer Term ------------ * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add `stat` mode similar to [mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html). @@ -948,9 +987,9 @@ Copyright and License This module is licensed under the BSD license. -Copyright (C) 2009-2014, by Xiaozhe Wang (chaoslawful) . +Copyright (C) 2009-2015, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2014, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +Copyright (C) 2009-2015, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. All rights reserved. @@ -1185,36 +1224,36 @@ Usually you can register (true) Lua global variables or pre-load Lua modules at ```nginx -init_by_lua 'cjson = require "cjson"'; + init_by_lua 'cjson = require "cjson"'; -server { - location = /api { - content_by_lua ' - ngx.say(cjson.encode({dog = 5, cat = 6})) - '; - } -} + server { + location = /api { + content_by_lua ' + ngx.say(cjson.encode({dog = 5, cat = 6})) + '; + } + } ``` You can also initialize the [lua_shared_dict](#lua_shared_dict) shm storage at this phase. Here is an example for this: ```nginx -lua_shared_dict dogs 1m; + lua_shared_dict dogs 1m; -init_by_lua ' - local dogs = ngx.shared.dogs; - dogs:set("Tom", 56) -'; + init_by_lua ' + local dogs = ngx.shared.dogs; + dogs:set("Tom", 56) + '; -server { - location = /api { - content_by_lua ' - local dogs = ngx.shared.dogs; - ngx.say(dogs:get("Tom")) - '; - } -} + server { + location = /api { + content_by_lua ' + local dogs = ngx.shared.dogs; + ngx.say(dogs:get("Tom")) + '; + } + } ``` But note that, the [lua_shared_dict](#lua_shared_dict)'s shm storage will not be cleared through a config reload (via the `HUP` signal, for example). So if you do *not* want to re-initialize the shm storage in your `init_by_lua` code in this case, then you just need to set a custom flag in the shm storage and always check the flag in your `init_by_lua` code. @@ -1270,30 +1309,30 @@ This hook is often used to create per-worker reoccurring timers (via the [ngx.ti ```nginx -init_worker_by_lua ' - local delay = 3 -- in seconds - local new_timer = ngx.timer.at - local log = ngx.log - local ERR = ngx.ERR - local check + init_worker_by_lua ' + local delay = 3 -- in seconds + local new_timer = ngx.timer.at + local log = ngx.log + local ERR = ngx.ERR + local check - check = function(premature) - if not premature then - -- do the health check or other routine work - local ok, err = new_timer(delay, check) - if not ok then - log(ERR, "failed to create timer: ", err) - return - end - end - end + check = function(premature) + if not premature then + -- do the health check or other routine work + local ok, err = new_timer(delay, check) + if not ok then + log(ERR, "failed to create timer: ", err) + return + end + end + end - local ok, err = new_timer(delay, check) - if not ok then - log(ERR, "failed to create timer: ", err) - return - end -'; + local ok, err = new_timer(delay, check) + if not ok then + log(ERR, "failed to create timer: ", err) + return + end + '; ``` This directive was first introduced in the `v0.9.5` release. @@ -1344,28 +1383,28 @@ a time. However, a workaround is possible using the [ngx.var.VARIABLE](#ngxvarva ```nginx -location /foo { - set $diff ''; # we have to predefine the $diff variable here - - set_by_lua $sum ' - local a = 32 - local b = 56 - - ngx.var.diff = a - b; -- write to $diff directly - return a + b; -- return the $sum value normally - '; - - echo "sum = $sum, diff = $diff"; -} + location /foo { + set $diff ''; # we have to predefine the $diff variable here + + set_by_lua $sum ' + local a = 32 + local b = 56 + + ngx.var.diff = a - b; -- write to $diff directly + return a + b; -- return the $sum value normally + '; + + echo "sum = $sum, diff = $diff"; + } ``` This directive can be freely mixed with all directives of the [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html), [set-misc-nginx-module](http://github.com/openresty/set-misc-nginx-module), and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module) modules. All of these directives will run in the same order as they appear in the config file. ```nginx -set $foo 32; -set_by_lua $bar 'tonumber(ngx.var.foo) + 1'; -set $baz "bar: $bar"; # $baz == "bar: 33" + set $foo 32; + set_by_lua $bar 'tonumber(ngx.var.foo) + 1'; + set $baz "bar: $bar"; # $baz == "bar: 33" ``` As from the `v0.5.0rc29` release, Nginx variable interpolation is disabled in the `` argument of this directive and therefore, the dollar sign character (`$`) can be used directly. @@ -1433,6 +1472,20 @@ and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. +Nginx variables are supported in the file path for dynamic dispatch, for example: + +```nginx + + # WARNING: contents in nginx var must be carefully filtered, + # otherwise there'll be great security risk! + location ~ ^/app/([-_a-zA-Z0-9/]+) { + set $path $1; + content_by_lua_file /path/to/lua/app/root/$path.lua; + } +``` + +But be very careful about malicious user inputs and always carefully validate or filter out the user-supplied path components. + [Back to TOC](#directives) rewrite_by_lua @@ -1451,12 +1504,12 @@ Note that this handler always runs *after* the standard [ngx_http_rewrite_module ```nginx -location /foo { - set $a 12; # create and initialize $a - set $b ""; # create and initialize $b - rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; - echo "res = $b"; -} + location /foo { + set $a 12; # create and initialize $a + set $b ""; # create and initialize $b + rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; + echo "res = $b"; + } ``` because `set $a 12` and `set $b ""` run *before* [rewrite_by_lua](#rewrite_by_lua). @@ -1465,17 +1518,17 @@ On the other hand, the following will not work as expected: ```nginx -? location /foo { -? set $a 12; # create and initialize $a -? set $b ''; # create and initialize $b -? rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; -? if ($b = '13') { -? rewrite ^ /bar redirect; -? break; -? } -? -? echo "res = $b"; -? } + ? location /foo { + ? set $a 12; # create and initialize $a + ? set $b ''; # create and initialize $b + ? rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; + ? if ($b = '13') { + ? rewrite ^ /bar redirect; + ? break; + ? } + ? + ? echo "res = $b"; + ? } ``` because `if` runs *before* [rewrite_by_lua](#rewrite_by_lua) even if it is placed after [rewrite_by_lua](#rewrite_by_lua) in the config. @@ -1484,56 +1537,56 @@ The right way of doing this is as follows: ```nginx -location /foo { - set $a 12; # create and initialize $a - set $b ''; # create and initialize $b - rewrite_by_lua ' - ngx.var.b = tonumber(ngx.var.a) + 1 - if tonumber(ngx.var.b) == 13 then - return ngx.redirect("/bar"); - end - '; - - echo "res = $b"; -} + location /foo { + set $a 12; # create and initialize $a + set $b ''; # create and initialize $b + rewrite_by_lua ' + ngx.var.b = tonumber(ngx.var.a) + 1 + if tonumber(ngx.var.b) == 13 then + return ngx.redirect("/bar"); + end + '; + + echo "res = $b"; + } ``` Note that the [ngx_eval](http://www.grid.net.ru/nginx/eval.en.html) module can be approximated by using [rewrite_by_lua](#rewrite_by_lua). For example, ```nginx -location / { - eval $res { - proxy_pass http://foo.com/check-spam; - } - - if ($res = 'spam') { - rewrite ^ /terms-of-use.html redirect; - } - - fastcgi_pass ...; -} + location / { + eval $res { + proxy_pass http://foo.com/check-spam; + } + + if ($res = 'spam') { + rewrite ^ /terms-of-use.html redirect; + } + + fastcgi_pass ...; + } ``` can be implemented in ngx_lua as: ```nginx -location = /check-spam { - internal; - proxy_pass http://foo.com/check-spam; -} - -location / { - rewrite_by_lua ' - local res = ngx.location.capture("/check-spam") - if res.body == "spam" then - return ngx.redirect("/terms-of-use.html") - end - '; - - fastcgi_pass ...; -} + location = /check-spam { + internal; + proxy_pass http://foo.com/check-spam; + } + + location / { + rewrite_by_lua ' + local res = ngx.location.capture("/check-spam") + if res.body == "spam" then + return ngx.redirect("/terms-of-use.html") + end + '; + + fastcgi_pass ...; + } ``` Just as any other rewrite phase handlers, [rewrite_by_lua](#rewrite_by_lua) also runs in subrequests. @@ -1544,13 +1597,13 @@ If the [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_ ```nginx -location /foo { - rewrite ^ /bar; - rewrite_by_lua 'ngx.exit(503)'; -} -location /bar { - ... -} + location /foo { + rewrite ^ /bar; + rewrite_by_lua 'ngx.exit(503)'; + } + location /bar { + ... + } ``` Here the Lua code `ngx.exit(503)` will never run. This will be the case if `rewrite ^ /bar last` is used as this will similarly initiate an internal redirection. If the `break` modifier is used instead, there will be no internal redirection and the `rewrite_by_lua` code will be executed. @@ -1578,6 +1631,8 @@ When the Lua code cache is turned on (by default), the user code is loaded once The `rewrite_by_lua_file` code will always run at the end of the `rewrite` request-processing phase unless [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) is turned on. +Nginx variables are supported in the file path for dynamic dispatch just as in [content_by_lua_file](#content_by_lua_file). + [Back to TOC](#directives) access_by_lua @@ -1596,19 +1651,19 @@ Note that this handler always runs *after* the standard [ngx_http_access_module] ```nginx -location / { - deny 192.168.1.1; - allow 192.168.1.0/24; - allow 10.1.1.0/16; - deny all; - - access_by_lua ' - local res = ngx.location.capture("/mysql", { ... }) - ... - '; - - # proxy_pass/fastcgi_pass/... -} + location / { + deny 192.168.1.1; + allow 192.168.1.0/24; + allow 10.1.1.0/16; + deny all; + + access_by_lua ' + local res = ngx.location.capture("/mysql", { ... }) + ... + '; + + # proxy_pass/fastcgi_pass/... + } ``` That is, if a client IP address is in the blacklist, it will be denied before the MySQL query for more complex authentication is executed by [access_by_lua](#access_by_lua). @@ -1617,34 +1672,34 @@ Note that the [ngx_auth_request](http://mdounin.ru/hg/ngx_http_auth_request_modu ```nginx -location / { - auth_request /auth; - - # proxy_pass/fastcgi_pass/postgres_pass/... -} + location / { + auth_request /auth; + + # proxy_pass/fastcgi_pass/postgres_pass/... + } ``` can be implemented in ngx_lua as: ```nginx -location / { - access_by_lua ' - local res = ngx.location.capture("/auth") - - if res.status == ngx.HTTP_OK then - return - end - - if res.status == ngx.HTTP_FORBIDDEN then - ngx.exit(res.status) - end - - ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) - '; - - # proxy_pass/fastcgi_pass/postgres_pass/... -} + location / { + access_by_lua ' + local res = ngx.location.capture("/auth") + + if res.status == ngx.HTTP_OK then + return + end + + if res.status == ngx.HTTP_FORBIDDEN then + ngx.exit(res.status) + end + + ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) + '; + + # proxy_pass/fastcgi_pass/postgres_pass/... + } ``` As with other access phase handlers, [access_by_lua](#access_by_lua) will *not* run in subrequests. @@ -1672,6 +1727,8 @@ When the Lua code cache is turned on (by default), the user code is loaded once and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid repeatedly reloading Nginx. +Nginx variables are supported in the file path for dynamic dispatch just as in [content_by_lua_file](#content_by_lua_file). + [Back to TOC](#directives) header_filter_by_lua @@ -1696,10 +1753,10 @@ Here is an example of overriding a response header (or adding one if absent) in ```nginx -location / { - proxy_pass http://mybackend; - header_filter_by_lua 'ngx.header.Foo = "blah"'; -} + location / { + proxy_pass http://mybackend; + header_filter_by_lua 'ngx.header.Foo = "blah"'; + } ``` This directive was first introduced in the `v0.2.1rc20` release. @@ -1734,7 +1791,7 @@ body_filter_by_lua Uses Lua code specified in `` to define an output body filter. -The input data chunk is passed via [ngx.arg](#ngxarg)[1] (as a Lua string value) and the "eof" flag indicating the end of the response body data stream is passed via [ngx.arg](#ngxarg)[2] (as a Lua boolean value). +The input data chunk is passed via [ngx.arg](#ngxarg)\[1\] (as a Lua string value) and the "eof" flag indicating the end of the response body data stream is passed via [ngx.arg](#ngxarg)\[2\] (as a Lua boolean value). Behind the scene, the "eof" flag is just the `last_buf` (for main requests) or `last_in_chain` (for subrequests) flag of the Nginx chain link buffers. (Before the `v0.7.14` release, the "eof" flag does not work at all in subrequests.) @@ -1742,42 +1799,42 @@ The output data stream can be aborted immediately by running the following Lua s ```lua -return ngx.ERROR + return ngx.ERROR ``` This will truncate the response body and usually result in incomplete and also invalid responses. -The Lua code can pass its own modified version of the input data chunk to the downstream Nginx output body filters by overriding [ngx.arg](#ngxarg)[1] with a Lua string or a Lua table of strings. For example, to transform all the lowercase letters in the response body, we can just write: +The Lua code can pass its own modified version of the input data chunk to the downstream Nginx output body filters by overriding [ngx.arg](#ngxarg)\[1\] with a Lua string or a Lua table of strings. For example, to transform all the lowercase letters in the response body, we can just write: ```nginx -location / { - proxy_pass http://mybackend; - body_filter_by_lua 'ngx.arg[1] = string.upper(ngx.arg[1])'; -} + location / { + proxy_pass http://mybackend; + body_filter_by_lua 'ngx.arg[1] = string.upper(ngx.arg[1])'; + } ``` When setting `nil` or an empty Lua string value to `ngx.arg[1]`, no data chunk will be passed to the downstream Nginx output filters at all. -Likewise, new "eof" flag can also be specified by setting a boolean value to [ngx.arg](#ngxarg)[2]. For example, +Likewise, new "eof" flag can also be specified by setting a boolean value to [ngx.arg](#ngxarg)\[2\]. For example, ```nginx -location /t { - echo hello world; - echo hiya globe; + location /t { + echo hello world; + echo hiya globe; - body_filter_by_lua ' - local chunk = ngx.arg[1] - if string.match(chunk, "hello") then - ngx.arg[2] = true -- new eof - return - end + body_filter_by_lua ' + local chunk = ngx.arg[1] + if string.match(chunk, "hello") then + ngx.arg[2] = true -- new eof + return + end - -- just throw away any remaining chunk data - ngx.arg[1] = nil - '; -} + -- just throw away any remaining chunk data + ngx.arg[1] = nil + '; + } ``` Then `GET /t` will just return the output @@ -1792,12 +1849,12 @@ When the Lua code may change the length of the response body, then it is require ```nginx -location /foo { - # fastcgi_pass/proxy_pass/... + location /foo { + # fastcgi_pass/proxy_pass/... - header_filter_by_lua 'ngx.header.content_length = nil'; - body_filter_by_lua 'ngx.arg[1] = string.len(ngx.arg[1]) .. "\\n"'; -} + header_filter_by_lua 'ngx.header.content_length = nil'; + body_filter_by_lua 'ngx.arg[1] = string.len(ngx.arg[1]) .. "\\n"'; + } ``` Note that the following API functions are currently disabled within this context due to the limitations in NGINX output filter's current implementation: @@ -1852,43 +1909,43 @@ Here is an example of gathering average data for [$upstream_response_time](http: ```nginx -lua_shared_dict log_dict 5M; + lua_shared_dict log_dict 5M; -server { - location / { - proxy_pass http://mybackend; + server { + location / { + proxy_pass http://mybackend; - log_by_lua ' - local log_dict = ngx.shared.log_dict - local upstream_time = tonumber(ngx.var.upstream_response_time) + log_by_lua ' + local log_dict = ngx.shared.log_dict + local upstream_time = tonumber(ngx.var.upstream_response_time) - local sum = log_dict:get("upstream_time-sum") or 0 - sum = sum + upstream_time - log_dict:set("upstream_time-sum", sum) + local sum = log_dict:get("upstream_time-sum") or 0 + sum = sum + upstream_time + log_dict:set("upstream_time-sum", sum) - local newval, err = log_dict:incr("upstream_time-nb", 1) - if not newval and err == "not found" then - log_dict:add("upstream_time-nb", 0) - log_dict:incr("upstream_time-nb", 1) - end - '; - } + local newval, err = log_dict:incr("upstream_time-nb", 1) + if not newval and err == "not found" then + log_dict:add("upstream_time-nb", 0) + log_dict:incr("upstream_time-nb", 1) + end + '; + } - location = /status { - content_by_lua ' - local log_dict = ngx.shared.log_dict - local sum = log_dict:get("upstream_time-sum") - local nb = log_dict:get("upstream_time-nb") + location = /status { + content_by_lua ' + local log_dict = ngx.shared.log_dict + local sum = log_dict:get("upstream_time-sum") + local nb = log_dict:get("upstream_time-nb") - if nb and sum then - ngx.say("average upstream response time: ", sum / nb, - " (", nb, " reqs)") - else - ngx.say("no data yet") - end - '; - } -} + if nb and sum then + ngx.say("average upstream response time: ", sum / nb, + " (", nb, " reqs)") + else + ngx.say("no data yet") + end + '; + } + } ``` This directive was first introduced in the `v0.5.0rc31` release. @@ -1959,10 +2016,10 @@ The `` argument accepts size units such as `k` and `m`: ```nginx -http { - lua_shared_dict dogs 10m; - ... -} + http { + lua_shared_dict dogs 10m; + ... + } ``` See [ngx.shared.DICT](#ngxshareddict) for details. @@ -2142,7 +2199,7 @@ This directive was first introduced in the `v0.9.11` release. lua_ssl_protocols ----------------- -**syntax:** *lua_ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2]* +**syntax:** *lua_ssl_protocols \[SSLv2\] \[SSLv3\] \[TLSv1\] [TLSv1.1] [TLSv1.2]* **default:** *lua_ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2* @@ -2260,7 +2317,7 @@ For example, on Linux, you can configure the standard [listen](http://nginx.org/ ```nginx -listen 80 so_keepalive=2s:2s:8; + listen 80 so_keepalive=2s:2s:8; ``` On FreeBSD, you can only tune the system-wide configuration for TCP keepalive, for example: @@ -2455,15 +2512,15 @@ The packages can be introduced into external Lua modules like this: ```lua -local say = ngx.say + local say = ngx.say -local _M = {} + local _M = {} -function _M.foo(a) - say(a) -end + function _M.foo(a) + say(a) + end -return _M + return _M ``` Use of the [package.seeall](http://www.lua.org/manual/5.1/manual.html#pdf-package.seeall) flag is strongly discouraged due to its various bad side-effects. @@ -2472,8 +2529,8 @@ It is also possible to directly require the packages in external Lua modules: ```lua -local ngx = require "ngx" -local ndk = require "ndk" + local ngx = require "ngx" + local ndk = require "ndk" ``` The ability to require these packages was introduced in the `v0.2.1rc19` release. @@ -2484,7 +2541,7 @@ Network I/O operations in user code should only be done through the Nginx Lua AP ngx.arg ------- -**syntax:** *val = ngx.arg[index]* +**syntax:** *val = ngx.arg\[index\]* **context:** *set_by_lua*, body_filter_by_lua** @@ -2492,23 +2549,23 @@ When this is used in the context of the [set_by_lua](#set_by_lua) or [set_by_lua ```lua -value = ngx.arg[n] + value = ngx.arg[n] ``` Here is an example ```nginx -location /foo { - set $a 32; - set $b 56; - - set_by_lua $sum - 'return tonumber(ngx.arg[1]) + tonumber(ngx.arg[2])' - $a $b; - - echo $sum; -} + location /foo { + set $a 32; + set $b 56; + + set_by_lua $sum + 'return tonumber(ngx.arg[1]) + tonumber(ngx.arg[2])' + $a $b; + + echo $sum; + } ``` that writes out `88`, the sum of `32` and `56`. @@ -2529,8 +2586,8 @@ Read and write Nginx variable values. ```nginx -value = ngx.var.some_nginx_variable_name -ngx.var.some_nginx_variable_name = value + value = ngx.var.some_nginx_variable_name + ngx.var.some_nginx_variable_name = value ``` Note that only already defined nginx variables can be written to. @@ -2538,19 +2595,19 @@ For example: ```nginx -location /foo { - set $my_var ''; # this line is required to create $my_var at config time - content_by_lua ' - ngx.var.my_var = 123; - ... - '; -} + location /foo { + set $my_var ''; # this line is required to create $my_var at config time + content_by_lua ' + ngx.var.my_var = 123; + ... + '; + } ``` That is, nginx variables cannot be created on-the-fly. Some special nginx variables like `$args` and `$limit_rate` can be assigned a value, -some are not, like `$arg_PARAMETER`. +many others are not, like `$query_string`, `$arg_PARAMETER`, and `$http_NAME`. Nginx regex group capturing variables `$1`, `$2`, `$3`, and etc, can be read by this interface as well, by writing `ngx.var[1]`, `ngx.var[2]`, `ngx.var[3]`, and etc. @@ -2559,15 +2616,15 @@ Setting `ngx.var.Foo` to a `nil` value will unset the `$Foo` Nginx variable. ```lua -ngx.var.args = nil + ngx.var.args = nil ``` **WARNING** When reading from an Nginx variable, Nginx will allocate memory in the per-request memory pool which is freed only at request termination. So when you need to read from an Nginx variable repeatedly in your Lua code, cache the Nginx variable value to your own Lua variable, for example, ```lua -local val = ngx.var.some_var ---- use the val repeatedly later + local val = ngx.var.some_var + --- use the val repeatedly later ``` to prevent (temporary) memory leaking within the current request's lifetime. Another way of caching the result is to use the [ngx.ctx](#ngxctx) table. @@ -2582,18 +2639,18 @@ Core constants ```lua - ngx.OK (0) - ngx.ERROR (-1) - ngx.AGAIN (-2) - ngx.DONE (-4) - ngx.DECLINED (-5) + ngx.OK (0) + ngx.ERROR (-1) + ngx.AGAIN (-2) + ngx.DONE (-4) + ngx.DECLINED (-5) ``` Note that only three of these constants are utilized by the [Nginx API for Lua](#nginx-api-for-lua) (i.e., [ngx.exit](#ngxexit) accepts `NGX_OK`, `NGX_ERROR`, and `NGX_DECLINED` as input). ```lua - ngx.null + ngx.null ``` The `ngx.null` constant is a `NULL` light userdata usually used to represent nil values in Lua tables etc and is similar to the [lua-cjson](http://www.kyne.com.au/~mark/software/lua-cjson.php) library's `cjson.null` constant. This constant was first introduced in the `v0.5.0rc5` release. @@ -2634,23 +2691,23 @@ HTTP status constants ```nginx - value = ngx.HTTP_OK (200) - value = ngx.HTTP_CREATED (201) - value = ngx.HTTP_SPECIAL_RESPONSE (300) - value = ngx.HTTP_MOVED_PERMANENTLY (301) - value = ngx.HTTP_MOVED_TEMPORARILY (302) - value = ngx.HTTP_SEE_OTHER (303) - value = ngx.HTTP_NOT_MODIFIED (304) - value = ngx.HTTP_BAD_REQUEST (400) - value = ngx.HTTP_UNAUTHORIZED (401) - value = ngx.HTTP_FORBIDDEN (403) - value = ngx.HTTP_NOT_FOUND (404) - value = ngx.HTTP_NOT_ALLOWED (405) - value = ngx.HTTP_GONE (410) - value = ngx.HTTP_INTERNAL_SERVER_ERROR (500) - value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501) - value = ngx.HTTP_SERVICE_UNAVAILABLE (503) - value = ngx.HTTP_GATEWAY_TIMEOUT (504) (first added in the v0.3.1rc38 release) + value = ngx.HTTP_OK (200) + value = ngx.HTTP_CREATED (201) + value = ngx.HTTP_SPECIAL_RESPONSE (300) + value = ngx.HTTP_MOVED_PERMANENTLY (301) + value = ngx.HTTP_MOVED_TEMPORARILY (302) + value = ngx.HTTP_SEE_OTHER (303) + value = ngx.HTTP_NOT_MODIFIED (304) + value = ngx.HTTP_BAD_REQUEST (400) + value = ngx.HTTP_UNAUTHORIZED (401) + value = ngx.HTTP_FORBIDDEN (403) + value = ngx.HTTP_NOT_FOUND (404) + value = ngx.HTTP_NOT_ALLOWED (405) + value = ngx.HTTP_GONE (410) + value = ngx.HTTP_INTERNAL_SERVER_ERROR (500) + value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501) + value = ngx.HTTP_SERVICE_UNAVAILABLE (503) + value = ngx.HTTP_GATEWAY_TIMEOUT (504) (first added in the v0.3.1rc38 release) ``` [Back to TOC](#nginx-api-for-lua) @@ -2661,15 +2718,15 @@ Nginx log level constants ```lua - ngx.STDERR - ngx.EMERG - ngx.ALERT - ngx.CRIT - ngx.ERR - ngx.WARN - ngx.NOTICE - ngx.INFO - ngx.DEBUG + ngx.STDERR + ngx.EMERG + ngx.ALERT + ngx.CRIT + ngx.ERR + ngx.WARN + ngx.NOTICE + ngx.INFO + ngx.DEBUG ``` These constants are usually used by the [ngx.log](#ngxlog) method. @@ -2688,7 +2745,7 @@ It is equivalent to ```lua -ngx.log(ngx.NOTICE, ...) + ngx.log(ngx.NOTICE, ...) ``` Lua `nil` arguments are accepted and result in literal `"nil"` strings while Lua booleans result in literal `"true"` or `"false"` strings. And the `ngx.null` constant will yield the `"null"` string output. @@ -2707,26 +2764,26 @@ Consider the following example, ```nginx -location /test { - rewrite_by_lua ' - ngx.say("foo = ", ngx.ctx.foo) - ngx.ctx.foo = 76 - '; - access_by_lua ' - ngx.ctx.foo = ngx.ctx.foo + 3 - '; - content_by_lua ' - ngx.say(ngx.ctx.foo) - '; -} + location /test { + rewrite_by_lua ' + ngx.say("foo = ", ngx.ctx.foo) + ngx.ctx.foo = 76 + '; + access_by_lua ' + ngx.ctx.foo = ngx.ctx.foo + 3 + '; + content_by_lua ' + ngx.say(ngx.ctx.foo) + '; + } ``` Then `GET /test` will yield the output ```bash -foo = nil -79 + foo = nil + 79 ``` That is, the `ngx.ctx.foo` entry persists across the rewrite, access, and content phases of a request. @@ -2735,33 +2792,33 @@ Every request, including subrequests, has its own copy of the table. For example ```nginx -location /sub { - content_by_lua ' - ngx.say("sub pre: ", ngx.ctx.blah) - ngx.ctx.blah = 32 - ngx.say("sub post: ", ngx.ctx.blah) - '; -} - -location /main { - content_by_lua ' - ngx.ctx.blah = 73 - ngx.say("main pre: ", ngx.ctx.blah) - local res = ngx.location.capture("/sub") - ngx.print(res.body) - ngx.say("main post: ", ngx.ctx.blah) - '; -} + location /sub { + content_by_lua ' + ngx.say("sub pre: ", ngx.ctx.blah) + ngx.ctx.blah = 32 + ngx.say("sub post: ", ngx.ctx.blah) + '; + } + + location /main { + content_by_lua ' + ngx.ctx.blah = 73 + ngx.say("main pre: ", ngx.ctx.blah) + local res = ngx.location.capture("/sub") + ngx.print(res.body) + ngx.say("main post: ", ngx.ctx.blah) + '; + } ``` Then `GET /main` will give the output ```bash -main pre: 73 -sub pre: nil -sub post: 32 -main post: 73 + main pre: 73 + sub pre: nil + sub post: 32 + main post: 73 ``` Here, modification of the `ngx.ctx.blah` entry in the subrequest does not affect the one in the parent request. This is because they have two separate versions of `ngx.ctx.blah`. @@ -2770,25 +2827,25 @@ Internal redirection will destroy the original request `ngx.ctx` data (if any) a ```nginx -location /new { - content_by_lua ' - ngx.say(ngx.ctx.foo) - '; -} - -location /orig { - content_by_lua ' - ngx.ctx.foo = "hello" - ngx.exec("/new") - '; -} + location /new { + content_by_lua ' + ngx.say(ngx.ctx.foo) + '; + } + + location /orig { + content_by_lua ' + ngx.ctx.foo = "hello" + ngx.exec("/new") + '; + } ``` Then `GET /orig` will give ```bash -nil + nil ``` rather than the original `"hello"` value. @@ -2799,7 +2856,7 @@ Overriding `ngx.ctx` with a new Lua table is also supported, for example, ```lua -ngx.ctx = { foo = 32, bar = 54 } + ngx.ctx = { foo = 32, bar = 54 } ``` When being used in the context of [init_worker_by_lua*](#init_worker_by_lua), this table just has the same lifetime of the current Lua handler. @@ -2829,7 +2886,7 @@ Here is a basic example: ```lua -res = ngx.location.capture(uri) + res = ngx.location.capture(uri) ``` Returns a Lua table with three slots (`res.status`, `res.header`, `res.body`, and `res.truncated`). @@ -2844,9 +2901,9 @@ lines: ```bash -Set-Cookie: a=3 -Set-Cookie: foo=bar -Set-Cookie: baz=blah + Set-Cookie: a=3 + Set-Cookie: foo=bar + Set-Cookie: baz=blah ``` Then `res.header["Set-Cookie"]` will be evaluated to the table value @@ -2858,7 +2915,7 @@ URI query strings can be concatenated to URI itself, for instance, ```lua -res = ngx.location.capture('/foo/bar?a=3&b=4') + res = ngx.location.capture('/foo/bar?a=3&b=4') ``` Named locations like `@foo` are not allowed due to a limitation in @@ -2881,7 +2938,7 @@ argument, which supports the options: * `copy_all_vars` specify whether to copy over all the Nginx variable values of the current request to the subrequest in question. modifications of the nginx variables in the subrequest will not affect the current (parent) request. This option was first introduced in the `v0.3.1rc31` release. * `share_all_vars` - specify whether to share all the Nginx variables of the subrequest with the current (parent) request. modifications of the Nginx variables in the subrequest will affect the current (parent) request. + specify whether to share all the Nginx variables of the subrequest with the current (parent) request. modifications of the Nginx variables in the subrequest will affect the current (parent) request. Enabling this option may lead to hard-to-debug issues due to bad side-effects and is considered bad and harmful. Only enable this option when you completely know what you are doing. * `always_forward_body` when set to true, the current (parent) request's request body will always be forwarded to the subrequest being created if the `body` option is not specified. The request body read by either [ngx.req.read_body()](#ngxreqread_body) or [lua_need_request_body on](#lua_need_request_body) will be directly forwarded to the subrequest without copying the whole request body data when creating the subrequest (no matter the request body data is buffered in memory buffers or temporary files). By default, this option is `false` and when the `body` option is not specified, the request body of the current (parent) request is only forwarded when the subrequest takes the `PUT` or `POST` request method. @@ -2889,10 +2946,10 @@ Issuing a POST subrequest, for example, can be done as follows ```lua -res = ngx.location.capture( - '/foo/bar', - { method = ngx.HTTP_POST, body = 'hello, world' } -) + res = ngx.location.capture( + '/foo/bar', + { method = ngx.HTTP_POST, body = 'hello, world' } + ) ``` See HTTP method constants methods other than POST. @@ -2902,16 +2959,16 @@ The `args` option can specify extra URI arguments, for instance, ```lua -ngx.location.capture('/foo?a=1', - { args = { b = 3, c = ':' } } -) + ngx.location.capture('/foo?a=1', + { args = { b = 3, c = ':' } } + ) ``` is equivalent to ```lua -ngx.location.capture('/foo?a=1&b=3&c=%3a') + ngx.location.capture('/foo?a=1&b=3&c=%3a') ``` that is, this method will escape argument keys and values according to URI rules and @@ -2921,9 +2978,9 @@ The `args` option can also take plain query strings: ```lua -ngx.location.capture('/foo?a=1', - { args = 'b=3&c=%3a' } } -) + ngx.location.capture('/foo?a=1', + { args = 'b=3&c=%3a' } } + ) ``` This is functionally identical to the previous examples. @@ -2937,21 +2994,21 @@ This option is set to `false` by default ```nginx -location /other { - set $dog "$dog world"; - echo "$uri dog: $dog"; -} + location /other { + set $dog "$dog world"; + echo "$uri dog: $dog"; + } -location /lua { - set $dog 'hello'; - content_by_lua ' - res = ngx.location.capture("/other", - { share_all_vars = true }); + location /lua { + set $dog 'hello'; + content_by_lua ' + res = ngx.location.capture("/other", + { share_all_vars = true }); - ngx.print(res.body) - ngx.say(ngx.var.uri, ": ", ngx.var.dog) - '; -} + ngx.print(res.body) + ngx.say(ngx.var.uri, ": ", ngx.var.dog) + '; + } ``` Accessing location `/lua` gives @@ -2965,21 +3022,21 @@ The `copy_all_vars` option provides a copy of the parent request's Nginx variabl ```nginx -location /other { - set $dog "$dog world"; - echo "$uri dog: $dog"; -} + location /other { + set $dog "$dog world"; + echo "$uri dog: $dog"; + } -location /lua { - set $dog 'hello'; - content_by_lua ' - res = ngx.location.capture("/other", - { copy_all_vars = true }); + location /lua { + set $dog 'hello'; + content_by_lua ' + res = ngx.location.capture("/other", + { copy_all_vars = true }); - ngx.print(res.body) - ngx.say(ngx.var.uri, ": ", ngx.var.dog) - '; -} + ngx.print(res.body) + ngx.say(ngx.var.uri, ": ", ngx.var.dog) + '; + } ``` Request `GET /lua` will give the output @@ -3000,23 +3057,23 @@ unescaping them in the Nginx config file. ```nginx -location /other { - content_by_lua ' - ngx.say("dog = ", ngx.var.dog) - ngx.say("cat = ", ngx.var.cat) - '; -} + location /other { + content_by_lua ' + ngx.say("dog = ", ngx.var.dog) + ngx.say("cat = ", ngx.var.cat) + '; + } -location /lua { - set $dog ''; - set $cat ''; - content_by_lua ' - res = ngx.location.capture("/other", - { vars = { dog = "hello", cat = 32 }}); + location /lua { + set $dog ''; + set $cat ''; + content_by_lua ' + res = ngx.location.capture("/other", + { vars = { dog = "hello", cat = 32 }}); - ngx.print(res.body) - '; -} + ngx.print(res.body) + '; + } ``` Accessing `/lua` will yield the output @@ -3030,20 +3087,20 @@ The `ctx` option can be used to specify a custom Lua table to serve as the [ngx. ```nginx -location /sub { - content_by_lua ' - ngx.ctx.foo = "bar"; - '; -} -location /lua { - content_by_lua ' - local ctx = {} - res = ngx.location.capture("/sub", { ctx = ctx }) + location /sub { + content_by_lua ' + ngx.ctx.foo = "bar"; + '; + } + location /lua { + content_by_lua ' + local ctx = {} + res = ngx.location.capture("/sub", { ctx = ctx }) - ngx.say(ctx.foo); - ngx.say(ngx.ctx.foo); - '; -} + ngx.say(ctx.foo); + ngx.say(ngx.ctx.foo); + '; + } ``` Then request `GET /lua` gives @@ -3057,17 +3114,17 @@ It is also possible to use this `ctx` option to share the same [ngx.ctx](#ngxctx ```nginx -location /sub { - content_by_lua ' - ngx.ctx.foo = "bar"; - '; -} -location /lua { - content_by_lua ' - res = ngx.location.capture("/sub", { ctx = ngx.ctx }) - ngx.say(ngx.ctx.foo); - '; -} + location /sub { + content_by_lua ' + ngx.ctx.foo = "bar"; + '; + } + location /lua { + content_by_lua ' + res = ngx.location.capture("/sub", { ctx = ngx.ctx }) + ngx.say(ngx.ctx.foo); + '; + } ``` Request `GET /lua` yields the output @@ -3109,19 +3166,19 @@ This function issues several parallel subrequests specified by the input table a ```lua -res1, res2, res3 = ngx.location.capture_multi{ - { "/foo", { args = "a=3&b=4" } }, - { "/bar" }, - { "/baz", { method = ngx.HTTP_POST, body = "hello" } }, -} - -if res1.status == ngx.HTTP_OK then - ... -end - -if res2.body == "BLAH" then - ... -end + res1, res2, res3 = ngx.location.capture_multi{ + { "/foo", { args = "a=3&b=4" } }, + { "/bar" }, + { "/baz", { method = ngx.HTTP_POST, body = "hello" } }, + } + + if res1.status == ngx.HTTP_OK then + ... + end + + if res2.body == "BLAH" then + ... + end ``` This function will not return until all the subrequests terminate. @@ -3131,20 +3188,20 @@ Lua tables can be used for both requests and responses when the number of subreq ```lua --- construct the requests table -local reqs = {} -table.insert(reqs, { "/mysql" }) -table.insert(reqs, { "/postgres" }) -table.insert(reqs, { "/redis" }) -table.insert(reqs, { "/memcached" }) - --- issue all the requests at once and wait until they all return -local resps = { ngx.location.capture_multi(reqs) } - --- loop over the responses table -for i, resp in ipairs(resps) do - -- process the response table "resp" -end + -- construct the requests table + local reqs = {} + table.insert(reqs, { "/mysql" }) + table.insert(reqs, { "/postgres" }) + table.insert(reqs, { "/redis" }) + table.insert(reqs, { "/memcached" }) + + -- issue all the requests at once and wait until they all return + local resps = { ngx.location.capture_multi(reqs) } + + -- loop over the responses table + for i, resp in ipairs(resps) do + -- process the response table "resp" + end ``` The [ngx.location.capture](#ngxlocationcapture) function is just a special form @@ -3152,10 +3209,10 @@ of this function. Logically speaking, the [ngx.location.capture](#ngxlocationcap ```lua -ngx.location.capture = - function (uri, args) - return ngx.location.capture_multi({ {uri, args} }) - end + ngx.location.capture = + function (uri, args) + return ngx.location.capture_multi({ {uri, args} }) + end ``` Please also refer to restrictions on capturing locations configured by [subrequest directives of other modules](#locations-configured-by-subrequest-directives-of-other-modules). @@ -3171,8 +3228,8 @@ before sending out the response headers. ```lua -ngx.status = ngx.HTTP_CREATED -status = ngx.status + ngx.status = ngx.HTTP_CREATED + status = ngx.status ``` Setting `ngx.status` after the response header is sent out has no effect but leaving an error message in your nginx's error log file: @@ -3199,25 +3256,25 @@ The header names are matched case-insensitively. ```lua --- equivalent to ngx.header["Content-Type"] = 'text/plain' -ngx.header.content_type = 'text/plain'; - -ngx.header["X-My-Header"] = 'blah blah'; + -- equivalent to ngx.header["Content-Type"] = 'text/plain' + ngx.header.content_type = 'text/plain'; + + ngx.header["X-My-Header"] = 'blah blah'; ``` Multi-value headers can be set this way: ```lua -ngx.header['Set-Cookie'] = {'a=32; path=/', 'b=4; path=/'} + ngx.header['Set-Cookie'] = {'a=32; path=/', 'b=4; path=/'} ``` will yield ```bash -Set-Cookie: a=32; path=/ -Set-Cookie: b=4; path=/ + Set-Cookie: a=32; path=/ + Set-Cookie: b=4; path=/ ``` in the response headers. @@ -3226,28 +3283,28 @@ Only Lua tables are accepted (Only the last element in the table will take effec ```lua -ngx.header.content_type = {'a', 'b'} + ngx.header.content_type = {'a', 'b'} ``` is equivalent to ```lua -ngx.header.content_type = 'b' + ngx.header.content_type = 'b' ``` Setting a slot to `nil` effectively removes it from the response headers: ```lua -ngx.header["X-My-Header"] = nil; + ngx.header["X-My-Header"] = nil; ``` The same applies to assigning an empty table: ```lua -ngx.header["X-My-Header"] = {}; + ngx.header["X-My-Header"] = {}; ``` Setting `ngx.header.HEADER` after sending out response headers (either explicitly with [ngx.send_headers](#ngxsend_headers) or implicitly with [ngx.print](#ngxprint) and similar) will throw out a Lua exception. @@ -3260,19 +3317,19 @@ This is particularly useful in the context of [header_filter_by_lua](#header_fil ```nginx -location /test { - set $footer ''; + location /test { + set $footer ''; - proxy_pass http://some-backend; + proxy_pass http://some-backend; - header_filter_by_lua ' - if ngx.header["X-My-Header"] == "blah" then - ngx.var.footer = "some value" - end - '; + header_filter_by_lua ' + if ngx.header["X-My-Header"] == "blah" then + ngx.var.footer = "some value" + end + '; - echo_after_body $footer; -} + echo_after_body $footer; + } ``` For multi-value headers, all of the values of header will be collected in order and returned as a Lua table. For example, response headers @@ -3286,7 +3343,7 @@ will result in ```lua -{"bar", "baz"} + {"bar", "baz"} ``` to be returned when reading `ngx.header.Foo`. @@ -3307,10 +3364,10 @@ Returns a Lua table holding all the current response headers for the current req ```lua -local h = ngx.resp.get_headers() -for k, v in pairs(h) do - ... -end + local h = ngx.resp.get_headers() + for k, v in pairs(h) do + ... + end ``` This function has the same signature as [ngx.req.get_headers](#ngxreqget_headers) except getting response headers instead of request headers. @@ -3331,7 +3388,7 @@ The following example emulates the `$request_time` variable value (provided by [ ```lua -local request_time = ngx.now() - ngx.req.start_time() + local request_time = ngx.now() - ngx.req.start_time() ``` This function was first introduced in the `v0.7.7` release. @@ -3366,7 +3423,7 @@ By default, the request line and trailing `CR LF` terminator will also be includ ```lua -ngx.print(ngx.req.raw_header()) + ngx.print(ngx.req.raw_header()) ``` gives something like this: @@ -3384,7 +3441,7 @@ You can specify the optional ```lua -ngx.print(ngx.req.raw_header(true)) + ngx.print(ngx.req.raw_header(true)) ``` outputs something like this: @@ -3448,35 +3505,35 @@ For example, the following nginx config snippet ```nginx -rewrite ^ /foo last; + rewrite ^ /foo last; ``` can be coded in Lua like this: ```lua -ngx.req.set_uri("/foo", true) + ngx.req.set_uri("/foo", true) ``` Similarly, Nginx config ```nginx -rewrite ^ /foo break; + rewrite ^ /foo break; ``` can be coded in Lua as ```lua -ngx.req.set_uri("/foo", false) + ngx.req.set_uri("/foo", false) ``` or equivalently, ```lua -ngx.req.set_uri("/foo") + ngx.req.set_uri("/foo") ``` The `jump` can only be set to `true` in [rewrite_by_lua](#rewrite_by_lua) and [rewrite_by_lua_file](#rewrite_by_lua_file). Use of jump in other contexts is prohibited and will throw out a Lua exception. @@ -3485,46 +3542,46 @@ A more sophisticated example involving regex substitutions is as follows ```nginx -location /test { - rewrite_by_lua ' - local uri = ngx.re.sub(ngx.var.uri, "^/test/(.*)", "$1", "o") - ngx.req.set_uri(uri) - '; - proxy_pass http://my_backend; -} + location /test { + rewrite_by_lua ' + local uri = ngx.re.sub(ngx.var.uri, "^/test/(.*)", "$1", "o") + ngx.req.set_uri(uri) + '; + proxy_pass http://my_backend; + } ``` which is functionally equivalent to ```nginx -location /test { - rewrite ^/test/(.*) /$1 break; - proxy_pass http://my_backend; -} + location /test { + rewrite ^/test/(.*) /$1 break; + proxy_pass http://my_backend; + } ``` Note that it is not possible to use this interface to rewrite URI arguments and that [ngx.req.set_uri_args](#ngxreqset_uri_args) should be used for this instead. For instance, Nginx config ```nginx -rewrite ^ /foo?a=3? last; + rewrite ^ /foo?a=3? last; ``` can be coded as ```nginx -ngx.req.set_uri_args("a=3") -ngx.req.set_uri("/foo", true) + ngx.req.set_uri_args("a=3") + ngx.req.set_uri("/foo", true) ``` or ```nginx -ngx.req.set_uri_args({a = 3}) -ngx.req.set_uri("/foo", true) + ngx.req.set_uri_args({a = 3}) + ngx.req.set_uri("/foo", true) ``` This interface was first introduced in the `v0.3.1rc14` release. @@ -3541,14 +3598,14 @@ Rewrite the current request's URI query arguments by the `args` argument. The `a ```lua -ngx.req.set_uri_args("a=3&b=hello%20world") + ngx.req.set_uri_args("a=3&b=hello%20world") ``` or a Lua table holding the query arguments' key-value pairs, as in ```lua -ngx.req.set_uri_args({ a = 3, b = "hello world" }) + ngx.req.set_uri_args({ a = 3, b = "hello world" }) ``` where in the latter case, this method will escape argument keys and values according to the URI escaping rule. @@ -3557,7 +3614,7 @@ Multi-value arguments are also supported: ```lua -ngx.req.set_uri_args({ a = 3, b = {5, 6} }) + ngx.req.set_uri_args({ a = 3, b = {5, 6} }) ``` which will result in a query string like `a=3&b=5&b=6`. @@ -3578,26 +3635,26 @@ Returns a Lua table holding all the current request URL query arguments. ```nginx -location = /test { - content_by_lua ' - local args = ngx.req.get_uri_args() - for key, val in pairs(args) do - if type(val) == "table" then - ngx.say(key, ": ", table.concat(val, ", ")) - else - ngx.say(key, ": ", val) - end - end - '; -} + location = /test { + content_by_lua ' + local args = ngx.req.get_uri_args() + for key, val in pairs(args) do + if type(val) == "table" then + ngx.say(key, ": ", table.concat(val, ", ")) + else + ngx.say(key, ": ", val) + end + end + '; + } ``` Then `GET /test?foo=bar&bar=baz&bar=blah` will yield the response body ```bash -foo: bar -bar: baz, blah + foo: bar + bar: baz, blah ``` Multiple occurrences of an argument key will result in a table value holding all the values for that key in order. @@ -3606,23 +3663,23 @@ Keys and values are unescaped according to URI escaping rules. In the settings a ```bash -a b: 1a 2 + a b: 1a 2 ``` Arguments without the `=` parts are treated as boolean arguments. `GET /test?foo&bar` will yield: ```bash -foo: true -bar: true + foo: true + bar: true ``` That is, they will take Lua boolean values `true`. However, they are different from arguments taking empty string values. `GET /test?foo=&bar=` will give something like ```bash -foo: -bar: + foo: + bar: ``` Empty key arguments are discarded. `GET /test?=hello&=world` will yield an empty output for instance. @@ -3631,15 +3688,15 @@ Updating query arguments via the nginx variable `$args` (or `ngx.var.args` in Lu ```lua -ngx.var.args = "a=3&b=42" -local args = ngx.req.get_uri_args() + ngx.var.args = "a=3&b=42" + local args = ngx.req.get_uri_args() ``` Here the `args` table will always look like ```lua -{a = 3, b = 42} + {a = 3, b = 42} ``` regardless of the actual request query string. @@ -3650,14 +3707,14 @@ However, the optional `max_args` function argument can be used to override this ```lua -local args = ngx.req.get_uri_args(10) + local args = ngx.req.get_uri_args(10) ``` This argument can be set to zero to remove the limit and to process all request arguments received: ```lua -local args = ngx.req.get_uri_args(0) + local args = ngx.req.get_uri_args(0) ``` Removing the `max_args` cap is strongly discouraged. @@ -3674,39 +3731,39 @@ Returns a Lua table holding all the current request POST query arguments (of the ```nginx -location = /test { - content_by_lua ' - ngx.req.read_body() - local args, err = ngx.req.get_post_args() - if not args then - ngx.say("failed to get post args: ", err) - return - end - for key, val in pairs(args) do - if type(val) == "table" then - ngx.say(key, ": ", table.concat(val, ", ")) - else - ngx.say(key, ": ", val) - end - end - '; -} + location = /test { + content_by_lua ' + ngx.req.read_body() + local args, err = ngx.req.get_post_args() + if not args then + ngx.say("failed to get post args: ", err) + return + end + for key, val in pairs(args) do + if type(val) == "table" then + ngx.say(key, ": ", table.concat(val, ", ")) + else + ngx.say(key, ": ", val) + end + end + '; + } ``` Then ```bash -# Post request with the body 'foo=bar&bar=baz&bar=blah' -$ curl --data 'foo=bar&bar=baz&bar=blah' localhost/test + # Post request with the body 'foo=bar&bar=baz&bar=blah' + $ curl --data 'foo=bar&bar=baz&bar=blah' localhost/test ``` will yield the response body like ```bash -foo: bar -bar: baz, blah + foo: bar + bar: baz, blah ``` Multiple occurrences of an argument key will result in a table value holding all of the values for that key in order. @@ -3717,31 +3774,31 @@ With the settings above, ```bash -# POST request with body 'a%20b=1%61+2' -$ curl -d 'a%20b=1%61+2' localhost/test + # POST request with body 'a%20b=1%61+2' + $ curl -d 'a%20b=1%61+2' localhost/test ``` will yield: ```bash -a b: 1a 2 + a b: 1a 2 ``` Arguments without the `=` parts are treated as boolean arguments. `GET /test?foo&bar` will yield: ```bash -foo: true -bar: true + foo: true + bar: true ``` That is, they will take Lua boolean values `true`. However, they are different from arguments taking empty string values. `POST /test` with request body `foo=&bar=` will return something like ```bash -foo: -bar: + foo: + bar: ``` Empty key arguments are discarded. `POST /test` with body `=hello&=world` will yield empty outputs for instance. @@ -3752,14 +3809,14 @@ However, the optional `max_args` function argument can be used to override this ```lua -local args = ngx.req.get_post_args(10) + local args = ngx.req.get_post_args(10) ``` This argument can be set to zero to remove the limit and to process all request arguments received: ```lua -local args = ngx.req.get_post_args(0) + local args = ngx.req.get_post_args(0) ``` Removing the `max_args` cap is strongly discouraged. @@ -3776,17 +3833,17 @@ Returns a Lua table holding all the current request headers. ```lua -local h = ngx.req.get_headers() -for k, v in pairs(h) do - ... -end + local h = ngx.req.get_headers() + for k, v in pairs(h) do + ... + end ``` To read an individual header: ```lua -ngx.say("Host: ", ngx.req.get_headers()["Host"]) + ngx.say("Host: ", ngx.req.get_headers()["Host"]) ``` Note that the [ngx.var.HEADER](#ngxvarvariable) API call, which uses core [$http_HEADER](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_http_) variables, may be more preferable for reading individual request headers. @@ -3795,16 +3852,16 @@ For multiple instances of request headers such as: ```bash -Foo: foo -Foo: bar -Foo: baz + Foo: foo + Foo: bar + Foo: baz ``` the value of `ngx.req.get_headers()["Foo"]` will be a Lua (array) table such as: ```lua -{"foo", "bar", "baz"} + {"foo", "bar", "baz"} ``` Note that a maximum of 100 request headers are parsed by default (including those with the same name) and that additional request headers are silently discarded to guard against potential denial of service attacks. @@ -3813,14 +3870,14 @@ However, the optional `max_headers` function argument can be used to override th ```lua -local args = ngx.req.get_headers(10) + local args = ngx.req.get_headers(10) ``` This argument can be set to zero to remove the limit and to process all request headers received: ```lua -local args = ngx.req.get_headers(0) + local args = ngx.req.get_headers(0) ``` Removing the `max_headers` cap is strongly discouraged. @@ -3831,9 +3888,9 @@ Also, by default, an `__index` metamethod is added to the resulting Lua table an ```lua -ngx.say(headers.my_foo_header) -ngx.say(headers["My-Foo-Header"]) -ngx.say(headers["my-foo-header"]) + ngx.say(headers.my_foo_header) + ngx.say(headers["My-Foo-Header"]) + ngx.say(headers["my-foo-header"]) ``` The `__index` metamethod will not be added when the `raw` argument is set to `true`. @@ -3850,11 +3907,11 @@ Set the current request's request header named `header_name` to value `header_va By default, all the subrequests subsequently initiated by [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) will inherit the new header. -Here is an example of setting the `Content-Length` header: +Here is an example of setting the `Content-Type` header: ```lua -ngx.req.set_header("Content-Type", "text/css") + ngx.req.set_header("Content-Type", "text/css") ``` The `header_value` can take an array list of values, @@ -3862,15 +3919,15 @@ for example, ```lua -ngx.req.set_header("Foo", {"a", "abc"}) + ngx.req.set_header("Foo", {"a", "abc"}) ``` will produce two new request headers: ```bash -Foo: a -Foo: abc + Foo: a + Foo: abc ``` and old `Foo` headers will be overridden if there is any. @@ -3879,14 +3936,14 @@ When the `header_value` argument is `nil`, the request header will be removed. S ```lua -ngx.req.set_header("X-Foo", nil) + ngx.req.set_header("X-Foo", nil) ``` is equivalent to ```lua -ngx.req.clear_header("X-Foo") + ngx.req.clear_header("X-Foo") ``` [Back to TOC](#nginx-api-for-lua) @@ -3911,8 +3968,8 @@ Reads the client request body synchronously without blocking the Nginx event loo ```lua -ngx.req.read_body() -local args = ngx.req.get_post_args() + ngx.req.read_body() + local args = ngx.req.get_post_args() ``` If the request body is already read previously by turning on [lua_need_request_body](#lua_need_request_body) or by using other modules, then this function does not run and returns immediately. @@ -4054,11 +4111,11 @@ The usage of this function is often like this: ```lua -ngx.req.init_body(128 * 1024) -- buffer is 128KB -for chunk in next_data_chunk() do - ngx.req.append_body(chunk) -- each chunk can be 4KB -end -ngx.req.finish_body() + ngx.req.init_body(128 * 1024) -- buffer is 128KB + for chunk in next_data_chunk() do + ngx.req.append_body(chunk) -- each chunk can be 4KB + end + ngx.req.finish_body() ``` This function can be used with [ngx.req.append_body](#ngxreqappend_body), [ngx.req.finish_body](#ngxreqfinish_body), and [ngx.req.socket](#ngxreqsocket) to implement efficient input filters in pure Lua (in the context of [rewrite_by_lua](#rewrite_by_lua)* or [access_by_lua](#access_by_lua)*), which can be used with other Nginx content handler or upstream modules like [ngx_http_proxy_module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html) and [ngx_http_fastcgi_module](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html). @@ -4140,23 +4197,23 @@ Does an internal redirect to `uri` with `args` and is similar to the [echo_exec] ```lua -ngx.exec('/some-location'); -ngx.exec('/some-location', 'a=3&b=5&c=6'); -ngx.exec('/some-location?a=3&b=5', 'c=6'); + ngx.exec('/some-location'); + ngx.exec('/some-location', 'a=3&b=5&c=6'); + ngx.exec('/some-location?a=3&b=5', 'c=6'); ``` The optional second `args` can be used to specify extra URI query arguments, for example: ```lua -ngx.exec("/foo", "a=3&b=hello%20world") + ngx.exec("/foo", "a=3&b=hello%20world") ``` Alternatively, a Lua table can be passed for the `args` argument for ngx_lua to carry out URI escaping and string concatenation. ```lua -ngx.exec("/foo", { a = 3, b = "hello world" }) + ngx.exec("/foo", { a = 3, b = "hello world" }) ``` The result is exactly the same as the previous example. @@ -4169,22 +4226,22 @@ Named locations are also supported but the second `args` argument will be ignore ```nginx -location /foo { - content_by_lua ' - ngx.exec("@bar", "a=goodbye"); - '; -} + location /foo { + content_by_lua ' + ngx.exec("@bar", "a=goodbye"); + '; + } -location @bar { - content_by_lua ' - local args = ngx.req.get_uri_args() - for key, val in pairs(args) do - if key == "a" then - ngx.say(val) - end - end - '; -} + location @bar { + content_by_lua ' + local args = ngx.req.get_uri_args() + for key, val in pairs(args) do + if key == "a" then + ngx.say(val) + end + end + '; + } ``` Note that the `ngx.exec` method is different from [ngx.redirect](#ngxredirect) in that @@ -4212,64 +4269,64 @@ Here is an example assuming the current server name is `localhost` and that it i ```lua -return ngx.redirect("/foo") + return ngx.redirect("/foo") ``` which is equivalent to ```lua -return ngx.redirect("http://localhost:1984/foo", ngx.HTTP_MOVED_TEMPORARILY) + return ngx.redirect("http://localhost:1984/foo", ngx.HTTP_MOVED_TEMPORARILY) ``` Redirecting arbitrary external URLs is also supported, for example: ```lua -return ngx.redirect("http://www.google.com") + return ngx.redirect("http://www.google.com") ``` We can also use the numerical code directly as the second `status` argument: ```lua -return ngx.redirect("/foo", 301) + return ngx.redirect("/foo", 301) ``` This method is similar to the [rewrite](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) directive with the `redirect` modifier in the standard -[[HttpRewriteModule]], for example, this `nginx.conf` snippet +[ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html), for example, this `nginx.conf` snippet ```nginx -rewrite ^ /foo? redirect; # nginx config + rewrite ^ /foo? redirect; # nginx config ``` is equivalent to the following Lua code ```lua -return ngx.redirect('/foo'); -- Lua code + return ngx.redirect('/foo'); -- Lua code ``` while ```nginx -rewrite ^ /foo? permanent; # nginx config + rewrite ^ /foo? permanent; # nginx config ``` is equivalent to ```lua -return ngx.redirect('/foo', ngx.HTTP_MOVED_PERMANENTLY) -- Lua code + return ngx.redirect('/foo', ngx.HTTP_MOVED_PERMANENTLY) -- Lua code ``` URI arguments can be specified as well, for example: ```lua -return ngx.redirect('/foo?a=3&b=4') + return ngx.redirect('/foo?a=3&b=4') ``` Note that this method call terminates the processing of the current request and that it *must* be called before [ngx.send_headers](#ngxsend_headers) or explicit response body @@ -4322,19 +4379,19 @@ Nested arrays of strings are permitted and the elements in the arrays will be se ```lua -local table = { - "hello, ", - {"world: ", true, " or ", false, - {": ", nil}} -} -ngx.print(table) + local table = { + "hello, ", + {"world: ", true, " or ", false, + {": ", nil}} + } + ngx.print(table) ``` will yield the output ```bash -hello, world: true or false: nil + hello, world: true or false: nil ``` Non-array table arguments will cause a Lua exception to be thrown. @@ -4410,32 +4467,32 @@ To return an error page with custom contents, use code snippets like this: ```lua -ngx.status = ngx.HTTP_GONE -ngx.say("This is our own content") --- to cause quit the whole request rather than the current phase handler -ngx.exit(ngx.HTTP_OK) + ngx.status = ngx.HTTP_GONE + ngx.say("This is our own content") + -- to cause quit the whole request rather than the current phase handler + ngx.exit(ngx.HTTP_OK) ``` The effect in action: ```bash -$ curl -i http://localhost/test -HTTP/1.1 410 Gone -Server: nginx/1.0.6 -Date: Thu, 15 Sep 2011 00:51:48 GMT -Content-Type: text/plain -Transfer-Encoding: chunked -Connection: keep-alive + $ curl -i http://localhost/test + HTTP/1.1 410 Gone + Server: nginx/1.0.6 + Date: Thu, 15 Sep 2011 00:51:48 GMT + Content-Type: text/plain + Transfer-Encoding: chunked + Connection: keep-alive -This is our own content + This is our own content ``` Number literals can be used directly as the argument, for instance, ```lua -ngx.exit(501) + ngx.exit(501) ``` Note that while this method accepts all [HTTP status constants](#http-status-constants) as input, it only accepts `NGX_OK` and `NGX_ERROR` of the [core constants](#core-constants). @@ -4458,21 +4515,21 @@ When you disable the HTTP 1.1 keep-alive feature for your downstream connections ```nginx -location = /async { - keepalive_timeout 0; - content_by_lua ' - ngx.say("got the task!") - ngx.eof() -- a descent HTTP client will close the connection at this point - -- access MySQL, PostgreSQL, Redis, Memcached, and etc here... - '; -} + location = /async { + keepalive_timeout 0; + content_by_lua ' + ngx.say("got the task!") + ngx.eof() -- a descent HTTP client will close the connection at this point + -- access MySQL, PostgreSQL, Redis, Memcached, and etc here... + '; + } ``` But if you create subrequests to access other locations configured by Nginx upstream modules, then you should configure those upstream modules to ignore client connection abortions if they are not by default. For example, by default the standard [ngx_http_proxy_module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html) will terminate both the subrequest and the main request as soon as the client closes the connection, so it is important to turn on the [proxy_ignore_client_abort](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_client_abort) directive in your location block configured by [ngx_http_proxy_module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html): ```nginx -proxy_ignore_client_abort on; + proxy_ignore_client_abort on; ``` A better way to do background jobs is to use the [ngx.timer.at](#ngxtimerat) API. @@ -4519,7 +4576,7 @@ For example, ```lua -ngx.say(ngx.unescape_uri("b%20r56+7")) + ngx.say(ngx.unescape_uri("b%20r56+7")) ``` gives the output @@ -4542,7 +4599,7 @@ For example, ```lua -ngx.encode_args({foo = 3, ["b r"] = "hello world"}) + ngx.encode_args({foo = 3, ["b r"] = "hello world"}) ``` yields @@ -4557,7 +4614,7 @@ Multi-value query args are also supported. Just use a Lua table for the argument ```lua -ngx.encode_args({baz = {32, "hello"}}) + ngx.encode_args({baz = {32, "hello"}}) ``` gives @@ -4572,7 +4629,7 @@ Boolean argument values are also supported, for instance, ```lua -ngx.encode_args({a = true, b = 1}) + ngx.encode_args({a = true, b = 1}) ``` yields @@ -4601,7 +4658,7 @@ This argument can be set to zero to remove the limit and to process all request ```lua -local args = ngx.decode_args(str, 0) + local args = ngx.decode_args(str, 0) ``` Removing the `max_args` cap is strongly discouraged. @@ -4676,10 +4733,10 @@ For example, ```lua -local key = "thisisverysecretstuff" -local src = "some string we want to sign" -local digest = ngx.hmac_sha1(key, src) -ngx.say(ngx.encode_base64(digest)) + local key = "thisisverysecretstuff" + local src = "some string we want to sign" + local digest = ngx.hmac_sha1(key, src) + ngx.say(ngx.encode_base64(digest)) ``` yields the output @@ -4706,9 +4763,9 @@ For example, ```nginx -location = /md5 { - content_by_lua 'ngx.say(ngx.md5("hello"))'; -} + location = /md5 { + content_by_lua 'ngx.say(ngx.md5("hello"))'; + } ``` yields the output @@ -4841,8 +4898,8 @@ Returns a formatted string can be used as the cookie expiration time. The parame ```nginx -ngx.say(ngx.cookie_time(1290079655)) - -- yields "Thu, 18-Nov-10 11:27:35 GMT" + ngx.say(ngx.cookie_time(1290079655)) + -- yields "Thu, 18-Nov-10 11:27:35 GMT" ``` [Back to TOC](#nginx-api-for-lua) @@ -4857,8 +4914,8 @@ Returns a formated string can be used as the http header time (for example, bein ```nginx -ngx.say(ngx.http_time(1290079655)) - -- yields "Thu, 18 Nov 2010 11:27:35 GMT" + ngx.say(ngx.http_time(1290079655)) + -- yields "Thu, 18 Nov 2010 11:27:35 GMT" ``` [Back to TOC](#nginx-api-for-lua) @@ -4873,10 +4930,10 @@ Parse the http time string (as returned by [ngx.http_time](#ngxhttp_time)) into ```nginx -local time = ngx.parse_http_time("Thu, 18 Nov 2010 11:27:35 GMT") -if time == nil then - ... -end + local time = ngx.parse_http_time("Thu, 18 Nov 2010 11:27:35 GMT") + if time == nil then + ... + end ``` [Back to TOC](#nginx-api-for-lua) @@ -4905,25 +4962,25 @@ When a match is found, a Lua table `captures` is returned, where `captures[0]` h ```lua -local m, err = ngx.re.match("hello, 1234", "[0-9]+") -if m then - -- m[0] == "1234" + local m, err = ngx.re.match("hello, 1234", "[0-9]+") + if m then + -- m[0] == "1234" -else - if err then - ngx.log(ngx.ERR, "error: ", err) - return - end + else + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end - ngx.say("match not found") -end + ngx.say("match not found") + end ``` ```lua -local m, err = ngx.re.match("hello, 1234", "([0-9])[0-9]+") --- m[0] == "1234" --- m[1] == "1" + local m, err = ngx.re.match("hello, 1234", "([0-9])[0-9]+") + -- m[0] == "1234" + -- m[1] == "1" ``` Named captures are also supported since the `v0.7.14` release @@ -4931,23 +4988,23 @@ and are returned in the same Lua table as key-value pairs as the numbered captur ```lua -local m, err = ngx.re.match("hello, 1234", "([0-9])(?[0-9]+)") --- m[0] == "1234" --- m[1] == "1" --- m[2] == "234" --- m["remaining"] == "234" + local m, err = ngx.re.match("hello, 1234", "([0-9])(?[0-9]+)") + -- m[0] == "1234" + -- m[1] == "1" + -- m[2] == "234" + -- m["remaining"] == "234" ``` Unmatched subpatterns will have `nil` values in their `captures` table fields. ```lua -local m, err = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") --- m[0] == "hello" --- m[1] == nil --- m[2] == "hello" --- m[3] == nil --- m["named"] == nil + local m, err = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") + -- m[0] == "hello" + -- m[1] == nil + -- m[2] == "hello" + -- m[3] == nil + -- m["named"] == nil ``` Specify `options` to control how the match operation will be performed. The following option characters are supported: @@ -5000,15 +5057,15 @@ These options can be combined: ```nginx -local m, err = ngx.re.match("hello, world", "HEL LO", "ix") --- m[0] == "hello" + local m, err = ngx.re.match("hello, world", "HEL LO", "ix") + -- m[0] == "hello" ``` ```nginx -local m, err = ngx.re.match("hello, 美好生活", "HELLO, (.{2})", "iu") --- m[0] == "hello, 美好" --- m[1] == "美好" + local m, err = ngx.re.match("hello, 美好生活", "HELLO, (.{2})", "iu") + -- m[0] == "hello, 美好" + -- m[1] == "美好" ``` The `o` option is useful for performance tuning, because the regex pattern in question will only be compiled once, cached in the worker-process level, and shared among all requests in the current Nginx worker process. The upper limit of the regex cache can be tuned via the [lua_regex_cache_max_entries](#lua_regex_cache_max_entries) directive. @@ -5017,18 +5074,18 @@ The optional fourth argument, `ctx`, can be a Lua table holding an optional `pos ```lua -local ctx = {} -local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) - -- m[0] = "1234" - -- ctx.pos == 5 + local ctx = {} + local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) + -- m[0] = "1234" + -- ctx.pos == 5 ``` ```lua -local ctx = { pos = 2 } -local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) - -- m[0] = "34" - -- ctx.pos == 5 + local ctx = { pos = 2 } + local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) + -- m[0] = "34" + -- ctx.pos == 5 ``` The `ctx` table argument combined with the `a` regex modifier can be used to construct a lexer atop `ngx.re.match`. @@ -5065,19 +5122,19 @@ Below is an example: ```lua -local s = "hello, 1234" -local from, to, err = ngx.re.find(s, "([0-9]+)", "jo") -if from then - ngx.say("from: ", from) - ngx.say("to: ", to) - ngx.say("matched: ", string.sub(s, from, to)) -else - if err then - ngx.say("error: ", err) - return - end - ngx.say("not matched!") -end + local s = "hello, 1234" + local from, to, err = ngx.re.find(s, "([0-9]+)", "jo") + if from then + ngx.say("from: ", from) + ngx.say("to: ", to) + ngx.say("matched: ", string.sub(s, from, to)) + else + if err then + ngx.say("error: ", err) + return + end + ngx.say("not matched!") + end ``` This example produces the output @@ -5092,11 +5149,11 @@ Since the `0.9.3` release, an optional 5th argument, `nth`, is supported to spec ```lua -local str = "hello, 1234" -local from, to = ngx.re.find(str, "([0-9])([0-9]+)", "jo", nil, 2) -if from then - ngx.say("matched 2nd submatch: ", string.sub(str, from, to)) -- yields "234" -end + local str = "hello, 1234" + local from, to = ngx.re.find(str, "([0-9])([0-9]+)", "jo", nil, 2) + if from then + ngx.say("matched 2nd submatch: ", string.sub(str, from, to)) -- yields "234" + end ``` This API function was first introduced in the `v0.9.2` release. @@ -5117,58 +5174,58 @@ Here is a small example to demonstrate its basic usage: ```lua -local iterator, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") -if not iterator then - ngx.log(ngx.ERR, "error: ", err) - return -end + local iterator, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + if not iterator then + ngx.log(ngx.ERR, "error: ", err) + return + end -local m -m, err = iterator() -- m[0] == m[1] == "hello" -if err then - ngx.log(ngx.ERR, "error: ", err) - return -end + local m + m, err = iterator() -- m[0] == m[1] == "hello" + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end -m, err = iterator() -- m[0] == m[1] == "world" -if err then - ngx.log(ngx.ERR, "error: ", err) - return -end + m, err = iterator() -- m[0] == m[1] == "world" + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end -m, err = iterator() -- m == nil -if err then - ngx.log(ngx.ERR, "error: ", err) - return -end + m, err = iterator() -- m == nil + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end ``` More often we just put it into a Lua loop: ```lua -local it, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") -if not it then - ngx.log(ngx.ERR, "error: ", err) - return -end + local it, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + if not it then + ngx.log(ngx.ERR, "error: ", err) + return + end -while true do - local m, err = it() - if err then - ngx.log(ngx.ERR, "error: ", err) - return - end + while true do + local m, err = it() + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end - if not m then - -- no match found (any more) - break - end + if not m then + -- no match found (any more) + break + end - -- found a match - ngx.say(m[0]) - ngx.say(m[1]) -end + -- found a match + ngx.say(m[0]) + ngx.say(m[1]) + end ``` The optional `options` argument takes exactly the same semantics as the [ngx.re.match](#ngxrematch) method. @@ -5195,14 +5252,14 @@ When the `replace` is a string, then it is treated as a special template for str ```lua -local newstr, n, err = ngx.re.sub("hello, 1234", "([0-9])[0-9]", "[$0][$1]") -if newstr then - -- newstr == "hello, [12][1]34" - -- n == 1 -else - ngx.log(ngx.ERR, "error: ", err) - return -end + local newstr, n, err = ngx.re.sub("hello, 1234", "([0-9])[0-9]", "[$0][$1]") + if newstr then + -- newstr == "hello, [12][1]34" + -- n == 1 + else + ngx.log(ngx.ERR, "error: ", err) + return + end ``` where `$0` referring to the whole substring matched by the pattern and `$1` referring to the first parenthesized capturing substring. @@ -5211,18 +5268,18 @@ Curly braces can also be used to disambiguate variable names from the background ```lua -local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "${0}00") - -- newstr == "hello, 100234" - -- n == 1 + local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "${0}00") + -- newstr == "hello, 100234" + -- n == 1 ``` Literal dollar sign characters (`$`) in the `replace` string argument can be escaped by another dollar sign, for instance, ```lua -local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "$$") - -- newstr == "hello, $234" - -- n == 1 + local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "$$") + -- newstr == "hello, $234" + -- n == 1 ``` Do not use backlashes to escape dollar signs; it will not work as expected. @@ -5231,12 +5288,12 @@ When the `replace` argument is of type "function", then it will be invoked with ```lua -local func = function (m) - return "[" .. m[0] .. "][" .. m[1] .. "]" -end -local newstr, n, err = ngx.re.sub("hello, 1234", "( [0-9] ) [0-9]", func, "x") - -- newstr == "hello, [12][1]34" - -- n == 1 + local func = function (m) + return "[" .. m[0] .. "][" .. m[1] .. "]" + end + local newstr, n, err = ngx.re.sub("hello, 1234", "( [0-9] ) [0-9]", func, "x") + -- newstr == "hello, [12][1]34" + -- n == 1 ``` The dollar sign characters in the return value of the `replace` function argument are not special at all. @@ -5259,24 +5316,24 @@ Here is some examples: ```lua -local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", "[$0,$1]", "i") -if newstr then - -- newstr == "[hello,h], [world,w]" - -- n == 2 -else - ngx.log(ngx.ERR, "error: ", err) - return -end + local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", "[$0,$1]", "i") + if newstr then + -- newstr == "[hello,h], [world,w]" + -- n == 2 + else + ngx.log(ngx.ERR, "error: ", err) + return + end ``` ```lua -local func = function (m) - return "[" .. m[0] .. "," .. m[1] .. "]" -end -local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", func, "i") - -- newstr == "[hello,h], [world,w]" - -- n == 2 + local func = function (m) + return "[" .. m[0] .. "," .. m[1] .. "]" + end + local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", func, "i") + -- newstr == "[hello,h], [world,w]" + -- n == 2 ``` This method requires the PCRE library enabled in Nginx. ([Known Issue With Special PCRE Sequences](#special-pcre-sequences)). @@ -5289,7 +5346,7 @@ ngx.shared.DICT --------------- **syntax:** *dict = ngx.shared.DICT* -**syntax:** *dict = ngx.shared[name_var]* +**syntax:** *dict = ngx.shared\[name_var\]* **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.** @@ -5316,38 +5373,38 @@ Here is an example: ```nginx -http { - lua_shared_dict dogs 10m; - server { - location /set { - content_by_lua ' - local dogs = ngx.shared.dogs - dogs:set("Jim", 8) - ngx.say("STORED") - '; - } - location /get { - content_by_lua ' - local dogs = ngx.shared.dogs - ngx.say(dogs:get("Jim")) - '; - } - } -} + http { + lua_shared_dict dogs 10m; + server { + location /set { + content_by_lua ' + local dogs = ngx.shared.dogs + dogs:set("Jim", 8) + ngx.say("STORED") + '; + } + location /get { + content_by_lua ' + local dogs = ngx.shared.dogs + ngx.say(dogs:get("Jim")) + '; + } + } + } ``` Let us test it: ```bash -$ curl localhost/set -STORED + $ curl localhost/set + STORED -$ curl localhost/get -8 + $ curl localhost/get + 8 -$ curl localhost/get -8 + $ curl localhost/get + 8 ``` The number `8` will be consistently output when accessing `/get` regardless of how many Nginx workers there are because the `dogs` dictionary resides in the shared memory and visible to *all* of the worker processes. @@ -5376,16 +5433,16 @@ The first argument to this method must be the dictionary object itself, for exam ```lua -local cats = ngx.shared.cats -local value, flags = cats.get(cats, "Marry") + local cats = ngx.shared.cats + local value, flags = cats.get(cats, "Marry") ``` or use Lua's syntactic sugar for method calls: ```lua -local cats = ngx.shared.cats -local value, flags = cats:get("Marry") + local cats = ngx.shared.cats + local value, flags = cats:get("Marry") ``` These two forms are fundamentally equivalent. @@ -5442,16 +5499,16 @@ The first argument to this method must be the dictionary object itself, for exam ```lua -local cats = ngx.shared.cats -local succ, err, forcible = cats.set(cats, "Marry", "it is a nice cat!") + local cats = ngx.shared.cats + local succ, err, forcible = cats.set(cats, "Marry", "it is a nice cat!") ``` or use Lua's syntactic sugar for method calls: ```lua -local cats = ngx.shared.cats -local succ, err, forcible = cats:set("Marry", "it is a nice cat!") + local cats = ngx.shared.cats + local succ, err, forcible = cats:set("Marry", "it is a nice cat!") ``` These two forms are fundamentally equivalent. @@ -5642,7 +5699,7 @@ Both IP addresses and domain names can be specified as the `host` argument. In c ```nginx -resolver 8.8.8.8; # use Google's public DNS nameserver + resolver 8.8.8.8; # use Google's public DNS nameserver ``` If the nameserver returns multiple IP addresses for the host name, this method will pick up one randomly. @@ -5653,32 +5710,32 @@ Here is an example for connecting to a UDP (memcached) server: ```nginx -location /test { - resolver 8.8.8.8; + location /test { + resolver 8.8.8.8; - content_by_lua ' - local sock = ngx.socket.udp() - local ok, err = sock:setpeername("my.memcached.server.domain", 11211) - if not ok then - ngx.say("failed to connect to memcached: ", err) - return - end - ngx.say("successfully connected to memcached!") - sock:close() - '; -} + content_by_lua ' + local sock = ngx.socket.udp() + local ok, err = sock:setpeername("my.memcached.server.domain", 11211) + if not ok then + ngx.say("failed to connect to memcached: ", err) + return + end + ngx.say("successfully connected to memcached!") + sock:close() + '; + } ``` Since the `v0.7.18` release, connecting to a datagram unix domain socket file is also possible on Linux: ```lua -local sock = ngx.socket.udp() -local ok, err = sock:setpeername("unix:/tmp/some-datagram-service.sock") -if not ok then - ngx.say("failed to connect to the datagram unix domain socket: ", err) - return -end + local sock = ngx.socket.udp() + local ok, err = sock:setpeername("unix:/tmp/some-datagram-service.sock") + if not ok then + ngx.say("failed to connect to the datagram unix domain socket: ", err) + return + end ``` assuming the datagram service is listening on the unix domain socket file `/tmp/some-datagram-service.sock` and the client socket will use the "autobind" feature on Linux. @@ -5725,13 +5782,13 @@ Timeout for the reading operation is controlled by the [lua_socket_read_timeout] ```lua -sock:settimeout(1000) -- one second timeout -local data, err = sock:receive() -if not data then - ngx.say("failed to read a packet: ", data) - return -end -ngx.say("successfully read a packet: ", data) + sock:settimeout(1000) -- one second timeout + local data, err = sock:receive() + if not data then + ngx.say("failed to read a packet: ", data) + return + end + ngx.say("successfully read a packet: ", data) ``` It is important here to call the [settimeout](#udpsocksettimeout) method *before* calling this method. @@ -5828,7 +5885,7 @@ Both IP addresses and domain names can be specified as the `host` argument. In c ```nginx -resolver 8.8.8.8; # use Google's public DNS nameserver + resolver 8.8.8.8; # use Google's public DNS nameserver ``` If the nameserver returns multiple IP addresses for the host name, this method will pick up one randomly. @@ -5839,32 +5896,32 @@ Here is an example for connecting to a TCP server: ```nginx -location /test { - resolver 8.8.8.8; + location /test { + resolver 8.8.8.8; - content_by_lua ' - local sock = ngx.socket.tcp() - local ok, err = sock:connect("www.google.com", 80) - if not ok then - ngx.say("failed to connect to google: ", err) - return - end - ngx.say("successfully connected to google!") - sock:close() - '; -} + content_by_lua ' + local sock = ngx.socket.tcp() + local ok, err = sock:connect("www.google.com", 80) + if not ok then + ngx.say("failed to connect to google: ", err) + return + end + ngx.say("successfully connected to google!") + sock:close() + '; + } ``` Connecting to a Unix Domain Socket file is also possible: ```lua -local sock = ngx.socket.tcp() -local ok, err = sock:connect("unix:/tmp/memcached.sock") -if not ok then - ngx.say("failed to connect to the memcached unix domain socket: ", err) - return -end + local sock = ngx.socket.tcp() + local ok, err = sock:connect("unix:/tmp/memcached.sock") + if not ok then + ngx.say("failed to connect to the memcached unix domain socket: ", err) + return + end ``` assuming memcached (or something else) is listening on the unix domain socket file `/tmp/memcached.sock`. @@ -5873,9 +5930,9 @@ Timeout for the connecting operation is controlled by the [lua_socket_connect_ti ```lua -local sock = ngx.socket.tcp() -sock:settimeout(1000) -- one second timeout -local ok, err = sock:connect(host, port) + local sock = ngx.socket.tcp() + sock:settimeout(1000) -- one second timeout + local ok, err = sock:connect(host, port) ``` It is important here to call the [settimeout](#tcpsocksettimeout) method *before* calling this method. @@ -5953,8 +6010,8 @@ Timeout for the sending operation is controlled by the [lua_socket_send_timeout] ```lua -sock:settimeout(1000) -- one second timeout -local bytes, err = sock:send(request) + sock:settimeout(1000) -- one second timeout + local bytes, err = sock:send(request) ``` It is important here to call the [settimeout](#tcpsocksettimeout) method *before* calling this method. @@ -5992,13 +6049,13 @@ Timeout for the reading operation is controlled by the [lua_socket_read_timeout] ```lua -sock:settimeout(1000) -- one second timeout -local line, err, partial = sock:receive() -if not line then - ngx.say("failed to read a line: ", err) - return -end -ngx.say("successfully read a line: ", line) + sock:settimeout(1000) -- one second timeout + local line, err, partial = sock:receive() + if not line then + ngx.say("failed to read a line: ", err) + return + end + ngx.say("successfully read a line: ", line) ``` It is important here to call the [settimeout](#tcpsocksettimeout) method *before* calling this method. @@ -6021,12 +6078,12 @@ Here is an example for using this method to read a data stream with the boundary ```lua -local reader = sock:receiveuntil("\r\n--abcedhb") -local data, err, partial = reader() -if not data then - ngx.say("failed to read the data stream: ", err) -end -ngx.say("read the data stream: ", data) + local reader = sock:receiveuntil("\r\n--abcedhb") + local data, err, partial = reader() + if not data then + ngx.say("failed to read the data stream: ", err) + end + ngx.say("read the data stream: ", data) ``` When called without any argument, the iterator function returns the received data right *before* the specified pattern string in the incoming data stream. So for the example above, if the incoming data stream is `'hello, world! -agentzh\r\n--abcedhb blah blah'`, then the string `'hello, world! -agentzh'` will be returned. @@ -6039,21 +6096,21 @@ The iterator function behaves differently (i.e., like a real iterator) when it i ```lua -local reader = sock:receiveuntil("\r\n--abcedhb") + local reader = sock:receiveuntil("\r\n--abcedhb") -while true do - local data, err, partial = reader(4) - if not data then - if err then - ngx.say("failed to read the data stream: ", err) - break - end + while true do + local data, err, partial = reader(4) + if not data then + if err then + ngx.say("failed to read the data stream: ", err) + break + end - ngx.say("read done") - break - end - ngx.say("read chunk: [", data, "]") -end + ngx.say("read done") + break + end + ngx.say("read chunk: [", data, "]") + end ``` Then for the incoming data stream `'hello, world! -agentzh\r\n--abcedhb blah blah'`, we shall get the following output from the sample code above: @@ -6074,15 +6131,15 @@ Timeout for the iterator function's reading operation is controlled by the [lua_ ```lua -local readline = sock:receiveuntil("\r\n") + local readline = sock:receiveuntil("\r\n") -sock:settimeout(1000) -- one second timeout -line, err, partial = readline() -if not line then - ngx.say("failed to read a line: ", err) - return -end -ngx.say("successfully read a line: ", line) + sock:settimeout(1000) -- one second timeout + line, err, partial = readline() + if not line then + ngx.say("failed to read a line: ", err) + return + end + ngx.say("successfully read a line: ", line) ``` It is important here to call the [settimeout](#tcpsocksettimeout) method *before* calling the iterator function (note that the `receiveuntil` call is irrelevant here). @@ -6095,9 +6152,9 @@ The `inclusive` takes a boolean value to control whether to include the pattern ```lua -local reader = tcpsock:receiveuntil("_END_", { inclusive = true }) -local data = reader() -ngx.say(data) + local reader = tcpsock:receiveuntil("_END_", { inclusive = true }) + local data = reader() + ngx.say(data) ``` Then for the input data stream `"hello world _END_ blah blah blah"`, then the example above will output `hello world _END_`, including the pattern string `_END_` itself. @@ -6206,12 +6263,12 @@ This function is a shortcut for combining [ngx.socket.tcp()](#ngxsockettcp) and ```lua -local sock = ngx.socket.tcp() -local ok, err = sock:connect(...) -if not ok then - return nil, err -end -return sock + local sock = ngx.socket.tcp() + local ok, err = sock:connect(...) + if not ok then + return nil, err + end + return sock ``` There is no way to use the [settimeout](#tcpsocksettimeout) method to specify connecting timeout for this method and the [lua_socket_connect_timeout](#lua_socket_connect_timeout) directive must be set at configure time instead. @@ -6304,31 +6361,31 @@ to do manual time-slicing: ```lua -local yield = coroutine.yield + local yield = coroutine.yield -function f() - local self = coroutine.running() - ngx.say("f 1") - yield(self) - ngx.say("f 2") - yield(self) - ngx.say("f 3") -end + function f() + local self = coroutine.running() + ngx.say("f 1") + yield(self) + ngx.say("f 2") + yield(self) + ngx.say("f 3") + end -local self = coroutine.running() -ngx.say("0") -yield(self) + local self = coroutine.running() + ngx.say("0") + yield(self) -ngx.say("1") -ngx.thread.spawn(f) + ngx.say("1") + ngx.thread.spawn(f) -ngx.say("2") -yield(self) + ngx.say("2") + yield(self) -ngx.say("3") -yield(self) + ngx.say("3") + yield(self) -ngx.say("4") + ngx.say("4") ``` Then it will generate the output @@ -6348,43 +6405,43 @@ Then it will generate the output ```lua --- query mysql, memcached, and a remote http service at the same time, --- output the results in the order that they --- actually return the results. + -- query mysql, memcached, and a remote http service at the same time, + -- output the results in the order that they + -- actually return the results. -local mysql = require "resty.mysql" -local memcached = require "resty.memcached" + local mysql = require "resty.mysql" + local memcached = require "resty.memcached" -local function query_mysql() - local db = mysql:new() - db:connect{ - host = "127.0.0.1", - port = 3306, - database = "test", - user = "monty", - password = "mypass" - } - local res, err, errno, sqlstate = - db:query("select * from cats order by id asc") - db:set_keepalive(0, 100) - ngx.say("mysql done: ", cjson.encode(res)) -end + local function query_mysql() + local db = mysql:new() + db:connect{ + host = "127.0.0.1", + port = 3306, + database = "test", + user = "monty", + password = "mypass" + } + local res, err, errno, sqlstate = + db:query("select * from cats order by id asc") + db:set_keepalive(0, 100) + ngx.say("mysql done: ", cjson.encode(res)) + end -local function query_memcached() - local memc = memcached:new() - memc:connect("127.0.0.1", 11211) - local res, err = memc:get("some_key") - ngx.say("memcached done: ", res) -end + local function query_memcached() + local memc = memcached:new() + memc:connect("127.0.0.1", 11211) + local res, err = memc:get("some_key") + ngx.say("memcached done: ", res) + end -local function query_http() - local res = ngx.location.capture("/my-http-proxy") - ngx.say("http done: ", res.body) -end + local function query_http() + local res = ngx.location.capture("/my-http-proxy") + ngx.say("http done: ", res.body) + end -ngx.thread.spawn(query_mysql) -- create thread 1 -ngx.thread.spawn(query_memcached) -- create thread 2 -ngx.thread.spawn(query_http) -- create thread 3 + ngx.thread.spawn(query_mysql) -- create thread 1 + ngx.thread.spawn(query_memcached) -- create thread 2 + ngx.thread.spawn(query_http) -- create thread 3 ``` This API was first enabled in the `v0.7.0` release. @@ -6409,30 +6466,30 @@ The following example demonstrates the use of `ngx.thread.wait` and [ngx.locatio ```lua -local capture = ngx.location.capture -local spawn = ngx.thread.spawn -local wait = ngx.thread.wait -local say = ngx.say + local capture = ngx.location.capture + local spawn = ngx.thread.spawn + local wait = ngx.thread.wait + local say = ngx.say -local function fetch(uri) - return capture(uri) -end + local function fetch(uri) + return capture(uri) + end -local threads = { - spawn(fetch, "/foo"), - spawn(fetch, "/bar"), - spawn(fetch, "/baz") -} + local threads = { + spawn(fetch, "/foo"), + spawn(fetch, "/bar"), + spawn(fetch, "/baz") + } -for i = 1, #threads do - local ok, res = wait(threads[i]) - if not ok then - say(i, ": failed to run: ", res) - else - say(i, ": status: ", res.status) - say(i, ": body: ", res.body) - end -end + for i = 1, #threads do + local ok, res = wait(threads[i]) + if not ok then + say(i, ": failed to run: ", res) + else + say(i, ": status: ", res.status) + say(i, ": body: ", res.body) + end + end ``` Here it essentially implements the "wait all" model. @@ -6441,44 +6498,44 @@ And below is an example demonstrating the "wait any" model: ```lua -function f() - ngx.sleep(0.2) - ngx.say("f: hello") - return "f done" -end + function f() + ngx.sleep(0.2) + ngx.say("f: hello") + return "f done" + end -function g() - ngx.sleep(0.1) - ngx.say("g: hello") - return "g done" -end + function g() + ngx.sleep(0.1) + ngx.say("g: hello") + return "g done" + end -local tf, err = ngx.thread.spawn(f) -if not tf then - ngx.say("failed to spawn thread f: ", err) - return -end + local tf, err = ngx.thread.spawn(f) + if not tf then + ngx.say("failed to spawn thread f: ", err) + return + end -ngx.say("f thread created: ", coroutine.status(tf)) + ngx.say("f thread created: ", coroutine.status(tf)) -local tg, err = ngx.thread.spawn(g) -if not tg then - ngx.say("failed to spawn thread g: ", err) - return -end + local tg, err = ngx.thread.spawn(g) + if not tg then + ngx.say("failed to spawn thread g: ", err) + return + end -ngx.say("g thread created: ", coroutine.status(tg)) + ngx.say("g thread created: ", coroutine.status(tg)) -ok, res = ngx.thread.wait(tf, tg) -if not ok then - ngx.say("failed to wait: ", res) - return -end + ok, res = ngx.thread.wait(tf, tg) + if not ok then + ngx.say("failed to wait: ", res) + return + end -ngx.say("res: ", res) + ngx.say("res: ", res) --- stop the "world", aborting other running threads -ngx.exit(ngx.OK) + -- stop the "world", aborting other running threads + ngx.exit(ngx.OK) ``` And it will generate the following output: @@ -6524,18 +6581,18 @@ The callback function can decide what to do with the client abortion event all b ```lua -local function my_cleanup() - -- custom cleanup work goes here, like cancelling a pending DB transaction + local function my_cleanup() + -- custom cleanup work goes here, like cancelling a pending DB transaction - -- now abort all the "light threads" running in the current request handler - ngx.exit(499) -end + -- now abort all the "light threads" running in the current request handler + ngx.exit(499) + end -local ok, err = ngx.on_abort(my_cleanup) -if not ok then - ngx.log(ngx.ERR, "failed to register the on_abort callback: ", err) - ngx.exit(500) -end + local ok, err = ngx.on_abort(my_cleanup) + if not ok then + ngx.log(ngx.ERR, "failed to register the on_abort callback: ", err) + ngx.exit(500) + end ``` When [lua_check_client_abort](#lua_check_client_abort) is set to `off` (which is the default), then this function call will always return the error message "lua_check_client_abort is off". @@ -6591,48 +6648,48 @@ Here is a simple example: ```nginx -location / { - ... - log_by_lua ' - local function push_data(premature, uri, args, status) - -- push the data uri, args, and status to the remote - -- via ngx.socket.tcp or ngx.socket.udp - -- (one may want to buffer the data in Lua a bit to - -- save I/O operations) - end - local ok, err = ngx.timer.at(0, push_data, - ngx.var.uri, ngx.var.args, ngx.header.status) - if not ok then - ngx.log(ngx.ERR, "failed to create timer: ", err) - return - end - '; -} + location / { + ... + log_by_lua ' + local function push_data(premature, uri, args, status) + -- push the data uri, args, and status to the remote + -- via ngx.socket.tcp or ngx.socket.udp + -- (one may want to buffer the data in Lua a bit to + -- save I/O operations) + end + local ok, err = ngx.timer.at(0, push_data, + ngx.var.uri, ngx.var.args, ngx.header.status) + if not ok then + ngx.log(ngx.ERR, "failed to create timer: ", err) + return + end + '; + } ``` One can also create infinite re-occuring timers, for instance, a timer getting triggered every `5` seconds, by calling `ngx.timer.at` recursively in the timer callback function. Here is such an example, ```lua -local delay = 5 -local handler -handler = function (premature) - -- do some routine job in Lua just like a cron job - if premature then - return - end - local ok, err = ngx.timer.at(delay, handler) - if not ok then - ngx.log(ngx.ERR, "failed to create the timer: ", err) - return - end -end + local delay = 5 + local handler + handler = function (premature) + -- do some routine job in Lua just like a cron job + if premature then + return + end + local ok, err = ngx.timer.at(delay, handler) + if not ok then + ngx.log(ngx.ERR, "failed to create the timer: ", err) + return + end + end -local ok, err = ngx.timer.at(delay, handler) -if not ok then - ngx.log(ngx.ERR, "failed to create the timer: ", err) - return -end + local ok, err = ngx.timer.at(delay, handler) + if not ok then + ngx.log(ngx.ERR, "failed to create the timer: ", err) + return + end ``` Because timer callbacks run in the background and their running time @@ -6792,8 +6849,8 @@ For instance, ```lua -local res = ndk.set_var.set_escape_uri('a/b'); --- now res == 'a%2fb' + local res = ndk.set_var.set_escape_uri('a/b'); + -- now res == 'a%2fb' ``` Similarly, the following directives provided by [encrypted-session-nginx-module](http://github.com/openresty/encrypted-session-nginx-module) can be invoked from within Lua too: diff --git a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki index 1446805..cfaa680 100644 --- a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.9.13] released on 21 November 2014. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.9.15] released on 18 February 2015. = Synopsis = @@ -148,10 +148,11 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t } # use nginx var in code path - # WARN: contents in nginx var must be carefully filtered, + # WARNING: contents in nginx var must be carefully filtered, # otherwise there'll be great security risk! - location ~ ^/app/(.+) { - content_by_lua_file /path/to/lua/app/root/$1.lua; + location ~ ^/app/([-_a-zA-Z0-9/]+) { + set $path $1; + content_by_lua_file /path/to/lua/app/root/$path.lua; } location / { @@ -232,7 +233,7 @@ The Lua state (Lua VM instance) is shared across all the requests handled by a s = Nginx Compatibility = The latest module is compatible with the following versions of Nginx: -* 1.7.x (last tested: 1.7.7) +* 1.7.x (last tested: 1.7.10) * 1.6.x * 1.5.x (last tested: 1.5.12) * 1.4.x (last tested: 1.4.4) @@ -245,7 +246,7 @@ The latest module is compatible with the following versions of Nginx: = Installation = -The [http://openresty.org ngx_openresty bundle] can be used to install Nginx, ngx_lua, either one of the standard Lua 5.1 interpreter or LuaJIT 2.0/2.1, as well as a package of powerful companion Nginx modules. The basic installation step is a simple ./configure --with-luajit && make && make install. +It is highly recommended to use the [http://openresty.org ngx_openresty bundle] that bundles Nginx, ngx_lua, LuaJIT 2.0/2.1 (or the optional standard Lua 5.1 interpreter), as well as a package of powerful companion Nginx modules. The basic installation step is a simple command: ./configure --with-luajit && make && make install. Alternatively, ngx_lua can be manually compiled into Nginx: @@ -257,9 +258,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.7.7.tar.gz' - tar -xzvf nginx-1.7.7.tar.gz - cd nginx-1.7.7/ + wget 'http://nginx.org/download/nginx-1.7.10.tar.gz' + tar -xzvf nginx-1.7.10.tar.gz + cd nginx-1.7.10/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -275,6 +276,7 @@ Build the source with this module: # Here we assume Nginx is to be installed under /opt/nginx/. ./configure --prefix=/opt/nginx \ + --with-ld-opt='-Wl,-rpath,/path/to/luajit-or-lua/lib" \ --add-module=/path/to/ngx_devel_kit \ --add-module=/path/to/lua-nginx-module @@ -599,7 +601,7 @@ The [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_m will not work as expected. -== Cocockets Not Available Everywhere == +== Cosockets Not Available Everywhere == Due the internal limitations in the nginx core, the cosocket API are disabled in the following contexts: [[#set_by_lua|set_by_lua*]], [[#log_by_lua|log_by_lua*]], [[#header_filter_by_lua|header_filter_by_lua*]], and [[#body_filter_by_lua|body_filter_by_lua]]. @@ -700,15 +702,56 @@ Certain Lua APIs provided by ngx_lua do not work in Nginx's SPDY mode yet: [[#ng = TODO = -== Short Term == +* add *_by_lua_block directives for existing *_by_lua directives so that we put literal Lua code directly in curly braces instead of an nginx literal string. For example, + + content_by_lua_block { + ngx.say("hello, world\r\n") + } + +: which is equivalent to + + content_by_lua ' + ngx.say("hello, world\\r\\n") + '; + +: but the former is much cleaner and nicer. +* cosocket: implement LuaSocket's unconnected UDP API. +* add support for implementing general TCP servers instead of HTTP servers in Lua. For example, + + tcp { + server { + listen 11212; + handler_by_lua ' + -- custom Lua code implementing the special TCP server... + '; + } + } + +* add support for implementing general UDP servers instead of HTTP servers in Lua. For example, + + udp { + server { + listen 1953; + handler_by_lua ' + -- custom Lua code implementing the special UDP server... + '; + } + } + +* ssl: implement directives ssl_certificate_by_lua and ssl_certificate_by_lua_file to allow using Lua to dynamically serve SSL certificates and keys for downstream SSL handshake. (already done in CloudFlare's private branch and powering CloudFlare's SSL gateway of its global network. expected to be opensourced in March 2015.) +* shm: implement a "shared queue API" to complement the existing [[#lua_shared_dict|shared dict]] API. +* cosocket: add support in the context of [[#init_by_lua|init_by_lua*]]. +* cosocket: implement the bind() method for stream-typed cosockets. +* cosocket: pool-based backend concurrency level control: implement automatic connect queueing when the backend concurrency exceeds its connection pool limit. +* cosocket: review and merge aviramc's [https://github.com/openresty/lua-nginx-module/pull/290 patch] for adding the bsdrecv method. +* add new API function ngx.resp.add_header to emulate the standard add_header config directive. +* [[#ngx.re.match|ngx.re]] API: use false instead of nil in the resulting match table to indicate non-existent submatch captures, such that we can avoid "holes" in the array table. * review and apply Jader H. Silva's patch for ngx.re.split(). * review and apply vadim-pavlov's patch for [[#ngx.location.capture|ngx.location.capture]]'s extra_headers option * use ngx_hash_t to optimize the built-in header look-up process for [[#ngx.req.set_header|ngx.req.set_header]], [[#ngx.header.HEADER|ngx.header.HEADER]], and etc. * add configure options for different strategies of handling the cosocket connection exceeding in the pools. * add directives to run Lua codes when nginx stops. * add ignore_resp_headers, ignore_resp_body, and ignore_resp options to [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] methods, to allow micro performance tuning on the user side. - -== Longer Term == * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add stat mode similar to [https://httpd.apache.org/docs/trunk/mod/mod_lua.html mod_lua]. @@ -777,9 +820,9 @@ There are also various testing modes based on mockeagain, valgrind, and etc. Ref This module is licensed under the BSD license. -Copyright (C) 2009-2014, by Xiaozhe Wang (chaoslawful) . +Copyright (C) 2009-2015, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2014, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +Copyright (C) 2009-2015, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. All rights reserved. @@ -1164,6 +1207,19 @@ and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [[#lua_code_cache|lua_code_cache]] off in nginx.conf to avoid reloading Nginx. +Nginx variables are supported in the file path for dynamic dispatch, for example: + + + # WARNING: contents in nginx var must be carefully filtered, + # otherwise there'll be great security risk! + location ~ ^/app/([-_a-zA-Z0-9/]+) { + set $path $1; + content_by_lua_file /path/to/lua/app/root/$path.lua; + } + + +But be very careful about malicious user inputs and always carefully validate or filter out the user-supplied path components. + == rewrite_by_lua == '''syntax:''' ''rewrite_by_lua '' @@ -1297,6 +1353,8 @@ When the Lua code cache is turned on (by default), the user code is loaded once The rewrite_by_lua_file code will always run at the end of the rewrite request-processing phase unless [[#rewrite_by_lua_no_postpone|rewrite_by_lua_no_postpone]] is turned on. +Nginx variables are supported in the file path for dynamic dispatch just as in [[#content_by_lua_file|content_by_lua_file]]. + == access_by_lua == '''syntax:''' ''access_by_lua '' @@ -1382,6 +1440,8 @@ When the Lua code cache is turned on (by default), the user code is loaded once and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [[#lua_code_cache|lua_code_cache]] off in nginx.conf to avoid repeatedly reloading Nginx. +Nginx variables are supported in the file path for dynamic dispatch just as in [[#content_by_lua_file|content_by_lua_file]]. + == header_filter_by_lua == '''syntax:''' ''header_filter_by_lua '' @@ -2027,7 +2087,7 @@ For example: That is, nginx variables cannot be created on-the-fly. Some special nginx variables like $args and $limit_rate can be assigned a value, -some are not, like $arg_PARAMETER. +many others are not, like $query_string, $arg_PARAMETER, and $http_NAME. Nginx regex group capturing variables $1, $2, $3, and etc, can be read by this interface as well, by writing ngx.var[1], ngx.var[2], ngx.var[3], and etc. @@ -2320,7 +2380,7 @@ argument, which supports the options: * copy_all_vars : specify whether to copy over all the Nginx variable values of the current request to the subrequest in question. modifications of the nginx variables in the subrequest will not affect the current (parent) request. This option was first introduced in the v0.3.1rc31 release. * share_all_vars -: specify whether to share all the Nginx variables of the subrequest with the current (parent) request. modifications of the Nginx variables in the subrequest will affect the current (parent) request. +: specify whether to share all the Nginx variables of the subrequest with the current (parent) request. modifications of the Nginx variables in the subrequest will affect the current (parent) request. Enabling this option may lead to hard-to-debug issues due to bad side-effects and is considered bad and harmful. Only enable this option when you completely know what you are doing. * always_forward_body : when set to true, the current (parent) request's request body will always be forwarded to the subrequest being created if the body option is not specified. The request body read by either [[#ngx.req.read_body|ngx.req.read_body()]] or [[#lua_need_request_body|lua_need_request_body on]] will be directly forwarded to the subrequest without copying the whole request body data when creating the subrequest (no matter the request body data is buffered in memory buffers or temporary files). By default, this option is false and when the body option is not specified, the request body of the current (parent) request is only forwarded when the subrequest takes the PUT or POST request method. @@ -3180,7 +3240,7 @@ Set the current request's request header named header_name to value By default, all the subrequests subsequently initiated by [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] will inherit the new header. -Here is an example of setting the Content-Length header: +Here is an example of setting the Content-Type header: ngx.req.set_header("Content-Type", "text/css") diff --git a/debian/modules/nginx-lua/misc/recv-until-pm/Makefile b/debian/modules/nginx-lua/misc/recv-until-pm/Makefile deleted file mode 100644 index eb4d937..0000000 --- a/debian/modules/nginx-lua/misc/recv-until-pm/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -test: - prove -Ilib -r t - diff --git a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h index 814754b..3700c1f 100644 --- a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 9013 +#define ngx_http_lua_version 9015 typedef struct { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_common.h b/debian/modules/nginx-lua/src/ngx_http_lua_common.h index 6111b3f..ff1c0bc 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_common.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_common.h @@ -287,9 +287,6 @@ struct ngx_http_lua_co_ctx_s { ngx_http_cleanup_pt cleanup; - unsigned nsubreqs; /* number of subrequests of the - * current request */ - ngx_int_t *sr_statuses; /* all capture subrequest statuses */ ngx_http_headers_out_t **sr_headers; @@ -298,6 +295,9 @@ struct ngx_http_lua_co_ctx_s { uint8_t *sr_flags; + unsigned nsubreqs; /* number of subrequests of the + * current request */ + unsigned pending_subreqs; /* number of subrequests being waited */ @@ -365,8 +365,6 @@ typedef struct ngx_http_lua_ctx_s { unsigned flushing_coros; /* number of coroutines waiting on ngx.flush(true) */ - int uthreads; /* number of active user threads */ - ngx_chain_t *out; /* buffered output chain for HTTP 1.0 */ ngx_chain_t *free_bufs; ngx_chain_t *busy_bufs; @@ -393,6 +391,8 @@ typedef struct ngx_http_lua_ctx_s { ngx_http_lua_posted_thread_t *posted_threads; + int uthreads; /* number of active user threads */ + uint16_t context; /* the current running directive context (or running phase) for the current Lua chunk */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_control.c b/debian/modules/nginx-lua/src/ngx_http_lua_control.c index f164b0b..95a8227 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_control.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_control.c @@ -195,6 +195,7 @@ ngx_http_lua_ngx_redirect(lua_State *L) u_char *p; u_char *uri; size_t len; + ngx_table_elt_t *h; ngx_http_request_t *r; n = lua_gettop(L); @@ -246,23 +247,23 @@ ngx_http_lua_ngx_redirect(lua_State *L) ngx_memcpy(uri, p, len); - r->headers_out.location = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.location == NULL) { + h = ngx_list_push(&r->headers_out.headers); + if (h == NULL) { return luaL_error(L, "no memory"); } - r->headers_out.location->hash = ngx_http_lua_location_hash; + h->hash = ngx_http_lua_location_hash; #if 0 dd("location hash: %lu == %lu", - (unsigned long) r->headers_out.location->hash, + (unsigned long) h->hash, (unsigned long) ngx_hash_key_lc((u_char *) "Location", sizeof("Location") - 1)); #endif - r->headers_out.location->value.len = len; - r->headers_out.location->value.data = uri; - ngx_str_set(&r->headers_out.location->key, "Location"); + h->value.len = len; + h->value.data = uri; + ngx_str_set(&h->key, "Location"); r->headers_out.status = rc; @@ -271,7 +272,16 @@ ngx_http_lua_ngx_redirect(lua_State *L) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua redirect to \"%V\" with code %i", - &r->headers_out.location->value, ctx->exit_code); + &h->value, ctx->exit_code); + + if (len && uri[0] != '/') { + r->headers_out.location = h; + } + + /* + * we do not set r->headers_out.location here to avoid the handling + * the local redirects without a host name by ngx_http_header_filter() + */ return lua_yield(L, 0); } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c b/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c index c54f54c..79bac65 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c @@ -28,10 +28,6 @@ static ngx_http_output_header_filter_pt ngx_http_next_header_filter; -/* light user data key for the "ngx" table in the Lua VM regsitry */ -static char ngx_http_lua_headerfilterby_ngx_key; - - /** * Set environment table for the given code closure. * @@ -64,12 +60,6 @@ ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) * */ ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); - /* {{{ initialize ngx.* namespace */ - lua_pushlightuserdata(L, &ngx_http_lua_headerfilterby_ngx_key); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setfield(L, -2, "ngx"); - /* }}} */ - /* {{{ make new env inheriting main thread's globals table */ lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new env */ ngx_http_lua_get_globals_table(L); @@ -141,6 +131,11 @@ ngx_http_lua_header_filter_by_chunk(lua_State *L, ngx_http_request_t *r) dd("exited: %d, exit code: %d, old exit code: %d", (int) ctx->exited, (int) ctx->exit_code, (int) old_exit_code); +#if 1 + /* clear Lua stack */ + lua_settop(L, 0); +#endif + if (ctx->exited && ctx->exit_code != old_exit_code) { if (ctx->exit_code == NGX_ERROR) { return NGX_ERROR; @@ -157,9 +152,6 @@ ngx_http_lua_header_filter_by_chunk(lua_State *L, ngx_http_request_t *r) return NGX_DECLINED; } - /* clear Lua stack */ - lua_settop(L, 0); - return NGX_OK; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c b/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c index 862c444..5039c27 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c @@ -38,6 +38,8 @@ static ngx_int_t ngx_http_clear_last_modified_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_clear_content_length_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_location_header(ngx_http_request_t *r, + ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { @@ -58,7 +60,7 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { { ngx_string("Location"), offsetof(ngx_http_headers_out_t, location), - ngx_http_set_builtin_header }, + ngx_http_set_location_header }, { ngx_string("Refresh"), offsetof(ngx_http_headers_out_t, refresh), @@ -237,6 +239,32 @@ new_header: } +static ngx_int_t +ngx_http_set_location_header(ngx_http_request_t *r, + ngx_http_lua_header_val_t *hv, ngx_str_t *value) +{ + ngx_int_t rc; + ngx_table_elt_t *h; + + rc = ngx_http_set_builtin_header(r, hv, value); + if (rc != NGX_OK) { + return rc; + } + + /* + * we do not set r->headers_out.location here to avoid the handling + * the local redirects without a host name by ngx_http_header_filter() + */ + + h = r->headers_out.location; + if (h && h->value.len && h->value.data[0] == '/') { + r->headers_out.location = NULL; + } + + return NGX_OK; +} + + static ngx_int_t ngx_http_set_builtin_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c index 36b44f2..fd2d017 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c @@ -1850,11 +1850,12 @@ exec: } else { if (offset < (int) subj.len) { - dd("adding trailer: %s (len %d)", &subj.data[offset], - (int) (subj.len - offset)); + dd("adding trailer: %s (len %d)", &subj.data[cp_offset], + (int) (subj.len - cp_offset)); - luaL_addlstring(&luabuf, (char *) &subj.data[offset], - subj.len - offset); + + luaL_addlstring(&luabuf, (char *) &subj.data[cp_offset], + subj.len - cp_offset); } luaL_pushresult(&luabuf); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c index 377f9ce..8c666f7 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c @@ -481,7 +481,7 @@ ngx_http_lua_shdict_get_helper(lua_State *L, int get_stale) (unsigned long) value.len); } - num = *(double *) value.data; + ngx_memcpy(&num, value.data, sizeof(double)); lua_pushnumber(L, num); break; @@ -1220,7 +1220,7 @@ ngx_http_lua_shdict_incr(lua_State *L) p = sd->data + key.len; - num = *(double *) p; + ngx_memcpy(&num, p, sizeof(double)); num += value; ngx_memcpy(p, (double *) &num, sizeof(double)); @@ -1711,7 +1711,7 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, } *str_value_len = value.len; - *num_value = *(double *) value.data; + ngx_memcpy(num_value, value.data, sizeof(double)); break; case LUA_TBOOLEAN: @@ -1801,7 +1801,7 @@ ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, p = sd->data + key_len; - num = *(double *) p; + ngx_memcpy(&num, p, sizeof(double)); num += *value; ngx_memcpy(p, (double *) &num, sizeof(double)); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c index b0bf4fa..e825308 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c @@ -4335,7 +4335,8 @@ ngx_http_lua_socket_tcp_getreusedtimes(lua_State *L) } -static int ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) +static int +ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) { ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_socket_tcp_upstream_t *u; @@ -4380,12 +4381,18 @@ static int ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) u = lua_touserdata(L, -1); lua_pop(L, 1); + if (u == NULL) { + lua_pushnil(L); + lua_pushliteral(L, "closed"); + return 2; + } + /* stack: obj cache key */ pc = &u->peer; c = pc->connection; - if (u == NULL || pc == NULL || u->read_closed || u->write_closed) { + if (c == NULL || u->read_closed || u->write_closed) { lua_pushnil(L); lua_pushliteral(L, "closed"); return 2; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_string.c b/debian/modules/nginx-lua/src/ngx_http_lua_string.c index e0f117c..52877bb 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_string.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_string.c @@ -238,7 +238,7 @@ ngx_http_lua_ngx_escape_sql_str(u_char *dst, u_char *src, size_t size) case '\n': case '\r': case '\t': - case 26: /* \z */ + case 26: /* \Z */ case '\\': case '\'': case '"': @@ -285,7 +285,7 @@ ngx_http_lua_ngx_escape_sql_str(u_char *dst, u_char *src, size_t size) case 26: *dst++ = '\\'; - *dst++ = 'z'; + *dst++ = 'Z'; break; case '\\': diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c index 6dda007..c0d66d6 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c @@ -17,15 +17,17 @@ typedef struct { - unsigned premature; /* :1 */ - - int co_ref; - lua_State *co; - void **main_conf; void **srv_conf; void **loc_conf; + /* event ident must be after 3 words (i.e. 3 pointers' size) as in + * ngx_connection_t. and we use the Lua coroutine reference number as + * the event ident */ + int co_ref; + unsigned premature; /* :1 */ + lua_State *co; + ngx_pool_t *pool; ngx_listening_t *listening; @@ -37,11 +39,6 @@ typedef struct { } ngx_http_lua_timer_ctx_t; -typedef struct { - ngx_connection_t *connection; -} ngx_http_lua_timer_log_ctx_t; - - static int ngx_http_lua_ngx_timer_at(lua_State *L); static void ngx_http_lua_timer_handler(ngx_event_t *ev); static u_char * ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, @@ -69,7 +66,7 @@ ngx_http_lua_ngx_timer_at(lua_State *L) lua_State *vm; /* the main thread */ lua_State *co; ngx_msec_t delay; - ngx_event_t *ev; + ngx_event_t *ev = NULL; ngx_http_request_t *r; ngx_connection_t *saved_c = NULL; ngx_http_lua_ctx_t *ctx; @@ -283,6 +280,10 @@ nomem: ngx_destroy_pool(tctx->pool); } + if (ev) { + ngx_free(ev); + } + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); @@ -306,7 +307,6 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) ngx_http_lua_timer_ctx_t tctx; ngx_http_lua_main_conf_t *lmcf; ngx_http_core_loc_conf_t *clcf; - ngx_http_lua_timer_log_ctx_t *logctx; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua ngx.timer expired"); @@ -331,15 +331,8 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) goto failed; } - logctx = ngx_palloc(c->pool, sizeof(ngx_http_lua_timer_log_ctx_t)); - if (logctx == NULL) { - goto failed; - } - - logctx->connection = c; - c->log->handler = ngx_http_lua_log_timer_error; - c->log->data = logctx; + c->log->data = c; c->listening = tctx.listening; c->addr_text = tctx.client_addr_text; @@ -476,24 +469,20 @@ ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, size_t len) u_char *p; ngx_connection_t *c; - ngx_http_lua_timer_log_ctx_t *ctx; - if (log->action) { p = ngx_snprintf(buf, len, " while %s", log->action); len -= p - buf; buf = p; } - ctx = log->data; + c = log->data; - dd("ctx = %p", ctx); + dd("ctx = %p", c); p = ngx_snprintf(buf, len, ", context: ngx.timer"); len -= p - buf; buf = p; - c = ctx->connection; - if (c->addr_text.len) { p = ngx_snprintf(buf, len, ", client: %V", &c->addr_text); len -= p - buf; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.c b/debian/modules/nginx-lua/src/ngx_http_lua_util.c index d1b59b2..879608b 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.c @@ -81,7 +81,7 @@ ngx_uint_t ngx_http_lua_content_length_hash = 0; static ngx_int_t ngx_http_lua_send_http10_headers(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); static void ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log); -static void ngx_http_lua_init_globals(lua_State *L, +static void ngx_http_lua_init_globals(lua_State *L, ngx_cycle_t *cycle, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log); static void ngx_http_lua_set_path(ngx_cycle_t *cycle, lua_State *L, int tab_idx, const char *fieldname, const char *path, const char *default_path, @@ -294,7 +294,7 @@ ngx_http_lua_new_state(lua_State *parent_vm, ngx_cycle_t *cycle, lua_pop(L, 1); /* remove the "package" table */ ngx_http_lua_init_registry(L, log); - ngx_http_lua_init_globals(L, lmcf, log); + ngx_http_lua_init_globals(L, cycle, lmcf, log); return L; } @@ -683,12 +683,15 @@ ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log) static void -ngx_http_lua_init_globals(lua_State *L, ngx_http_lua_main_conf_t *lmcf, - ngx_log_t *log) +ngx_http_lua_init_globals(lua_State *L, ngx_cycle_t *cycle, + ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "lua initializing lua globals"); + lua_pushlightuserdata(L, cycle); + lua_setglobal(L, "__ngx_cycle"); + #if defined(NDK) && NDK ngx_http_lua_inject_ndk_api(L); #endif /* defined(NDK) && NDK */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.h b/debian/modules/nginx-lua/src/ngx_http_lua_util.h index 163395e..3dfb819 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.h @@ -20,6 +20,7 @@ #ifndef NGX_LUA_NO_FFI_API typedef struct { int len; + /* this padding hole on 64-bit systems is expected */ u_char *data; } ngx_http_lua_ffi_str_t; diff --git a/debian/modules/nginx-lua/t/014-bugs.t b/debian/modules/nginx-lua/t/014-bugs.t index e5fa86f..1042b29 100644 --- a/debian/modules/nginx-lua/t/014-bugs.t +++ b/debian/modules/nginx-lua/t/014-bugs.t @@ -773,7 +773,7 @@ See more details here: http://mailman.nginx.org/pipermail/nginx-devel/2013-Janua location /t { set $myserver nginx.org; proxy_pass http://$myserver/; - resolver 127.0.0.1; + resolver 127.0.0.1:6789; } --- request GET /t diff --git a/debian/modules/nginx-lua/t/016-resp-header.t b/debian/modules/nginx-lua/t/016-resp-header.t index df1ffa5..f119fb9 100644 --- a/debian/modules/nginx-lua/t/016-resp-header.t +++ b/debian/modules/nginx-lua/t/016-resp-header.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 24); +plan tests => repeat_each() * (blocks() * 3 + 26); #no_diff(); no_long_string(); @@ -1346,3 +1346,41 @@ hi --- error_log my Transfer-Encoding: nil + + +=== TEST 65: set Location (no host) +--- config + location = /t { + content_by_lua ' + ngx.header.location = "/foo/bar" + return ngx.exit(301) + '; + } +--- request +GET /t +--- response_headers +Location: /foo/bar +--- response_body_like: 301 Moved Permanently +--- error_code: 301 +--- no_error_log +[error] + + + +=== TEST 66: set Location (with host) +--- config + location = /t { + content_by_lua ' + ngx.header.location = "http://test.com/foo/bar" + return ngx.exit(301) + '; + } +--- request +GET /t +--- response_headers +Location: http://test.com/foo/bar +--- response_body_like: 301 Moved Permanently +--- error_code: 301 +--- no_error_log +[error] + diff --git a/debian/modules/nginx-lua/t/022-redirect.t b/debian/modules/nginx-lua/t/022-redirect.t index 6132f42..1f874ec 100644 --- a/debian/modules/nginx-lua/t/022-redirect.t +++ b/debian/modules/nginx-lua/t/022-redirect.t @@ -121,7 +121,7 @@ GET /read } --- request GET /read ---- raw_response_headers_like: Location: http://localhost(?::\d+)?/echo\r\n +--- raw_response_headers_like: Location: /echo\r\n --- response_body_like: 302 Found --- error_code: 302 diff --git a/debian/modules/nginx-lua/t/023-rewrite/redirect.t b/debian/modules/nginx-lua/t/023-rewrite/redirect.t index 3b93eee..e4a46cc 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/redirect.t +++ b/debian/modules/nginx-lua/t/023-rewrite/redirect.t @@ -120,7 +120,7 @@ GET /read } --- request GET /read ---- raw_response_headers_like: Location: http://localhost(?::\d+)?/foo\r\n +--- raw_response_headers_like: Location: /foo\r\n --- response_body_like: 302 Found --- error_code: 302 diff --git a/debian/modules/nginx-lua/t/024-access/auth.t b/debian/modules/nginx-lua/t/024-access/auth.t index 4b48afc..4b7927c 100644 --- a/debian/modules/nginx-lua/t/024-access/auth.t +++ b/debian/modules/nginx-lua/t/024-access/auth.t @@ -76,7 +76,7 @@ POST /lua He fucks himself! --- response_body_like: 302 Found --- response_headers_like -Location: http://[^:]+:\d+/terms_of_use\.html +Location: /terms_of_use\.html --- error_code: 302 diff --git a/debian/modules/nginx-lua/t/024-access/redirect.t b/debian/modules/nginx-lua/t/024-access/redirect.t index 0704c9a..b8c3519 100644 --- a/debian/modules/nginx-lua/t/024-access/redirect.t +++ b/debian/modules/nginx-lua/t/024-access/redirect.t @@ -120,7 +120,7 @@ GET /read } --- request GET /read ---- raw_response_headers_like: Location: http://localhost(?::\d+)?/foo\r\n +--- raw_response_headers_like: Location: /foo\r\n --- response_body_like: 302 Found --- error_code: 302 diff --git a/debian/modules/nginx-lua/t/036-sub.t b/debian/modules/nginx-lua/t/036-sub.t index 27ecd92..ad8638c 100644 --- a/debian/modules/nginx-lua/t/036-sub.t +++ b/debian/modules/nginx-lua/t/036-sub.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 15); +plan tests => repeat_each() * (blocks() * 2 + 18); #no_diff(); no_long_string(); @@ -651,3 +651,85 @@ ngx.say("sub: ", cnt) --- response_body sub: 0 + + +=== TEST 30: bug: sub incorrectly swallowed a character is the first character +Original bad result: estCase +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.sub("TestCase", "^ *", "", "o") + if s then + ngx.say(s) + end + '; + } +--- request + GET /re +--- response_body +TestCase + + + +=== TEST 31: bug: sub incorrectly swallowed a character is not the first character +Original bad result: .b.d +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.sub("abcd", "(?=c)", ".") + if s then + ngx.say(s) + end + '; + } +--- request + GET /re +--- response_body +ab.cd + + + +=== TEST 32: ngx.re.gsub: recursive calling (github #445) +--- config + +location = /t { + content_by_lua ' + function test() + local data = [[ + OUTER {FIRST} +]] + + local p1 = "(OUTER)(.+)" + local p2 = "{([A-Z]+)}" + + ngx.print(data) + + local res = ngx.re.gsub(data, p1, function(m) + -- ngx.say("pre: m[1]: [", m[1], "]") + -- ngx.say("pre: m[2]: [", m[2], "]") + + local res = ngx.re.gsub(m[2], p2, function(_) + return "REPLACED" + end, "") + + -- ngx.say("post: m[1]: [", m[1], "]") + -- ngx.say("post m[2]: [", m[2], "]") + return m[1] .. res + end, "") + + ngx.print(res) + end + + test() + '; +} +--- request +GET /t +--- response_body + OUTER {FIRST} + OUTER REPLACED +--- no_error_log +[error] +bad argument type +NYI + diff --git a/debian/modules/nginx-lua/t/037-gsub.t b/debian/modules/nginx-lua/t/037-gsub.t index b50edd2..fb4a706 100644 --- a/debian/modules/nginx-lua/t/037-gsub.t +++ b/debian/modules/nginx-lua/t/037-gsub.t @@ -9,7 +9,7 @@ log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 14); +plan tests => repeat_each() * (blocks() * 2 + 16); #no_diff(); no_long_string(); @@ -573,3 +573,105 @@ ngx.say("gsub: ", cnt) gsub: 0 --- timeout: 10 + + +=== TEST 25: bug: gsub incorrectly swallowed a character is the first character +Original bad result: estCase +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.gsub("TestCase", "^ *", "", "o") + if s then + ngx.say(s) + end + '; + } +--- request + GET /re +--- response_body +TestCase + + + +=== TEST 26: bug: gsub incorrectly swallowed a character is not the first character +Original bad result: .b.d +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.gsub("abcd", "a|(?=c)", ".") + if s then + ngx.say(s) + end + '; + } +--- request + GET /re +--- response_body +.b.cd + + + +=== TEST 27: use of ngx.req.get_headers in the user callback +--- config + +location = /t { + content_by_lua ' + local data = [[ + INNER + INNER +]] + + -- ngx.say(data) + + local res = ngx.re.gsub(data, "INNER", function(inner_matches) + local header = ngx.req.get_headers()["Host"] + -- local header = ngx.var["http_HEADER"] + return "INNER_REPLACED" + end, "s") + + ngx.print(res) + '; +} + +--- request +GET /t +--- response_body + INNER_REPLACED + INNER_REPLACED + +--- no_error_log +[error] + + + +=== TEST 28: use of ngx.var in the user callback +--- config + +location = /t { + content_by_lua ' + local data = [[ + INNER + INNER +]] + + -- ngx.say(data) + + local res = ngx.re.gsub(data, "INNER", function(inner_matches) + -- local header = ngx.req.get_headers()["Host"] + local header = ngx.var["http_HEADER"] + return "INNER_REPLACED" + end, "s") + + ngx.print(res) + '; +} + +--- request +GET /t +--- response_body + INNER_REPLACED + INNER_REPLACED + +--- no_error_log +[error] + diff --git a/debian/modules/nginx-lua/t/041-header-filter.t b/debian/modules/nginx-lua/t/041-header-filter.t index b81d5af..c3d495c 100644 --- a/debian/modules/nginx-lua/t/041-header-filter.t +++ b/debian/modules/nginx-lua/t/041-header-filter.t @@ -11,7 +11,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * 91; +plan tests => repeat_each() * 94; #no_diff(); #no_long_string(); @@ -767,3 +767,28 @@ GET /lua?a=1&b=2 --- error_log eval qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ + + +=== TEST 41: filter finalize +--- config + error_page 582 = /bar; + location = /t { + echo ok; + header_filter_by_lua ' + return ngx.exit(582) + '; + } + + location = /bar { + echo hi; + header_filter_by_lua ' + return ngx.exit(302) + '; + } +--- request +GET /t +--- response_body_like: 302 Found +--- error_code: 302 +--- no_error_log +[error] + diff --git a/debian/modules/nginx-lua/t/058-tcp-socket.t b/debian/modules/nginx-lua/t/058-tcp-socket.t index 8e764cf..a4e6a56 100644 --- a/debian/modules/nginx-lua/t/058-tcp-socket.t +++ b/debian/modules/nginx-lua/t/058-tcp-socket.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 172; +plan tests => repeat_each() * 175; our $HtmlDir = html_dir; @@ -3300,3 +3300,47 @@ close: 1 nil --- no_error_log [error] + + +=== TEST 55: kill a thread with a connecting socket +--- config + server_tokens off; + lua_socket_connect_timeout 1s; + resolver $TEST_NGINX_RESOLVER; + resolver_timeout 3s; + location /t { + content_by_lua ' + local sock + + local thr = ngx.thread.spawn(function () + sock = ngx.socket.tcp() + local ok, err = sock:connect("agentzh.org", 12345) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + end) + + ngx.sleep(0.002) + ngx.thread.kill(thr) + ngx.sleep(0.001) + + local ok, err = sock:setkeepalive() + if not ok then + ngx.say("failed to setkeepalive: ", err) + else + ngx.say("setkeepalive: ", ok) + end + '; + } + +--- request +GET /t +--- response_body +failed to setkeepalive: closed +--- error_log +lua tcp socket connect timeout: 100 +--- timeout: 10 + diff --git a/debian/modules/nginx-lua/t/115-quote-sql-str.t b/debian/modules/nginx-lua/t/115-quote-sql-str.t index 7c6785e..e473b21 100644 --- a/debian/modules/nginx-lua/t/115-quote-sql-str.t +++ b/debian/modules/nginx-lua/t/115-quote-sql-str.t @@ -62,7 +62,7 @@ GET /set -=== TEST 4: \z +=== TEST 4: \Z --- config location = /set { content_by_lua ' @@ -72,7 +72,7 @@ GET /set --- request GET /set --- response_body -'a\zb\z' +'a\Zb\Z' --- no_error_log [error] diff --git a/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t b/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t index 3853515..571bdc8 100644 --- a/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t +++ b/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t @@ -469,7 +469,7 @@ receive: nil closed send: nil closed close: nil closed getreusedtimes: nil closed -setkeepalive: nil socket busy connecting +setkeepalive: nil closed connect: nil socket busy connecting connect: nil some2.agentzh.org could not be resolved (110: Operation timed out) close: nil closed diff --git a/debian/modules/nginx-lua/t/130-internal-api.t b/debian/modules/nginx-lua/t/130-internal-api.t new file mode 100644 index 0000000..c40bf13 --- /dev/null +++ b/debian/modules/nginx-lua/t/130-internal-api.t @@ -0,0 +1,50 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_process_enabled(1); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * 3; + +#no_diff(); +no_long_string(); +#master_on(); +#workers(2); + +run_tests(); + +__DATA__ + +=== TEST 1: __ngx_req and __ngx_cycle +--- http_config + init_by_lua ' + my_cycle = __ngx_cycle + '; + +--- config + location = /t { + content_by_lua ' + local ffi = require "ffi" + local function tonum(ud) + return tonumber(ffi.cast("uintptr_t", ud)) + end + ngx.say(string.format("init: cycle=%#x", tonum(my_cycle))) + ngx.say(string.format("content cycle=%#x", tonum(__ngx_cycle))) + ngx.say(string.format("content req=%#x", tonum(__ngx_req))) + '; + } +--- request +GET /t + +--- response_body_like chop +^init: cycle=(0x[a-f0-9]{4,}) +content cycle=\1 +content req=0x[a-f0-9]{4,} +$ +--- no_error_log +[error] + diff --git a/debian/modules/nginx-lua/util/reindex b/debian/modules/nginx-lua/util/reindex deleted file mode 100755 index bd54c9d..0000000 --- a/debian/modules/nginx-lua/util/reindex +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/perl -#: reindex.pl -#: reindex .t files for Test::Base based test files -#: Copyright (c) 2006 Agent Zhang -#: 2006-04-27 2006-05-09 - -use strict; -use warnings; - -#use File::Copy; -use Getopt::Std; - -my %opts; -getopts('hb:', \%opts); -if ($opts{h} or ! @ARGV) { - die "Usage: reindex [-b 0] t/*.t\n"; -} - -my $init = $opts{b}; -$init = 1 if not defined $init; - -my @files = map glob, @ARGV; -for my $file (@files) { - next if -d $file or $file !~ /\.t_?$/; - reindex($file); -} - -sub reindex { - my $file = $_[0]; - open my $in, $file or - die "Can't open $file for reading: $!"; - my @lines; - my $counter = $init; - my $changed; - while (<$in>) { - s/\r$//; - my $num; - s/ ^ === \s+ TEST \s+ (\d+)/$num=$1; "=== TEST " . $counter++/xie; - next if !defined $num; - if ($num != $counter-1) { - $changed++; - } - } continue { - push @lines, $_; - } - close $in; - my $text = join '', @lines; - $text =~ s/(?x) \n+ === \s+ TEST/\n\n\n\n=== TEST/ixsg; - $text =~ s/__(DATA|END)__\n+=== TEST/__${1}__\n\n=== TEST/; - #$text =~ s/\n+$/\n\n/s; - if (! $changed and $text eq join '', @lines) { - warn "reindex: $file:\tskipped.\n"; - return; - } - #File::Copy::copy( $file, "$file.bak" ); - open my $out, "> $file" or - die "Can't open $file for writing: $!"; - binmode $out; - print $out $text; - close $out; - - warn "reindex: $file:\tdone.\n"; -} - diff --git a/debian/modules/nginx-lua/util/releng b/debian/modules/nginx-lua/util/releng deleted file mode 100755 index adc2f4d..0000000 --- a/debian/modules/nginx-lua/util/releng +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -./update-readme -ack '(?<=\#define)\s*DDEBUG\s*1' src -echo ==================================================== -ack '(?<=_version_string) "\d+\.\d+\.\d+"' src -ack '(?<=This document describes rds-json-nginx-module v)\d+\.\d+' README - diff --git a/debian/modules/ngx-fancyindex/.gitignore b/debian/modules/ngx-fancyindex/.gitignore new file mode 100644 index 0000000..dbec55f --- /dev/null +++ b/debian/modules/ngx-fancyindex/.gitignore @@ -0,0 +1 @@ +*.sw[op] diff --git a/debian/modules/ngx-fancyindex/.todo b/debian/modules/ngx-fancyindex/.todo deleted file mode 100644 index 7b15329..0000000 --- a/debian/modules/ngx-fancyindex/.todo +++ /dev/null @@ -1,42 +0,0 @@ - - - - readme:iframe - - done in r23 - - - - readme:div - - will not be done - - - - readme:pre - - will not be done - - - - header:inline - - - footer:inline - - - install handler *after* index handler - - done - - - - split big handler function into smaller pieces - - - proper error message on subrequest errors - - done - - - diff --git a/debian/modules/ngx-fancyindex/CHANGELOG.md b/debian/modules/ngx-fancyindex/CHANGELOG.md new file mode 100644 index 0000000..0028c8c --- /dev/null +++ b/debian/modules/ngx-fancyindex/CHANGELOG.md @@ -0,0 +1,37 @@ +# Change Log +All notable changes to this project will be documented in this file. + +## Unreleased +### Added +- New feature: Allow setting the default sort criterion using the + `fancyindex_default_sort` configuration directive. (Patch by + Алексей Урбанский). +- New feature: Allos changing the maximum length of file names, using + the `fancyindex_name_length` configuration directive. (Patch by + Martin Herkt). +### Changed +- Renames `NEWS.rst` to `CHANGELOG.md`, which follows the recommendations + from [Keep a Change Log](http://keepachangelog.com/). + +## 0.3.4 - 2014-09-03 +### Added +- Viewport is now defined in the generated HTML, which works better + for mobile devices. +### Changed +- Even-odd row styling moved to the CSS using :nth-child(). This + makes the HTML served to clients smaller. + +## 0.3.3 - 2013-10-25 +### Added +- New feature: table headers in the default template are now clickable + to set the sorting criteria and direction of the index entries. + (https://github.com/aperezdc/ngx-fancyindex/issues/7) + +## 0.3.2 - 2013-06-05 +### Fixed +- Solved a bug that would leave certain clients stalled forever. +- Improved handling of subrequests for non-builtin headers/footers. + +## 0.3.1 - 2011-04-04 +### Added +- `NEWS.rst` file, to act as change log. diff --git a/debian/modules/ngx-fancyindex/HACKING.md b/debian/modules/ngx-fancyindex/HACKING.md new file mode 100644 index 0000000..0748517 --- /dev/null +++ b/debian/modules/ngx-fancyindex/HACKING.md @@ -0,0 +1,24 @@ +# Fancy Index module Hacking HOW-TO + +## How to modify the template + +The template is in the `template.html` file. Note that comment markers are +used to control how the `template.awk` Awk script generates the C header +which gets ultimately included in the compiled object code. Comment markers +have the `` format. Here `identifier` must be +a valid C identifier. All the text following the marker until the next +marker will be flattened into a C string. + +If the identifier is `NONE` (capitalized) the text from that marker up to +the next marker will be discarded. + + +## Regenerating the C header + +You will need Awk. I hope any decent implementation will do, but the GNU one +is known to work flawlessly. Just do: + + $ awk -f template.awk template.html > template.h + +If your copy of `awk` is not the GNU implementation, you will need to +install it and use `gawk` instead in the command line above. diff --git a/debian/modules/ngx-fancyindex/HACKING.rst b/debian/modules/ngx-fancyindex/HACKING.rst deleted file mode 100644 index 8ffc76f..0000000 --- a/debian/modules/ngx-fancyindex/HACKING.rst +++ /dev/null @@ -1,33 +0,0 @@ -=================================== - Fancy Index module Hacking HOW-TO -=================================== - -.. contents:: - - -How to modify the template -========================== - -The template is in the ``template.html`` file. Note that comment markers are -used to control how the ``template.awk`` Awk script generates the C header -which gets ultimately included in the compiled object code. Comment markers -have the ```` format. Here ``identifier`` must be -a valid C identifier. All the text following the marker until the next -marker will be flattened into a C string. - -If the identifier is ``NONE`` (capitalized) the text from that marker up to -the next marker will be discarded. - - -Regenerating the C header -~~~~~~~~~~~~~~~~~~~~~~~~~ -You will need Awk. I hope any decent implementation will do, but the GNU one -is known to work flawlessly. Just do:: - - $ awk -f template.awk template.html > template.h - -If your copy of ``awk`` is not the GNU implementation, you will need to -install it and use ``gawk`` instead in the command line above. - -.. vim: spell spelllang=en expandtab - diff --git a/debian/modules/ngx-fancyindex/NEWS.rst b/debian/modules/ngx-fancyindex/NEWS.rst deleted file mode 100644 index 717345d..0000000 --- a/debian/modules/ngx-fancyindex/NEWS.rst +++ /dev/null @@ -1,25 +0,0 @@ -============================== - Major changes among versions -============================== - -v0.3.4 -====== -- Viewport is now defined in the generated HTML, which works better - for mobile devices. -- Even-odd row styling moved to the CSS using :nth-child(). This - makes the HTML served to clients smaller. - -v0.3.3 -====== -- New feature: table headers in the default template are now clickable - to set the sorting criteria and direction of the index entries. - (https://github.com/aperezdc/ngx-fancyindex/issues/7) - -v0.3.2 -====== -- Solved a bug that would leave certain clients stalled forever. -- Improved handling of subrequests for non-builtin headers/footers. - -v0.3.1 -====== -(First entry in the NEWS file.) diff --git a/debian/modules/ngx-fancyindex/README.rst b/debian/modules/ngx-fancyindex/README.rst index 8d9ebef..fd9f775 100644 --- a/debian/modules/ngx-fancyindex/README.rst +++ b/debian/modules/ngx-fancyindex/README.rst @@ -2,6 +2,10 @@ Nginx Fancy Index module ======================== +.. image:: https://drone.io/github.com/aperezdc/ngx-fancyindex/status.png + :target: https://drone.io/github.com/aperezdc/ngx-fancyindex/latest + :alt: Build Status + .. contents:: The Fancy Index module makes possible the generation of file listings, like @@ -70,6 +74,15 @@ a ``server`` section in your Nginx_ configuration file:: } +Advanced Theming +~~~~~~~~~~~~~~~~ + +For a more elaborate example using `fancyindex_header`_ and +`fancyindex_footer`_ you can check `nice theme +`__ +designed by `@TheInsomniac `__. + + Directives ========== @@ -81,6 +94,14 @@ fancyindex :Description: Enables or disables fancy directory indexes. +fancyindex_default_sort +~~~~~~~~~~~~~~~~~~~~~~~ +:Syntax: *fancyindex_default_sort* [*name* | *size* | *date* | *name_desc* | *size_desc* | *date_desc*] +:Default: fancyindex_default_sort name +:Context: http, server, location +:Description: + Defines sorting criterion by default. + fancyindex_css_href ~~~~~~~~~~~~~~~~~~~ :Syntax: *fancyindex_css_href uri* @@ -102,6 +123,14 @@ fancyindex_exact_size accurately, or rounding off to the kilobyte, the megabyte and the gigabyte. +fancyindex_name_length +~~~~~~~~~~~~~~~~~~~~~~ +:Syntax: *fancyindex_name_length length* +:Default: fancyindex_name_length 50 +:Context: http, server, location +:Description: + Defines the maximum file name length limit in bytes. + fancyindex_footer ~~~~~~~~~~~~~~~~~ :Syntax: *fancyindex_footer path* diff --git a/debian/modules/ngx-fancyindex/ngx_http_fancyindex_module.c b/debian/modules/ngx-fancyindex/ngx_http_fancyindex_module.c index 2ec239e..9675e92 100644 --- a/debian/modules/ngx-fancyindex/ngx_http_fancyindex_module.c +++ b/debian/modules/ngx-fancyindex/ngx_http_fancyindex_module.c @@ -40,8 +40,10 @@ */ typedef struct { ngx_flag_t enable; /**< Module is enabled. */ + ngx_uint_t default_sort; /**< Default sort criterion. */ ngx_flag_t localtime; /**< File mtime dates are sent in local time. */ ngx_flag_t exact_size; /**< Sizes are sent always in bytes. */ + ngx_uint_t name_length; /**< Maximum length of file names in bytes. */ ngx_str_t header; /**< File name for header, or empty if none. */ ngx_str_t footer; /**< File name for footer, or empty if none. */ @@ -50,9 +52,25 @@ typedef struct { ngx_array_t *ignore; /**< List of files to ignore in listings. */ } ngx_http_fancyindex_loc_conf_t; +#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME 0 +#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE 1 +#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE 2 +#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME_DESC 3 +#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE_DESC 4 +#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE_DESC 5 + +static ngx_conf_enum_t ngx_http_fancyindex_sort_criteria[] = { + { ngx_string("name"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME }, + { ngx_string("size"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE }, + { ngx_string("date"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE }, + { ngx_string("name_desc"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME_DESC }, + { ngx_string("size_desc"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE_DESC }, + { ngx_string("date_desc"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE_DESC }, + { ngx_null_string, 0 } +}; + #define NGX_HTTP_FANCYINDEX_PREALLOCATE 50 -#define NGX_HTTP_FANCYINDEX_NAME_LEN 50 /** @@ -149,6 +167,13 @@ static ngx_command_t ngx_http_fancyindex_commands[] = { offsetof(ngx_http_fancyindex_loc_conf_t, enable), NULL }, + { ngx_string("fancyindex_default_sort"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fancyindex_loc_conf_t, default_sort), + &ngx_http_fancyindex_sort_criteria }, + { ngx_string("fancyindex_localtime"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -163,6 +188,13 @@ static ngx_command_t ngx_http_fancyindex_commands[] = { offsetof(ngx_http_fancyindex_loc_conf_t, exact_size), NULL }, + { ngx_string("fancyindex_name_length"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fancyindex_loc_conf_t, name_length), + NULL }, + { ngx_string("fancyindex_header"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_str_slot, @@ -579,7 +611,7 @@ make_content_buf( + ngx_sizeof_ssz("?C=x&O=y") /* URL sorting arguments */ + ngx_sizeof_ssz("\">") + entry[i].name.len + entry[i].utf_len - + NGX_HTTP_FANCYINDEX_NAME_LEN + ngx_sizeof_ssz(">") + + alcf->name_length + ngx_sizeof_ssz(">") + ngx_sizeof_ssz("") + 20 /* File size */ + ngx_sizeof_ssz("") @@ -613,20 +645,24 @@ make_content_buf( case 'M': /* Sort by mtime */ if (sort_descending) { sort_cmp_func = ngx_http_fancyindex_cmp_entries_mtime_desc; - sort_url_args = "?C=M&O=D"; + if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE_DESC) + sort_url_args = "?C=M&O=D"; } else { sort_cmp_func = ngx_http_fancyindex_cmp_entries_mtime_asc; - sort_url_args = "?C=M&O=A"; + if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE) + sort_url_args = "?C=M&O=A"; } break; case 'S': /* Sort by size */ if (sort_descending) { sort_cmp_func = ngx_http_fancyindex_cmp_entries_size_desc; - sort_url_args = "?C=S&O=D"; + if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE_DESC) + sort_url_args = "?C=S&O=D"; } else { sort_cmp_func = ngx_http_fancyindex_cmp_entries_size_asc; + if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE) sort_url_args = "?C=S&O=A"; } break; @@ -634,16 +670,39 @@ make_content_buf( default: if (sort_descending) { sort_cmp_func = ngx_http_fancyindex_cmp_entries_name_desc; - sort_url_args = "?C=N&O=D"; + if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME_DESC) + sort_url_args = "?C=N&O=D"; } else { sort_cmp_func = ngx_http_fancyindex_cmp_entries_name_asc; + if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME) + sort_url_args = "?C=N&O=A"; } break; } } else { - sort_cmp_func = ngx_http_fancyindex_cmp_entries_name_asc; + switch (alcf->default_sort) { + case NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE_DESC: + sort_cmp_func = ngx_http_fancyindex_cmp_entries_mtime_desc; + break; + case NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE: + sort_cmp_func = ngx_http_fancyindex_cmp_entries_mtime_asc; + break; + case NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE_DESC: + sort_cmp_func = ngx_http_fancyindex_cmp_entries_size_desc; + break; + case NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE: + sort_cmp_func = ngx_http_fancyindex_cmp_entries_size_asc; + break; + case NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME_DESC: + sort_cmp_func = ngx_http_fancyindex_cmp_entries_name_desc; + break; + case NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME: + default: + sort_cmp_func = ngx_http_fancyindex_cmp_entries_name_asc; + break; + } } /* Sort entries, if needed */ @@ -704,10 +763,10 @@ make_content_buf( len = entry[i].utf_len; if (entry[i].name.len - len) { - if (len > NGX_HTTP_FANCYINDEX_NAME_LEN) { - copy = NGX_HTTP_FANCYINDEX_NAME_LEN - 3 + 1; + if (len > alcf->name_length) { + copy = alcf->name_length - 3 + 1; } else { - copy = NGX_HTTP_FANCYINDEX_NAME_LEN + 1; + copy = alcf->name_length + 1; } b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data, @@ -716,15 +775,15 @@ make_content_buf( } else { b->last = ngx_cpystrn(b->last, entry[i].name.data, - NGX_HTTP_FANCYINDEX_NAME_LEN + 1); + alcf->name_length + 1); last = b->last - 3; } - if (len > NGX_HTTP_FANCYINDEX_NAME_LEN) { + if (len > alcf->name_length) { b->last = ngx_cpymem_ssz(last, "..>"); } else { - if (entry[i].dir && NGX_HTTP_FANCYINDEX_NAME_LEN - len > 0) { + if (entry[i].dir && alcf->name_length - len > 0) { *b->last++ = '/'; len++; } @@ -1117,10 +1176,12 @@ ngx_http_fancyindex_create_loc_conf(ngx_conf_t *cf) * conf->footer.len = 0 * conf->footer.data = NULL */ - conf->enable = NGX_CONF_UNSET; - conf->localtime = NGX_CONF_UNSET; - conf->exact_size = NGX_CONF_UNSET; - conf->ignore = NGX_CONF_UNSET_PTR; + conf->enable = NGX_CONF_UNSET; + conf->default_sort = NGX_CONF_UNSET_UINT; + conf->localtime = NGX_CONF_UNSET; + conf->name_length = NGX_CONF_UNSET_UINT; + conf->exact_size = NGX_CONF_UNSET; + conf->ignore = NGX_CONF_UNSET_PTR; return conf; } @@ -1133,8 +1194,10 @@ ngx_http_fancyindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_fancyindex_loc_conf_t *conf = child; ngx_conf_merge_value(conf->enable, prev->enable, 0); + ngx_conf_merge_uint_value(conf->default_sort, prev->default_sort, NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME); ngx_conf_merge_value(conf->localtime, prev->localtime, 0); ngx_conf_merge_value(conf->exact_size, prev->exact_size, 1); + ngx_conf_merge_uint_value(conf->name_length, prev->name_length, 50); ngx_conf_merge_str_value(conf->header, prev->header, ""); ngx_conf_merge_str_value(conf->footer, prev->footer, "");