Compare commits

..

2 commits

Author SHA1 Message Date
Jan Mojžíš
9bd8be0d50
d/control: add libnginx-mod-http-lua dependency for nginx-extras package
for riscv64 platform
2025-02-12 19:43:05 +01:00
Jan Mojžíš
9947f2a2f0
d/changelog: fix whitespace 2025-02-12 19:38:28 +01:00
760 changed files with 14 additions and 155760 deletions

10
.gitignore vendored
View file

@ -1,10 +0,0 @@
objs/*
!objs/ndk_*
.pc/
.vscode/
modules/media-framework/
modules/nginx-srt-module/
modules/nginx-vod-module/
Makefile
*.orig
*.txt

View file

@ -2,11 +2,6 @@
# Copyright (C) Igor Sysoev
# Copyright (C) Nginx, Inc.
basename_last2() {
local basename_1=`basename \`dirname $1\``
local basename_2=$(basename "$1")
echo $(printf "$basename_1/$basename_2" | sed 's/\.\.\///')
}
echo "creating $NGX_MAKEFILE"
@ -179,7 +174,7 @@ ngx_all_srcs=`echo $ngx_all_srcs | sed -e "s/\//$ngx_regex_dirsep/g"`
for ngx_src in $NGX_ADDON_SRCS
do
ngx_obj="addon/`basename_last2 \`dirname $ngx_src\``"
ngx_obj="addon/`basename \`dirname $ngx_src\``"
test -d $NGX_OBJS/$ngx_obj || mkdir -p $NGX_OBJS/$ngx_obj
@ -418,7 +413,7 @@ if test -n "$NGX_ADDON_SRCS"; then
for ngx_src in $NGX_ADDON_SRCS
do
ngx_obj="addon/`basename_last2 \`dirname $ngx_src\``"
ngx_obj="addon/`basename \`dirname $ngx_src\``"
ngx_obj=`echo $ngx_obj/\`basename $ngx_src\` \
| sed -e "s/\//$ngx_regex_dirsep/g"`
@ -581,7 +576,7 @@ END
ngx_obj=$ngx_src
;;
*)
ngx_obj="addon/`basename_last2 \`dirname $ngx_src\``"
ngx_obj="addon/`basename \`dirname $ngx_src\``"
mkdir -p $NGX_OBJS/$ngx_obj
ngx_obj="$ngx_obj/`basename $ngx_src`"
;;
@ -643,7 +638,7 @@ END
ngx_obj=`echo $ngx_source | sed -e "s/\//$ngx_regex_dirsep/g"`
;;
*)
ngx_obj="addon/`basename_last2 \`dirname $ngx_source\``"
ngx_obj="addon/`basename \`dirname $ngx_source\``"
ngx_obj=`echo $ngx_obj/\`basename $ngx_source\` \
| sed -e "s/\//$ngx_regex_dirsep/g"`
;;

View file

@ -1,69 +0,0 @@
#!/bin/bash
./configure \
--with-cc-opt="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -fPIC -D_FORTIFY_SOURCE=2 -I/tmp/build/quickjs/" \
--with-ld-opt="-Wl,-z,relro -Wl,-z,now -fPIC -L/tmp/build/quickjs/" \
--sbin-path=/usr/local/sbin/nginx \
--conf-path=/video_server/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/nginx/nginx.lock \
--http-log-path=/var/log/nginx/access.log \
--http-client-body-temp-path=/tmp/nginx-client-body \
--with-compat \
--with-debug \
--with-pcre-jit \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-http_auth_request_module \
--with-http_v2_module \
--with-http_dav_module \
--with-http_slice_module \
--with-threads \
--with-http_addition_module \
--with-http_flv_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_mp4_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_sub_module \
--with-mail_ssl_module \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-stream_realip_module \
--with-http_geoip_module=dynamic \
--with-http_image_filter_module=dynamic \
--with-http_perl_module=dynamic \
--with-http_xslt_module=dynamic \
--with-mail=dynamic \
--with-stream=dynamic \
--with-stream_geoip_module=dynamic \
--add-module=./modules_deb/libnginx-mod-http-ndk-0.3.4 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-brotli-1.0.0~rc \
--add-dynamic-module=./modules_deb/libnginx-mod-http-cache-purge-2.5.3 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-echo-0.63 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-geoip2-3.4 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-headers-more-filter-0.38 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-memc-0.20 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-set-misc-0.33 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-srcache-filter-0.33 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-subs-filter-0.6.4 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409 \
--add-dynamic-module=./modules_deb/libnginx-mod-nchan-1.3.7+dfsg \
--add-dynamic-module=./modules/njs/nginx \
--add-dynamic-module=./modules/nginx-vod-module \
--add-module=./modules/media-framework/nginx-common \
--add-dynamic-module=./modules/nginx-stream-preread-str-module \
--add-dynamic-module=./modules/media-framework/nginx-kmp-in-module \
--add-dynamic-module=./modules/media-framework/nginx-kmp-out-module \
--add-dynamic-module=./modules/media-framework/nginx-rtmp-module \
--add-dynamic-module=./modules/media-framework/nginx-rtmp-kmp-module \
--add-dynamic-module=./modules/media-framework/nginx-mpegts-module \
--add-dynamic-module=./modules/media-framework/nginx-mpegts-kmp-module \
--add-dynamic-module=./modules/media-framework/nginx-kmp-cc-module \
--add-dynamic-module=./modules/media-framework/nginx-kmp-rtmp-module \
--add-dynamic-module=./modules/media-framework/nginx-live-module \
--add-dynamic-module=./modules/nginx-srt-module \
--add-dynamic-module=./modules/media-framework/nginx-pckg-module \
--add-dynamic-module=./modules/nginx-secure-token-module

View file

@ -1,66 +0,0 @@
#!/bin/bash
./configure \
--with-cc-opt="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -fPIC -D_FORTIFY_SOURCE=2 -I/usr/local/include/quickjs/" \
--with-ld-opt="-Wl,-z,relro -Wl,-z,now -fPIC -L/usr/local/lib/quickjs/" \
--prefix=/usr/local/temp/nginx/ \
--error-log-path=stderr \
--lock-path=/var/lock/nginx.lock \
--pid-path=/run/nginx.pid \
--with-compat \
--with-debug \
--with-pcre-jit \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-http_auth_request_module \
--with-http_v2_module \
--with-http_dav_module \
--with-http_slice_module \
--with-threads \
--with-http_addition_module \
--with-http_flv_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_mp4_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_sub_module \
--with-mail_ssl_module \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-stream_realip_module \
--with-http_geoip_module=dynamic \
--with-http_image_filter_module=dynamic \
--with-http_perl_module=dynamic \
--with-http_xslt_module=dynamic \
--with-mail=dynamic \
--with-stream=dynamic \
--with-stream_geoip_module=dynamic \
--add-module=./modules_deb/libnginx-mod-http-ndk-0.3.4 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-brotli-1.0.0~rc \
--add-dynamic-module=./modules_deb/libnginx-mod-http-cache-purge-2.5.3 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-echo-0.63 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-geoip2-3.4 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-headers-more-filter-0.38 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-memc-0.20 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-set-misc-0.33 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-srcache-filter-0.33 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-subs-filter-0.6.4 \
--add-dynamic-module=./modules_deb/libnginx-mod-http-upstream-fair-0.0~git20120408.a18b409 \
--add-dynamic-module=./modules_deb/libnginx-mod-nchan-1.3.7+dfsg \
--add-dynamic-module=./modules/njs/nginx \
--add-dynamic-module=./modules/nginx-vod-module \
--add-module=./modules/media-framework/nginx-common \
--add-dynamic-module=./modules/nginx-stream-preread-str-module \
--add-dynamic-module=./modules/media-framework/nginx-kmp-in-module \
--add-dynamic-module=./modules/media-framework/nginx-kmp-out-module \
--add-dynamic-module=./modules/media-framework/nginx-rtmp-module \
--add-dynamic-module=./modules/media-framework/nginx-rtmp-kmp-module \
--add-dynamic-module=./modules/media-framework/nginx-mpegts-module \
--add-dynamic-module=./modules/media-framework/nginx-mpegts-kmp-module \
--add-dynamic-module=./modules/media-framework/nginx-kmp-cc-module \
--add-dynamic-module=./modules/media-framework/nginx-kmp-rtmp-module \
--add-dynamic-module=./modules/media-framework/nginx-live-module \
--add-dynamic-module=./modules/nginx-srt-module \
--add-dynamic-module=./modules/media-framework/nginx-pckg-module \
--add-dynamic-module=./modules/nginx-secure-token-module

13
debian/changelog vendored
View file

@ -1,17 +1,10 @@
nginx (1.26.3-3) unstable; urgency=medium
nginx (1.26.3-3) UNRELEASED; urgency=medium
[ Jan Mojžíš ]
* d/changelog: fix whitespace in 1.26.3-2 record
* d/changelog: fix whitespace
* d/control: add libnginx-mod-http-lua dependency for nginx-extras package
for riscv64 platform
[ Thomas Ward ]
* d/nginx-common.nginx.service: Add ConditionFileIsExecutable to
SystemD service file, prevents starting of service if nginx is
not installed (which can happen if nginx-common is installed
independently from `nginx` itself (Closes: #1098477)
-- Jan Mojžíš <janmojzis@debian.org> Thu, 15 May 2025 15:31:38 +0200
-- Jan Mojžíš <janmojzis@debian.org> Wed, 12 Feb 2025 19:37:40 +0100
nginx (1.26.3-2) unstable; urgency=medium

View file

@ -15,7 +15,6 @@ Description=A high performance web server and a reverse proxy server
Documentation=man:nginx(8)
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
ConditionFileIsExecutable=/usr/sbin/nginx
[Service]
Type=forking

View file

@ -1 +0,0 @@
Subproject commit 24f7b99d9b665e11c92e585d6645ed6f45f7d310

@ -1 +0,0 @@
Subproject commit 7326626fce5d6ec31ac892377e0a734e503d40e6

@ -1 +0,0 @@
Subproject commit 4fd3ff98e413ede57c88456cf84b116a8382061a

@ -1 +0,0 @@
Subproject commit 1fdc768fdc8571300755cdd3e4654ce99c0255ce

View file

@ -1,46 +0,0 @@
# required for http2 support in curl.
dist: bionic
language: c
sudo: false
matrix:
include:
# unfortunately, gcc-4.9 is dropped in bionic
- os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-5
env:
- MATRIX_EVAL="CC=gcc-5 && CXX=g++-5"
- os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-6
env:
- MATRIX_EVAL="CC=gcc-6 && CXX=g++-6"
- os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-7
env:
- MATRIX_EVAL="CC=gcc-7 && CXX=g++-7"
script:
- script/.travis-compile.sh
- script/.travis-before-test.sh
- script/.travis-test.sh
after_success:
- killall nginx
after_failure:
- killall nginx

View file

@ -1,27 +0,0 @@
# Contributing
Want to contribute? Great! First, read this page (including the small print at the end).
### Before you contribute
Before we can use your code, you must sign the
[Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual)
(CLA), which you can do online. The CLA is necessary mainly because you own the
copyright to your changes, even after your contribution becomes part of our
codebase, so we need your permission to use and distribute your code. We also
need to be sure of various other things—for instance that you'll tell us if you
know that your code infringes on other people's patents. You don't have to sign
the CLA until after you've submitted your code for review and a member has
approved it, but you must do it before we can put your code into our codebase.
Before you start working on a larger contribution, you should get in touch with
us first through the issue tracker with your idea so that we can help out and
possibly guide you. Coordinating up front makes it much easier to avoid
frustration later on.
### Code reviews
All submissions, including submissions by project members, require review. We
use Github pull requests for this purpose.
### The small print
Contributions made by corporations are covered by a different agreement than
the one above, the
[Software Grant and Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate).

View file

@ -1,27 +0,0 @@
/*
* Copyright (C) 2002-2015 Igor Sysoev
* Copyright (C) 2011-2015 Nginx, Inc.
* Copyright (C) 2015-2019 Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

View file

@ -1,177 +0,0 @@
# ngx_brotli
Brotli is a generic-purpose lossless compression algorithm that compresses data
using a combination of a modern variant of the LZ77 algorithm, Huffman coding
and 2nd order context modeling, with a compression ratio comparable to the best
currently available general-purpose compression methods. It is similar in speed
with deflate but offers more dense compression.
ngx_brotli is a set of two nginx modules:
- ngx_brotli filter module - used to compress responses on-the-fly,
- ngx_brotli static module - used to serve pre-compressed files.
[![TravisCI Build Status](https://travis-ci.org/google/ngx_brotli.svg?branch=master)](https://travis-ci.org/google/ngx_brotli)
## Table of Contents
- [Status](#status)
- [Installation](#installation)
- [Configuration directives](#configuration-directives)
- [`brotli_static`](#brotli_static)
- [`brotli`](#brotli)
- [`brotli_types`](#brotli_types)
- [`brotli_buffers`](#brotli_buffers)
- [`brotli_comp_level`](#brotli_comp_level)
- [`brotli_window`](#brotli_window)
- [`brotli_min_length`](#brotli_min_length)
- [Variables](#variables)
- [`$brotli_ratio`](#brotli_ratio)
- [Sample configuration](#sample-configuration)
- [Contributing](#contributing)
- [License](#license)
## Status
Both Brotli library and nginx module are under active development.
## Installation
### Dynamically loaded
$ cd nginx-1.x.x
$ ./configure --with-compat --add-dynamic-module=/path/to/ngx_brotli
$ make modules
You will need to use **exactly** the same `./configure` arguments as your Nginx configuration and append `--with-compat --add-dynamic-module=/path/to/ngx_brotli` to the end, otherwise you will get a "module is not binary compatible" error on startup. You can run `nginx -V` to get the configuration arguments for your Nginx installation.
`make modules` will result in `ngx_http_brotli_filter_module.so` and `ngx_http_brotli_static_module.so` in the `objs` directory. Copy these to `/usr/lib/nginx/modules/` then add the `load_module` directives to `nginx.conf` (above the http block):
```nginx
load_module modules/ngx_http_brotli_filter_module.so;
load_module modules/ngx_http_brotli_static_module.so;
```
### Statically compiled
$ cd nginx-1.x.x
$ ./configure --add-module=/path/to/ngx_brotli
$ make && make install
This will compile the module directly into Nginx.
## Configuration directives
### `brotli_static`
- **syntax**: `brotli_static on|off|always`
- **default**: `off`
- **context**: `http`, `server`, `location`
Enables or disables checking of the existence of pre-compressed files with`.br`
extension. With the `always` value, pre-compressed file is used in all cases,
without checking if the client supports it.
### `brotli`
- **syntax**: `brotli on|off`
- **default**: `off`
- **context**: `http`, `server`, `location`, `if`
Enables or disables on-the-fly compression of responses.
### `brotli_types`
- **syntax**: `brotli_types <mime_type> [..]`
- **default**: `text/html`
- **context**: `http`, `server`, `location`
Enables on-the-fly compression of responses for the specified MIME types
in addition to `text/html`. The special value `*` matches any MIME type.
Responses with the `text/html` MIME type are always compressed.
### `brotli_buffers`
- **syntax**: `brotli_buffers <number> <size>`
- **default**: `32 4k|16 8k`
- **context**: `http`, `server`, `location`
**Deprecated**, ignored.
### `brotli_comp_level`
- **syntax**: `brotli_comp_level <level>`
- **default**: `6`
- **context**: `http`, `server`, `location`
Sets on-the-fly compression Brotli quality (compression) `level`.
Acceptable values are in the range from `0` to `11`.
### `brotli_window`
- **syntax**: `brotli_window <size>`
- **default**: `512k`
- **context**: `http`, `server`, `location`
Sets Brotli window `size`. Acceptable values are `1k`, `2k`, `4k`, `8k`, `16k`,
`32k`, `64k`, `128k`, `256k`, `512k`, `1m`, `2m`, `4m`, `8m` and `16m`.
### `brotli_min_length`
- **syntax**: `brotli_min_length <length>`
- **default**: `20`
- **context**: `http`, `server`, `location`
Sets the minimum `length` of a response that will be compressed.
The length is determined only from the `Content-Length` response header field.
## Variables
### `$brotli_ratio`
Achieved compression ratio, computed as the ratio between the original
and compressed response sizes.
## Sample configuration
```
brotli on;
brotli_comp_level 6;
brotli_static on;
brotli_types application/atom+xml application/javascript application/json application/rss+xml
application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype
application/x-font-ttf application/x-javascript application/xhtml+xml application/xml
font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon
image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml;
```
## Contributing
See [Contributing](CONTRIBUTING.md).
## License
Copyright (C) 2002-2015 Igor Sysoev
Copyright (C) 2011-2015 Nginx, Inc.
Copyright (C) 2015 Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

View file

@ -1,34 +0,0 @@
# Copyright (C) 2019 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# Make sure the module knows it is a submodule.
ngx_addon_name=ngx_brotli
. $ngx_addon_dir/filter/config
# Make sure the module knows it is a submodule.
ngx_addon_name=ngx_brotli
. $ngx_addon_dir/static/config
# The final name for reporting.
ngx_addon_name=ngx_brotli

View file

@ -1,49 +0,0 @@
libnginx-mod-http-brotli (1.0.0~rc-6) unstable; urgency=medium
* d/control: update my email to janmojzis@debian.org
* d/copyright: update my email to janmojzis@debian.org
* d/control: bump Standards-Version: 4.7.2, no changes
* d/copyright: bump debian/* copyright year
* d/watch: use more generic template
-- Jan Mojžíš <janmojzis@debian.org> Fri, 11 Apr 2025 14:26:55 +0200
libnginx-mod-http-brotli (1.0.0~rc-5) unstable; urgency=medium
* d/control: remove Build-Depends nginx-abi-1.24.0-1
-- Jan Mojžíš <jan.mojzis@gmail.com> Sat, 07 Oct 2023 15:31:24 +0200
libnginx-mod-http-brotli (1.0.0~rc-4) unstable; urgency=medium
* NEW ABI: rebuild with nginx-abi-1.24.0-1
-- Jan Mojžíš <jan.mojzis@gmail.com> Tue, 27 Jun 2023 23:16:35 +0200
libnginx-mod-http-brotli (1.0.0~rc-3) unstable; urgency=medium
* d/watch: updated uversionmangle to be more generic
* d/copyright: reformat text to be compatible with 'cme update dpkg-copyright'
* NEW ABI: rebuild with nginx-abi-1.22.1-7
-- Jan Mojžíš <jan.mojzis@gmail.com> Mon, 13 Feb 2023 12:56:11 +0100
libnginx-mod-http-brotli (1.0.0~rc-2) unstable; urgency=medium
* d/t/generic rework. The test now checks module after
installation/reload/restart.
* d/control: bump Standards-Version: 4.6.2, no changes
* d/p/0001-Fix-Vary-header.patch added (Closes: 1028153)
"brotli_static on;" causes "Vary: Accept-Encoding" to be added to every
file (including images, ...)
The patch fixes the problem and adds "Vary: Accept-Encoding" only to
responses when brotli static compression is used.
* d/changelog: bump my copyright year
-- Jan Mojžíš <jan.mojzis@gmail.com> Fri, 13 Jan 2023 17:45:13 +0100
libnginx-mod-http-brotli (1.0.0~rc-1) unstable; urgency=medium
* Initial release. (Closes: 1025515)
-- Jan Mojžíš <jan.mojzis@gmail.com> Tue, 06 Dec 2022 10:25:40 +0100

View file

@ -1,41 +0,0 @@
Source: libnginx-mod-http-brotli
Section: httpd
Priority: optional
Maintainer: Debian Nginx Maintainers <pkg-nginx-maintainers@alioth-lists.debian.net>
Uploaders: Jan Mojžíš <janmojzis@debian.org>,
Build-Depends: debhelper-compat (= 13),
dh-sequence-nginx,
libbrotli-dev,
Standards-Version: 4.7.2
Homepage: https://github.com/google/ngx_brotli
Vcs-Git: https://salsa.debian.org/nginx-team/libnginx-mod-http-brotli.git
Vcs-Browser: https://salsa.debian.org/nginx-team/libnginx-mod-http-brotli
Rules-Requires-Root: no
Package: libnginx-mod-http-brotli-filter
Architecture: any
Multi-Arch: foreign
Depends: ${misc:Depends},
${shlibs:Depends},
Description: Brotli lossless compression support for Nginx - filter
Brotli is a generic-purpose lossless compression algorithm that compresses
data using a combination of a modern variant of the LZ77 algorithm, Huffman
coding and 2nd order context modeling, with a compression ratio comparable
to the best currently available general-purpose compression methods. It is
similar in speed with deflate but offers more dense compression.
.
ngx_brotli filter module - used to compress responses on-the-fly
Package: libnginx-mod-http-brotli-static
Architecture: any
Multi-Arch: foreign
Depends: ${misc:Depends},
${shlibs:Depends},
Description: Brotli lossless compression support for Nginx - static
Brotli is a generic-purpose lossless compression algorithm that compresses
data using a combination of a modern variant of the LZ77 algorithm, Huffman
coding and 2nd order context modeling, with a compression ratio comparable
to the best currently available general-purpose compression methods. It is
similar in speed with deflate but offers more dense compression.
.
ngx_brotli static module - used to serve pre-compressed files

View file

@ -1,72 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: ngx-brotli
Source: https://github.com/google/ngx_brotli
Files: *
Copyright: 2015-2019, Google Inc.
2011-2015, Nginx, Inc.
2002-2015, Igor Sysoev
License: BSD-2-clause
Files: CONTRIBUTING.md
Copyright: Copyright (C) 2015 Google Inc.
Copyright (C) 2011-2015 Nginx, Inc.
Copyright (C) 2002-2015 Igor Sysoev
License: BSD-2-clause
Files: config
Copyright: 2015-2019, Google Inc.
License: BSD-2-clause
Files: debian/*
Copyright: 2022, Miao Wang <shankerwangmiao@gmail.com>
2022-2025, Jan Mojzis <janmojzis@debian.org>
License: BSD-2-clause
Files: filter/*
Copyright: 2015-2019, Google Inc.
License: BSD-2-clause
Files: filter/ngx_http_brotli_filter_module.c
Copyright: Nginx, Inc.
Igor Sysoev
Google Inc.
License: BSD-2-clause
Files: script/*
Copyright: Copyright (C) 2015 Google Inc.
Copyright (C) 2011-2015 Nginx, Inc.
Copyright (C) 2002-2015 Igor Sysoev
License: BSD-2-clause
Files: static/*
Copyright: 2015-2019, Google Inc.
License: BSD-2-clause
Files: static/ngx_http_brotli_static_module.c
Copyright: Nginx, Inc.
Igor Sysoev
Google Inc.
License: BSD-2-clause
License: BSD-2-clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

View file

@ -1,9 +0,0 @@
[DEFAULT]
debian-branch = main
upstream-branch = upstream
upstream-tag = upstream/%(version)s
pristine-tar = True
sign-tags = True
[import-orig]
merge-mode = replace

View file

@ -1 +0,0 @@
/usr/lib/nginx/modules/ngx_http_brotli_filter_module.so

View file

@ -1 +0,0 @@
/usr/lib/nginx/modules/ngx_http_brotli_static_module.so

View file

@ -1,38 +0,0 @@
From: Jan Mojzis <jan.mojzis@gmail.com>
Date: Fri, 13 Jan 2023 12:59:07 +0100
Subject: Fix 'Vary' header
The patch fixes problem described here:
https://github.com/google/ngx_brotli/issues/97
"brotli_static on;" causes "Vary: Accept-Encoding" to be added to every
file (including images, ...)
The patch fixes the problem and adds "Vary: Accept-Encoding" only to
responses when brotli static compression is used.
---
static/ngx_http_brotli_static_module.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/static/ngx_http_brotli_static_module.c b/static/ngx_http_brotli_static_module.c
index 8f96177..44f0cb0 100644
--- a/static/ngx_http_brotli_static_module.c
+++ b/static/ngx_http_brotli_static_module.c
@@ -168,7 +168,6 @@ static ngx_int_t handler(ngx_http_request_t* req) {
/* Ignore request properties (e.g. Accept-Encoding). */
} else {
/* NGX_HTTP_BROTLI_STATIC_ON */
- req->gzip_vary = 1;
rc = check_eligility(req);
if (rc != NGX_OK) return NGX_DECLINED;
}
@@ -227,6 +226,10 @@ static ngx_int_t handler(ngx_http_request_t* req) {
return NGX_DECLINED;
}
+ if (cfg->enable == NGX_HTTP_BROTLI_STATIC_ON) {
+ req->gzip_vary = 1;
+ }
+
/* So far so good. */
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d",
file_info.fd);

View file

@ -1 +0,0 @@
0001-Fix-Vary-header.patch

View file

@ -1,6 +0,0 @@
#!/usr/bin/make -f
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
%:
dh $@

View file

@ -1,22 +0,0 @@
Tests: generic
Restrictions: allow-stderr isolation-container needs-root
Depends: curl,
nginx,
nginx-core,
@,
Tests: static
Restrictions: allow-stderr isolation-container needs-root
Depends: brotli,
curl,
libnginx-mod-http-brotli-static,
nginx,
nginx-core,
Tests: filter
Restrictions: allow-stderr isolation-container needs-root
Depends: brotli,
curl,
libnginx-mod-http-brotli-filter,
nginx,
nginx-core,

View file

@ -1,44 +0,0 @@
#!/bin/sh
set -e
cat <<EOF > "/etc/nginx/sites-enabled/default"
server {
listen 80 default_server;
root /var/www/html;
location /helloworld {
default_type text/plain;
brotli on;
brotli_types text/plain;
brotli_min_length 10;
brotli_comp_level 11;
}
}
EOF
mkdir -p /var/www/html
echo 'hello world' > /var/www/html/helloworld
exp="content-encoding: br
hello world
response_code: 200"
nginx -t
invoke-rc.d nginx restart || { journalctl -n all -xu nginx.service; exit 1; }
out=`curl --compressed --fail -D- -w "response_code: %{http_code}\n" http://127.0.0.1/helloworld`
out=`echo "${out}" | sed 's/\r//'`
out=`echo "${out}" | awk '{print tolower($0)}'`
out=`echo "${out}" | grep '^content-encoding: \|^hello world$\|response_code: '`
if [ x"${out}" != x"${exp}" ]; then
echo "output:"
echo "====================="
echo "${out}"
echo "====================="
echo "expected output:"
echo "====================="
echo "${exp}"
echo "====================="
exit 1
fi

View file

@ -1,73 +0,0 @@
#!/bin/sh
# version 20221215
# generic test that only verifies that nginx is running with the given
# libnginx-... module
# - after installation
# - after nginx reload
# - after nginx restart
EX=0
CURL_CMD="curl --max-time 60 --silent --fail -o /dev/null"
#change directory to $AUTOPKGTEST_TMP
cd "${AUTOPKGTEST_TMP}"
echo -n "curl after installation: http status="
if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then
echo "OK"
else
EX=1
echo "FAILED"
fi
echo -n "nginx reload ... "
if invoke-rc.d nginx reload; then
echo "OK"
else
EX=1
echo "FAILED"
fi
sleep 5
echo -n "curl after reload: http status="
if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then
echo "OK"
else
EX=1
echo "FAILED"
fi
echo -n "nginx restart ... "
if invoke-rc.d nginx restart; then
echo "OK"
else
EX=1
echo "FAILED"
fi
sleep 5
echo -n "curl after restart: http status="
if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then
echo "OK"
else
EX=1
echo "FAILED"
fi
if [ ${EX} -ne 0 ]; then
echo "=== journalctl ==="
journalctl -n all -xu nginx.service || :
echo "=== error.log ==="
if [ `wc -l /var/log/nginx/error.log | cut -d ' ' -f1` -gt 100 ]; then
head -n 50 /var/log/nginx/error.log
echo '...'
tail -n 50 /var/log/nginx/error.log
else
cat /var/log/nginx/error.log
fi
fi
exit ${EX}

View file

@ -1,36 +0,0 @@
#!/bin/sh
set -e
cat <<EOF > "/etc/nginx/sites-enabled/default"
server {
listen 80 default_server;
root /var/www/html;
location /helloworld {
brotli_static on;
}
}
EOF
mkdir -p /var/www/html
echo 'hello world' | brotli -9 > /var/www/html/helloworld.br
exp="hello world
response_code: 200"
nginx -t
invoke-rc.d nginx restart || { journalctl -n all -xu nginx.service; exit 1; }
out=`curl --compressed --fail -w "response_code: %{http_code}\n" http://127.0.0.1/helloworld`
if [ x"${out}" != x"${exp}" ]; then
echo "output:"
echo "====================="
echo "${out}"
echo "====================="
echo "expected output:"
echo "====================="
echo "${exp}"
echo "====================="
exit 1
fi

View file

@ -1,4 +0,0 @@
---
Bug-Database: https://github.com/google/ngx_brotli/issues
Bug-Submit: https://github.com/google/ngx_brotli/issues/new
Repository-Browse: https://github.com/google/ngx_brotli

View file

@ -1,6 +0,0 @@
version=4
opts="\
uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha|a|b)\d*)$/$1~$2/,\
" \
https://github.com/google/ngx_brotli/tags \
(?:.*?/)?v?@ANY_VERSION@@ARCHIVE_EXT@

View file

@ -1,132 +0,0 @@
# Copyright (C) 2015-2016 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
if [ "$ngx_addon_name" = "ngx_brotli" ]; then
BROTLI_MODULE_SRC_DIR="$ngx_addon_dir/filter"
else
BROTLI_MODULE_SRC_DIR="$ngx_addon_dir"
fi
ngx_addon_name=ngx_brotli_filter
if [ -z "$ngx_module_link" ]; then
cat << END
$0: error: Brotli module requires recent version of NGINX (1.9.11+).
END
exit 1
fi
ngx_module_type=HTTP_FILTER
ngx_module_name=ngx_http_brotli_filter_module
brotli="$ngx_addon_dir/deps/brotli/c"
if [ ! -f "$brotli/include/brotli/encode.h" ]; then
brotli="/usr/local"
fi
if [ ! -f "$brotli/include/brotli/encode.h" ]; then
brotli="/usr"
fi
if [ ! -f "$brotli/include/brotli/encode.h" ]; then
cat << END
$0: error: \
Brotli library is missing from the $brotli directory.
Please make sure that the git submodule has been checked out:
cd $ngx_addon_dir && git submodule update --init && cd $PWD
END
exit 1
fi
BROTLI_LISTS_FILE="$brotli/../scripts/sources.lst"
if [ -f "$BROTLI_LISTS_FILE" ]; then
BROTLI_LISTS=`cat "$BROTLI_LISTS_FILE" | grep -v "#" | tr '\n' '#' | \
sed 's/\\\\#//g' | tr -s ' ' '+' | tr -s '#' ' ' | \
sed 's/+c/+$brotli/g' | sed 's/+=+/=/g'`
for ITEM in ${BROTLI_LISTS}; do
VAR=`echo $ITEM | sed 's/=.*//'`
VAL=`echo $ITEM | sed 's/.*=//' | tr '+' ' '`
eval ${VAR}=\"$VAL\"
done
else # BROTLI_LISTS_FILE
BROTLI_ENC_H="$brotli/include/brotli/encode.h \
$brotli/include/brotli/port.h \
$brotli/include/brotli/types.h"
BROTLI_ENC_LIB="-lbrotlienc"
fi
ngx_module_incs="$brotli/include"
ngx_module_deps="$BROTLI_COMMON_H $BROTLI_ENC_H"
ngx_module_srcs="$BROTLI_COMMON_C $BROTLI_ENC_C \
$BROTLI_MODULE_SRC_DIR/ngx_http_brotli_filter_module.c"
ngx_module_libs="$BROTLI_ENC_LIB -lm"
ngx_module_order="$ngx_module_name \
ngx_pagespeed \
ngx_http_postpone_filter_module \
ngx_http_ssi_filter_module \
ngx_http_charset_filter_module \
ngx_http_xslt_filter_module \
ngx_http_image_filter_module \
ngx_http_sub_filter_module \
ngx_http_addition_filter_module \
ngx_http_gunzip_filter_module \
ngx_http_userid_filter_module \
ngx_http_headers_filter_module \
ngx_http_copy_filter_module \
ngx_http_range_body_filter_module \
ngx_http_not_modified_filter_module \
ngx_http_slice_filter_module"
. auto/module
if [ "$ngx_module_link" != DYNAMIC ]; then
# ngx_module_order doesn't work with static modules,
# so we must re-order filters here.
if [ "$HTTP_GZIP" = YES ]; then
next=ngx_http_gzip_filter_module
elif echo $HTTP_FILTER_MODULES | grep pagespeed_etag_filter >/dev/null; then
next=ngx_pagespeed_etag_filter
else
next=ngx_http_range_header_filter_module
fi
HTTP_FILTER_MODULES=`echo $HTTP_FILTER_MODULES \
| sed "s/$ngx_module_name//" \
| sed "s/$next/$next $ngx_module_name/"`
fi
CFLAGS="$CFLAGS -Wno-deprecated-declarations"
have=NGX_HTTP_BROTLI_FILTER . auto/have
have=NGX_HTTP_BROTLI_FILTER_MODULE . auto/have # deprecated

View file

@ -1,770 +0,0 @@
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
* Copyright (C) Google Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#if (NGX_HAVE_BROTLI_ENC_ENCODE_H)
#include <brotli/enc/encode.h>
#else
#include <brotli/encode.h>
#endif
/* Brotli and GZip modules never stack, i.e. when one of them sets
"Content-Encoding" the other becomes a pass-through filter. Consequently,
it is almost legal to reuse this "buffered" bit.
IIUC, buffered == some data passed to filter has not been pushed further. */
#define NGX_HTTP_BROTLI_BUFFERED NGX_HTTP_GZIP_BUFFERED
/* Module configuration. */
typedef struct {
ngx_flag_t enable;
/* Supported MIME types. */
ngx_hash_t types;
ngx_array_t* types_keys;
/* Minimal required length for compression (if known). */
ssize_t min_length;
ngx_bufs_t deprecated_unused_bufs;
/* Brotli encoder parameter: quality */
ngx_int_t quality;
/* Brotli encoder parameter: (max) lg_win */
size_t lg_win;
} ngx_http_brotli_conf_t;
/* Instance context. */
typedef struct {
/* Brotli encoder instance. */
BrotliEncoderState* encoder;
/* Payload length; -1, if unknown. */
off_t content_length;
/* (uncompressed) bytes pushed to encoder. */
size_t bytes_in;
/* (compressed) bytes pulled from encoder. */
size_t bytes_out;
/* Input buffer chain. */
ngx_chain_t* in;
/* Output chain. */
ngx_chain_t* out_chain;
/* Output buffer. */
ngx_buf_t* out_buf;
/* Various state flags. */
/* 1 if encoder is initialized, output chain and buffer are allocated. */
unsigned initialized : 1;
/* 1 if compression is finished / failed. */
unsigned closed : 1;
/* 1 if compression is finished. */
unsigned success : 1;
/* 1 if out_chain is ready to be committed, 0 otherwise. */
unsigned output_ready : 1;
/* 1 if output buffer is committed to the next filter and not yet fully used.
0 otherwise. */
unsigned output_busy : 1;
unsigned end_of_input : 1;
unsigned end_of_block : 1;
ngx_http_request_t* request;
} ngx_http_brotli_ctx_t;
/* Forward declarations. */
/* Initializes encoder, output chain and buffer, if necessary. Returns NGX_OK
if encoder is successfully initialized (have been already initialized),
and requires objects are allocated. Returns NGX_ERROR otherwise. */
static ngx_int_t ngx_http_brotli_filter_ensure_stream_initialized(
ngx_http_request_t* r, ngx_http_brotli_ctx_t* ctx);
/* Marks instance as closed and performs cleanup. */
static void ngx_http_brotli_filter_close(ngx_http_brotli_ctx_t* ctx);
static void* ngx_http_brotli_filter_alloc(void* opaque, size_t size);
static void ngx_http_brotli_filter_free(void* opaque, void* address);
static ngx_int_t ngx_http_brotli_check_request(ngx_http_request_t* r);
static ngx_int_t ngx_http_brotli_add_variables(ngx_conf_t* cf);
static ngx_int_t ngx_http_brotli_ratio_variable(ngx_http_request_t* r,
ngx_http_variable_value_t* v,
uintptr_t data);
static void* ngx_http_brotli_create_conf(ngx_conf_t* cf);
static char* ngx_http_brotli_merge_conf(ngx_conf_t* cf, void* parent,
void* child);
static ngx_int_t ngx_http_brotli_filter_init(ngx_conf_t* cf);
static char* ngx_http_brotli_parse_wbits(ngx_conf_t* cf, void* post,
void* data);
/* Configuration literals. */
static ngx_conf_num_bounds_t ngx_http_brotli_comp_level_bounds = {
ngx_conf_check_num_bounds, BROTLI_MIN_QUALITY, BROTLI_MAX_QUALITY};
static ngx_conf_post_handler_pt ngx_http_brotli_parse_wbits_p =
ngx_http_brotli_parse_wbits;
static ngx_command_t ngx_http_brotli_filter_commands[] = {
{ngx_string("brotli"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF |
NGX_HTTP_LIF_CONF | NGX_CONF_FLAG,
ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_brotli_conf_t, enable), NULL},
/* Deprecated, unused. */
{ngx_string("brotli_buffers"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF |
NGX_CONF_TAKE2,
ngx_conf_set_bufs_slot, NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_brotli_conf_t, deprecated_unused_bufs), NULL},
{ngx_string("brotli_types"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF |
NGX_CONF_1MORE,
ngx_http_types_slot, NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_brotli_conf_t, types_keys),
&ngx_http_html_default_types[0]},
{ngx_string("brotli_comp_level"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF |
NGX_CONF_TAKE1,
ngx_conf_set_num_slot, NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_brotli_conf_t, quality),
&ngx_http_brotli_comp_level_bounds},
{ngx_string("brotli_window"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF |
NGX_CONF_TAKE1,
ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_brotli_conf_t, lg_win), &ngx_http_brotli_parse_wbits_p},
{ngx_string("brotli_min_length"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF |
NGX_CONF_TAKE1,
ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_brotli_conf_t, min_length), NULL},
ngx_null_command};
/* Module context hooks. */
static ngx_http_module_t ngx_http_brotli_filter_module_ctx = {
ngx_http_brotli_add_variables, /* pre-configuration */
ngx_http_brotli_filter_init, /* post-configuration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_brotli_create_conf, /* create location configuration */
ngx_http_brotli_merge_conf /* merge location configuration */
};
/* Module descriptor. */
ngx_module_t ngx_http_brotli_filter_module = {
NGX_MODULE_V1,
&ngx_http_brotli_filter_module_ctx, /* module context */
ngx_http_brotli_filter_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING};
/* Variable names. */
static ngx_str_t ngx_http_brotli_ratio = ngx_string("brotli_ratio");
/* Next filter in the filter chain. */
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static /* const */ char kEncoding[] = "br";
static const size_t kEncodingLen = 2;
static ngx_int_t check_accept_encoding(ngx_http_request_t* req) {
ngx_table_elt_t* accept_encoding_entry;
ngx_str_t* accept_encoding;
u_char* cursor;
u_char* end;
u_char before;
u_char after;
accept_encoding_entry = req->headers_in.accept_encoding;
if (accept_encoding_entry == NULL) return NGX_DECLINED;
accept_encoding = &accept_encoding_entry->value;
cursor = accept_encoding->data;
end = cursor + accept_encoding->len;
while (1) {
u_char digit;
/* It would be an idiotic idea to rely on compiler to produce performant
binary, that is why we just do -1 at every call site. */
cursor = ngx_strcasestrn(cursor, kEncoding, kEncodingLen - 1);
if (cursor == NULL) return NGX_DECLINED;
before = (cursor == accept_encoding->data) ? ' ' : cursor[-1];
cursor += kEncodingLen;
after = (cursor >= end) ? ' ' : *cursor;
if (before != ',' && before != ' ') continue;
if (after != ',' && after != ' ' && after != ';') continue;
/* Check for ";q=0[.[0[0[0]]]]" */
while (*cursor == ' ') cursor++;
if (*(cursor++) != ';') break;
while (*cursor == ' ') cursor++;
if (*(cursor++) != 'q') break;
while (*cursor == ' ') cursor++;
if (*(cursor++) != '=') break;
while (*cursor == ' ') cursor++;
if (*(cursor++) != '0') break;
if (*(cursor++) != '.') return NGX_DECLINED; /* ;q=0, */
digit = *(cursor++);
if (digit < '0' || digit > '9') return NGX_DECLINED; /* ;q=0., */
if (digit > '0') break;
digit = *(cursor++);
if (digit < '0' || digit > '9') return NGX_DECLINED; /* ;q=0.0, */
if (digit > '0') break;
digit = *(cursor++);
if (digit < '0' || digit > '9') return NGX_DECLINED; /* ;q=0.00, */
if (digit > '0') break;
return NGX_DECLINED; /* ;q=0.000 */
}
return NGX_OK;
}
/* Process headers and decide if request is eligible for brotli compression. */
static ngx_int_t ngx_http_brotli_header_filter(ngx_http_request_t* r) {
ngx_table_elt_t* h;
ngx_http_brotli_ctx_t* ctx;
ngx_http_brotli_conf_t* conf;
conf = ngx_http_get_module_loc_conf(r, ngx_http_brotli_filter_module);
/* Filter only if enabled. */
if (!conf->enable) {
return ngx_http_next_header_filter(r);
}
/* Only compress OK / forbidden / not found responses. */
if (r->headers_out.status != NGX_HTTP_OK &&
r->headers_out.status != NGX_HTTP_FORBIDDEN &&
r->headers_out.status != NGX_HTTP_NOT_FOUND) {
return ngx_http_next_header_filter(r);
}
/* Bypass "header only" responses. */
if (r->header_only) {
return ngx_http_next_header_filter(r);
}
/* Bypass already compressed responses. */
if (r->headers_out.content_encoding &&
r->headers_out.content_encoding->value.len) {
return ngx_http_next_header_filter(r);
}
/* If response size is known, do not compress tiny responses. */
if (r->headers_out.content_length_n != -1 &&
r->headers_out.content_length_n < conf->min_length) {
return ngx_http_next_header_filter(r);
}
/* Compress only certain MIME-typed responses. */
if (ngx_http_test_content_type(r, &conf->types) == NULL) {
return ngx_http_next_header_filter(r);
}
r->gzip_vary = 1;
/* Check if client support brotli encoding. */
if (ngx_http_brotli_check_request(r) != NGX_OK) {
return ngx_http_next_header_filter(r);
}
/* Prepare instance context. */
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_brotli_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
}
ctx->request = r;
ctx->content_length = r->headers_out.content_length_n;
ngx_http_set_ctx(r, ctx, ngx_http_brotli_filter_module);
/* Prepare response headers, so that following filters in the chain will
notice that response body is compressed. */
h = ngx_list_push(&r->headers_out.headers);
if (h == NULL) {
return NGX_ERROR;
}
h->hash = 1;
ngx_str_set(&h->key, "Content-Encoding");
ngx_str_set(&h->value, "br");
r->headers_out.content_encoding = h;
r->main_filter_need_in_memory = 1;
ngx_http_clear_content_length(r);
ngx_http_clear_accept_ranges(r);
ngx_http_weak_etag(r);
return ngx_http_next_header_filter(r);
}
/* Response body filtration (compression). */
static ngx_int_t ngx_http_brotli_body_filter(ngx_http_request_t* r,
ngx_chain_t* in) {
int rc;
ngx_http_brotli_ctx_t* ctx;
size_t available_output;
ptrdiff_t available_busy_output;
size_t input_size;
size_t available_input;
const uint8_t* next_input_byte;
size_t consumed_input;
BROTLI_BOOL ok;
u_char* out;
ngx_chain_t* link;
ctx = ngx_http_get_module_ctx(r, ngx_http_brotli_filter_module);
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http brotli filter");
if (ctx == NULL || ctx->closed || r->header_only) {
return ngx_http_next_body_filter(r, in);
}
if (ngx_http_brotli_filter_ensure_stream_initialized(r, ctx) != NGX_OK) {
ngx_http_brotli_filter_close(ctx);
return NGX_ERROR;
}
/* If more input is provided - append it to our input chain. */
if (in) {
if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
ngx_http_brotli_filter_close(ctx);
return NGX_ERROR;
}
r->connection->buffered |= NGX_HTTP_BROTLI_BUFFERED;
}
/* Main loop:
- if output is not yet consumed - stop; encoder should not be touched,
until all the output is consumed
- if encoder has output - wrap it and send to consumer
- if encoder is finished (and all output is consumed) - stop
- if there is more input - push it to encoder */
for (;;) {
if (ctx->output_busy || ctx->output_ready) {
if (ctx->output_busy) {
available_busy_output = ngx_buf_size(ctx->out_buf);
} else {
available_busy_output = 0;
}
rc = ngx_http_next_body_filter(r,
ctx->output_ready ? ctx->out_chain : NULL);
if (ctx->output_ready) {
ctx->output_ready = 0;
ctx->output_busy = 1;
}
if (ngx_buf_size(ctx->out_buf) == 0) {
ctx->output_busy = 0;
}
if (rc == NGX_OK) {
if (ctx->output_busy &&
available_busy_output == ngx_buf_size(ctx->out_buf)) {
r->connection->buffered |= NGX_HTTP_BROTLI_BUFFERED;
return NGX_AGAIN;
}
continue;
} else if (rc == NGX_AGAIN) {
if (ctx->output_busy) {
/* Can't continue compression, let the outer filer decide. */
if (ctx->in != NULL) {
r->connection->buffered |= NGX_HTTP_BROTLI_BUFFERED;
}
return NGX_AGAIN;
} else {
/* Inner filter has given up, but we can continue processing. */
continue;
}
} else {
ngx_http_brotli_filter_close(ctx);
return NGX_ERROR;
}
}
if (BrotliEncoderHasMoreOutput(ctx->encoder)) {
available_output = 0;
out = (u_char*)BrotliEncoderTakeOutput(ctx->encoder, &available_output);
if (out == NULL || available_output == 0) {
ngx_http_brotli_filter_close(ctx);
return NGX_ERROR;
}
ctx->out_buf->start = out;
ctx->out_buf->pos = out;
ctx->out_buf->last = out + available_output;
ctx->out_buf->end = out + available_output;
ctx->bytes_out += available_output;
ctx->out_buf->last_buf = 0;
ctx->out_buf->flush = 0;
if (ctx->end_of_input && BrotliEncoderIsFinished(ctx->encoder)) {
ctx->out_buf->last_buf = 1;
r->connection->buffered &= ~NGX_HTTP_BROTLI_BUFFERED;
} else if (ctx->end_of_block) {
ctx->out_buf->flush = 1;
r->connection->buffered &= ~NGX_HTTP_BROTLI_BUFFERED;
}
ctx->end_of_block = 0;
ctx->output_ready = 1;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"brotli out: %p, size:%uz", ctx->out_buf,
ngx_buf_size(ctx->out_buf));
continue;
}
if (BrotliEncoderIsFinished(ctx->encoder)) {
ctx->success = 1;
r->connection->buffered &= ~NGX_HTTP_BROTLI_BUFFERED;
ngx_http_brotli_filter_close(ctx);
return NGX_OK;
}
if (ctx->end_of_input) {
// Ask the encoder to dump the leftover.
available_input = 0;
available_output = 0;
ok = BrotliEncoderCompressStream(ctx->encoder, BROTLI_OPERATION_FINISH,
&available_input, NULL,
&available_output, NULL, NULL);
r->connection->buffered |= NGX_HTTP_BROTLI_BUFFERED;
if (!ok) {
ngx_http_brotli_filter_close(ctx);
return NGX_ERROR;
}
continue;
}
if (ctx->in == NULL) {
return NGX_OK;
}
/* TODO: coalesce tiny inputs, if they are not last/flush. */
input_size = ngx_buf_size(ctx->in->buf);
if (input_size == 0) {
if (!ctx->in->buf->last_buf && !ctx->in->buf->flush) {
link = ctx->in;
ctx->in = ctx->in->next;
ngx_free_chain(r->pool, link);
continue;
}
}
available_input = input_size;
next_input_byte = (const uint8_t*)ctx->in->buf->pos;
available_output = 0;
ok = BrotliEncoderCompressStream(
ctx->encoder,
ctx->in->buf->last_buf ? BROTLI_OPERATION_FINISH
: ctx->in->buf->flush ? BROTLI_OPERATION_FLUSH
: BROTLI_OPERATION_PROCESS,
&available_input, &next_input_byte, &available_output, NULL, NULL);
r->connection->buffered |= NGX_HTTP_BROTLI_BUFFERED;
if (!ok) {
ngx_http_brotli_filter_close(ctx);
return NGX_ERROR;
}
consumed_input = input_size - available_input;
ctx->bytes_in += consumed_input;
ctx->in->buf->pos += consumed_input;
if (consumed_input == input_size) {
if (ctx->in->buf->last_buf) {
ctx->end_of_input = 1;
} else if (ctx->in->buf->flush) {
ctx->end_of_block = 1;
}
link = ctx->in;
ctx->in = ctx->in->next;
ngx_free_chain(r->pool, link);
continue;
}
/* Should never happen, just to make sure we don't enter infinite loop. */
if (consumed_input == 0) {
ngx_http_brotli_filter_close(ctx);
return NGX_ERROR;
}
}
/* unreachable */
ngx_http_brotli_filter_close(ctx);
return NGX_ERROR;
}
static ngx_int_t ngx_http_brotli_filter_ensure_stream_initialized(
ngx_http_request_t* r, ngx_http_brotli_ctx_t* ctx) {
ngx_http_brotli_conf_t* conf;
BROTLI_BOOL ok;
size_t wbits;
if (ctx->initialized) {
return NGX_OK;
}
ctx->initialized = 1;
conf = ngx_http_get_module_loc_conf(r, ngx_http_brotli_filter_module);
/* Tune lg_win, if size is known. */
if (ctx->content_length > 0) {
wbits = BROTLI_MIN_WINDOW_BITS;
while ((wbits < conf->lg_win) && (ctx->content_length > (1 << wbits))) {
wbits++;
}
} else {
wbits = conf->lg_win;
}
ctx->encoder = BrotliEncoderCreateInstance(
ngx_http_brotli_filter_alloc, ngx_http_brotli_filter_free, r->pool);
if (ctx->encoder == NULL) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"OOM / BrotliEncoderCreateInstance");
return NGX_ERROR;
}
ok = BrotliEncoderSetParameter(ctx->encoder, BROTLI_PARAM_QUALITY,
(uint32_t)conf->quality);
if (!ok) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"BrotliEncoderSetParameter(QUALITY, %uD) failed",
(uint32_t)conf->quality);
return NGX_ERROR;
}
ok = BrotliEncoderSetParameter(ctx->encoder, BROTLI_PARAM_LGWIN,
(uint32_t)wbits);
if (!ok) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"BrotliEncoderSetParameter(LGWIN, %uD) failed",
(uint32_t)wbits);
return NGX_ERROR;
}
ctx->out_buf = ngx_calloc_buf(r->pool);
if (ctx->out_buf == NULL) {
return NGX_ERROR;
}
ctx->out_buf->temporary = 1;
ctx->out_chain = ngx_alloc_chain_link(r->pool);
if (ctx->out_chain == NULL) {
return NGX_ERROR;
}
ctx->out_chain->buf = ctx->out_buf;
ctx->out_chain->next = NULL;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"brotli encoder initialized: lvl:%i win:%d", conf->quality,
(1 << wbits));
return NGX_OK;
}
static void* ngx_http_brotli_filter_alloc(void* opaque, size_t size) {
ngx_pool_t* pool = opaque;
void* p;
p = ngx_palloc(pool, size);
#if (NGX_DEBUG)
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pool->log, 0, "brotli alloc: %p, size:%uz",
p, size);
#endif
return p;
}
static void ngx_http_brotli_filter_free(void* opaque, void* address) {
ngx_pool_t* pool = opaque;
#if (NGX_DEBUG)
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0, "brotli free: %p", address);
#endif
ngx_pfree(pool, address);
}
static void ngx_http_brotli_filter_close(ngx_http_brotli_ctx_t* ctx) {
ctx->closed = 1;
if (ctx->encoder) {
BrotliEncoderDestroyInstance(ctx->encoder);
ctx->encoder = NULL;
}
if (ctx->out_chain) {
ngx_free_chain(ctx->request->pool, ctx->out_chain);
ctx->out_chain = NULL;
}
if (ctx->out_buf) {
ngx_pfree(ctx->request->pool, ctx->out_buf);
ctx->out_buf = NULL;
}
}
static ngx_int_t ngx_http_brotli_check_request(ngx_http_request_t* req) {
if (req != req->main) return NGX_DECLINED;
if (check_accept_encoding(req) != NGX_OK) return NGX_DECLINED;
req->gzip_tested = 1;
req->gzip_ok = 0;
return NGX_OK;
}
static ngx_int_t ngx_http_brotli_add_variables(ngx_conf_t* cf) {
ngx_http_variable_t* var;
var = ngx_http_add_variable(cf, &ngx_http_brotli_ratio, 0);
if (var == NULL) {
return NGX_ERROR;
}
var->get_handler = ngx_http_brotli_ratio_variable;
return NGX_OK;
}
static ngx_int_t ngx_http_brotli_ratio_variable(ngx_http_request_t* r,
ngx_http_variable_value_t* v,
uintptr_t data) {
ngx_uint_t ratio_int;
ngx_uint_t ratio_frac;
ngx_http_brotli_ctx_t* ctx;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
ctx = ngx_http_get_module_ctx(r, ngx_http_brotli_filter_module);
/* Only report variable on non-failing streams. */
if (ctx == NULL || !ctx->success) {
v->not_found = 1;
return NGX_OK;
}
v->data = ngx_pnalloc(r->pool, NGX_INT32_LEN + 3);
if (v->data == NULL) {
return NGX_ERROR;
}
ratio_int = (ngx_uint_t)(ctx->bytes_in / ctx->bytes_out);
ratio_frac = (ngx_uint_t)((ctx->bytes_in * 100 / ctx->bytes_out) % 100);
/* Rounding; e.g. 2.125 to 2.13 */
if ((ctx->bytes_in * 1000 / ctx->bytes_out) % 10 > 4) {
ratio_frac++;
if (ratio_frac > 99) {
ratio_int++;
ratio_frac = 0;
}
}
v->len = ngx_sprintf(v->data, "%ui.%02ui", ratio_int, ratio_frac) - v->data;
return NGX_OK;
}
static void* ngx_http_brotli_create_conf(ngx_conf_t* cf) {
ngx_http_brotli_conf_t* conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_brotli_conf_t));
if (conf == NULL) {
return NULL;
}
/* ngx_pcalloc fills result with zeros ->
conf->bufs.num = 0;
conf->types = { NULL };
conf->types_keys = NULL; */
conf->enable = NGX_CONF_UNSET;
conf->quality = NGX_CONF_UNSET;
conf->lg_win = NGX_CONF_UNSET_SIZE;
conf->min_length = NGX_CONF_UNSET;
return conf;
}
static char* ngx_http_brotli_merge_conf(ngx_conf_t* cf, void* parent,
void* child) {
ngx_http_brotli_conf_t* prev = parent;
ngx_http_brotli_conf_t* conf = child;
char* rc;
ngx_conf_merge_value(conf->enable, prev->enable, 0);
ngx_conf_merge_value(conf->quality, prev->quality, 6);
ngx_conf_merge_size_value(conf->lg_win, prev->lg_win, 19);
ngx_conf_merge_value(conf->min_length, prev->min_length, 20);
rc = ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
&prev->types_keys, &prev->types,
ngx_http_html_default_types);
if (rc != NGX_CONF_OK) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
/* Prepend to filter chain. */
static ngx_int_t ngx_http_brotli_filter_init(ngx_conf_t* cf) {
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_brotli_header_filter;
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_brotli_body_filter;
return NGX_OK;
}
/* Translate "window size" to window bits (log2), and check bounds. */
static char* ngx_http_brotli_parse_wbits(ngx_conf_t* cf, void* post,
void* data) {
size_t* parameter = data;
size_t bits;
size_t wsize;
for (bits = BROTLI_MIN_WINDOW_BITS; bits <= BROTLI_MAX_WINDOW_BITS; bits++) {
wsize = 1u << bits;
if (*parameter == wsize) {
*parameter = bits;
return NGX_CONF_OK;
}
}
return "must be 1k, 2k, 4k, 8k, 16k, 32k, 64k, 128k, 256k, 512k, 1m, 2m, 4m, "
"8m or 16m";
}

View file

@ -1,24 +0,0 @@
#!/bin/bash
set -ex
# Setup shortcuts.
ROOT=`pwd`
FILES=$ROOT/script/test
# Setup directory structure.
cd $ROOT/script
if [ ! -d test ]; then
mkdir test
fi
cd test
if [ ! -d logs ]; then
mkdir logs
fi
# Download sample texts.
curl --compressed -o $FILES/war-and-peace.txt http://www.gutenberg.org/files/2600/2600-0.txt
echo "Kot lomom kolol slona!" > $FILES/small.txt
echo "<html>Kot lomom kolol slona!</html>" > $FILES/small.html
# Restore status-quo.
cd $ROOT

View file

@ -1,29 +0,0 @@
#!/bin/bash
set -ex
# Setup shortcuts.
ROOT=`pwd`
# Clone nginx read-only git repository.
if [ ! -d "nginx" ]; then
git clone https://github.com/nginx/nginx.git
fi
# Build nginx + filter module.
cd $ROOT/nginx
# Pro memoria: --with-debug
./auto/configure \
--prefix=$ROOT/script/test \
--with-http_v2_module \
--add-module=$ROOT
make -j 16
# Build brotli CLI.
cd $ROOT/deps/brotli
mkdir out
cd out
cmake ..
make -j 16 brotli
# Restore status-quo.
cd $ROOT

View file

@ -1,168 +0,0 @@
#!/bin/bash
# Setup shortcuts.
ROOT=`pwd`
NGINX=$ROOT/nginx/objs/nginx
BROTLI=$ROOT/deps/brotli/out/brotli
SERVER=http://localhost:8080
FILES=$ROOT/script/test
HR="---------------------------------------------------------------------------"
if [ ! -d tmp ]; then
mkdir tmp
fi
rm tmp/*
add_result() {
echo $1 >&2
echo $1 >> tmp/results.log
}
get_failed() {
echo `cat tmp/results.log | grep -v OK | wc -l`
}
get_count() {
echo `cat tmp/results.log | wc -l`
}
expect_equal() {
expected=$1
actual=$2
if cmp $expected $actual; then
add_result "OK"
else
add_result "FAIL (equality)"
fi
}
expect_br_equal() {
expected=$1
actual_br=$2
if $BROTLI -dfk ./${actual_br}.br; then
expect_equal $expected $actual_br
else
add_result "FAIL (decompression)"
fi
}
################################################################################
# Start default server.
echo "Statring NGINX"
$NGINX -c $ROOT/script/test.conf
# Fetch vanilla 404 response.
curl -s -o tmp/notfound.txt $SERVER/notfound
CURL="curl -s"
# Run tests.
echo $HR
echo "Test: long file with rate limit"
$CURL -H 'Accept-encoding: br' -o tmp/war-and-peace.br --limit-rate 300K $SERVER/war-and-peace.txt
expect_br_equal $FILES/war-and-peace.txt tmp/war-and-peace
echo "Test: compressed 404"
$CURL -H 'Accept-encoding: br' -o tmp/notfound.br $SERVER/notfound
expect_br_equal tmp/notfound.txt tmp/notfound
echo "Test: A-E: 'gzip, br'"
$CURL -H 'Accept-encoding: gzip, br' -o tmp/ae-01.br $SERVER/small.txt
expect_br_equal $FILES/small.txt tmp/ae-01
echo "Test: A-E: 'gzip, br, deflate'"
$CURL -H 'Accept-encoding: gzip, br, deflate' -o tmp/ae-02.br $SERVER/small.txt
expect_br_equal $FILES/small.txt tmp/ae-02
echo "Test: A-E: 'gzip, br;q=1, deflate'"
$CURL -H 'Accept-encoding: gzip, br;q=1, deflate' -o tmp/ae-03.br $SERVER/small.txt
expect_br_equal $FILES/small.txt tmp/ae-03
echo "Test: A-E: 'br;q=0.001'"
$CURL -H 'Accept-encoding: br;q=0.001' -o tmp/ae-04.br $SERVER/small.txt
expect_br_equal $FILES/small.txt tmp/ae-04
echo "Test: A-E: 'bro'"
$CURL -H 'Accept-encoding: bro' -o tmp/ae-05.txt $SERVER/small.txt
expect_equal $FILES/small.txt tmp/ae-05.txt
echo "Test: A-E: 'bo'"
$CURL -H 'Accept-encoding: bo' -o tmp/ae-06.txt $SERVER/small.txt
expect_equal $FILES/small.txt tmp/ae-06.txt
echo "Test: A-E: 'br;q=0'"
$CURL -H 'Accept-encoding: br;q=0' -o tmp/ae-07.txt $SERVER/small.txt
expect_equal $FILES/small.txt tmp/ae-07.txt
echo "Test: A-E: 'br;q=0.'"
$CURL -H 'Accept-encoding: br;q=0.' -o tmp/ae-08.txt $SERVER/small.txt
expect_equal $FILES/small.txt tmp/ae-08.txt
echo "Test: A-E: 'br;q=0.0'"
$CURL -H 'Accept-encoding: br;q=0.0' -o tmp/ae-09.txt $SERVER/small.txt
expect_equal $FILES/small.txt tmp/ae-09.txt
echo "Test: A-E: 'br;q=0.00'"
$CURL -H 'Accept-encoding: br;q=0.00' -o tmp/ae-10.txt $SERVER/small.txt
expect_equal $FILES/small.txt tmp/ae-10.txt
echo "Test: A-E: 'br ; q = 0.000'"
$CURL -H 'Accept-encoding: br ; q = 0.000' -o tmp/ae-11.txt $SERVER/small.txt
expect_equal $FILES/small.txt tmp/ae-11.txt
echo "Test: A-E: 'bar'"
$CURL -H 'Accept-encoding: bar' -o tmp/ae-12.txt $SERVER/small.html
expect_equal $FILES/small.html tmp/ae-12.txt
echo "Test: A-E: 'b'"
$CURL -H 'Accept-encoding: b' -o tmp/ae-13.txt $SERVER/small.html
expect_equal $FILES/small.html tmp/ae-13.txt
echo $HR
echo "Stopping default NGINX"
# Stop server.
$NGINX -c $ROOT/script/test.conf -s stop
################################################################################
# Start default server.
echo "Statring h2 NGINX"
$NGINX -c $ROOT/script/test_h2.conf
CURL="curl --http2-prior-knowledge -s"
# Run tests.
echo $HR
echo "Test: long file with rate limit"
$CURL -H 'Accept-encoding: br' -o tmp/h2-war-and-peace.br --limit-rate 300K $SERVER/war-and-peace.txt
expect_br_equal $FILES/war-and-peace.txt tmp/h2-war-and-peace
echo "Test: A-E: 'gzip, br'"
$CURL -H 'Accept-encoding: gzip, br' -o tmp/h2-ae-01.br $SERVER/small.txt
expect_br_equal $FILES/small.txt tmp/h2-ae-01
echo "Test: A-E: 'b'"
$CURL -H 'Accept-encoding: b' -o tmp/h2-ae-13.txt $SERVER/small.html
expect_equal $FILES/small.html tmp/h2-ae-13.txt
echo $HR
echo "Stopping h2 NGINX"
# Stop server.
$NGINX -c $ROOT/script/test_h2.conf -s stop
################################################################################
# Report.
FAILED=$(get_failed $STATUS)
COUNT=$(get_count $STATUS)
echo $HR
echo "Results: $FAILED of $COUNT tests failed"
# Restore status-quo.
cd $ROOT
exit $FAILED

View file

@ -1,32 +0,0 @@
events {
worker_connections 4;
}
daemon on;
error_log /dev/stdout info;
http {
access_log ./access.log;
error_log ./error.log;
gzip on;
gzip_comp_level 1;
gzip_types text/plain text/css;
brotli on;
brotli_comp_level 1;
brotli_types text/plain text/css;
server {
listen 8080 default_server;
listen [::]:8080 default_server;
root ./;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
}

View file

@ -1,32 +0,0 @@
events {
worker_connections 4;
}
daemon on;
error_log /dev/stdout info;
http {
access_log ./access.log;
error_log ./error.log;
gzip on;
gzip_comp_level 1;
gzip_types text/plain text/css;
brotli on;
brotli_comp_level 1;
brotli_types text/plain text/css;
server {
listen 8080 http2;
listen [::]:8080 http2;
root ./;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
}

View file

@ -1,54 +0,0 @@
# Copyright (C) 2015-2019 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
if [ "$ngx_addon_name" = "ngx_brotli" ]; then
BROTLI_MODULE_SRC_DIR="$ngx_addon_dir/static"
else
BROTLI_MODULE_SRC_DIR="$ngx_addon_dir"
fi
ngx_addon_name=ngx_brotli_static
if [ -z "$ngx_module_link" ]; then
cat << END
$0: error: Brotli module requires recent version of NGINX (1.9.11+).
END
exit 1
fi
ngx_module_type=HTTP
ngx_module_name=ngx_http_brotli_static_module
ngx_module_incs=
ngx_module_deps=
ngx_module_srcs="$BROTLI_MODULE_SRC_DIR/ngx_http_brotli_static_module.c"
ngx_module_libs=
ngx_module_order=
. auto/module
have=NGX_HTTP_GZIP . auto/have
have=NGX_HTTP_BROTLI_STATIC . auto/have
have=NGX_HTTP_BROTLI_STATIC_MODULE . auto/have # deprecated

View file

@ -1,323 +0,0 @@
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
* Copyright (C) Google Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
/* >> Configuration */
#define NGX_HTTP_BROTLI_STATIC_OFF 0
#define NGX_HTTP_BROTLI_STATIC_ON 1
#define NGX_HTTP_BROTLI_STATIC_ALWAYS 2
typedef struct {
ngx_uint_t enable;
} configuration_t;
static ngx_conf_enum_t kBrotliStaticEnum[] = {
{ngx_string("off"), NGX_HTTP_BROTLI_STATIC_OFF},
{ngx_string("on"), NGX_HTTP_BROTLI_STATIC_ON},
{ngx_string("always"), NGX_HTTP_BROTLI_STATIC_ALWAYS},
{ngx_null_string, 0}};
/* << Configuration */
/* >> Forward declarations */
static ngx_int_t handler(ngx_http_request_t* req);
static void* create_conf(ngx_conf_t* root_cfg);
static char* merge_conf(ngx_conf_t* root_cfg, void* parent, void* child);
static ngx_int_t init(ngx_conf_t* root_cfg);
/* << Forward declarations*/
/* >> Module definition */
static ngx_command_t kCommands[] = {
{ngx_string("brotli_static"),
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(configuration_t, enable), &kBrotliStaticEnum},
ngx_null_command};
static ngx_http_module_t kModuleContext = {
NULL, /* preconfiguration */
init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
create_conf, /* create location configuration */
merge_conf /* merge location configuration */
};
ngx_module_t ngx_http_brotli_static_module = {
NGX_MODULE_V1,
&kModuleContext, /* module context */
kCommands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING};
/* << Module definition*/
static const u_char kContentEncoding[] = "Content-Encoding";
static /* const */ char kEncoding[] = "br";
static const size_t kEncodingLen = 2;
static /* const */ u_char kSuffix[] = ".br";
static const size_t kSuffixLen = 3;
static ngx_int_t check_accept_encoding(ngx_http_request_t* req) {
ngx_table_elt_t* accept_encoding_entry;
ngx_str_t* accept_encoding;
u_char* cursor;
u_char* end;
u_char before;
u_char after;
accept_encoding_entry = req->headers_in.accept_encoding;
if (accept_encoding_entry == NULL) return NGX_DECLINED;
accept_encoding = &accept_encoding_entry->value;
cursor = accept_encoding->data;
end = cursor + accept_encoding->len;
while (1) {
u_char digit;
/* It would be an idiotic idea to rely on compiler to produce performant
binary, that is why we just do -1 at every call site. */
cursor = ngx_strcasestrn(cursor, kEncoding, kEncodingLen - 1);
if (cursor == NULL) return NGX_DECLINED;
before = (cursor == accept_encoding->data) ? ' ' : cursor[-1];
cursor += kEncodingLen;
after = (cursor >= end) ? ' ' : *cursor;
if (before != ',' && before != ' ') continue;
if (after != ',' && after != ' ' && after != ';') continue;
/* Check for ";q=0[.[0[0[0]]]]" */
while (*cursor == ' ') cursor++;
if (*(cursor++) != ';') break;
while (*cursor == ' ') cursor++;
if (*(cursor++) != 'q') break;
while (*cursor == ' ') cursor++;
if (*(cursor++) != '=') break;
while (*cursor == ' ') cursor++;
if (*(cursor++) != '0') break;
if (*(cursor++) != '.') return NGX_DECLINED; /* ;q=0, */
digit = *(cursor++);
if (digit < '0' || digit > '9') return NGX_DECLINED; /* ;q=0., */
if (digit > '0') break;
digit = *(cursor++);
if (digit < '0' || digit > '9') return NGX_DECLINED; /* ;q=0.0, */
if (digit > '0') break;
digit = *(cursor++);
if (digit < '0' || digit > '9') return NGX_DECLINED; /* ;q=0.00, */
if (digit > '0') break;
return NGX_DECLINED; /* ;q=0.000 */
}
return NGX_OK;
}
/* Test if this request is allowed to have the brotli response. */
static ngx_int_t check_eligility(ngx_http_request_t* req) {
if (req != req->main) return NGX_DECLINED;
if (check_accept_encoding(req) != NGX_OK) return NGX_DECLINED;
req->gzip_tested = 1;
req->gzip_ok = 0;
return NGX_OK;
}
static ngx_int_t handler(ngx_http_request_t* req) {
configuration_t* cfg;
ngx_int_t rc;
u_char* last;
ngx_str_t path;
size_t root;
ngx_log_t* log;
ngx_http_core_loc_conf_t* location_cfg;
ngx_open_file_info_t file_info;
ngx_table_elt_t* content_encoding_entry;
ngx_buf_t* buf;
ngx_chain_t out;
/* Only GET and HEAD requensts are supported. */
if (!(req->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))) return NGX_DECLINED;
/* Only files are supported. */
if (req->uri.data[req->uri.len - 1] == '/') return NGX_DECLINED;
/* Get configuration and check if module is disabled. */
cfg = ngx_http_get_module_loc_conf(req, ngx_http_brotli_static_module);
if (cfg->enable == NGX_HTTP_BROTLI_STATIC_OFF) return NGX_DECLINED;
if (cfg->enable == NGX_HTTP_BROTLI_STATIC_ALWAYS) {
/* Ignore request properties (e.g. Accept-Encoding). */
} else {
/* NGX_HTTP_BROTLI_STATIC_ON */
rc = check_eligility(req);
if (rc != NGX_OK) return NGX_DECLINED;
}
/* Get path and append the suffix. */
last = ngx_http_map_uri_to_path(req, &path, &root, kSuffixLen);
if (last == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR;
/* +1 for reinstating the terminating 0. */
ngx_cpystrn(last, kSuffix, kSuffixLen + 1);
path.len += kSuffixLen;
log = req->connection->log;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"",
path.data);
/* Prepare to read the file. */
location_cfg = ngx_http_get_module_loc_conf(req, ngx_http_core_module);
ngx_memzero(&file_info, sizeof(ngx_open_file_info_t));
file_info.read_ahead = location_cfg->read_ahead;
file_info.directio = location_cfg->directio;
file_info.valid = location_cfg->open_file_cache_valid;
file_info.min_uses = location_cfg->open_file_cache_min_uses;
file_info.errors = location_cfg->open_file_cache_errors;
file_info.events = location_cfg->open_file_cache_events;
rc = ngx_http_set_disable_symlinks(req, location_cfg, &path, &file_info);
if (rc != NGX_OK) return NGX_HTTP_INTERNAL_SERVER_ERROR;
/* Try to fetch file and process errors. */
rc = ngx_open_cached_file(location_cfg->open_file_cache, &path, &file_info,
req->pool);
if (rc != NGX_OK) {
ngx_uint_t level;
switch (file_info.err) {
case 0:
return NGX_HTTP_INTERNAL_SERVER_ERROR;
case NGX_ENOENT:
case NGX_ENOTDIR:
case NGX_ENAMETOOLONG:
return NGX_DECLINED;
#if (NGX_HAVE_OPENAT)
case NGX_EMLINK:
case NGX_ELOOP:
#endif
case NGX_EACCES:
level = NGX_LOG_ERR;
break;
default:
level = NGX_LOG_CRIT;
break;
}
ngx_log_error(level, log, file_info.err, "%s \"%s\" failed",
file_info.failed, path.data);
return NGX_DECLINED;
}
if (cfg->enable == NGX_HTTP_BROTLI_STATIC_ON) {
req->gzip_vary = 1;
}
/* So far so good. */
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d",
file_info.fd);
/* Only files are supported. */
if (file_info.is_dir) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");
return NGX_DECLINED;
}
#if !(NGX_WIN32)
if (!file_info.is_file) {
ngx_log_error(NGX_LOG_CRIT, log, 0, "\"%s\" is not a regular file",
path.data);
return NGX_HTTP_NOT_FOUND;
}
#endif
/* Prepare request push the body. */
req->root_tested = !req->error_page;
rc = ngx_http_discard_request_body(req);
if (rc != NGX_OK) return rc;
log->action = "sending response to client";
req->headers_out.status = NGX_HTTP_OK;
req->headers_out.content_length_n = file_info.size;
req->headers_out.last_modified_time = file_info.mtime;
rc = ngx_http_set_etag(req);
if (rc != NGX_OK) return NGX_HTTP_INTERNAL_SERVER_ERROR;
rc = ngx_http_set_content_type(req);
if (rc != NGX_OK) return NGX_HTTP_INTERNAL_SERVER_ERROR;
/* Set "Content-Encoding" header. */
content_encoding_entry = ngx_list_push(&req->headers_out.headers);
if (content_encoding_entry == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR;
content_encoding_entry->hash = 1;
ngx_str_set(&content_encoding_entry->key, kContentEncoding);
ngx_str_set(&content_encoding_entry->value, kEncoding);
req->headers_out.content_encoding = content_encoding_entry;
/* Setup response body. */
buf = ngx_pcalloc(req->pool, sizeof(ngx_buf_t));
if (buf == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR;
buf->file = ngx_pcalloc(req->pool, sizeof(ngx_file_t));
if (buf->file == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR;
buf->file_pos = 0;
buf->file_last = file_info.size;
buf->in_file = buf->file_last ? 1 : 0;
buf->last_buf = (req == req->main) ? 1 : 0;
buf->last_in_chain = 1;
buf->file->fd = file_info.fd;
buf->file->name = path;
buf->file->log = log;
buf->file->directio = file_info.is_directio;
out.buf = buf;
out.next = NULL;
/* Push the response header. */
rc = ngx_http_send_header(req);
if (rc == NGX_ERROR || rc > NGX_OK || req->header_only) {
return rc;
}
/* Push the response body. */
return ngx_http_output_filter(req, &out);
}
static void* create_conf(ngx_conf_t* root_cfg) {
configuration_t* cfg;
cfg = ngx_palloc(root_cfg->pool, sizeof(configuration_t));
if (cfg == NULL) return NULL;
cfg->enable = NGX_CONF_UNSET_UINT;
return cfg;
}
static char* merge_conf(ngx_conf_t* root_cfg, void* parent, void* child) {
configuration_t* prev = parent;
configuration_t* cfg = child;
ngx_conf_merge_uint_value(cfg->enable, prev->enable,
NGX_HTTP_BROTLI_STATIC_OFF);
return NGX_CONF_OK;
}
static ngx_int_t init(ngx_conf_t* root_cfg) {
ngx_http_core_main_conf_t* core_cfg;
ngx_http_handler_pt* handler_slot;
core_cfg = ngx_http_conf_get_module_main_conf(root_cfg, ngx_http_core_module);
handler_slot =
ngx_array_push(&core_cfg->phases[NGX_HTTP_CONTENT_PHASE].handlers);
if (handler_slot == NULL) return NGX_ERROR;
*handler_slot = handler;
return NGX_OK;
}

View file

@ -1,22 +0,0 @@
# astylerc
align-pointer=name
align-reference=name
break-after-logical
#indent=spaces=2
max-code-length=120
style=google
suffix=none
# Indent
indent-preproc-block
# Padding
pad-header
unpad-paren
# Formatting:
add-brackets
#convert-tabs
# Output:
formatted

View file

@ -1,14 +0,0 @@
#!/bin/sh
# Search in the script folder
pushd "$(dirname $0)" >/dev/null
CWD="$(pwd -P)"
popd >/dev/null
FILES='ngx_cache_purge_module.c'
# The file format in accordance with the style defined in .astylerc
astyle -v --options='.astylerc' ${FILES} || (echo 'astyle failed'; exit 1);
# To correct this, the issuance dos2unix on each file
# sometimes adds in Windows as a string-endins (\r\n).
dos2unix --quiet ${FILES} || (echo 'dos2unix failed'; exit 2);

View file

@ -1 +0,0 @@
*.t linguist-language=Text

View file

@ -1,49 +0,0 @@
sudo: required
os: linux
dist: trusty
language: c
compiler:
- gcc
- clang
cache:
apt: true
directories:
- download-cache
env:
global:
- JOBS=4
- NGINX_PREFIX=/opt/nginx
matrix:
- NGINX_VERSION=1.18.0
- NGINX_VERSION=1.19.2
before_install:
- mkdir --parents download-cache
- sudo apt-get update -qq
- sudo apt-get install -qq zlib1g-dev libpcre3-dev cpanminus
# Get OpenSSL 1.0.2 from Ubuntu Xenial
# https://packages.ubuntu.com/xenial-updates/libssl1.0.0
- test -f download-cache/libssl1.0.0_1.0.2g-1ubuntu4.16_amd64.deb || wget -O download-cache/libssl1.0.0_1.0.2g-1ubuntu4.17_amd64.deb "http://de.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.0.0_1.0.2g-1ubuntu4.17_amd64.deb"
# https://packages.ubuntu.com/xenial/libssl-dev
- test -f download-cache/libssl-dev_1.0.2g-1ubuntu4.16_amd64.deb || wget -O download-cache/libssl-dev_1.0.2g-1ubuntu4.17_amd64.deb "http://de.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl-dev_1.0.2g-1ubuntu4.17_amd64.deb"
- sudo dpkg -i download-cache/libssl*_amd64.deb
# Test::Nginx
- git clone https://github.com/openresty/test-nginx.git test-nginx
- cd test-nginx/ && sudo cpanm . && cd ..
# NGINX source
- test -f download-cache/nginx-$NGINX_VERSION.tar.gz || wget -O download-cache/nginx-$NGINX_VERSION.tar.gz http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz
install:
- tar -xzf download-cache/nginx-${NGINX_VERSION}.tar.gz
- cd nginx-${NGINX_VERSION}/
- ./configure --prefix=${NGINX_PREFIX} --with-debug --with-http_ssl_module --add-module=${PWD}/..
- make -j${JOBS}
- sudo make install
- cd ..
- export PATH="${NGINX_PREFIX}/sbin:$PATH"
# - export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}
script:
- nginx -V
- ldd $(which nginx)
- prove t

View file

@ -1,103 +0,0 @@
2020-06-27 VERSION 2.5.1
* fix: empty key check - it coredumps when cache key is empty, Tuğrul Topuz
* fix: purge report calloc fix - Report template has not cache file path but it's length is use in buffer memory allocation, Tuğrul Topuz
2018-08-04 VERSION 2.5
* feat/docs: cache_purge_response_type directive, selecting response type (html|json|xml|text)
* break: changed status of HTTP code 404 (Not Found) to 412 (Precondition Failed)
* fix: remove path information of response body (#4, 3a8c08a, #11)
2020-06-27 VERSION 2.4.3
* fix: empty key check - it coredumps when cache key is empty, Tuğrul Topuz
2017-09-28 VERSION 2.4.2
* fix: segfault in call to `ngx_read_file` of partial key purge, Frankie Dintino
* fix: segfault in `cplcf->conf->purge_all` with separate location syntax, Frankie Dintino
2017-02-21 VERSION 2.4.1
* Fix compatibility with nginx-1.11.6+, Sułowicz Paweł
2016-11-20 VERSION 2.4
* Fix compatibility with nginx-1.7.12+.
* explain the purge logic
* feat(purge all): Include option to purge all the cached files
This option can be slow if a lot of content is cached, or if the
storage used for the cache is slow. But you really should be using
RAM as your cache storage.
* feat(partial keys): Support partial keys to purge multiple keys.
Put an '*' at the end of your purge cache URL.
e.g:
proxy_cache_key $scheme$host$uri$is_args$args$cookie_JSESSIONID;
curl -X PURGE https://example.com/pass*
This will remove every cached page whose key cache starting with:
httpsexample.com/pass*
Be careful not passing any value for the values after the $uri, or put
it at the end of your cache key.
* Convert a config file to build a dynamic module
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.
Previously, it would pass such requests to the upstream.
2012-12-07 VERSION 2.0
* Add alternative "same location" syntax.
From CloudFlare.
2012-07-02 VERSION 1.6
* Fix compatibility with nginx-1.3.2+.
Reported by MagicBear, patch from Ruslan Ermilov.
2011-12-20 VERSION 1.5
* Fix on-disk cache size calculation.
Since the initial release, recorded on-disk cache size was
decreased twice for purged content (once during cache purge
and once during subsequent cache update).
This resulted in recorded on-disk cache size being much
smaller than in reality, which could lead to on-disk cache
outgrowing defined "max_size" parameter.
Patch from Pyry Hakulinen.
2011-10-05 VERSION 1.4
* Add AIO support.
Requested by Emin Hasanov.
2011-05-03 VERSION 1.3
* Fix compatibility with nginx-1.0.1.
Reported by Sergey A. Osokin and Markus Linnala.
2010-08-29
* Fix compatibility with nginx-0.8.0 and versions older than
nginx-0.7.60.
2010-08-11 VERSION 1.2
* Fix various build scenarios with disabled upstream modules.
Reported by Johan Bergstroem.
* Add ability to purge content from SCGI's cache.
Requested by Johan Bergstroem.
2010-06-08 VERSION 1.1
* Fix compatibility with nginx-0.8.40+.
* Add ability to purge content from uWSGI's cache.
2010-01-10 VERSION 1.0
* Initial module release.
2009-11-17
* Fix patch compatibility with nginx-0.8.11+.
Reported by Bing Ran.
2009-08-11
* Initial patch release.

View file

@ -1,26 +0,0 @@
Copyright (c) 2009-2014, FRiCKLE <info@frickle.com>
Copyright (c) 2009-2014, Piotr Sikora <piotr.sikora@frickle.com>
All rights reserved.
This project was fully funded by yo.se.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,283 +0,0 @@
About
=====
`ngx_cache_purge` is `nginx` module which adds ability to purge content from
`FastCGI`, `proxy`, `SCGI` and `uWSGI` caches. A purge operation removes the
content with the same cache key as the purge request has.
Sponsors
========
Work on the original patch was fully funded by [yo.se](http://yo.se).
Status
======
This module is production-ready.
Configuration directives (same location syntax)
===============================================
fastcgi_cache_purge
-------------------
* **syntax**: `fastcgi_cache_purge on|off|<method> [purge_all] [from all|<ip> [.. <ip>]]`
* **default**: `none`
* **context**: `http`, `server`, `location`
Allow purging of selected pages from `FastCGI`'s cache.
proxy_cache_purge
-----------------
* **syntax**: `proxy_cache_purge on|off|<method> [purge_all] [from all|<ip> [.. <ip>]]`
* **default**: `none`
* **context**: `http`, `server`, `location`
Allow purging of selected pages from `proxy`'s cache.
scgi_cache_purge
----------------
* **syntax**: `scgi_cache_purge on|off|<method> [purge_all] [from all|<ip> [.. <ip>]]`
* **default**: `none`
* **context**: `http`, `server`, `location`
Allow purging of selected pages from `SCGI`'s cache.
uwsgi_cache_purge
-----------------
* **syntax**: `uwsgi_cache_purge on|off|<method> [purge_all] [from all|<ip> [.. <ip>]]`
* **default**: `none`
* **context**: `http`, `server`, `location`
Allow purging of selected pages from `uWSGI`'s cache.
Configuration directives (separate location syntax)
===================================================
fastcgi_cache_purge
-------------------
* **syntax**: `fastcgi_cache_purge zone_name key`
* **default**: `none`
* **context**: `location`
Sets area and key used for purging selected pages from `FastCGI`'s cache.
proxy_cache_purge
-----------------
* **syntax**: `proxy_cache_purge zone_name key`
* **default**: `none`
* **context**: `location`
Sets area and key used for purging selected pages from `proxy`'s cache.
scgi_cache_purge
----------------
* **syntax**: `scgi_cache_purge zone_name key`
* **default**: `none`
* **context**: `location`
Sets area and key used for purging selected pages from `SCGI`'s cache.
uwsgi_cache_purge
-----------------
* **syntax**: `uwsgi_cache_purge zone_name key`
* **default**: `none`
* **context**: `location`
Sets area and key used for purging selected pages from `uWSGI`'s cache.
Configuration directives (Optional)
===================================================
cache_purge_response_type
-----------------
* **syntax**: `cache_purge_response_type html|json|xml|text`
* **default**: `html`
* **context**: `http`, `server`, `location`
Sets a response type of purging result.
Partial Keys
============
Sometimes it's not possible to pass the exact key cache to purge a page. For example; when the content of a cookie or the params are part of the key.
You can specify a partial key adding an asterisk at the end of the URL.
curl -X PURGE /page*
The asterisk must be the last character of the key, so you **must** put the $uri variable at the end.
Sample configuration (same location syntax)
===========================================
http {
proxy_cache_path /tmp/cache keys_zone=tmpcache:10m;
server {
location / {
proxy_pass http://127.0.0.1:8000;
proxy_cache tmpcache;
proxy_cache_key "$uri$is_args$args";
proxy_cache_purge PURGE from 127.0.0.1;
}
}
}
Sample configuration (same location syntax - purge all cached files)
====================================================================
http {
proxy_cache_path /tmp/cache keys_zone=tmpcache:10m;
server {
location / {
proxy_pass http://127.0.0.1:8000;
proxy_cache tmpcache;
proxy_cache_key "$uri$is_args$args";
proxy_cache_purge PURGE purge_all from 127.0.0.1 192.168.0.0/8;
}
}
}
Sample configuration (separate location syntax)
===============================================
http {
proxy_cache_path /tmp/cache keys_zone=tmpcache:10m;
server {
location / {
proxy_pass http://127.0.0.1:8000;
proxy_cache tmpcache;
proxy_cache_key "$uri$is_args$args";
}
location ~ /purge(/.*) {
allow 127.0.0.1;
deny all;
proxy_cache tmpcache;
proxy_cache_key "$1$is_args$args";
}
}
}
Sample configuration (Optional)
===============================================
http {
proxy_cache_path /tmp/cache keys_zone=tmpcache:10m;
cache_purge_response_type text;
server {
cache_purge_response_type json;
location / { #json
proxy_pass http://127.0.0.1:8000;
proxy_cache tmpcache;
proxy_cache_key "$uri$is_args$args";
}
location ~ /purge(/.*) { #xml
allow 127.0.0.1;
deny all;
proxy_cache tmpcache;
proxy_cache_key "$1$is_args$args";
cache_purge_response_type xml;
}
location ~ /purge2(/.*) { # json
allow 127.0.0.1;
deny all;
proxy_cache tmpcache;
proxy_cache_key "$1$is_args$args";
}
}
server {
location / { #text
proxy_pass http://127.0.0.1:8000;
proxy_cache tmpcache;
proxy_cache_key "$uri$is_args$args";
}
location ~ /purge(/.*) { #text
allow 127.0.0.1;
deny all;
proxy_cache tmpcache;
proxy_cache_key "$1$is_args$args";
}
location ~ /purge2(/.*) { #html
allow 127.0.0.1;
deny all;
proxy_cache tmpcache;
proxy_cache_key "$1$is_args$args";
cache_purge_response_type html;
}
}
}
Solve problems
==============
* Enabling [`gzip_vary`](https://nginx.org/r/gzip_vary) can lead to different results when clearing, when enabling it, you may have problems clearing the cache. For reliable operation, you can disable [`gzip_vary`](https://nginx.org/r/gzip_vary) inside the location [#20](https://github.com/nginx-modules/ngx_cache_purge/issues/20).
Testing
=======
`ngx_cache_purge` comes with complete test suite based on [Test::Nginx](http://github.com/agentzh/test-nginx).
You can test it by running:
`$ prove`
License
=======
Copyright (c) 2009-2014, FRiCKLE <info@frickle.com>
Copyright (c) 2009-2014, Piotr Sikora <piotr.sikora@frickle.com>
All rights reserved.
This project was fully funded by yo.se.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
See also
========
- [ngx_slowfs_cache](http://github.com/FRiCKLE/ngx_slowfs_cache).
- http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#purger
- http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_cache_purge
- https://github.com/wandenberg/nginx-selective-cache-purge-module
- https://github.com/wandenberg/nginx-sorted-querystring-module
- https://github.com/ledgetech/ledge
- [Faking Surrogate Cache-Keys for Nginx Plus](https://www.innoq.com/en/blog/faking-surrogate-cache-keys-for-nginx-plus/) ([gist](https://gist.github.com/titpetric/2f142e89eaa0f36ba4e4383b16d61474))
- [Delete NGINX cached md5 items with a PURGE with wildcard support](https://gist.github.com/nosun/0cfb58d3164f829e2f027fd37b338ede)

View file

@ -1,31 +0,0 @@
if [ "$HTTP_PROXY" = "YES" ]; then
have=NGX_HTTP_PROXY . auto/have
fi
if [ "$HTTP_FASTCGI" = "YES" ]; then
have=NGX_HTTP_FASTCGI . auto/have
fi
if [ "$HTTP_SCGI" = "YES" ]; then
have=NGX_HTTP_SCGI . auto/have
fi
if [ "$HTTP_UWSGI" = "YES" ]; then
have=NGX_HTTP_UWSGI . auto/have
fi
ngx_addon_name=ngx_http_cache_purge_module
CACHE_PURGE_SRCS="$ngx_addon_dir/ngx_cache_purge_module.c"
if [ -n "$ngx_module_link" ]; then
ngx_module_type=HTTP
ngx_module_name="$ngx_addon_name"
ngx_module_srcs="$CACHE_PURGE_SRCS"
. auto/module
else
HTTP_MODULES="$HTTP_MODULES $ngx_addon_name"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $CACHE_PURGE_SRCS"
fi
have=NGX_CACHE_PURGE_MODULE . auto/have

View file

@ -1,74 +0,0 @@
libnginx-mod-http-cache-purge (1:2.5.3-3) unstable; urgency=medium
* d/control: update my email to janmojzis@debian.org
* d/copyright: update my email to janmojzis@debian.org
* d/control: bump Standards-Version: 4.7.2, no changes
* d/copyright: bump debian/* copyright year
* d/watch: use more generic template
-- Jan Mojžíš <janmojzis@debian.org> Fri, 11 Apr 2025 14:26:56 +0200
libnginx-mod-http-cache-purge (1:2.5.3-2) unstable; urgency=medium
* d/changelog fix closed bug number 1019003 -> 1055742 (Closes: 1055742)
-- Jan Mojžíš <jan.mojzis@gmail.com> Fri, 21 Jun 2024 19:34:05 +0200
libnginx-mod-http-cache-purge (1:2.5.3-1) unstable; urgency=medium
* switch to a new upstream
https://github.com/nginx-modules/ngx_cache_purge
(Closes: 1072836) (Closes: 1055742)
* d/p/dynamic-module.patch remove, fixed in upstream
* d/p/segfault-1.11.6.patch remove, fixed in upstream
* d/t/purgetest added
* d/copyright: bump my copyright year
* d/gbp.conf: add [pull] track-missing = True
* d/control: bump Standards-Version: 4.7.0, no changes
-- Jan Mojžíš <jan.mojzis@gmail.com> Fri, 21 Jun 2024 13:36:53 +0200
libnginx-mod-http-cache-purge (1:2.3-6) unstable; urgency=medium
* d/control: remove Build-Depends nginx-abi-1.24.0-1
-- Jan Mojžíš <jan.mojzis@gmail.com> Sat, 07 Oct 2023 15:31:25 +0200
libnginx-mod-http-cache-purge (1:2.3-5) unstable; urgency=medium
* NEW ABI: rebuild with nginx-abi-1.24.0-1
-- Jan Mojžíš <jan.mojzis@gmail.com> Tue, 27 Jun 2023 23:16:35 +0200
libnginx-mod-http-cache-purge (1:2.3-4) unstable; urgency=medium
* d/t/generic rework. The test now checks module after
installation/reload/restart.
* d/control: bump Standards-Version: 4.6.2, no changes
* d/gbb.conf: switched to debian branch main (debian-branch = main)
* d/copyright: bump my copyright year
* d/copyright: reformat text to be compatible with 'cme update dpkg-copyright'
* NEW ABI: rebuild with nginx-abi-1.22.1-7
-- Jan Mojžíš <jan.mojzis@gmail.com> Mon, 13 Feb 2023 12:56:14 +0100
libnginx-mod-http-cache-purge (1:2.3-3) unstable; urgency=medium
* d/copyright: fixed typo (empty line ngx_cache_purge_module.c)
-- Jan Mojžíš <jan.mojzis@gmail.com> Fri, 09 Dec 2022 14:50:48 +0100
libnginx-mod-http-cache-purge (1:2.3-2) experimental; urgency=medium
* d/control: added Multi-Arch: foreign
* d/copyright: add Igor Sysoev + Nginx, Inc.
-- Jan Mojžíš <jan.mojzis@gmail.com> Mon, 05 Dec 2022 21:15:13 +0100
libnginx-mod-http-cache-purge (1:2.3-1) experimental; urgency=medium
* Initial release. (Closes: 1024213)
* Additional info: The separate package libnginx-mod-http-cache-purge ships
newest version of ngx_cache_purge (Closes: 911099)
-- Jan Mojžíš <jan.mojzis@gmail.com> Wed, 30 Nov 2022 14:46:45 +0100

View file

@ -1,23 +0,0 @@
Source: libnginx-mod-http-cache-purge
Section: httpd
Priority: optional
Maintainer: Debian Nginx Maintainers <pkg-nginx-maintainers@alioth-lists.debian.net>
Uploaders: Jan Mojžíš <janmojzis@debian.org>,
Build-Depends: debhelper-compat (= 13),
dh-sequence-nginx,
Standards-Version: 4.7.2
Homepage: https://github.com/FRiCKLE/ngx_cache_purge
Vcs-Git: https://salsa.debian.org/nginx-team/libnginx-mod-http-cache-purge.git
Vcs-Browser: https://salsa.debian.org/nginx-team/libnginx-mod-http-cache-purge
Rules-Requires-Root: no
Package: libnginx-mod-http-cache-purge
Architecture: any
Multi-Arch: foreign
Depends: ${misc:Depends},
${shlibs:Depends},
Recommends: nginx,
Description: Purge content from Nginx caches
Cache Purge module adds purging capabilities to Nginx. It allows purging
content from caches used by all of Nginx proxy modules, like FastCGI, Proxy,
SCGI and uWSGI.

View file

@ -1,36 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: ngx_cache_purge
Upstream-Contact: FRiCKLE <info@frickle.com>
Source: https://github.com/FRiCKLE/ngx_cache_purge
Files: *
Copyright: 2009-2014, Piotr Sikora <piotr.sikora@frickle.com>
2009-2014, FRiCKLE <info@frickle.com>
License: BSD-2-clause
Files: debian/*
Copyright: 2022, Miao Wang <shankerwangmiao@gmail.com>
2022-2025, Jan Mojzis <janmojzis@debian.org>
License: BSD-2-clause
License: BSD-2-clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,12 +0,0 @@
[DEFAULT]
debian-branch = main
upstream-branch = upstream
upstream-tag = upstream/%(version)s
pristine-tar = True
sign-tags = True
[import-orig]
merge-mode = replace
[pull]
track-missing = True

View file

@ -1,6 +0,0 @@
#!/usr/bin/make -f
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
%:
dh $@

View file

@ -1,13 +0,0 @@
Tests: generic
Restrictions: allow-stderr isolation-container needs-root
Depends: curl,
nginx,
nginx-core,
@,
Tests: purgetest
Restrictions: allow-stderr isolation-container needs-root
Depends: curl,
nginx,
nginx-core,
@,

View file

@ -1,73 +0,0 @@
#!/bin/sh
# version 20221215
# generic test that only verifies that nginx is running with the given
# libnginx-... module
# - after installation
# - after nginx reload
# - after nginx restart
EX=0
CURL_CMD="curl --max-time 60 --silent --fail -o /dev/null"
#change directory to $AUTOPKGTEST_TMP
cd "${AUTOPKGTEST_TMP}"
echo -n "curl after installation: http status="
if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then
echo "OK"
else
EX=1
echo "FAILED"
fi
echo -n "nginx reload ... "
if invoke-rc.d nginx reload; then
echo "OK"
else
EX=1
echo "FAILED"
fi
sleep 5
echo -n "curl after reload: http status="
if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then
echo "OK"
else
EX=1
echo "FAILED"
fi
echo -n "nginx restart ... "
if invoke-rc.d nginx restart; then
echo "OK"
else
EX=1
echo "FAILED"
fi
sleep 5
echo -n "curl after restart: http status="
if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then
echo "OK"
else
EX=1
echo "FAILED"
fi
if [ ${EX} -ne 0 ]; then
echo "=== journalctl ==="
journalctl -n all -xu nginx.service || :
echo "=== error.log ==="
if [ `wc -l /var/log/nginx/error.log | cut -d ' ' -f1` -gt 100 ]; then
head -n 50 /var/log/nginx/error.log
echo '...'
tail -n 50 /var/log/nginx/error.log
else
cat /var/log/nginx/error.log
fi
fi
exit ${EX}

View file

@ -1,34 +0,0 @@
#!/bin/sh
set -e
cat <<EOF > "/etc/nginx/sites-enabled/default"
proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m;
proxy_temp_path /tmp/ngx_cache_purge_temp 1 2;
server {
listen 127.0.0.1:80 default_server;
location /proxy {
proxy_pass \$scheme://127.0.0.1:\$server_port/etc/passwd;
proxy_cache test_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 test_cache \$1\$is_args\$args;
}
location = /etc/passwd {
root /;
}
}
EOF
nginx -t
invoke-rc.d nginx restart || { journalctl -n all -xu nginx.service; exit 1; }
curl --fail -s -o /dev/null -w "GET key: %{http_code}\n" http://127.0.0.1/proxy/passwd
curl --fail -s -o /dev/null -w "PURGE existing key: %{http_code}\n" -X PURGE http://127.0.0.1/purge/proxy/passwd
curl -s -o /dev/null -w "PURGE non-existing key: %{http_code}\n" -X PURGE http://127.0.0.1/purge/proxy/passwd

View file

@ -1,4 +0,0 @@
---
Bug-Database: https://github.com/FRiCKLE/ngx_cache_purge/issues
Bug-Submit: https://github.com/FRiCKLE/ngx_cache_purge/issues/new
Repository-Browse: https://github.com/FRiCKLE/ngx_cache_purge

View file

@ -1,6 +0,0 @@
version=4
opts="\
uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha|a|b)\d*)$/$1~$2/,\
" \
https://github.com/nginx-modules/ngx_cache_purge/tags \
(?:.*?/)?v?@ANY_VERSION@@ARCHIVE_EXT@

View file

@ -1,136 +0,0 @@
# 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_';
location /proxy {
proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd;
proxy_cache test_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 test_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_nginx2: 4: < 0.8.3 or < 0.7.62
=== 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_nginx2: 5: < 0.8.3 or < 0.7.62
=== 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_nginx2: 4: < 0.8.3 or < 0.7.62
=== TEST 4: purge from empty cache
--- http_config eval: $::http_config
--- config eval: $::config
--- request
PURGE /purge/proxy/passwd
--- error_code: 412
--- response_headers
Content-Type: text/html
--- response_body_like: 412 Precondition Failed
--- timeout: 10
--- no_error_log eval
qr/\[(warn|error|crit|alert|emerg)\]/
--- skip_nginx2: 4: < 0.8.3 or < 0.7.62
=== 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_nginx2: 5: < 0.8.3 or < 0.7.62
=== 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_nginx2: 5: < 0.8.3 or < 0.7.62

View file

@ -1,138 +0,0 @@
# 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: 412
--- response_headers
Content-Type: text/html
--- response_body_like: 412 Precondition Failed
--- 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

View file

@ -1,349 +0,0 @@
# 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;
location /proxy {
proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd;
proxy_cache test_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;
location /proxy {
proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd;
proxy_cache test_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;
location /proxy {
proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd;
proxy_cache test_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_nginx2: 4: < 0.8.3 or < 0.7.62
=== 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_nginx2: 5: < 0.8.3 or < 0.7.62
=== 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_nginx2: 4: < 0.8.3 or < 0.7.62
=== TEST 4: purge from empty cache
--- http_config eval: $::http_config
--- config eval: $::config
--- request
PURGE /proxy/passwd
--- error_code: 412
--- response_headers
Content-Type: text/html
--- response_body_like: 412 Precondition Failed
--- timeout: 10
--- no_error_log eval
qr/\[(warn|error|crit|alert|emerg)\]/
--- skip_nginx2: 4: < 0.8.3 or < 0.7.62
=== 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_nginx2: 5: < 0.8.3 or < 0.7.62
=== 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_nginx2: 5: < 0.8.3 or < 0.7.62
=== 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_nginx2: 4: < 0.8.3 or < 0.7.62
=== TEST 8: purge from empty cache (PURGE allowed)
--- http_config eval: $::http_config
--- config eval: $::config_allowed
--- request
PURGE /proxy/passwd
--- error_code: 412
--- response_headers
Content-Type: text/html
--- response_body_like: 412 Precondition Failed
--- timeout: 10
--- no_error_log eval
qr/\[(warn|error|crit|alert|emerg)\]/
--- skip_nginx2: 4: < 0.8.3 or < 0.7.62
=== 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_nginx2: 5: < 0.8.3 or < 0.7.62
=== 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_nginx2: 5: < 0.8.3 or < 0.7.62
=== 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_nginx2: 4: < 0.8.3 or < 0.7.62
=== 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_nginx2: 5: < 0.8.3 or < 0.7.62
=== 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_nginx2: 4: < 0.8.3 or < 0.7.62
=== 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_nginx2: 4: < 0.8.3 or < 0.7.62
=== TEST 15: multiple cache purge directives
--- http_config eval: $::http_config
--- config
fastcgi_cache_purge on;
proxy_cache_purge on;
location /proxy {
proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd;
proxy_cache test_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_nginx2: 4: < 0.8.3 or < 0.7.62

View file

@ -1,353 +0,0 @@
# 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: 412
--- response_headers
Content-Type: text/html
--- response_body_like: 412 Precondition Failed
--- 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: 412
--- response_headers
Content-Type: text/html
--- response_body_like: 412 Precondition Failed
--- 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

View file

@ -1,140 +0,0 @@
# vi:filetype=perl
use lib 'lib';
use Test::Nginx::Socket;
repeat_each(1);
plan tests => 32;
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_';
location /proxy {
proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd;
proxy_cache test_cache;
proxy_cache_key $uri$is_args$args;
proxy_cache_valid 3m;
add_header X-Cache-Status $upstream_cache_status;
proxy_cache_purge PURGE purge_all from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8;
}
location = /etc/passwd {
root /;
}
_EOC_
worker_connections(128);
no_shuffle();
run_tests();
no_diff();
__DATA__
=== TEST 1: prepare passwd
--- 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)\]/
=== TEST 2: prepare shadow
--- http_config eval: $::http_config
--- config eval: $::config
--- request
GET /proxy/shadow
--- 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)\]/
=== TEST 3: get from cache passwd
--- 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)\]/
=== TEST 4: get from cache shadow
--- http_config eval: $::http_config
--- config eval: $::config
--- request
GET /proxy/shadow
--- 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)\]/
=== TEST 5: purge from cache
--- http_config eval: $::http_config
--- config eval: $::config
--- request
PURGE /proxy/any
--- 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)\]/
=== TEST 6: get from empty cache passwd
--- 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)\]/
=== TEST 7: get from empty cache shadow
--- http_config eval: $::http_config
--- config eval: $::config
--- request
GET /proxy/shadow
--- 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)\]/

View file

@ -1,168 +0,0 @@
# vi:filetype=perl
use lib 'lib';
use Test::Nginx::Socket;
repeat_each(1);
plan tests => 41;
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_';
location /proxy {
proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd;
proxy_cache test_cache;
proxy_cache_key $uri$is_args$args;
proxy_cache_valid 3m;
add_header X-Cache-Status $upstream_cache_status;
proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8;
}
location = /etc/passwd {
root /;
}
_EOC_
worker_connections(128);
no_shuffle();
run_tests();
no_diff();
__DATA__
=== TEST 1: prepare passwd
--- 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)\]/
=== TEST 2: prepare passwd2
--- http_config eval: $::http_config
--- config eval: $::config
--- request
GET /proxy/passwd2
--- 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)\]/
=== TEST 3: prepare shadow
--- http_config eval: $::http_config
--- config eval: $::config
--- request
GET /proxy/shadow
--- 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)\]/
=== TEST 4: get from cache passwd
--- 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)\]/
=== TEST 5: get from cache passwd2
--- http_config eval: $::http_config
--- config eval: $::config
--- request
GET /proxy/passwd2
--- 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)\]/
=== TEST 6: purge from cache
--- http_config eval: $::http_config
--- config eval: $::config
--- request
PURGE /proxy/pass*
--- 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)\]/
=== TEST 7: get from empty cache passwd
--- 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)\]/
=== TEST 8: get from empty cache passwd2
--- http_config eval: $::http_config
--- config eval: $::config
--- request
GET /proxy/passwd2
--- 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)\]/
=== TEST 9: get from cache shadow
--- http_config eval: $::http_config
--- config eval: $::config
--- request
GET /proxy/shadow
--- 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)\]/

View file

@ -1,245 +0,0 @@
# 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_';
cache_purge_response_type json;
location /proxy {
proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd;
proxy_cache test_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 test_cache $1$is_args$args;
cache_purge_response_type html;
}
location ~ /purge_json(/.*) {
proxy_cache_purge test_cache $1$is_args$args;
}
location ~ /purge_xml(/.*) {
proxy_cache_purge test_cache $1$is_args$args;
cache_purge_response_type xml;
}
location ~ /purge_text(/.*) {
proxy_cache_purge test_cache $1$is_args$args;
cache_purge_response_type text;
}
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_nginx2: 4: < 0.8.3 or < 0.7.62
=== 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_nginx2: 5: < 0.8.3 or < 0.7.62
=== 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_nginx2: 4: < 0.8.3 or < 0.7.62
=== TEST 4: purge from empty cache
--- http_config eval: $::http_config
--- config eval: $::config
--- request
PURGE /purge/proxy/passwd
--- error_code: 412
--- response_headers
Content-Type: text/html
--- response_body_like: 412 Precondition Failed
--- timeout: 10
--- no_error_log eval
qr/\[(warn|error|crit|alert|emerg)\]/
--- skip_nginx2: 4: < 0.8.3 or < 0.7.62
=== 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_nginx2: 5: < 0.8.3 or < 0.7.62
=== 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_nginx2: 5: < 0.8.3 or < 0.7.62
=== TEST 7-prepare: prepare purge
--- http_config eval: $::http_config
--- config eval: $::config
--- request
GET /proxy/passwd?t=7
--- 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_nginx2: 4: < 0.8.3 or < 0.7.62
=== TEST 7: get a JSON response after purge from cache
--- http_config eval: $::http_config
--- config eval: $::config
--- request
PURGE /purge_json/proxy/passwd?t=7
--- error_code: 200
--- response_headers
Content-Type: application/json
--- response_body_like: {\"Key\": \"\/proxy\/passwd\?t=7\"
--- timeout: 10
--- no_error_log eval
qr/\[(warn|error|crit|alert|emerg)\]/
--- skip_nginx2: 4: < 0.8.3 or < 0.7.62
=== TEST 8-prepare: prepare purge
--- http_config eval: $::http_config
--- config eval: $::config
--- request
GET /proxy/passwd?t=8
--- 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_nginx2: 4: < 0.8.3 or < 0.7.62
=== TEST 8: get a XML response after purge from cache
--- http_config eval: $::http_config
--- config eval: $::config
--- request
PURGE /purge_xml/proxy/passwd?t=8
--- error_code: 200
--- response_headers
Content-Type: text/xml
--- response_body_like: \<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><status><Key><\!\[CDATA\[\/proxy\/passwd\?t=8\]\]><\/Key>
--- timeout: 10
--- no_error_log eval
qr/\[(warn|error|crit|alert|emerg)\]/
--- skip_nginx2: 4: < 0.8.3 or < 0.7.62
=== TEST 9-prepare: prepare purge
--- http_config eval: $::http_config
--- config eval: $::config
--- request
GET /proxy/passwd?t=9
--- 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_nginx2: 4: < 0.8.3 or < 0.7.62
=== TEST 9: get a TEXT response after purge from cache
--- http_config eval: $::http_config
--- config eval: $::config
--- request
PURGE /purge_text/proxy/passwd?t=9
--- error_code: 200
--- response_headers
Content-Type: text/plain
--- response_body_like: Key
--- timeout: 10
--- no_error_log eval
qr/\[(warn|error|crit|alert|emerg)\]/
--- skip_nginx2: 4: < 0.8.3 or < 0.7.62

View file

@ -1 +0,0 @@
*.t linguist-language=Text

View file

@ -1,65 +0,0 @@
.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

View file

@ -1,48 +0,0 @@
sudo: required
dist: bionic
os: linux
language: c
compiler:
- gcc
env:
global:
- LUAJIT_PREFIX=/opt/luajit21
- LUAJIT_LIB=$LUAJIT_PREFIX/lib
- LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1
- LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH
matrix:
- NGINX_VERSION=1.17.8
- NGINX_VERSION=1.19.9
before_install:
- sudo apt-get install -qq -y cpanminus libgd-dev ca-certificates
- sudo cpanm -v --notest Test::Nginx > build.log 2>&1 || (cat build.log && exit 1)
install:
- wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && tar -xzf nginx-${NGINX_VERSION}.tar.gz
- git clone https://github.com/simpl/ngx_devel_kit.git
- git clone https://github.com/openresty/set-misc-nginx-module.git
- git clone https://github.com/openresty/xss-nginx-module.git
- git clone https://github.com/openresty/rds-json-nginx-module.git
- git clone https://github.com/openresty/headers-more-nginx-module.git
- git clone https://github.com/openresty/lua-nginx-module.git
- git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core
- git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache
- git clone https://github.com/openresty/nginx-eval-module.git
- git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git luajit2
script:
- cd luajit2/
- make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT -msse4.2' > build.log 2>&1 || (cat build.log && exit 1)
- sudo make install PREFIX=$LUAJIT_PREFIX > build.log 2>&1 || (cat build.log && exit 1)
- cd ..
- cd nginx-${NGINX_VERSION}/
- ./configure --without-http_ssi_module --with-debug --with-select_module --with-poll_module --with-http_stub_status_module --with-http_image_filter_module --add-module=../ngx_devel_kit --add-module=../set-misc-nginx-module --add-module=../nginx-eval-module --add-module=../xss-nginx-module --add-module=../rds-json-nginx-module --add-module=../headers-more-nginx-module --add-module=../lua-nginx-module --add-module=.. > build.log 2>&1 || (cat build.log && exit 1)
- make -j2 > build.log 2>&1 || (cat build.log && exit 1)
- export PATH=$PATH:`pwd`/objs
- cd ..
- prove -I. -r t

View file

@ -1,25 +0,0 @@
Copyright (C) 2009-2014, Yichun "agentzh" Zhang <agentzh@gmail.com>.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

File diff suppressed because it is too large Load diff

View file

@ -1,63 +0,0 @@
ngx_addon_name=ngx_http_echo_module
ECHO_SRCS=" \
$ngx_addon_dir/src/ngx_http_echo_module.c \
$ngx_addon_dir/src/ngx_http_echo_util.c \
$ngx_addon_dir/src/ngx_http_echo_timer.c \
$ngx_addon_dir/src/ngx_http_echo_var.c \
$ngx_addon_dir/src/ngx_http_echo_handler.c \
$ngx_addon_dir/src/ngx_http_echo_filter.c \
$ngx_addon_dir/src/ngx_http_echo_sleep.c \
$ngx_addon_dir/src/ngx_http_echo_location.c \
$ngx_addon_dir/src/ngx_http_echo_echo.c \
$ngx_addon_dir/src/ngx_http_echo_request_info.c \
$ngx_addon_dir/src/ngx_http_echo_subrequest.c \
$ngx_addon_dir/src/ngx_http_echo_foreach.c \
"
ECHO_DEPS=" \
$ngx_addon_dir/src/ddebug.h \
$ngx_addon_dir/src/ngx_http_echo_module.h \
$ngx_addon_dir/src/ngx_http_echo_handler.h \
$ngx_addon_dir/src/ngx_http_echo_util.h \
$ngx_addon_dir/src/ngx_http_echo_sleep.h \
$ngx_addon_dir/src/ngx_http_echo_filter.h \
$ngx_addon_dir/src/ngx_http_echo_var.h \
$ngx_addon_dir/src/ngx_http_echo_location.h \
$ngx_addon_dir/src/ngx_http_echo_echo.h \
$ngx_addon_dir/src/ngx_http_echo_request_info.h \
$ngx_addon_dir/src/ngx_http_echo_subrequest.h \
$ngx_addon_dir/src/ngx_http_echo_foreach.h \
"
# nginx 1.17.0+ unconditionally enables the postpone filter
if [ ! -z "$HTTP_POSTPONE" ]; then
# nginx won't have HTTP_POSTPONE_FILTER_MODULE & HTTP_POSTPONE_FILTER_SRCS
# defined since 1.9.11
if [ -z "$HTTP_POSTPONE_FILTER_MODULE" ]; then
HTTP_POSTPONE_FILTER_MODULE=ngx_http_postpone_filter_module
HTTP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c
fi
# This module depends upon the postpone filter being activated
if [ "$HTTP_POSTPONE" != YES ]; then
HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_POSTPONE_FILTER_MODULE"
HTTP_SRCS="$HTTP_SRCS $HTTP_POSTPONE_FILTER_SRCS"
HTTP_POSTPONE=YES
fi
fi
if [ -n "$ngx_module_link" ]; then
ngx_module_type=HTTP_AUX_FILTER
ngx_module_name=$ngx_addon_name
ngx_module_incs=
ngx_module_deps="$ECHO_DEPS"
ngx_module_srcs="$ECHO_SRCS"
ngx_module_libs=
. auto/module
else
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ECHO_SRCS"
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ECHO_DEPS"
fi

View file

@ -1,53 +0,0 @@
libnginx-mod-http-echo (1:0.63-7) unstable; urgency=medium
* d/control: update my email to janmojzis@debian.org
* d/copyright: update my email to janmojzis@debian.org
* d/control: bump Standards-Version: 4.7.2, no changes
* d/copyright: bump debian/* copyright year
* d/watch: use more generic template
-- Jan Mojžíš <janmojzis@debian.org> Fri, 11 Apr 2025 14:26:58 +0200
libnginx-mod-http-echo (1:0.63-6) unstable; urgency=medium
* d/control: remove Build-Depends nginx-abi-1.24.0-1
-- Jan Mojžíš <jan.mojzis@gmail.com> Sat, 07 Oct 2023 15:31:26 +0200
libnginx-mod-http-echo (1:0.63-5) unstable; urgency=medium
* NEW ABI: rebuild with nginx-abi-1.24.0-1
-- Jan Mojžíš <jan.mojzis@gmail.com> Tue, 27 Jun 2023 23:16:36 +0200
libnginx-mod-http-echo (1:0.63-4) unstable; urgency=medium
* d/t/generic rework. The test now checks module after
installation/reload/restart.
* d/control: bump Standards-Version: 4.6.2, no changes
* d/gbb.conf: added
* d/copyright: bump my copyright year
* d/copyright: reformat text to be compatible with 'cme update dpkg-copyright'
* d/fix.scanned.copyright: added, fixes upstream author name parsing
* NEW ABI: rebuild with nginx-abi-1.22.1-7
-- Jan Mojžíš <jan.mojzis@gmail.com> Mon, 13 Feb 2023 15:03:42 +0100
libnginx-mod-http-echo (1:0.63-3) unstable; urgency=medium
* No source change upload to unstable.
-- Jan Mojžíš <jan.mojzis@gmail.com> Fri, 09 Dec 2022 14:36:45 +0100
libnginx-mod-http-echo (1:0.63-2) experimental; urgency=medium
* d/control: added Multi-Arch: foreign
* d/copyright: update, add Igor Sysoev
-- Jan Mojžíš <jan.mojzis@gmail.com> Mon, 05 Dec 2022 21:14:02 +0100
libnginx-mod-http-echo (1:0.63-1) experimental; urgency=medium
* Initial release. (Closes: 1024153)
-- Jan Mojžíš <jan.mojzis@gmail.com> Wed, 30 Nov 2022 14:46:48 +0100

View file

@ -1,36 +0,0 @@
Source: libnginx-mod-http-echo
Section: httpd
Priority: optional
Maintainer: Debian Nginx Maintainers <pkg-nginx-maintainers@alioth-lists.debian.net>
Uploaders: Jan Mojžíš <janmojzis@debian.org>,
Build-Depends: debhelper-compat (= 13),
dh-sequence-nginx,
Standards-Version: 4.7.2
Homepage: https://github.com/agentzh/echo-nginx-module
Vcs-Git: https://salsa.debian.org/nginx-team/libnginx-mod-http-echo.git
Vcs-Browser: https://salsa.debian.org/nginx-team/libnginx-mod-http-echo
Rules-Requires-Root: no
Package: libnginx-mod-http-echo
Architecture: any
Multi-Arch: foreign
Depends: ${misc:Depends},
${shlibs:Depends},
Recommends: nginx,
Description: Bring echo and more shell style goodies to Nginx
Echo module wraps lots of Nginx internal APIs for streaming input and output,
parallel/sequential subrequests, timers and sleeping, as well as various meta
data accessing.
.
Basically it provides various utilities that help testing and debugging of
other modules by trivially emulating different kinds of faked subrequest
locations.
.
People will also find it useful in real-world applications that need to:
.
1. Serve static contents directly from memory.
2. Wrap the upstream response with custom header and footer (kinda like the
addition module but with contents read directly from the config file and
Nginx variables).
3. Merge contents of various "Nginx locations" (i.e., subrequests) together in
a single main request (using echo_location and its friends).

View file

@ -1,71 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: echo-nginx-module
Upstream-Contact: Yichun "agentzh" Zhang <agentzh@gmail.com>
Source: https://github.com/agentzh/echo-nginx-module
Files: *
Copyright: 2009-2018, Yichun "agentzh" Zhang (章亦春) <agentzh@gmail.com>, OpenResty Inc.
2009-2014, Yichun "agentzh" Zhang <agentzh@gmail.com>.
License: BSD-2-clause
Files: README.markdown
Copyright: 2009-2018, Yichun "agentzh" Zhang (章亦春) <agentzh@gmail.com>, OpenResty Inc.
License: BSD-2-clause
Files: config
Copyright: 2009-2018, Yichun "agentzh" Zhang <agentzh@gmail.com>.
License: BSD-2-clause
Files: debian/*
Copyright: 2022, Miao Wang <shankerwangmiao@gmail.com>
2022-2025, Jan Mojzis <janmojzis@debian.org>
License: BSD-2-clause
Files: src/*
Copyright: 2009-2018, Yichun "agentzh" Zhang <agentzh@gmail.com>.
License: BSD-2-clause
Files: src/ngx_http_echo_handler.c
src/ngx_http_echo_module.c
src/ngx_http_echo_module.h
src/ngx_http_echo_request_info.c
src/ngx_http_echo_sleep.c
src/ngx_http_echo_subrequest.c
src/ngx_http_echo_util.c
src/ngx_http_echo_util.h
Copyright: Yichun Zhang (agentzh)
License: BSD-2-clause
Files: t/*
Copyright: 2009-2018, Yichun "agentzh" Zhang <agentzh@gmail.com>.
License: BSD-2-clause
Files: util/*
Copyright: 2009-2018, Yichun "agentzh" Zhang <agentzh@gmail.com>.
License: BSD-2-clause
License: BSD-2-clause
All rights reserved.
.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
.
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,2 +0,0 @@
# fixes upstream author name parsing
! copyright Files:~/.*/ Copyright=~"s/(Zhang)\s\(.*x\{6625\}\)/$1\ (章亦春)/"

View file

@ -1,9 +0,0 @@
[DEFAULT]
debian-branch = main
upstream-branch = upstream
upstream-tag = upstream/%(version)s
pristine-tar = False
sign-tags = True
[import-orig]
merge-mode = replace

View file

@ -1,6 +0,0 @@
#!/usr/bin/make -f
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
%:
dh $@

View file

@ -1 +0,0 @@
3.0 (quilt)

View file

@ -1,13 +0,0 @@
Tests: generic
Restrictions: allow-stderr isolation-container needs-root
Depends: curl,
nginx,
nginx-core,
@,
Tests: helloworld
Restrictions: allow-stderr isolation-container needs-root
Depends: curl,
nginx,
nginx-core,
@,

View file

@ -1,73 +0,0 @@
#!/bin/sh
# version 20221215
# generic test that only verifies that nginx is running with the given
# libnginx-... module
# - after installation
# - after nginx reload
# - after nginx restart
EX=0
CURL_CMD="curl --max-time 60 --silent --fail -o /dev/null"
#change directory to $AUTOPKGTEST_TMP
cd "${AUTOPKGTEST_TMP}"
echo -n "curl after installation: http status="
if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then
echo "OK"
else
EX=1
echo "FAILED"
fi
echo -n "nginx reload ... "
if invoke-rc.d nginx reload; then
echo "OK"
else
EX=1
echo "FAILED"
fi
sleep 5
echo -n "curl after reload: http status="
if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then
echo "OK"
else
EX=1
echo "FAILED"
fi
echo -n "nginx restart ... "
if invoke-rc.d nginx restart; then
echo "OK"
else
EX=1
echo "FAILED"
fi
sleep 5
echo -n "curl after restart: http status="
if $CURL_CMD -w "response_code: %{http_code}, ... " http://127.0.0.1/; then
echo "OK"
else
EX=1
echo "FAILED"
fi
if [ ${EX} -ne 0 ]; then
echo "=== journalctl ==="
journalctl -n all -xu nginx.service || :
echo "=== error.log ==="
if [ `wc -l /var/log/nginx/error.log | cut -d ' ' -f1` -gt 100 ]; then
head -n 50 /var/log/nginx/error.log
echo '...'
tail -n 50 /var/log/nginx/error.log
else
cat /var/log/nginx/error.log
fi
fi
exit ${EX}

View file

@ -1,32 +0,0 @@
#!/bin/sh
set -e
cat <<EOF > "/etc/nginx/sites-enabled/default"
server {
listen 80 default_server;
location /helloworld {
echo "hello world";
}
}
EOF
exp="hello world
response_code: 200"
nginx -t
invoke-rc.d nginx restart || { journalctl -n all -xu nginx.service; exit 1; }
out=`curl --fail -w "response_code: %{http_code}\n" http://127.0.0.1/helloworld`
if [ x"${out}" != x"${exp}" ]; then
echo "output:"
echo "====================="
echo "${out}"
echo "====================="
echo "expected output:"
echo "====================="
echo "${exp}"
echo "====================="
exit 1
fi

View file

@ -1,4 +0,0 @@
---
Bug-Database: https://github.com/agentzh/echo-nginx-module/issues
Bug-Submit: https://github.com/agentzh/echo-nginx-module/issues/new
Repository-Browse: https://github.com/agentzh/echo-nginx-module

View file

@ -1,6 +0,0 @@
version=4
opts="\
uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha|a|b)\d*)$/$1~$2/,\
" \
https://github.com/agentzh/echo-nginx-module/tags \
(?:.*?/)?v?@ANY_VERSION@@ARCHIVE_EXT@

View file

@ -1,114 +0,0 @@
#ifndef DDEBUG_H
#define DDEBUG_H
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#if defined(DDEBUG) && (DDEBUG)
# if (NGX_HAVE_VARIADIC_MACROS)
# define dd(...) fprintf(stderr, "echo *** %s: ", __func__); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, " at %s line %d.\n", __FILE__, __LINE__)
# else
#include <stdarg.h>
#include <stdio.h>
#include <stdarg.h>
static ngx_inline void
dd(const char * fmt, ...) {
}
# endif
# if DDEBUG > 1
# define dd_enter() dd_enter_helper(r, __func__)
static ngx_inline void
dd_enter_helper(ngx_http_request_t *r, const char *func) {
ngx_http_posted_request_t *pr;
fprintf(stderr, ">enter %s %.*s %.*s?%.*s c:%d m:%p r:%p ar:%p pr:%p",
func,
(int) r->method_name.len, r->method_name.data,
(int) r->uri.len, r->uri.data,
(int) r->args.len, r->args.data,
0/*(int) r->main->count*/, r->main,
r, r->connection->data, r->parent);
if (r->posted_requests) {
fprintf(stderr, " posted:");
for (pr = r->posted_requests; pr; pr = pr->next) {
fprintf(stderr, "%p,", pr);
}
}
fprintf(stderr, "\n");
}
# else
# define dd_enter()
# endif
#else
# if (NGX_HAVE_VARIADIC_MACROS)
# define dd(...)
# define dd_enter()
# else
#include <stdarg.h>
static ngx_inline void
dd(const char * fmt, ...) {
}
static ngx_inline void
dd_enter() {
}
# endif
#endif
#if defined(DDEBUG) && (DDEBUG)
#define dd_check_read_event_handler(r) \
dd("r->read_event_handler = %s", \
r->read_event_handler == ngx_http_block_reading ? \
"ngx_http_block_reading" : \
r->read_event_handler == ngx_http_test_reading ? \
"ngx_http_test_reading" : \
r->read_event_handler == ngx_http_request_empty_handler ? \
"ngx_http_request_empty_handler" : "UNKNOWN")
#define dd_check_write_event_handler(r) \
dd("r->write_event_handler = %s", \
r->write_event_handler == ngx_http_handler ? \
"ngx_http_handler" : \
r->write_event_handler == ngx_http_core_run_phases ? \
"ngx_http_core_run_phases" : \
r->write_event_handler == ngx_http_request_empty_handler ? \
"ngx_http_request_empty_handler" : "UNKNOWN")
#else
#define dd_check_read_event_handler(r)
#define dd_check_write_event_handler(r)
#endif
#endif /* DDEBUG_H */

View file

@ -1,342 +0,0 @@
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_echo_echo.h"
#include "ngx_http_echo_util.h"
#include "ngx_http_echo_filter.h"
#include <nginx.h>
static ngx_buf_t ngx_http_echo_space_buf;
static ngx_buf_t ngx_http_echo_newline_buf;
ngx_int_t
ngx_http_echo_echo_init(ngx_conf_t *cf)
{
static u_char space_str[] = " ";
static u_char newline_str[] = "\n";
dd("global init...");
ngx_memzero(&ngx_http_echo_space_buf, sizeof(ngx_buf_t));
ngx_http_echo_space_buf.memory = 1;
ngx_http_echo_space_buf.start =
ngx_http_echo_space_buf.pos =
space_str;
ngx_http_echo_space_buf.end =
ngx_http_echo_space_buf.last =
space_str + sizeof(space_str) - 1;
ngx_memzero(&ngx_http_echo_newline_buf, sizeof(ngx_buf_t));
ngx_http_echo_newline_buf.memory = 1;
ngx_http_echo_newline_buf.start =
ngx_http_echo_newline_buf.pos =
newline_str;
ngx_http_echo_newline_buf.end =
ngx_http_echo_newline_buf.last =
newline_str + sizeof(newline_str) - 1;
return NGX_OK;
}
ngx_int_t
ngx_http_echo_exec_echo_sync(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx)
{
ngx_buf_t *buf;
ngx_chain_t *cl = NULL; /* the head of the chain link */
buf = ngx_calloc_buf(r->pool);
if (buf == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
buf->sync = 1;
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
cl->buf = buf;
cl->next = NULL;
return ngx_http_echo_send_chain_link(r, ctx, cl);
}
ngx_int_t
ngx_http_echo_exec_echo(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args,
ngx_flag_t in_filter, ngx_array_t *opts)
{
ngx_uint_t i;
ngx_buf_t *space_buf;
ngx_buf_t *newline_buf;
ngx_buf_t *buf;
ngx_str_t *computed_arg;
ngx_str_t *computed_arg_elts;
ngx_str_t *opt;
ngx_chain_t *cl = NULL; /* the head of the chain link */
ngx_chain_t **ll = &cl; /* always point to the address of the last link */
dd_enter();
if (computed_args == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
computed_arg_elts = computed_args->elts;
for (i = 0; i < computed_args->nelts; i++) {
computed_arg = &computed_arg_elts[i];
if (computed_arg->len == 0) {
buf = NULL;
} else {
buf = ngx_calloc_buf(r->pool);
if (buf == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
buf->start = buf->pos = computed_arg->data;
buf->last = buf->end = computed_arg->data +
computed_arg->len;
buf->memory = 1;
}
if (cl == NULL) {
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
cl->buf = buf;
cl->next = NULL;
ll = &cl->next;
} else {
/* append a space first */
*ll = ngx_alloc_chain_link(r->pool);
if (*ll == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
space_buf = ngx_calloc_buf(r->pool);
if (space_buf == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
/* nginx clears buf flags at the end of each request handling,
* so we have to make a clone here. */
*space_buf = ngx_http_echo_space_buf;
(*ll)->buf = space_buf;
(*ll)->next = NULL;
ll = &(*ll)->next;
/* then append the buf only if it's non-empty */
if (buf) {
*ll = ngx_alloc_chain_link(r->pool);
if (*ll == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
(*ll)->buf = buf;
(*ll)->next = NULL;
ll = &(*ll)->next;
}
}
} /* end for */
if (cl && cl->buf == NULL) {
cl = cl->next;
}
if (opts && opts->nelts > 0) {
opt = opts->elts;
/* FIXME handle other unrecognized options here */
if (opt[0].len == 1 && opt[0].data[0] == 'n') {
goto done;
}
}
/* append the newline character */
newline_buf = ngx_calloc_buf(r->pool);
if (newline_buf == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
*newline_buf = ngx_http_echo_newline_buf;
if (cl == NULL) {
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
cl->buf = newline_buf;
cl->next = NULL;
/* ll = &cl->next; */
} else {
*ll = ngx_alloc_chain_link(r->pool);
if (*ll == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
(*ll)->buf = newline_buf;
(*ll)->next = NULL;
/* ll = &(*ll)->next; */
}
done:
if (cl == NULL || cl->buf == NULL) {
return NGX_OK;
}
if (in_filter) {
return ngx_http_echo_next_body_filter(r, cl);
}
return ngx_http_echo_send_chain_link(r, ctx, cl);
}
ngx_int_t
ngx_http_echo_exec_echo_flush(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx)
{
return ngx_http_send_special(r, NGX_HTTP_FLUSH);
}
ngx_int_t
ngx_http_echo_exec_echo_request_body(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx)
{
ngx_buf_t *b;
ngx_chain_t *out, *cl, **ll;
if (r->request_body == NULL || r->request_body->bufs == NULL) {
return NGX_OK;
}
out = NULL;
ll = &out;
for (cl = r->request_body->bufs; cl; cl = cl->next) {
if (ngx_buf_special(cl->buf)) {
/* we do not want to create zero-size bufs */
continue;
}
*ll = ngx_alloc_chain_link(r->pool);
if (*ll == NULL) {
return NGX_ERROR;
}
b = ngx_alloc_buf(r->pool);
if (b == NULL) {
return NGX_ERROR;
}
(*ll)->buf = b;
(*ll)->next = NULL;
ngx_memcpy(b, cl->buf, sizeof(ngx_buf_t));
b->tag = (ngx_buf_tag_t) &ngx_http_echo_exec_echo_request_body;
b->last_buf = 0;
b->last_in_chain = 0;
ll = &(*ll)->next;
}
if (out == NULL) {
return NGX_OK;
}
return ngx_http_echo_send_chain_link(r, ctx, out);
}
ngx_int_t
ngx_http_echo_exec_echo_duplicate(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args)
{
ngx_str_t *computed_arg;
ngx_str_t *computed_arg_elts;
ssize_t i, count;
ngx_str_t *str;
u_char *p;
ngx_int_t rc;
ngx_buf_t *buf;
ngx_chain_t *cl;
dd_enter();
computed_arg_elts = computed_args->elts;
computed_arg = &computed_arg_elts[0];
count = ngx_http_echo_atosz(computed_arg->data, computed_arg->len);
if (count == NGX_ERROR) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"invalid size specified: \"%V\"", computed_arg);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
str = &computed_arg_elts[1];
if (count == 0 || str->len == 0) {
rc = ngx_http_echo_send_header_if_needed(r, ctx);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
return NGX_OK;
}
buf = ngx_create_temp_buf(r->pool, count * str->len);
if (buf == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
p = buf->pos;
for (i = 0; i < count; i++) {
p = ngx_copy(p, str->data, str->len);
}
buf->last = p;
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
cl->next = NULL;
cl->buf = buf;
return ngx_http_echo_send_chain_link(r, ctx, cl);
}

View file

@ -1,25 +0,0 @@
#ifndef ECHO_ECHO_H
#define ECHO_ECHO_H
#include "ngx_http_echo_module.h"
ngx_int_t ngx_http_echo_echo_init(ngx_conf_t *cf);
ngx_int_t ngx_http_echo_exec_echo_sync(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx);
ngx_int_t ngx_http_echo_exec_echo(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args,
ngx_flag_t in_filter, ngx_array_t *opts);
ngx_int_t ngx_http_echo_exec_echo_request_body(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx);
ngx_int_t ngx_http_echo_exec_echo_flush(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx);
ngx_int_t ngx_http_echo_exec_echo_duplicate(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args);
#endif /* ECHO_ECHO_H */

View file

@ -1,282 +0,0 @@
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_echo_filter.h"
#include "ngx_http_echo_util.h"
#include "ngx_http_echo_echo.h"
#include <ngx_log.h>
ngx_http_output_header_filter_pt ngx_http_echo_next_header_filter;
ngx_http_output_body_filter_pt ngx_http_echo_next_body_filter;
static ngx_int_t ngx_http_echo_header_filter(ngx_http_request_t *r);
static ngx_int_t ngx_http_echo_body_filter(ngx_http_request_t *r,
ngx_chain_t *in);
/* filter handlers */
static ngx_int_t ngx_http_echo_exec_filter_cmds(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *cmds, ngx_uint_t *iterator);
static volatile ngx_cycle_t *ngx_http_echo_prev_cycle = NULL;
ngx_int_t
ngx_http_echo_filter_init(ngx_conf_t *cf)
{
int multi_http_blocks;
ngx_http_echo_main_conf_t *emcf;
emcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_echo_module);
if (ngx_http_echo_prev_cycle != ngx_cycle) {
ngx_http_echo_prev_cycle = ngx_cycle;
multi_http_blocks = 0;
} else {
multi_http_blocks = 1;
}
if (multi_http_blocks || emcf->requires_filter) {
dd("top header filter: %ld",
(unsigned long) ngx_http_top_header_filter);
ngx_http_echo_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_echo_header_filter;
dd("top body filter: %ld", (unsigned long) ngx_http_top_body_filter);
ngx_http_echo_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_echo_body_filter;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_echo_header_filter(ngx_http_request_t *r)
{
ngx_http_echo_loc_conf_t *conf;
ngx_http_echo_ctx_t *ctx;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"echo header filter, uri \"%V?%V\"", &r->uri, &r->args);
ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module);
/* XXX we should add option to insert contents for responses
* of non-200 status code here... */
/*
if (r->headers_out.status != NGX_HTTP_OK) {
if (ctx != NULL) {
ctx->skip_filter = 1;
}
return ngx_http_echo_next_header_filter(r);
}
*/
conf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module);
if (conf->before_body_cmds == NULL && conf->after_body_cmds == NULL) {
if (ctx != NULL) {
ctx->skip_filter = 1;
}
return ngx_http_echo_next_header_filter(r);
}
if (ctx == NULL) {
ctx = ngx_http_echo_create_ctx(r);
if (ctx == NULL) {
return NGX_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_echo_module);
}
/* enable streaming here (use chunked encoding) */
ngx_http_clear_content_length(r);
ngx_http_clear_accept_ranges(r);
return ngx_http_echo_next_header_filter(r);
}
static ngx_int_t
ngx_http_echo_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_http_echo_ctx_t *ctx;
ngx_int_t rc;
ngx_http_echo_loc_conf_t *conf;
unsigned last;
ngx_chain_t *cl;
ngx_buf_t *b;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"echo body filter, uri \"%V?%V\"", &r->uri, &r->args);
if (in == NULL || r->header_only) {
return ngx_http_echo_next_body_filter(r, in);
}
ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module);
if (ctx == NULL || ctx->skip_filter) {
return ngx_http_echo_next_body_filter(r, in);
}
conf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module);
if (!ctx->before_body_sent) {
ctx->before_body_sent = 1;
if (conf->before_body_cmds != NULL) {
rc = ngx_http_echo_exec_filter_cmds(r, ctx, conf->before_body_cmds,
&ctx->next_before_body_cmd);
if (rc != NGX_OK) {
return NGX_ERROR;
}
}
}
if (conf->after_body_cmds == NULL) {
ctx->skip_filter = 1;
return ngx_http_echo_next_body_filter(r, in);
}
last = 0;
for (cl = in; cl; cl = cl->next) {
dd("cl %p, special %d", cl, ngx_buf_special(cl->buf));
if (cl->buf->last_buf || cl->buf->last_in_chain) {
cl->buf->last_buf = 0;
cl->buf->last_in_chain = 0;
cl->buf->sync = 1;
last = 1;
}
}
dd("in %p, last %d", in, (int) last);
if (in) {
rc = ngx_http_echo_next_body_filter(r, in);
#if 0
if (rc == NGX_AGAIN) {
return NGX_ERROR;
}
#endif
dd("next filter returns %d, last %d", (int) rc, (int) last);
if (rc == NGX_ERROR || rc > NGX_OK || !last) {
return rc;
}
}
dd("exec filter cmds for after body cmds");
rc = ngx_http_echo_exec_filter_cmds(r, ctx, conf->after_body_cmds,
&ctx->next_after_body_cmd);
if (rc == NGX_ERROR || rc > NGX_OK) {
dd("FAILED: exec filter cmds for after body cmds");
return NGX_ERROR;
}
ctx->skip_filter = 1;
dd("after body cmds executed...terminating...");
/* XXX we can NOT use
* ngx_http_send_special(r, NGX_HTTP_LAST) here
* because we should bypass the upstream filters. */
b = ngx_calloc_buf(r->pool);
if (b == NULL) {
return NGX_ERROR;
}
if (r == r->main && !r->post_action) {
b->last_buf = 1;
} else {
b->sync = 1;
b->last_in_chain = 1;
}
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
cl->next = NULL;
cl->buf = b;
return ngx_http_echo_next_body_filter(r, cl);
}
static ngx_int_t
ngx_http_echo_exec_filter_cmds(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *cmds, ngx_uint_t *iterator)
{
ngx_int_t rc;
ngx_array_t *opts = NULL;
ngx_array_t *computed_args = NULL;
ngx_http_echo_cmd_t *cmd;
ngx_http_echo_cmd_t *cmd_elts;
for (cmd_elts = cmds->elts; *iterator < cmds->nelts; (*iterator)++) {
cmd = &cmd_elts[*iterator];
/* evaluate arguments for the current cmd (if any) */
if (cmd->args) {
computed_args = ngx_array_create(r->pool, cmd->args->nelts,
sizeof(ngx_str_t));
if (computed_args == NULL) {
return NGX_ERROR;
}
opts = ngx_array_create(r->pool, 1, sizeof(ngx_str_t));
if (opts == NULL) {
return NGX_ERROR;
}
rc = ngx_http_echo_eval_cmd_args(r, cmd, computed_args, opts);
if (rc != NGX_OK) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"Failed to evaluate arguments for "
"the directive.");
return rc;
}
}
/* do command dispatch based on the opcode */
switch (cmd->opcode) {
case echo_opcode_echo_before_body:
case echo_opcode_echo_after_body:
dd("exec echo_before_body or echo_after_body...");
rc = ngx_http_echo_exec_echo(r, ctx, computed_args,
1 /* in filter */, opts);
if (rc == NGX_ERROR || rc > NGX_OK) {
return rc;
}
break;
default:
break;
}
}
return NGX_OK;
}

View file

@ -1,15 +0,0 @@
#ifndef ECHO_FILTER_H
#define ECHO_FILTER_H
#include "ngx_http_echo_module.h"
extern ngx_http_output_header_filter_pt ngx_http_echo_next_header_filter;
extern ngx_http_output_body_filter_pt ngx_http_echo_next_body_filter;
ngx_int_t ngx_http_echo_filter_init (ngx_conf_t *cf);
#endif /* ECHO_FILTER_H */

View file

@ -1,183 +0,0 @@
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_echo_foreach.h"
#include "ngx_http_echo_util.h"
#include <nginx.h>
ngx_int_t
ngx_http_echo_it_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ngx_http_echo_ctx_t *ctx;
ngx_uint_t i;
ngx_array_t *choices;
ngx_str_t *choice_elts, *choice;
ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module);
if (ctx && ctx->foreach != NULL) {
choices = ctx->foreach->choices;
i = ctx->foreach->next_choice;
if (i < choices->nelts) {
choice_elts = choices->elts;
choice = &choice_elts[i];
v->len = choice->len;
v->data = choice->data;
v->valid = 1;
v->no_cacheable = 1;
v->not_found = 0;
return NGX_OK;
}
}
v->not_found = 1;
return NGX_OK;
}
ngx_int_t
ngx_http_echo_exec_echo_foreach_split(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args)
{
ngx_http_echo_loc_conf_t *elcf;
ngx_str_t *delimiter, *compound;
u_char *pos, *last, *end;
ngx_str_t *choice;
ngx_str_t *computed_arg_elts;
ngx_array_t *cmds;
ngx_http_echo_cmd_t *cmd;
ngx_http_echo_cmd_t *cmd_elts;
if (ctx->foreach != NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"Nested echo_foreach not supported yet.");
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (computed_args->nelts < 2) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"echo_foreach should take at least two arguments. "
"(if your delimiter starts with \"-\", preceding it "
"with a \"--\".)");
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
computed_arg_elts = computed_args->elts;
compound = &computed_arg_elts[1];
dd("HEY coumpound len: %u", (int) compound->len);
ctx->foreach = ngx_palloc(r->pool, sizeof(ngx_http_echo_foreach_ctx_t));
if (ctx->foreach == NULL) {
return NGX_ERROR;
}
ctx->foreach->cmd_index = ctx->next_handler_cmd;
ctx->foreach->next_choice = 0;
ctx->foreach->choices = ngx_array_create(r->pool, 10, sizeof(ngx_str_t));
if (ctx->foreach->choices == NULL) {
return NGX_ERROR;
}
delimiter = &computed_arg_elts[0];
pos = compound->data;
end = compound->data + compound->len;
while ((last = ngx_http_echo_strlstrn(pos, end, delimiter->data,
delimiter->len - 1)) != NULL)
{
dd("entered the loop");
if (last == pos) {
dd("!!! len == 0");
pos = last + delimiter->len;
continue;
}
choice = ngx_array_push(ctx->foreach->choices);
if (choice == NULL) {
return NGX_ERROR;
}
choice->data = pos;
choice->len = last - pos;
pos = last + delimiter->len;
}
if (pos < end) {
choice = ngx_array_push(ctx->foreach->choices);
if (choice == NULL) {
return NGX_ERROR;
}
choice->data = pos;
choice->len = end - pos;
}
if (ctx->foreach->choices->nelts == 0) {
/* skip the foreach body entirely */
elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module);
cmds = elcf->handler_cmds;
cmd_elts = cmds->elts;
for (/* void */; ctx->next_handler_cmd < cmds->nelts;
ctx->next_handler_cmd++)
{
cmd = &cmd_elts[ctx->next_handler_cmd + 1];
if (cmd->opcode == echo_opcode_echo_end) {
return NGX_OK;
}
}
}
return NGX_OK;
}
ngx_int_t
ngx_http_echo_exec_echo_end(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx)
{
if (ctx->foreach == NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"Found a echo_end that has no corresponding echo_foreach "
"before it.");
return NGX_ERROR;
}
ctx->foreach->next_choice++;
if (ctx->foreach->next_choice >= ctx->foreach->choices->nelts) {
/* TODO We need to explicitly free the foreach ctx from
* the pool */
ctx->foreach = NULL;
return NGX_OK;
}
dd("echo_end: ++ next_choice (total: %u): %u",
(unsigned) ctx->foreach->choices->nelts,
(unsigned) ctx->foreach->next_choice);
/* the main handler dispatcher loop will increment
* ctx->next_handler_cmd for us anyway. */
ctx->next_handler_cmd = ctx->foreach->cmd_index;
return NGX_OK;
}

View file

@ -1,16 +0,0 @@
#ifndef ECHO_FOREACH_H
#define ECHO_FOREACH_H
#include "ngx_http_echo_module.h"
ngx_int_t ngx_http_echo_exec_echo_foreach_split(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args);
ngx_int_t ngx_http_echo_exec_echo_end(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx);
ngx_int_t ngx_http_echo_it_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
#endif /* ECHO_FOREACH_H */

View file

@ -1,433 +0,0 @@
/*
* Copyright (C) Yichun Zhang (agentzh)
*/
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_echo_filter.h"
#include "ngx_http_echo_handler.h"
#include "ngx_http_echo_echo.h"
#include "ngx_http_echo_util.h"
#include "ngx_http_echo_sleep.h"
#include "ngx_http_echo_var.h"
#include "ngx_http_echo_timer.h"
#include "ngx_http_echo_location.h"
#include "ngx_http_echo_subrequest.h"
#include "ngx_http_echo_request_info.h"
#include "ngx_http_echo_foreach.h"
#include <nginx.h>
#include <ngx_log.h>
void
ngx_http_echo_wev_handler(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_http_echo_ctx_t *ctx;
dd("wev handler");
ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module);
if (ctx == NULL) {
ngx_http_finalize_request(r, NGX_ERROR);
return;
}
dd("waiting: %d, done: %d", (int) ctx->waiting, (int) ctx->done);
if (ctx->waiting && ! ctx->done) {
if (r == r->connection->data && r->postponed) {
if (r->postponed->request) {
r->connection->data = r->postponed->request;
#if defined(nginx_version) && nginx_version >= 8012
ngx_http_post_request(r->postponed->request, NULL);
#else
ngx_http_post_request(r->postponed->request);
#endif
} else {
ngx_http_echo_flush_postponed_outputs(r);
}
}
return;
}
ctx->done = 0;
ctx->next_handler_cmd++;
rc = ngx_http_echo_run_cmds(r);
dd("rc: %d", (int) rc);
if (rc == NGX_ERROR || rc == NGX_DONE) {
ngx_http_finalize_request(r, rc);
return;
}
if (rc == NGX_AGAIN) {
dd("mark busy %d for %.*s", (int) ctx->next_handler_cmd,
(int) r->uri.len,
r->uri.data);
ctx->waiting = 1;
ctx->done = 0;
} else {
dd("mark ready %d", (int) ctx->next_handler_cmd);
ctx->waiting = 0;
ctx->done = 1;
dd("finalizing with rc %d", (int) rc);
dd("finalize request %.*s with %d", (int) r->uri.len, r->uri.data,
(int) rc);
ngx_http_finalize_request(r, rc);
}
}
ngx_int_t
ngx_http_echo_handler(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_http_echo_ctx_t *ctx;
dd("subrequest in memory: %d", (int) r->subrequest_in_memory);
rc = ngx_http_echo_run_cmds(r);
dd("run cmds returned %d", (int) rc);
if (rc == NGX_ERROR
|| rc == NGX_OK
|| rc == NGX_DONE
|| rc == NGX_DECLINED)
{
return rc;
}
ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module);
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
if (ctx && r->header_sent) {
return NGX_ERROR;
}
return rc;
}
/* rc == NGX_AGAIN */
#if defined(nginx_version) && nginx_version >= 8011
r->main->count++;
#endif
dd("%d", r->connection->destroyed);
dd("%d", r->done);
if (ctx) {
dd("mark busy %d for %.*s", (int) ctx->next_handler_cmd,
(int) r->uri.len,
r->uri.data);
ctx->waiting = 1;
ctx->done = 0;
}
return NGX_DONE;
}
ngx_int_t
ngx_http_echo_run_cmds(ngx_http_request_t *r)
{
ngx_http_echo_loc_conf_t *elcf;
ngx_http_echo_ctx_t *ctx;
ngx_int_t rc;
ngx_array_t *cmds;
ngx_array_t *computed_args = NULL;
ngx_http_echo_cmd_t *cmd;
ngx_http_echo_cmd_t *cmd_elts;
ngx_array_t *opts = NULL;
elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module);
cmds = elcf->handler_cmds;
if (cmds == NULL) {
return NGX_DECLINED;
}
ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module);
if (ctx == NULL) {
ctx = ngx_http_echo_create_ctx(r);
if (ctx == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_echo_module);
}
dd("exec handler: %.*s: %i", (int) r->uri.len, r->uri.data,
(int) ctx->next_handler_cmd);
cmd_elts = cmds->elts;
for (; ctx->next_handler_cmd < cmds->nelts; ctx->next_handler_cmd++) {
cmd = &cmd_elts[ctx->next_handler_cmd];
/* evaluate arguments for the current cmd (if any) */
if (cmd->args) {
computed_args = ngx_array_create(r->pool, cmd->args->nelts,
sizeof(ngx_str_t));
if (computed_args == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
opts = ngx_array_create(r->pool, 1, sizeof(ngx_str_t));
if (opts == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
rc = ngx_http_echo_eval_cmd_args(r, cmd, computed_args, opts);
if (rc != NGX_OK) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"Failed to evaluate arguments for "
"the directive.");
return rc;
}
}
if (computed_args == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
/* do command dispatch based on the opcode */
switch (cmd->opcode) {
case echo_opcode_echo_sync:
rc = ngx_http_echo_exec_echo_sync(r, ctx);
break;
case echo_opcode_echo:
/* XXX moved the following code to a separate
* function */
dd("found echo opcode");
rc = ngx_http_echo_exec_echo(r, ctx, computed_args,
0 /* in filter */, opts);
break;
case echo_opcode_echo_request_body:
rc = ngx_http_echo_exec_echo_request_body(r, ctx);
break;
case echo_opcode_echo_location_async:
if (!r->request_body) {
/* we require reading the request body before doing
* subrequests */
ctx->next_handler_cmd--; /* re-run the current cmd */
goto read_request_body;
}
dd("found opcode echo location async...");
rc = ngx_http_echo_exec_echo_location_async(r, ctx,
computed_args);
break;
case echo_opcode_echo_location:
if (!r->request_body) {
/* we require reading the request body before doing
* subrequests */
ctx->next_handler_cmd--; /* re-run the current cmd */
goto read_request_body;
}
return ngx_http_echo_exec_echo_location(r, ctx, computed_args);
case echo_opcode_echo_subrequest_async:
if (!r->request_body) {
/* we require reading the request body before doing
* subrequests */
ctx->next_handler_cmd--; /* re-run the current cmd */
goto read_request_body;
}
dd("found opcode echo subrequest async...");
rc = ngx_http_echo_exec_echo_subrequest_async(r, ctx,
computed_args);
break;
case echo_opcode_echo_subrequest:
if (!r->request_body) {
/* we require reading the request body before doing
* subrequests */
ctx->next_handler_cmd--; /* re-run the current cmd */
goto read_request_body;
}
return ngx_http_echo_exec_echo_subrequest(r, ctx, computed_args);
case echo_opcode_echo_sleep:
return ngx_http_echo_exec_echo_sleep(r, ctx, computed_args);
case echo_opcode_echo_flush:
rc = ngx_http_echo_exec_echo_flush(r, ctx);
break;
case echo_opcode_echo_blocking_sleep:
rc = ngx_http_echo_exec_echo_blocking_sleep(r, ctx,
computed_args);
break;
case echo_opcode_echo_reset_timer:
rc = ngx_http_echo_exec_echo_reset_timer(r, ctx);
break;
case echo_opcode_echo_duplicate:
rc = ngx_http_echo_exec_echo_duplicate(r, ctx, computed_args);
break;
case echo_opcode_echo_read_request_body:
read_request_body:
ctx->wait_read_request_body = 0;
rc = ngx_http_echo_exec_echo_read_request_body(r, ctx);
if (rc == NGX_ERROR) {
return NGX_ERROR;
}
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
#if (nginx_version >= 8011 && nginx_version < 1002006) \
|| (nginx_version >= 1003000 && nginx_version < 1003009)
r->main->count--;
#endif
return rc;
}
#if nginx_version >= 8011
r->main->count--;
#endif
dd("read request body: %d", (int) rc);
if (rc == NGX_OK) {
continue;
}
/* rc == NGX_AGAIN */
ctx->wait_read_request_body = 1;
return NGX_AGAIN;
case echo_opcode_echo_foreach_split:
rc = ngx_http_echo_exec_echo_foreach_split(r, ctx, computed_args);
break;
case echo_opcode_echo_end:
rc = ngx_http_echo_exec_echo_end(r, ctx);
break;
case echo_opcode_echo_exec:
dd("echo_exec");
return ngx_http_echo_exec_exec(r, ctx, computed_args);
default:
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"unknown opcode: %d", cmd->opcode);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
return rc;
}
}
rc = ngx_http_echo_send_chain_link(r, ctx, NULL /* indicate LAST */);
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
return rc;
}
if (!r->request_body) {
if (ngx_http_discard_request_body(r) != NGX_OK) {
return NGX_ERROR;
}
}
return NGX_OK;
}
ngx_int_t
ngx_http_echo_post_subrequest(ngx_http_request_t *r,
void *data, ngx_int_t rc)
{
ngx_http_echo_ctx_t *ctx = data;
ngx_http_request_t *pr;
ngx_http_echo_ctx_t *pr_ctx;
dd("echo post_subrequest: %.*s", (int) r->uri.len, r->uri.data);
if (ctx->run_post_subrequest) {
dd("already run post_subrequest: %p: %.*s", ctx,
(int) r->uri.len, r->uri.data);
return rc;
}
dd("setting run_post_subrequest to 1 for %p for %.*s", ctx,
(int) r->uri.len, r->uri.data);
ctx->run_post_subrequest = 1;
pr = r->parent;
pr_ctx = ngx_http_get_module_ctx(pr, ngx_http_echo_module);
if (pr_ctx == NULL) {
return NGX_ERROR;
}
dd("mark ready %d", (int) pr_ctx->next_handler_cmd);
pr_ctx->waiting = 0;
pr_ctx->done = 1;
pr->write_event_handler = ngx_http_echo_wev_handler;
/* work-around issues in nginx's event module */
if (r != r->connection->data
&& r->postponed
&& (r->main->posted_requests == NULL
|| r->main->posted_requests->request != pr))
{
#if defined(nginx_version) && nginx_version >= 8012
ngx_http_post_request(pr, NULL);
#else
ngx_http_post_request(pr);
#endif
}
return rc;
}

View file

@ -1,18 +0,0 @@
#ifndef ECHO_HANDLER_H
#define ECHO_HANDLER_H
#include "ngx_http_echo_module.h"
void ngx_http_echo_wev_handler(ngx_http_request_t *r);
ngx_int_t ngx_http_echo_handler(ngx_http_request_t *r);
ngx_int_t ngx_http_echo_run_cmds(ngx_http_request_t *r);
ngx_int_t ngx_http_echo_post_subrequest(ngx_http_request_t *r,
void *data, ngx_int_t rc);
#endif /* ECHO_HANDLER_H */

View file

@ -1,182 +0,0 @@
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_echo_util.h"
#include "ngx_http_echo_location.h"
#include "ngx_http_echo_handler.h"
#include <nginx.h>
static ngx_int_t ngx_http_echo_adjust_subrequest(ngx_http_request_t *sr);
ngx_int_t
ngx_http_echo_exec_echo_location_async(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args)
{
ngx_int_t rc;
ngx_http_request_t *sr; /* subrequest object */
ngx_str_t *computed_arg_elts;
ngx_str_t location;
ngx_str_t *url_args;
ngx_str_t args;
ngx_uint_t flags = 0;
dd_enter();
computed_arg_elts = computed_args->elts;
location = computed_arg_elts[0];
if (location.len == 0) {
return NGX_ERROR;
}
if (computed_args->nelts > 1) {
url_args = &computed_arg_elts[1];
} else {
url_args = NULL;
}
args.data = NULL;
args.len = 0;
if (ngx_http_parse_unsafe_uri(r, &location, &args, &flags) != NGX_OK) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"echo_location_async sees unsafe uri: \"%V\"",
&location);
return NGX_ERROR;
}
if (args.len > 0 && url_args == NULL) {
url_args = &args;
}
rc = ngx_http_echo_send_header_if_needed(r, ctx);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
rc = ngx_http_subrequest(r, &location, url_args, &sr, NULL, 0);
if (rc != NGX_OK) {
return NGX_ERROR;
}
rc = ngx_http_echo_adjust_subrequest(sr);
if (rc != NGX_OK) {
return NGX_ERROR;
}
return NGX_OK;
}
ngx_int_t
ngx_http_echo_exec_echo_location(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args)
{
ngx_int_t rc;
ngx_http_request_t *sr; /* subrequest object */
ngx_str_t *computed_arg_elts;
ngx_str_t location;
ngx_str_t *url_args;
ngx_http_post_subrequest_t *psr;
ngx_str_t args;
ngx_uint_t flags = 0;
ngx_http_echo_ctx_t *sr_ctx;
if (computed_args == NULL) {
return NGX_ERROR;
}
computed_arg_elts = computed_args->elts;
location = computed_arg_elts[0];
if (location.len == 0) {
return NGX_ERROR;
}
if (computed_args->nelts > 1) {
url_args = &computed_arg_elts[1];
} else {
url_args = NULL;
}
args.data = NULL;
args.len = 0;
if (ngx_http_parse_unsafe_uri(r, &location, &args, &flags) != NGX_OK) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"echo_location sees unsafe uri: \"%V\"",
&location);
return NGX_ERROR;
}
if (args.len > 0 && url_args == NULL) {
url_args = &args;
}
rc = ngx_http_echo_send_header_if_needed(r, ctx);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
sr_ctx = ngx_http_echo_create_ctx(r);
psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
if (psr == NULL) {
return NGX_ERROR;
}
psr->handler = ngx_http_echo_post_subrequest;
psr->data = sr_ctx;
rc = ngx_http_subrequest(r, &location, url_args, &sr, psr, 0);
if (rc != NGX_OK) {
return NGX_ERROR;
}
rc = ngx_http_echo_adjust_subrequest(sr);
if (rc != NGX_OK) {
return NGX_ERROR;
}
return NGX_AGAIN;
}
static ngx_int_t
ngx_http_echo_adjust_subrequest(ngx_http_request_t *sr)
{
ngx_http_core_main_conf_t *cmcf;
ngx_http_request_t *r;
/* we do not inherit the parent request's variables */
cmcf = ngx_http_get_module_main_conf(sr, ngx_http_core_module);
r = sr->parent;
sr->header_in = r->header_in;
/* XXX work-around a bug in ngx_http_subrequest */
if (r->headers_in.headers.last == &r->headers_in.headers.part) {
sr->headers_in.headers.last = &sr->headers_in.headers.part;
}
sr->variables = ngx_pcalloc(sr->pool, cmcf->variables.nelts
* sizeof(ngx_http_variable_value_t));
if (sr->variables == NULL) {
return NGX_ERROR;
}
return NGX_OK;
}

View file

@ -1,13 +0,0 @@
#ifndef ECHO_LOCATION_H
#define ECHO_LOCATION_H
#include "ngx_http_echo_module.h"
ngx_int_t ngx_http_echo_exec_echo_location_async(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args);
ngx_int_t ngx_http_echo_exec_echo_location(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args);
#endif /* ECHO_LOCATION_H */

View file

@ -1,682 +0,0 @@
/*
* Copyright (C) Yichun Zhang (agentzh)
*/
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_echo_handler.h"
#include "ngx_http_echo_filter.h"
#include "ngx_http_echo_echo.h"
#include "ngx_http_echo_request_info.h"
#include "ngx_http_echo_var.h"
#include "ngx_http_echo_util.h"
#include <nginx.h>
#include <ngx_config.h>
#include <ngx_log.h>
/* config init handler */
static void *ngx_http_echo_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent,
void *child);
static void *ngx_http_echo_create_main_conf(ngx_conf_t *cf);
static ngx_int_t ngx_http_echo_post_config(ngx_conf_t *cf);
/* config directive handlers */
static char *ngx_http_echo_echo(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_echo_echo_request_body(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_echo_echo_sleep(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_echo_echo_flush(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_echo_echo_blocking_sleep(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_echo_echo_reset_timer(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_echo_echo_before_body(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_echo_echo_after_body(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_echo_echo_location_async(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_echo_echo_location(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_echo_echo_subrequest_async(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_echo_echo_subrequest(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_echo_echo_duplicate(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_echo_echo_read_request_body(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_echo_echo_foreach_split(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_echo_echo_end(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_echo_echo_abort_parent(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_echo_echo_exec(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_http_echo_helper(ngx_http_echo_opcode_t opcode,
ngx_http_echo_cmd_category_t cat,
ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_http_module_t ngx_http_echo_module_ctx = {
NULL, /* preconfiguration */
ngx_http_echo_post_config, /* postconfiguration */
ngx_http_echo_create_main_conf, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_echo_create_loc_conf, /* create location configuration */
ngx_http_echo_merge_loc_conf /* merge location configuration */
};
static ngx_command_t ngx_http_echo_commands[] = {
{ ngx_string("echo"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_ANY,
ngx_http_echo_echo,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_request_body"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS,
ngx_http_echo_echo_request_body,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_sleep"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
ngx_http_echo_echo_sleep,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_flush"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS,
ngx_http_echo_echo_flush,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_blocking_sleep"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
ngx_http_echo_echo_blocking_sleep,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_reset_timer"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS,
ngx_http_echo_echo_reset_timer,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_before_body"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_ANY,
ngx_http_echo_echo_before_body,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, before_body_cmds),
NULL },
{ ngx_string("echo_after_body"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_ANY,
ngx_http_echo_echo_after_body,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, after_body_cmds),
NULL },
{ ngx_string("echo_location_async"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12,
ngx_http_echo_echo_location_async,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_location"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12,
ngx_http_echo_echo_location,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_subrequest_async"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE,
ngx_http_echo_echo_subrequest_async,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_subrequest"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE,
ngx_http_echo_echo_subrequest,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_duplicate"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE,
ngx_http_echo_echo_duplicate,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_read_request_body"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS,
ngx_http_echo_echo_read_request_body,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_foreach_split"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE,
ngx_http_echo_echo_foreach_split,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_end"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS,
ngx_http_echo_echo_end,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_abort_parent"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS,
ngx_http_echo_echo_abort_parent,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_exec"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12,
ngx_http_echo_echo_exec,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
NULL },
{ ngx_string("echo_status"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t, status),
NULL },
ngx_null_command
};
ngx_module_t ngx_http_echo_module = {
NGX_MODULE_V1,
&ngx_http_echo_module_ctx, /* module context */
ngx_http_echo_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static void *
ngx_http_echo_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_echo_loc_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_loc_conf_t));
if (conf == NULL) {
return NULL;
}
/* set by ngx_pcalloc
* conf->handler_cmds = NULL
* conf->before_body_cmds = NULL
* conf->after_body_cmds = NULL
* conf->seen_leading_output = 0
* conf->seen_trailing_output = 0
*/
conf->status = NGX_CONF_UNSET;
return conf;
}
static char *
ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_echo_loc_conf_t *prev = parent;
ngx_http_echo_loc_conf_t *conf = child;
if (conf->handler_cmds == NULL) {
conf->handler_cmds = prev->handler_cmds;
conf->seen_leading_output = prev->seen_leading_output;
}
if (conf->before_body_cmds == NULL) {
conf->before_body_cmds = prev->before_body_cmds;
}
if (conf->after_body_cmds == NULL) {
conf->after_body_cmds = prev->after_body_cmds;
}
ngx_conf_merge_value(conf->status, prev->status, 200);
return NGX_CONF_OK;
}
static char *
ngx_http_echo_helper(ngx_http_echo_opcode_t opcode,
ngx_http_echo_cmd_category_t cat,
ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_str_t *raw_args;
ngx_uint_t i, n;
ngx_array_t **args_ptr;
ngx_array_t **cmds_ptr;
ngx_http_echo_cmd_t *echo_cmd;
ngx_http_core_loc_conf_t *clcf;
ngx_http_script_compile_t sc;
ngx_http_echo_main_conf_t *emcf;
ngx_http_echo_arg_template_t *arg;
emcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_echo_module);
/* cmds_ptr points to ngx_http_echo_loc_conf_t's
* handler_cmds, before_body_cmds, or after_body_cmds
* array, depending on the actual offset */
cmds_ptr = (ngx_array_t **) (((u_char *) conf) + cmd->offset);
if (*cmds_ptr == NULL) {
*cmds_ptr = ngx_array_create(cf->pool, 1,
sizeof(ngx_http_echo_cmd_t));
if (*cmds_ptr == NULL) {
return NGX_CONF_ERROR;
}
if (cat == echo_handler_cmd) {
dd("registering the content handler");
/* register the content handler */
clcf = ngx_http_conf_get_module_loc_conf(cf,
ngx_http_core_module);
dd("registering the content handler (2)");
clcf->handler = ngx_http_echo_handler;
} else {
dd("filter used = 1");
emcf->requires_filter = 1;
}
}
echo_cmd = ngx_array_push(*cmds_ptr);
if (echo_cmd == NULL) {
return NGX_CONF_ERROR;
}
echo_cmd->opcode = opcode;
args_ptr = &echo_cmd->args;
*args_ptr = ngx_array_create(cf->pool, 1,
sizeof(ngx_http_echo_arg_template_t));
if (*args_ptr == NULL) {
return NGX_CONF_ERROR;
}
raw_args = cf->args->elts;
/* we skip the first arg and start from the second */
for (i = 1 ; i < cf->args->nelts; i++) {
arg = ngx_array_push(*args_ptr);
if (arg == NULL) {
return NGX_CONF_ERROR;
}
arg->raw_value = raw_args[i];
dd("found raw arg %s", raw_args[i].data);
arg->lengths = NULL;
arg->values = NULL;
n = ngx_http_script_variables_count(&arg->raw_value);
if (n > 0) {
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
sc.cf = cf;
sc.source = &arg->raw_value;
sc.lengths = &arg->lengths;
sc.values = &arg->values;
sc.variables = n;
sc.complete_lengths = 1;
sc.complete_values = 1;
if (ngx_http_script_compile(&sc) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
} /* end for */
return NGX_CONF_OK;
}
static char *
ngx_http_echo_echo(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_echo_loc_conf_t *elcf = conf;
if (!elcf->seen_leading_output) {
elcf->seen_leading_output = 1;
}
dd("in echo_echo...");
return ngx_http_echo_helper(echo_opcode_echo, echo_handler_cmd,
cf, cmd, conf);
}
static char *
ngx_http_echo_echo_request_body(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
ngx_http_echo_loc_conf_t *elcf = conf;
if (!elcf->seen_leading_output) {
elcf->seen_leading_output = 1;
}
dd("in echo_echo_request_body...");
return ngx_http_echo_helper(echo_opcode_echo_request_body, echo_handler_cmd,
cf, cmd, conf);
}
static char *
ngx_http_echo_echo_sleep(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
dd("in echo_sleep...");
return ngx_http_echo_helper(echo_opcode_echo_sleep, echo_handler_cmd,
cf, cmd, conf);
}
static char *
ngx_http_echo_echo_flush(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_echo_loc_conf_t *elcf = conf;
if (!elcf->seen_leading_output) {
elcf->seen_leading_output = 1;
}
dd("in echo_flush...");
return ngx_http_echo_helper(echo_opcode_echo_flush, echo_handler_cmd,
cf, cmd, conf);
}
static char *
ngx_http_echo_echo_blocking_sleep(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
dd("in echo_blocking_sleep...");
return ngx_http_echo_helper(echo_opcode_echo_blocking_sleep,
echo_handler_cmd, cf, cmd, conf);
}
static char *
ngx_http_echo_echo_reset_timer(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
return ngx_http_echo_helper(echo_opcode_echo_reset_timer, echo_handler_cmd,
cf, cmd, conf);
}
static char *
ngx_http_echo_echo_before_body(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
dd("processing echo_before_body directive...");
return ngx_http_echo_helper(echo_opcode_echo_before_body, echo_filter_cmd,
cf, cmd, conf);
}
static char *
ngx_http_echo_echo_after_body(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
return ngx_http_echo_helper(echo_opcode_echo_after_body, echo_filter_cmd,
cf, cmd, conf);
}
static char *
ngx_http_echo_echo_location_async(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
ngx_http_echo_loc_conf_t *elcf = conf;
char *ret;
if (!elcf->seen_leading_output) {
elcf->seen_leading_output = 1;
ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd,
cf, cmd, conf);
if (ret != NGX_CONF_OK) {
return ret;
}
}
return ngx_http_echo_helper(echo_opcode_echo_location_async,
echo_handler_cmd, cf, cmd, conf);
}
static char *
ngx_http_echo_echo_location(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_echo_loc_conf_t *elcf = conf;
char *ret;
if (!elcf->seen_leading_output) {
elcf->seen_leading_output = 1;
ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd,
cf, cmd, conf);
if (ret != NGX_CONF_OK) {
return ret;
}
}
return ngx_http_echo_helper(echo_opcode_echo_location, echo_handler_cmd,
cf, cmd, conf);
}
static char *
ngx_http_echo_echo_subrequest_async(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
char *ret;
ngx_http_echo_loc_conf_t *elcf = conf;
if (!elcf->seen_leading_output) {
elcf->seen_leading_output = 1;
ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd,
cf, cmd, conf);
if (ret != NGX_CONF_OK) {
return ret;
}
}
return ngx_http_echo_helper(echo_opcode_echo_subrequest_async,
echo_handler_cmd, cf, cmd, conf);
}
static char *
ngx_http_echo_echo_subrequest(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
ngx_http_echo_loc_conf_t *elcf = conf;
char *ret;
if (!elcf->seen_leading_output) {
elcf->seen_leading_output = 1;
ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd,
cf, cmd, conf);
if (ret != NGX_CONF_OK) {
return ret;
}
}
return ngx_http_echo_helper(echo_opcode_echo_subrequest, echo_handler_cmd,
cf, cmd, conf);
}
static char *
ngx_http_echo_echo_duplicate(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_echo_loc_conf_t *elcf = conf;
if (!elcf->seen_leading_output) {
elcf->seen_leading_output = 1;
}
return ngx_http_echo_helper(echo_opcode_echo_duplicate, echo_handler_cmd,
cf, cmd, conf);
}
static char *
ngx_http_echo_echo_read_request_body(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
return ngx_http_echo_helper(echo_opcode_echo_read_request_body,
echo_handler_cmd, cf, cmd, conf);
}
static char *
ngx_http_echo_echo_foreach_split(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
return ngx_http_echo_helper(echo_opcode_echo_foreach_split,
echo_handler_cmd, cf, cmd, conf);
}
static char *
ngx_http_echo_echo_end(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
return ngx_http_echo_helper(echo_opcode_echo_end, echo_handler_cmd, cf,
cmd, conf);
}
static char *
ngx_http_echo_echo_abort_parent(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
return ngx_http_echo_helper(echo_opcode_echo_abort_parent, echo_handler_cmd,
cf, cmd, conf);
}
static char *
ngx_http_echo_echo_exec(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
return ngx_http_echo_helper(echo_opcode_echo_exec, echo_handler_cmd,
cf, cmd, conf);
}
static void *
ngx_http_echo_create_main_conf(ngx_conf_t *cf)
{
#if nginx_version >= 1011011
ngx_pool_cleanup_t *cln;
#endif
ngx_http_echo_main_conf_t *emcf;
emcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_main_conf_t));
if (emcf == NULL) {
return NULL;
}
/* set by ngx_pcalloc:
* hmcf->requires_filter = 0;
*/
#if nginx_version >= 1011011
cln = ngx_pool_cleanup_add(cf->pool, 0);
if (cln == NULL) {
return NULL;
}
cln->data = emcf;
cln->handler = ngx_http_echo_request_headers_cleanup;
#endif
return emcf;
}
static ngx_int_t
ngx_http_echo_post_config(ngx_conf_t *cf)
{
ngx_int_t rc;
rc = ngx_http_echo_filter_init(cf);
if (rc != NGX_OK) {
return rc;
}
rc = ngx_http_echo_echo_init(cf);
if (rc != NGX_OK) {
return rc;
}
ngx_http_echo_content_length_hash =
ngx_http_echo_hash_literal("content-length");
return ngx_http_echo_add_variables(cf);
}

View file

@ -1,151 +0,0 @@
/*
* Copyright (C) Yichun Zhang (agentzh)
*/
#ifndef NGX_HTTP_ECHO_MODULE_H
#define NGX_HTTP_ECHO_MODULE_H
#include <ngx_core.h>
#include <ngx_http.h>
#include <nginx.h>
extern ngx_module_t ngx_http_echo_module;
/* config directive's opcode */
typedef enum {
echo_opcode_echo_sync,
echo_opcode_echo,
echo_opcode_echo_request_body,
echo_opcode_echo_sleep,
echo_opcode_echo_flush,
echo_opcode_echo_blocking_sleep,
echo_opcode_echo_reset_timer,
echo_opcode_echo_before_body,
echo_opcode_echo_after_body,
echo_opcode_echo_location_async,
echo_opcode_echo_location,
echo_opcode_echo_subrequest_async,
echo_opcode_echo_subrequest,
echo_opcode_echo_duplicate,
echo_opcode_echo_read_request_body,
echo_opcode_echo_foreach_split,
echo_opcode_echo_end,
echo_opcode_echo_abort_parent,
echo_opcode_echo_exec
} ngx_http_echo_opcode_t;
/* all the various config directives (or commands) are
* divided into two categories: "handler commands",
* and "filter commands". For instance, the "echo"
* directive is a handler command while
* "echo_before_body" is a filter one. */
typedef enum {
echo_handler_cmd,
echo_filter_cmd
} ngx_http_echo_cmd_category_t;
/* compiled form of a config directive argument's value */
typedef struct {
/* holds the raw string of the argument value */
ngx_str_t raw_value;
/* fields "lengths" and "values" are set by
* the function ngx_http_script_compile,
* iff the argument value indeed contains
* nginx variables like "$foo" */
ngx_array_t *lengths;
ngx_array_t *values;
} ngx_http_echo_arg_template_t;
/* represent a config directive (or command) like "echo". */
typedef struct {
ngx_http_echo_opcode_t opcode;
/* each argument is of type echo_arg_template_t: */
ngx_array_t *args;
} ngx_http_echo_cmd_t;
/* location config struct */
typedef struct {
/* elements of the following arrays are of type
* ngx_http_echo_cmd_t */
ngx_array_t *handler_cmds;
ngx_array_t *before_body_cmds;
ngx_array_t *after_body_cmds;
unsigned seen_leading_output;
ngx_int_t status;
} ngx_http_echo_loc_conf_t;
typedef struct {
ngx_int_t requires_filter;
#if nginx_version >= 1011011
ngx_buf_t **busy_buf_ptrs;
ngx_int_t busy_buf_ptr_count;
#endif
} ngx_http_echo_main_conf_t;
typedef struct {
ngx_array_t *choices; /* items after splitting */
ngx_uint_t next_choice; /* current item index */
ngx_uint_t cmd_index; /* cmd index for the echo_foreach direcitve */
} ngx_http_echo_foreach_ctx_t;
/* context struct in the request handling cycle, holding
* the current states of the command evaluator */
typedef struct {
/* index of the next handler command in
* ngx_http_echo_loc_conf_t's "handler_cmds" array. */
ngx_uint_t next_handler_cmd;
/* index of the next before-body filter command in
* ngx_http_echo_loc_conf_t's "before_body_cmds" array. */
ngx_uint_t next_before_body_cmd;
/* index of the next after-body filter command in
* ngx_http_echo_loc_conf_t's "after_body_cmds" array. */
ngx_uint_t next_after_body_cmd;
ngx_http_echo_foreach_ctx_t *foreach;
ngx_time_t timer_begin;
ngx_event_t sleep;
ngx_uint_t counter;
unsigned before_body_sent:1;
unsigned skip_filter:1;
unsigned wait_read_request_body:1;
unsigned waiting:1;
unsigned done:1;
unsigned run_post_subrequest:1;
unsigned header_sent:1; /* r->header_sent is not sufficient
* because special header filters like
* ngx_http_image_filter_module's may
* intercept the whole header filter chain
* leaving r->header_sent unset. So we
* should always test both flags. */
} ngx_http_echo_ctx_t;
#endif /* NGX_HTTP_ECHO_MODULE_H */

View file

@ -1,522 +0,0 @@
/*
* Copyright (C) Yichun Zhang (agentzh)
*/
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_echo_request_info.h"
#include "ngx_http_echo_util.h"
#include "ngx_http_echo_handler.h"
#include <nginx.h>
static void ngx_http_echo_post_read_request_body(ngx_http_request_t *r);
#if nginx_version >= 1011011
void ngx_http_echo_request_headers_cleanup(void *data);
#endif
ngx_int_t
ngx_http_echo_exec_echo_read_request_body(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx)
{
return ngx_http_read_client_request_body(r,
ngx_http_echo_post_read_request_body);
}
static void
ngx_http_echo_post_read_request_body(ngx_http_request_t *r)
{
ngx_http_echo_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module);
dd("wait read request body %d", (int) ctx->wait_read_request_body);
if (ctx->wait_read_request_body) {
ctx->waiting = 0;
ctx->done = 1;
r->write_event_handler = ngx_http_echo_wev_handler;
ngx_http_echo_wev_handler(r);
}
}
/* this function's implementation is borrowed from nginx 0.8.20
* and modified a bit to work with subrequests.
* Copyrighted (C) by Igor Sysoev */
ngx_int_t
ngx_http_echo_request_method_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->method_name.data) {
v->len = r->method_name.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = r->method_name.data;
} else {
v->not_found = 1;
}
return NGX_OK;
}
/* this function's implementation is borrowed from nginx 0.8.20
* and modified a bit to work with subrequests.
* Copyrighted (C) by Igor Sysoev */
ngx_int_t
ngx_http_echo_client_request_method_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->main->method_name.data) {
v->len = r->main->method_name.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = r->main->method_name.data;
} else {
v->not_found = 1;
}
return NGX_OK;
}
/* this function's implementation is borrowed from nginx 0.8.20
* and modified a bit to work with subrequests.
* Copyrighted (C) by Igor Sysoev */
ngx_int_t
ngx_http_echo_request_body_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p;
size_t len;
ngx_buf_t *b;
ngx_chain_t *cl;
ngx_chain_t *in;
if (r->request_body == NULL
|| r->request_body->bufs == NULL
|| r->request_body->temp_file)
{
v->not_found = 1;
return NGX_OK;
}
in = r->request_body->bufs;
len = 0;
for (cl = in; cl; cl = cl->next) {
b = cl->buf;
if (!ngx_buf_in_memory(b)) {
if (b->in_file) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"variable echo_request_body sees in-file only "
"buffers and discard the whole body data");
v->not_found = 1;
return NGX_OK;
}
} else {
len += b->last - b->pos;
}
}
p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
return NGX_ERROR;
}
v->data = p;
for (cl = in; cl; cl = cl->next) {
b = cl->buf;
if (ngx_buf_in_memory(b)) {
p = ngx_copy(p, b->pos, b->last - b->pos);
}
}
if (p - v->data != (ssize_t) len) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"variable echo_request_body: buffer error");
v->not_found = 1;
return NGX_OK;
}
v->len = len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
return NGX_OK;
}
ngx_int_t
ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
int line_break_len;
size_t size;
u_char *p, *last, *pos;
ngx_int_t i, j;
ngx_buf_t *b, *first = NULL;
unsigned found;
#if nginx_version >= 1011011
ngx_buf_t **bb;
ngx_chain_t *cl;
ngx_http_echo_main_conf_t *emcf;
#endif
ngx_connection_t *c;
ngx_http_request_t *mr;
ngx_http_connection_t *hc;
mr = r->main;
hc = r->main->http_connection;
c = mr->connection;
#if (NGX_HTTP_V2)
/* TODO */
if (mr->stream) {
v->not_found = 1;
return NGX_OK;
}
#endif
#if nginx_version >= 1011011
emcf = ngx_http_get_module_main_conf(r, ngx_http_echo_module);
#endif
size = 0;
b = c->buffer;
if (mr->request_line.data[mr->request_line.len] == CR) {
line_break_len = 2;
} else {
line_break_len = 1;
}
if (mr->request_line.data >= b->start
&& mr->request_line.data + mr->request_line.len + line_break_len
<= b->pos)
{
first = b;
size += b->pos - mr->request_line.data;
}
if (hc->nbusy) {
b = NULL;
#if nginx_version >= 1011011
if (hc->nbusy > emcf->busy_buf_ptr_count) {
if (emcf->busy_buf_ptrs) {
ngx_free(emcf->busy_buf_ptrs);
}
emcf->busy_buf_ptrs = ngx_alloc(hc->nbusy * sizeof(ngx_buf_t *),
r->connection->log);
if (emcf->busy_buf_ptrs == NULL) {
return NGX_ERROR;
}
emcf->busy_buf_ptr_count = hc->nbusy;
}
bb = emcf->busy_buf_ptrs;
for (cl = hc->busy; cl; cl = cl->next) {
*bb++ = cl->buf;
}
bb = emcf->busy_buf_ptrs;
for (i = hc->nbusy; i > 0; i--) {
b = bb[i - 1];
#else
for (i = 0; i < hc->nbusy; i++) {
b = hc->busy[i];
#endif
if (first == NULL) {
if (mr->request_line.data >= b->pos
|| mr->request_line.data + mr->request_line.len
+ line_break_len <= b->start)
{
continue;
}
dd("found first at %d", (int) i);
first = b;
}
size += b->pos - b->start;
}
}
size++; /* plus the null terminator, as required by the later
ngx_strstr() call */
v->data = ngx_palloc(r->pool, size);
if (v->data == NULL) {
return NGX_ERROR;
}
last = v->data;
b = c->buffer;
found = 0;
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') {
i++;
if (p + 1 != last && *(p + 1) == LF) {
*p = CR;
} else if (i % 2 == 1) {
*p = ':';
} else {
*p = LF;
}
}
}
}
if (hc->nbusy) {
#if nginx_version >= 1011011
bb = emcf->busy_buf_ptrs;
for (i = hc->nbusy; i > 0; i--) {
b = bb[i - 1];
#else
for (i = 0; i < hc->nbusy; i++) {
b = hc->busy[i];
#endif
if (!found) {
if (b != first) {
continue;
}
dd("found first");
found = 1;
}
p = last;
pos = b->pos;
if (b == first) {
dd("request line: %.*s", (int) mr->request_line.len,
mr->request_line.data);
last = ngx_copy(last,
mr->request_line.data,
pos - mr->request_line.data);
} else {
last = ngx_copy(last, b->start, pos - b->start);
}
#if 1
/* skip truncated header entries (if any) */
while (last > p && last[-1] != LF) {
last--;
}
#endif
j = 0;
for (; p != last; p++) {
if (*p == '\0') {
j++;
if (p + 1 == last) {
/* XXX this should not happen */
dd("found string end!!");
} else if (*(p + 1) == LF) {
*p = CR;
} else if (j % 2 == 1) {
*p = ':';
} else {
*p = LF;
}
}
}
if (b == mr->header_in) {
break;
}
}
}
*last++ = '\0';
if (last - v->data > (ssize_t) size) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"buffer error when evaluating "
"$echo_client__request_headers: \"%V\"",
(ngx_int_t) (last - v->data - size));
return NGX_ERROR;
}
/* strip the leading part (if any) of the request body in our header.
* the first part of the request body could slip in because nginx core's
* ngx_http_request_body_length_filter and etc can move r->header_in->pos
* in case that some of the body data has been preread into r->header_in.
*/
if ((p = (u_char *) ngx_strstr(v->data, CRLF CRLF)) != NULL) {
last = p + sizeof(CRLF CRLF) - 1;
} else if ((p = (u_char *) ngx_strstr(v->data, CRLF "\n")) != NULL) {
last = p + sizeof(CRLF "\n") - 1;
} else if ((p = (u_char *) ngx_strstr(v->data, "\n" CRLF)) != NULL) {
last = p + sizeof("\n" CRLF) - 1;
} else {
for (p = last - 1; p - v->data >= 2; p--) {
if (p[0] == LF && p[-1] == CR) {
p[-1] = LF;
last = p + 1;
break;
}
if (p[0] == LF && p[-1] == LF) {
last = p + 1;
break;
}
}
}
v->len = last - v->data;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
return NGX_OK;
}
ngx_int_t
ngx_http_echo_cacheable_request_uri_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->uri.len) {
v->len = r->uri.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = r->uri.data;
} else {
v->not_found = 1;
}
return NGX_OK;
}
ngx_int_t
ngx_http_echo_request_uri_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->uri.len) {
v->len = r->uri.len;
v->valid = 1;
v->no_cacheable = 1;
v->not_found = 0;
v->data = r->uri.data;
} else {
v->not_found = 1;
}
return NGX_OK;
}
ngx_int_t
ngx_http_echo_response_status_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p;
if (r->headers_out.status) {
dd("headers out status: %d", (int) r->headers_out.status);
p = ngx_palloc(r->pool, NGX_INT_T_LEN);
if (p == NULL) {
return NGX_ERROR;
}
v->len = ngx_sprintf(p, "%ui", r->headers_out.status) - p;
v->data = p;
v->valid = 1;
v->no_cacheable = 1;
v->not_found = 0;
} else {
v->not_found = 1;
}
return NGX_OK;
}
#if nginx_version >= 1011011
void
ngx_http_echo_request_headers_cleanup(void *data)
{
ngx_http_echo_main_conf_t *emcf;
emcf = (ngx_http_echo_main_conf_t *) data;
if (emcf->busy_buf_ptrs) {
ngx_free(emcf->busy_buf_ptrs);
emcf->busy_buf_ptrs = NULL;
}
}
#endif
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */

Some files were not shown because too many files have changed in this diff Show more