├── .flake8
├── .github
└── workflows
│ ├── ci-alpine.yml
│ ├── ci-linux.yml
│ └── ci-macos.yml
├── .gitignore
├── COPYING
├── contrib
├── angel.conf
├── core.lua
├── core__cached_html.lua
├── core__xsendfile.lua
├── create-mimetypes.conf.pl
├── default.html
├── lighttpd.conf
├── meson.build
├── mimetypes.conf
├── secdownload.lua
├── secdownload__secdownload.lua
├── service
│ ├── log
│ │ └── run
│ └── run
└── systemd
│ └── lighttpd2.service
├── diff-dist-git.sh
├── doc
├── .gitignore
├── bootstrap-theme.min.css
├── bootstrap.min.css
├── bootstrap.min.js
├── compile.rb
├── core_config.xml
├── core_config_angel.xml
├── core_fetch.xml
├── core_introduction.xml
├── core_lua.xml
├── core_pattern.xml
├── core_regex.xml
├── doc_schema.xsd
├── jquery-1.10.1.min.js
├── lighttpd2-worker.8
├── lighttpd2.8
├── meson.build
├── mod_access.xml
├── mod_accesslog.xml
├── mod_auth.xml
├── mod_balance.xml
├── mod_cache_disk_etag.xml
├── mod_core.lua.xml
├── mod_debug.xml
├── mod_deflate.xml
├── mod_dirlist.xml
├── mod_expire.xml
├── mod_fastcgi.xml
├── mod_flv.xml
├── mod_fortune.xml
├── mod_gnutls.xml
├── mod_limit.xml
├── mod_lua.xml
├── mod_memcached.xml
├── mod_openssl.xml
├── mod_progress.xml
├── mod_proxy.xml
├── mod_redirect.xml
├── mod_rewrite.xml
├── mod_scgi.xml
├── mod_secdownload.lua.xml
├── mod_status.xml
├── mod_throttle.xml
├── mod_userdir.xml
├── mod_vhost.xml
├── plugin_core.xml
└── style.css
├── include
├── lighttpd
│ ├── actions.h
│ ├── actions_lua.h
│ ├── angel.h
│ ├── angel_base.h
│ ├── angel_config_parser.h
│ ├── angel_connection.h
│ ├── angel_data.h
│ ├── angel_log.h
│ ├── angel_plugin.h
│ ├── angel_plugin_core.h
│ ├── angel_proc.h
│ ├── angel_server.h
│ ├── angel_typedefs.h
│ ├── backends.h
│ ├── base.h
│ ├── base_lua.h
│ ├── buffer.h
│ ├── chunk.h
│ ├── chunk_parser.h
│ ├── collect.h
│ ├── condition.h
│ ├── condition_lua.h
│ ├── config_lua.h
│ ├── config_parser.h
│ ├── connection.h
│ ├── core_lua.h
│ ├── encoding.h
│ ├── environment.h
│ ├── etag.h
│ ├── events.h
│ ├── fetch.h
│ ├── filter.h
│ ├── filter_buffer_on_disk.h
│ ├── filter_chunked.h
│ ├── hedley.h
│ ├── http_headers.h
│ ├── http_range_parser.h
│ ├── http_request_parser.h
│ ├── http_response_parser.h
│ ├── idlist.h
│ ├── ip_parsers.h
│ ├── jobqueue.h
│ ├── lighttpd-glue.h
│ ├── log.h
│ ├── memcached.h
│ ├── mempool.h
│ ├── meson.build
│ ├── mimetype.h
│ ├── module.h
│ ├── network.h
│ ├── options.h
│ ├── pattern.h
│ ├── plugin.h
│ ├── plugin_core.h
│ ├── profiler.h
│ ├── radix.h
│ ├── request.h
│ ├── response.h
│ ├── server.h
│ ├── settings.h
│ ├── stat_cache.h
│ ├── stream.h
│ ├── stream_http_response.h
│ ├── sys_memory.h
│ ├── sys_socket.h
│ ├── tasklet.h
│ ├── throttle.h
│ ├── typedefs.h
│ ├── url_parser.h
│ ├── utils.h
│ ├── value.h
│ ├── value_lua.h
│ ├── version.h
│ ├── virtualrequest.h
│ ├── waitqueue.h
│ └── worker.h
└── meson.build
├── meson.build
├── meson_options.txt
├── packdist.sh
├── pyproject.toml
├── src
├── angel
│ ├── angel_config_parser.rl
│ ├── angel_log.c
│ ├── angel_main.c
│ ├── angel_plugin.c
│ ├── angel_plugin_core.c
│ ├── angel_proc.c
│ ├── angel_server.c
│ ├── angel_value.c
│ └── meson.build
├── common
│ ├── angel_connection.c
│ ├── angel_data.c
│ ├── buffer.c
│ ├── encoding.c
│ ├── events.c
│ ├── fetch.c
│ ├── idlist.c
│ ├── ip_parsers.rl
│ ├── jobqueue.c
│ ├── memcached.c
│ ├── mempool.c
│ ├── meson.build
│ ├── module.c
│ ├── profiler.c
│ ├── radix.c
│ ├── sys_memory.c
│ ├── sys_socket.c
│ ├── tasklet.c
│ ├── utils.c
│ ├── value.c
│ ├── value_impl.c
│ └── waitqueue.c
├── lighttpd2.pc.in
├── main
│ ├── actions.c
│ ├── actions_lua.c
│ ├── angel.c
│ ├── angel_fake.c
│ ├── backends.c
│ ├── base_lua.c
│ ├── chunk.c
│ ├── chunk_lua.c
│ ├── chunk_parser.c
│ ├── collect.c
│ ├── condition.c
│ ├── condition_lua.c
│ ├── config_lua.c
│ ├── config_parser.rl
│ ├── connection.c
│ ├── core_lua.c
│ ├── environment.c
│ ├── environment_lua.c
│ ├── etag.c
│ ├── filter.c
│ ├── filter_buffer_on_disk.c
│ ├── filter_chunked.c
│ ├── filters_lua.c
│ ├── http_headers.c
│ ├── http_headers_lua.c
│ ├── http_range_parser.rl
│ ├── http_request_parser.rl
│ ├── http_response_parser.rl
│ ├── lighttpd_glue.c
│ ├── lighttpd_worker.c
│ ├── log.c
│ ├── meson.build
│ ├── mimetype.c
│ ├── network.c
│ ├── network_sendfile.c
│ ├── network_write.c
│ ├── network_writev.c
│ ├── options.c
│ ├── pattern.c
│ ├── physical_lua.c
│ ├── plugin.c
│ ├── plugin_core.c
│ ├── request.c
│ ├── request_lua.c
│ ├── response.c
│ ├── response_lua.c
│ ├── server.c
│ ├── stat_cache.c
│ ├── stat_lua.c
│ ├── stream.c
│ ├── stream_http_response.c
│ ├── stream_simple_socket.c
│ ├── subrequest_lua.c
│ ├── throttle.c
│ ├── url_parser.rl
│ ├── value.c
│ ├── value_lua.c
│ ├── virtualrequest.c
│ ├── virtualrequest_lua.c
│ └── worker.c
├── meson.build
├── modules
│ ├── fastcgi_stream.c
│ ├── fastcgi_stream.h
│ ├── gnutls_filter.c
│ ├── gnutls_filter.h
│ ├── gnutls_ocsp.c
│ ├── gnutls_ocsp.h
│ ├── meson.build
│ ├── mod_access.c
│ ├── mod_accesslog.c
│ ├── mod_auth.c
│ ├── mod_balance.c
│ ├── mod_cache_disk_etag.c
│ ├── mod_debug.c
│ ├── mod_deflate.c
│ ├── mod_dirlist.c
│ ├── mod_expire.c
│ ├── mod_fastcgi.c
│ ├── mod_flv.c
│ ├── mod_fortune.c
│ ├── mod_gnutls.c
│ ├── mod_limit.c
│ ├── mod_lua.c
│ ├── mod_memcached.c
│ ├── mod_openssl.c
│ ├── mod_progress.c
│ ├── mod_proxy.c
│ ├── mod_redirect.c
│ ├── mod_rewrite.c
│ ├── mod_scgi.c
│ ├── mod_status.c
│ ├── mod_throttle.c
│ ├── mod_userdir.c
│ ├── mod_vhost.c
│ ├── openssl_filter.c
│ ├── openssl_filter.h
│ ├── ssl-session-db.h
│ └── ssl_client_hello_parser.h
└── unittests
│ ├── meson.build
│ ├── test-chunk.c
│ ├── test-http-request-parser.c
│ ├── test-ip-parser.c
│ ├── test-radix.c
│ ├── test-range-parser.c
│ └── test-utils.c
└── tests
├── .gitignore
├── CONTRIBUTE.md
├── autowrapper.sh
├── ca
├── ca.crt
├── ca.key
├── ca.pub
├── ca.template
├── client1.crt
├── client1.key
├── client1.pub
├── client1.template
├── client_ca.crt
├── client_ca.key
├── client_ca.pub
├── client_ca.template
├── createca.sh
├── intermediate.crt
├── intermediate.key
├── intermediate.pub
├── intermediate.template
├── server.key
├── server.pub
├── server_test1.ssl.crt
├── server_test1.ssl.pem
├── server_test1.ssl.template
├── server_test2.ssl.crt
├── server_test2.ssl.pem
└── server_test2.ssl.template
├── meson.build
├── pylt
├── __init__.py
├── base.py
├── fastcgi.py
├── logfile.py
├── requests.py
├── run.py
├── service.py
└── tests
│ ├── __init__.py
│ ├── t-alias.py
│ ├── t-basic-docroot.py
│ ├── t-basic-gets.py
│ ├── t-cgi.py
│ ├── t-deflate.py
│ ├── t-dirlist.py
│ ├── t-env-set.py
│ ├── t-etag.py
│ ├── t-gnutls.py
│ ├── t-header-modify.py
│ ├── t-lua.py
│ ├── t-map-cidr.py
│ ├── t-memcached.py
│ ├── t-mime-type.py
│ ├── t-mod-auth.py
│ ├── t-mod-lua.py
│ ├── t-mod-proxy.py
│ ├── t-openssl.py
│ ├── t-redirect.py
│ ├── t-rewrite.py
│ ├── t-scgi.py
│ └── t-secdownload.py
├── run-fcgi-cgi.py
├── run-memcached.py
├── run-scgi-envcheck.py
└── runtests.py
/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | # E266 too many leading '#' for block comment [ I like marking disabled code blocks with '### ' ]
3 | # E402 module level import not at top of file [ usually on purpose. might use individual overrides instead? ]
4 | # E713 test for membership should be ‘not in’ [ disagree: want `not a in x` ]
5 | # E714 test for object identity should be 'is not' [ disagree: want `not a is x` ]
6 | # W503 line break before binary operator [ gotta pick one way ]
7 | extend-ignore = E266,E402,E713,E714,W503
8 | max-line-length = 120
9 |
--------------------------------------------------------------------------------
/.github/workflows/ci-alpine.yml:
--------------------------------------------------------------------------------
1 | name: "Checks (alpine, many platforms)"
2 |
3 | on: [push, pull_request]
4 |
5 | concurrency:
6 | group: ${{ github.workflow }}-${{ github.head_ref }}
7 | cancel-in-progress: true
8 |
9 | jobs:
10 | linux-alpine:
11 | runs-on: ubuntu-latest
12 | name: linux-alpine-${{ matrix.platform }}
13 | # abort if x86_64 fails
14 | continue-on-error: ${{ matrix.platform != 'x86_64' }}
15 | strategy:
16 | fail-fast: true
17 | matrix:
18 | platform: ['x86_64','x86','armhf','armv7','aarch64','ppc64le','riscv64','s390x']
19 | steps:
20 | - uses: actions/checkout@v4
21 | - uses: jirutka/setup-alpine@v1
22 | with:
23 | # riscv64 currently requires 'edge'
24 | branch: edge
25 | arch: ${{ matrix.platform }}
26 | packages: >
27 | build-base
28 | meson
29 | libev-dev
30 | ragel
31 | glib-dev
32 | lua5.1-dev
33 | zlib-dev
34 | bzip2-dev
35 | pkgconf
36 | openssl-dev
37 | gnutls-dev
38 | libidn-dev
39 | libunwind-dev
40 | python3
41 | py3-curl
42 | - name: meson setup
43 | shell: alpine.sh {0}
44 | run: meson setup mesonbuilddir
45 | - name: meson compile
46 | shell: alpine.sh {0}
47 | run: meson compile -C mesonbuilddir
48 | - name: meson test
49 | shell: alpine.sh {0}
50 | run: meson test -C mesonbuilddir -v
51 |
--------------------------------------------------------------------------------
/.github/workflows/ci-linux.yml:
--------------------------------------------------------------------------------
1 | name: "Checks (Ubuntu: gcc+clang)"
2 |
3 | on: [push, pull_request]
4 |
5 | concurrency:
6 | group: ${{github.workflow}}-${{github.head_ref}}
7 | cancel-in-progress: true
8 |
9 | jobs:
10 | linux-build-docs:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v4
14 | - name: Install dependencies
15 | run: |
16 | pkgs=(
17 | ruby
18 | ruby-nokogiri
19 | ruby-kramdown
20 | libxml2-utils
21 | )
22 | sudo apt-get install "${pkgs[@]}"
23 | - name: Build docs
24 | run: |
25 | mkdir -p out
26 | ruby doc/compile.rb out
27 | cp doc/*.css doc/*.js out
28 | - uses: actions/upload-artifact@v4
29 | with:
30 | name: lighttpd2-docs
31 | path: out
32 |
33 | linux-ubuntu:
34 | runs-on: ubuntu-latest
35 | name: linux-ubuntu-${{ matrix.compiler }}
36 | strategy:
37 | matrix:
38 | compiler: ['gcc', 'clang']
39 | steps:
40 | - uses: actions/checkout@v4
41 | - if: ${{ matrix.compiler == 'clang' }}
42 | uses: egor-tensin/setup-clang@v1
43 | - name: Install dependencies
44 | run: |
45 | pkgs=(
46 | meson
47 | libev-dev
48 | ragel
49 | libglib2.0-dev
50 | liblua5.1-dev
51 | zlib1g-dev
52 | libbz2-dev
53 | pkg-config
54 | libssl-dev
55 | libgnutls28-dev
56 | libidn-dev
57 | libunwind8-dev
58 | python3
59 | python3-pycurl
60 | )
61 | sudo apt-get install "${pkgs[@]}"
62 | - name: meson setup
63 | run: meson setup mesonbuilddir
64 | - name: meson compile
65 | run: meson compile -C mesonbuilddir
66 | - name: meson test
67 | run: meson test -C mesonbuilddir -v
68 |
--------------------------------------------------------------------------------
/.github/workflows/ci-macos.yml:
--------------------------------------------------------------------------------
1 | name: "Checks (macOS)"
2 |
3 | on: [push, pull_request]
4 |
5 | concurrency:
6 | group: ${{github.workflow}}-${{github.head_ref}}
7 | cancel-in-progress: true
8 |
9 | env:
10 | C_INCLUDE_PATH: /opt/homebrew/opt/libev/include
11 | LIBRARY_PATH: /opt/homebrew/opt/libev/lib
12 |
13 | jobs:
14 | macOS:
15 | runs-on: macos-latest
16 | steps:
17 | - uses: actions/checkout@v4
18 | - name: Install dependencies
19 | run: |
20 | pkgs=(
21 | meson
22 | libev
23 | ragel
24 | glib
25 | lua@5.4
26 | # zlib # keg-only
27 | # bzip2 # keg-only
28 | openssl@3
29 | gnutls
30 | libidn
31 | python3
32 | md5sha1sum
33 | )
34 | brew install "${pkgs[@]}"
35 | - name: python venv setup
36 | run: |
37 | python3 -m venv venv
38 | venv/bin/pip3 install pycurl
39 | venv/bin/python3 -c 'import pycurl'
40 | - name: meson setup
41 | run: meson setup -D unwind=false mesonbuilddir
42 | - name: meson compile
43 | run: meson compile -C mesonbuilddir
44 | - name: prepare environment for tests
45 | run: |
46 | sudo ifconfig lo0 alias 127.0.0.2 up
47 |
48 | # try to create a tmpdir with a short relative path (for shorter unix socket paths)
49 | NEWTMPDIR=~/tmp
50 | ln -sf "${TMPDIR}" "${NEWTMPDIR}"
51 | echo "TMPDIR=$NEWTMPDIR" >> "$GITHUB_ENV"
52 | echo "PATH=$(brew --prefix python)/libexec/bin:$PATH" >> "$GITHUB_ENV"
53 |
54 | if [ ! -f $(brew --prefix python)/libexec/bin/python3 ]; then
55 | # the brew path only provides "python", not "python3"...
56 | ln -s python $(brew --prefix python)/libexec/bin/python3
57 | fi
58 | - name: meson test
59 | run: |
60 | source venv/bin/activate
61 | meson test -C mesonbuilddir -v
62 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *build/
2 | .vscode
3 | .mypy_cache
4 |
--------------------------------------------------------------------------------
/COPYING:
--------------------------------------------------------------------------------
1 |
2 | The MIT License
3 |
4 | Copyright (c) 2004-2008 Jan Kneschke
5 | Copyright (c) 2008-2010 Stefan Bühler
6 | Copyright (c) 2008-2010 Thomas Porzelt
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 |
27 |
28 |
29 | The doc/ directory contains some assets by 3rd parties:
30 | From doc/bootstrap* (Apache License 2.0):
31 | Copyright 2013 Twitter, Inc.
32 | Licensed under https://www.apache.org/licenses/LICENSE-2.0
33 | From doc/jquery-1.10.1.min.js (MIT License):
34 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
35 |
36 | Also include/lighttpd/hedley.h is licensed as CC0-1.0 by Evan Nemerson.
37 |
--------------------------------------------------------------------------------
/contrib/angel.conf:
--------------------------------------------------------------------------------
1 | user "www-data";
2 | max_open_files 16384;
3 |
4 | copy_env [ "PATH" ];
5 | # env [ "G_SLICE=always-malloc", "G_DEBUG=gc-friendly,fatal_criticals" ];
6 | # wrapper [ "/usr/bin/valgrind", "--leak-check=full", "--show-reachable=yes", "--leak-resolution=high" ];
7 |
8 | # need separate statements for IPv4 and IPv6. if none are configured, allow
9 | # TCP port 80 and 443 on all IPv4 and IPv6.
10 | # no port means 80 and 443 are allowed:
11 | # allow_listen "0.0.0.0/0";
12 | # allow_listen "[::/0]";
13 |
14 | # allow_listen "0.0.0.0/0:8080";
15 | # allow_listen "[::/0]:8080";
16 |
--------------------------------------------------------------------------------
/contrib/core__cached_html.lua:
--------------------------------------------------------------------------------
1 | local function try_cached_html(vr)
2 | local p = vr.phys.path
3 | if p:sub(-1) == '/' then
4 | p = p:sub(0, -2) .. '.html'
5 | else
6 | p = p .. '.html'
7 | end
8 | st, res = vr:stat(p)
9 | if st and st.is_file then
10 | -- found the file
11 | vr.phys.path = p
12 | elseif res == lighty.HANDLER_WAIT_FOR_EVENT then
13 | return lighty.HANDLER_WAIT_FOR_EVENT
14 | end
15 | -- ignore other errors
16 | end
17 |
18 | actions = try_cached_html
19 |
--------------------------------------------------------------------------------
/contrib/core__xsendfile.lua:
--------------------------------------------------------------------------------
1 |
2 | local filename, args = ...
3 |
4 | local docroot = args
5 |
6 | -- create new class XFilterDrop
7 | local XFilterDrop = { }
8 | XFilterDrop.__index = XFilterDrop
9 |
10 | -- "classmethod" to create new instance
11 | function XFilterDrop:new(vr)
12 | -- vr:debug("New XSendfile instance")
13 | local o = { }
14 | setmetatable(o, self)
15 | return o
16 | end
17 |
18 | -- normal method to handle content
19 | function XFilterDrop:handle(vr, outq, inq)
20 | -- drop input, close it
21 | if nil ~= inq then
22 | inq.is_closed = true
23 | inq:skip_all()
24 | end
25 | return lighty.HANDLER_GO_ON
26 | end
27 |
28 | -- create a new filter which drops all input and adds it to the vrequest
29 | -- returns the filter object so you can insert your own content in f.out (it is already closed)
30 | local function add_drop_filter(vr)
31 | local f = vr:add_filter_out(XFilterDrop:new())
32 | local inq = f['in']
33 | if nil ~= inq then
34 | inq.is_closed = true
35 | inq:skip_all()
36 | end
37 | f.out.is_closed = true
38 | return f
39 | end
40 |
41 | local function handle_x_sendfile(vr)
42 | -- vr:debug("handle x-sendfile")
43 | -- wait for response
44 | if not vr.has_response then
45 | if vr.is_handled then
46 | -- vr:debug("x-sendfile: waiting for response headers")
47 | return lighty.HANDLER_WAIT_FOR_EVENT
48 | else
49 | -- vr:debug("No response handler yet, cannot handle X-Sendfile")
50 | return lighty.HANDLER_GO_ON
51 | end
52 | end
53 | -- vr:debug("handle x-sendfile: headers available")
54 | -- add filter if x-sendfile header is not empty
55 | local xs = vr.resp.headers["X-Sendfile"]
56 | if xs and xs ~= "" then
57 | xs = lighty.path_simplify(xs)
58 | if docroot and xs:sub(docroot.len()) ~= docroot then
59 | vr:error("x-sendfile: File '".. xs .. "'not in required docroot '" .. docroot .. "'")
60 | return lighty.HANDLER_GO_ON
61 | end
62 |
63 | -- make sure to drop all other content from the backend
64 | local f = add_drop_filter(vr)
65 |
66 | vr.resp.headers["X-Sendfile"] = nil -- remove header from response
67 |
68 | -- Add checks for the pathname here
69 |
70 | vr:debug("XSendfile:handle: pushing file '" .. xs .. "' as content")
71 | f.out:add_file(xs)
72 | end
73 | end
74 |
75 | actions = handle_x_sendfile
76 |
--------------------------------------------------------------------------------
/contrib/lighttpd.conf:
--------------------------------------------------------------------------------
1 |
2 | setup {
3 |
4 | module_load [
5 | "mod_accesslog",
6 | "mod_dirlist"
7 | ];
8 |
9 | listen "0.0.0.0:80";
10 | listen "[::]:80";
11 |
12 | log ["debug" => "", default => "/var/log/lighttpd2/error.log"];
13 | accesslog "/var/log/lighttpd2/access.log";
14 | accesslog.format "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"";
15 |
16 | static.exclude_extensions [ ".php", ".pl", ".fcgi", "~", ".inc" ];
17 |
18 | }
19 |
20 | include "/etc/lighttpd2/mimetypes.conf";
21 |
22 | docroot "/var/www";
23 | index [ "index.php", "index.html", "index.htm", "default.htm", "index.lighttpd.html" ];
24 | dirlist;
25 | static;
26 |
--------------------------------------------------------------------------------
/contrib/meson.build:
--------------------------------------------------------------------------------
1 | if get_option('lua')
2 | install_data(
3 | 'core__cached_html.lua',
4 | 'core.lua',
5 | 'core__xsendfile.lua',
6 | 'secdownload.lua',
7 | 'secdownload__secdownload.lua',
8 | install_dir: lua_dir,
9 | install_tag: 'runtime',
10 | )
11 | endif
12 |
--------------------------------------------------------------------------------
/contrib/secdownload.lua:
--------------------------------------------------------------------------------
1 |
2 | -- secdownload.lua
3 |
4 | -- usage:
5 | -- a) load mod_lua and this plugin:
6 | -- setup {
7 | -- module_load "mod_lua";
8 | -- lua.plugin "/path/secdownload.lua";
9 | -- }
10 | -- b) activate it anywhere you want:
11 | -- secdownload [ "prefix" => "/sec/", "document-root" => "/secret/path", "secret" => "abc", "timeout" => 600 ];
12 |
13 | local filename, args = ...
14 |
15 | -- basepath for loading sub handlers with lua.handler
16 | -- this allows us to have lua actions that don't use the global lock
17 | local basepath = filename:gsub("(.*/)(.*)", "%1")
18 |
19 | local function secdownload(options)
20 | if type(options) ~= "table" then
21 | lighty.error("secdownload expects a hashtable as parameter")
22 | return nil
23 | end
24 |
25 | local uri_prefix = options["prefix"]
26 | local doc_root = options["document-root"]
27 | local secret = options["secret"]
28 | local timeout = tonumber(options["timeout"]) or 60
29 |
30 | if secret == nil then
31 | lighty.error("secdownload: need secret in options")
32 | return nil
33 | end
34 |
35 | if doc_root == nil then
36 | lighty.error("secdownload: need doc_root in options")
37 | return nil
38 | end
39 |
40 | if doc_root:sub(-1) ~= "/" then
41 | doc_root = doc_root .. "/"
42 | end
43 |
44 | if uri_prefix == nil then
45 | uri_prefix = "/"
46 | end
47 |
48 | local args = { ["prefix"] = uri_prefix, ["document-root"] = doc_root, ["secret"] = secret, ["timeout"] = timeout }
49 |
50 | local handle_secdownload = action.lua.handler(basepath .. 'secdownload__secdownload.lua', nil, args)
51 |
52 | return handle_secdownload
53 | end
54 |
55 | actions = {
56 | ["secdownload"] = secdownload
57 | }
58 |
--------------------------------------------------------------------------------
/contrib/secdownload__secdownload.lua:
--------------------------------------------------------------------------------
1 |
2 | local filename, args = ...
3 |
4 | local uri_prefix = args["prefix"]
5 | local doc_root = args["document-root"]
6 | local secret = args["secret"]
7 | local timeout = tonumber(args["timeout"])
8 |
9 | local function deny_access(vr, status)
10 | vr:handle_direct()
11 | vr.resp.status = status
12 | end
13 |
14 | local function handle_secdownload(vr)
15 | local path = vr.req.uri.path
16 | local prefix_len = uri_prefix:len()
17 | if path:sub(1, prefix_len) == uri_prefix and not vr.is_handled then
18 | local md5str = path:sub(prefix_len + 1, prefix_len + 32)
19 |
20 | if md5str:len() ~= 32 then return deny_access(vr, 403) end
21 |
22 | if path:sub(prefix_len + 33, prefix_len + 33) ~= "/" then return deny_access(vr, 403) end
23 |
24 | local slash = path:find("/", prefix_len + 34)
25 | if slash == nil then return deny_access(vr, 403) end
26 |
27 | local ts_string = path:sub(prefix_len + 34, slash - 1)
28 | local timestamp = tonumber(ts_string, 16)
29 | if timestamp == nil then return deny_access(vr, 403) end
30 |
31 | path = path:sub(slash)
32 |
33 | local ts = os.time()
34 | if (timestamp < ts - timeout) or (timestamp > ts + timeout) then
35 | -- Gone, not Timeout (don't retry later)
36 | return deny_access(vr, 410)
37 | end
38 |
39 | -- modify md5content as you wish :)
40 | local md5content = secret .. path .. ts_string
41 | -- vr:debug("checking md5: '" .. md5content .. "', md5: " .. md5str)
42 | if md5str ~= lighty.md5(secret .. path .. ts_string) then
43 | return deny_access(vr, 403)
44 | end
45 |
46 | -- rewrite physical paths
47 | vr.phys.doc_root = doc_root
48 | vr.phys.path = doc_root .. path
49 | end
50 | end
51 |
52 | actions = handle_secdownload
53 |
--------------------------------------------------------------------------------
/contrib/service/log/run:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | LOG=/var/log/lighttpd2/sv.log
5 |
6 | test -d "$LOG" || mkdir -p -m2750 "$LOG" && chown root:adm "$LOG"
7 | exec svlogd -tt "$LOG"
8 |
--------------------------------------------------------------------------------
/contrib/service/run:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | exec 2>&1
3 | echo 'lighttpd2 starting.'
4 |
5 | LANG=C LC_ALL=C \
6 | exec /usr/sbin/lighttpd2 -c /etc/lighttpd2/angel.conf
7 |
--------------------------------------------------------------------------------
/contrib/systemd/lighttpd2.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Lighttpd2
3 | After=network.target
4 |
5 | [Service]
6 | Type=simple
7 | ExecStart=/usr/sbin/lighttpd2 -c /etc/lighttpd2/angel.conf
8 | ExecReload=/bin/kill -HUP $MAINPID
9 | Restart=on-failure
10 |
11 | [Install]
12 | WantedBy=multi-user.target
13 |
--------------------------------------------------------------------------------
/diff-dist-git.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | if [ ! -f "$1" ]; then
6 | (
7 | echo "Syntax: $0 [path-to-dist.tar.gz]"
8 | echo
9 | echo "Build such file with ./autogen.sh; ./configure; make dist-gzip"
10 | echo "This tool can then be used to check the differences between the git"
11 | echo "repository and the tar; it might show added files for autotools"
12 | echo "(compile, configure, Makefile.in, m4, ...) and should remove"
13 | echo ".gitignore files and some helper scripts (packdist.sh and this file)"
14 | ) >&2
15 | exit 1
16 | fi
17 |
18 | tmpdir=$(mktemp --tmpdir -d diff-dist-tar-git-XXXXXXX)
19 | trap 'rm -rf "${tmpdir}"' EXIT
20 |
21 | git archive --format tar.gz -o "${tmpdir}/lighttpd.tar.gz" --prefix "lighttpd-2.0.0/" HEAD
22 | tardiff --modified --autoskip "${tmpdir}/lighttpd.tar.gz" "$1"
23 |
--------------------------------------------------------------------------------
/doc/.gitignore:
--------------------------------------------------------------------------------
1 | *.html
2 |
--------------------------------------------------------------------------------
/doc/core_fetch.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The Fetch API provides a common interface between lighttpd modules to lookup entries in a database. Both lookup key and data are simple (binary) strings.
5 |
6 | So far only a [fetch.files_static](plugin_core.html#plugin_core__setup_fetch-files_static) is providing a database, and only [gnutls](mod_gnutls.html#mod_gnutls__setup_gnutls) is using it to lookup SNI certificates.
7 |
8 |
9 |
--------------------------------------------------------------------------------
/doc/core_introduction.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/doc/core_regex.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | lighttpd2 uses the "Perl-compatible regular expressions" implementation from GLib, see their [Regular expression syntax](https://developer.gnome.org/glib/stable/glib-regex-syntax.html) documentation.
5 |
6 | The config format has different ways to provide strings (you can quote with either `'` or `"`; the character used to quote has to be escaped with `\` if used inside the string).
7 | The simple (standard) way `"text"` has the following escape rules:
8 |
9 | * `"\n"` is a newline, `"\r"` a carriage return, `"\t"` a tab stop
10 | * `"\\"` is one `\`, `"\""` is one double quote `"` and `"\'"` a single quote `'`
11 | * escaping single/double quote is optional if the symbol is not used to terminate the string, i.e. `'\"'` = `'"'` and `"\'"` = `"'"`
12 | * `"\xNN"`: NN must be hexadecimal characters, and the string is replaced with the decoded 8-bit value as a single byte
13 | * All other `\` occurences are **not** removed from the string.
14 |
15 | This way is the preferred one for regular expressions; only to actually match a `\` you have to do additional escaping (`"\\\\"`; `"\x5C"` = `"\\"` is not working), and `\\` is usually not doing what you wanted (matching a digit: `"\\d"` = `"\d"`). All other escape rules are compatible with what pcre is doing.
16 |
17 | The second way is to place an `e` before the string like this: `e"text"`. It has the same rules like the normal string, but does not allow unknown escape sequences (the last rule above).
18 | To match a digit with pcre this way you'd have to write `e"\\d"` instead of `"\d"`.
19 |
20 |
21 |
--------------------------------------------------------------------------------
/doc/lighttpd2-worker.8:
--------------------------------------------------------------------------------
1 | .TH lighttpd2-worker "8" "2010-08-24" "" ""
2 | .
3 | .SH NAME
4 | lighttpd \- a fast, secure and flexible web server
5 | .
6 | .SH SYNOPSIS
7 | \fBlighttpd2-worker\fP [\fB\-ltvh\fP] \fB\-c\fP \fIconfigfile\fP [\fB\-m\fP \fImoduledir\fP]
8 | .
9 | .SH DESCRIPTION
10 | \fBlighttpd\fP (pronounced 'lighty') is an advanced HTTP daemon that aims
11 | to be secure, fast, compliant and very flexible. It has been optimized for
12 | high performance. Its feature set includes, but is not limited to, FastCGI,
13 | CGI, basic and digest HTTP authentication, output compression, URL rewriting.
14 | .PP
15 | This manual page only lists the command line arguments. For details
16 | on how to configure \fBlighttpd\fP and its modules see the online documentation:
17 | https://redmine.lighttpd.net/projects/lighttpd2/wiki
18 | .PP
19 | You probably want to use the angel instead of this application: lighttpd2(8)
20 | .
21 | .SH OPTIONS
22 | The following options are supported:
23 | .TP 8
24 | \fB\-c, --config\ \fP \fIconfigfile\fP
25 | Load configuration file \fIconfigfile\fP.
26 | .TP 8
27 | \fB\-l, --lua\fP
28 | Interpret the configuration file as lua script.
29 | .TP 8
30 | \fB\-m, --module-dir\ \fP \fImoduledir\fP
31 | Use
32 | \fImoduledir\fP
33 | as the directory that contains modules, instead of the default.
34 | .TP 8
35 | \fB\-t, --test\fP
36 | Test the configuration file for errors and exit.
37 | .TP 8
38 | \fB\-v, --version\fP
39 | Show version and exit.
40 | .TP 8
41 | \fB\-h, --help, -?\fP
42 | Show a brief help message and exit.
43 | .
44 | .SH SEE ALSO
45 | Online Documentation: https://redmine.lighttpd.net/projects/lighttpd2/wiki
46 | .PP
47 | spawn-fcgi(1), lighttpd2(8)
48 | .
49 | .SH AUTHOR
50 | Jan Kneschke
51 | .PP
52 | Stefan Buehler
53 | .PP
54 | Thomas Porzelt
55 |
--------------------------------------------------------------------------------
/doc/lighttpd2.8:
--------------------------------------------------------------------------------
1 | .TH lighttpd2 "8" "2010-08-24" "" ""
2 | .
3 | .SH NAME
4 | lighttpd \- a fast, secure and flexible web server
5 | .
6 | .SH SYNOPSIS
7 | \fBlighttpd2\fP [\fB\-nvh\fP] \fB\-c\fP \fIconfigfile\fP [\fB\-m\fP \fImoduledir\fP] [\fB\--pid-file\fP \fIpidfile\fP]
8 | .
9 | .SH DESCRIPTION
10 | \fBlighttpd\fP (pronounced 'lighty') is an advanced HTTP daemon that aims
11 | to be secure, fast, compliant and very flexible. It has been optimized for
12 | high performance. Its feature set includes, but is not limited to, FastCGI,
13 | CGI, basic and digest HTTP authentication, output compression, URL rewriting.
14 | .PP
15 | The angel is used to keep the worker running and for other tasks where root
16 | permissions are needed (opening network sockets, ...)
17 | .PP
18 | This manual page only lists the command line arguments. For details
19 | on how to configure \fBlighttpd\fP and its modules see the online documentation:
20 | https://redmine.lighttpd.net/projects/lighttpd2/wiki
21 | .
22 | .SH OPTIONS
23 | The following options are supported:
24 | .TP 8
25 | \fB\-c, --config\ \fP \fIconfigfile\fP
26 | Load configuration file \fIconfigfile\fP.
27 | .TP 8
28 | \fB\-m, --module-dir\ \fP \fImoduledir\fP
29 | Use
30 | \fImoduledir\fP
31 | as the directory that contains modules, instead of the default.
32 | .TP 8
33 | \fB\--pid-file\ \fP \fIpidfile\fP
34 | Location of the pid file (only valid in daemon mode).
35 | .TP 8
36 | \fB\-v, --version\fP
37 | Show version and exit.
38 | .TP 8
39 | \fB\-h, --help, -?\fP
40 | Show a brief help message and exit.
41 | .
42 | .SH SEE ALSO
43 | Online Documentation: https://redmine.lighttpd.net/projects/lighttpd2/wiki
44 | .PP
45 | lighttpd2-worker(8)
46 | .
47 | .SH AUTHOR
48 | Jan Kneschke
49 | .PP
50 | Stefan Buehler
51 | .PP
52 | Thomas Porzelt
53 |
--------------------------------------------------------------------------------
/doc/meson.build:
--------------------------------------------------------------------------------
1 | install_man(
2 | 'lighttpd2.8',
3 | 'lighttpd2-worker.8',
4 | )
5 |
--------------------------------------------------------------------------------
/doc/mod_access.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | lets you filter clients by IP address.
5 |
6 |
7 |
8 | denies access by returning a 403 status code
9 |
10 |
11 |
12 | allows or denies access based on client IP address
13 |
14 | A key value list mapping "access" and/or "deny" keys to a list of CIDR addresses or "all".
15 |
16 |
17 | Checks the client IP address against the rules. Default is to deny all addresses. The most precise matching rule defines the result ("192.168.100.0/24" takes precedence over "192.168.0.0/16"; similar to routing tables); if the same CIDR is in both lists the second action is taken. "all" is a synonym for "0.0.0.0/0" and "::/0", matching all IPv4 and IPv6 addresses.
18 |
19 |
20 |
21 | Limit access to clients from the local network. The deny rule isn't strictly required, as the default is to deny anyway. The smaller CIDR strings for the local networks override the global deny rule.
22 |
23 |
24 | setup {
25 | module_load "mod_access";
26 | }
27 |
28 | access.check (
29 | "allow" => ("127.0.0.0/8", "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"),
30 | "deny" => ("all")
31 | );
32 |
33 |
34 |
35 |
36 | Limit access to clients from "192.168.10.0/24", but deny access to "192.168.10.1". As "192.168.10.1" (equivalent to "192.168.10.1/32") is a more precise match it overwrites the allow rule for the subnet "192.168.10.0/24" containing it.
37 |
38 |
39 | setup {
40 | module_load "mod_access";
41 | }
42 |
43 | access.check (
44 | "allow" => ("192.168.10.0/24"),
45 | "deny" => ("192.168.10.1")
46 | );
47 |
48 |
49 |
50 |
51 |
52 | url to redirect to if access was denied (not implemented yet)
53 |
54 | not set
55 |
56 | **NOT IMPLEMENTED YET**
57 |
58 |
59 |
60 |
61 | whether to log when access was denied (with log level "info")
62 |
63 | false
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/doc/mod_balance.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | balances between different backends.
4 |
5 |
6 | Using an action from mod_balance also activates a backlog: lighttpd2 will then put requests in a backlog if no backend is available and try again later.
7 |
8 | Be careful: the referenced actions may get executed more than once (until one is successful!), so don't loop rewrites in them or something similar.
9 |
10 |
11 |
12 | balance between actions (list or single action) with Round-Robin
13 |
14 | the actions to balance between
15 |
16 |
17 | Round-Robin (rr) the requests are distributed equally over all backends.
18 |
19 |
20 |
21 | balance.rr { fastcgi "127.0.0.1:9090"; };
22 |
23 |
24 |
25 |
26 | balance.rr ({ fastcgi "127.0.0.1:9090"; }, { fastcgi "127.0.0.1:9091"; });
27 |
28 |
29 |
30 |
31 |
32 | balance between actions (list or single action) with SQF
33 |
34 | the actions to balance between
35 |
36 |
37 | Shortest-Queue-First (sqf) is similar to Round-Robin and prefers the backend with the shortest wait-queue.
38 |
39 |
40 |
41 | balance.sqf { fastcgi "127.0.0.1:9090"; };
42 |
43 |
44 |
45 |
46 |
47 | enable debug output
48 | false
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/doc/mod_cache_disk_etag.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | caches generated content on disk if an etag response header is set; if the backend sends an already cached etag, the backend is closed and the file is sent directly.
4 |
5 |
6 | Please note: This will not skip the backend, as it will need at least the response headers.
7 |
8 | **Hint:**
9 | Use a cron-job like the following to remove old cached data, e.g. in crontab daily:
10 |
11 | ```
12 | find /var/cache/lighttpd/cache_etag/ -type f -mtime +2 -exec rm -r {} \;
13 | ```
14 |
15 | **Hint:**
16 | Have a look at [mod_deflate](mod_deflate.html#mod_deflate) to see this module in action.
17 |
18 |
19 |
20 | cache responses based on the ETag response header
21 |
22 | directory to store the cached results in
23 |
24 |
25 | This blocks action progress until the response headers are done (i.e. there has to be a content generator before it (like fastcgi/dirlist/static file).
26 | You could insert it multiple times of course (e.g. before and after deflate).
27 |
28 |
29 |
30 |
31 | setup {
32 | module_load "mod_cache_disk_etag";
33 | }
34 |
35 | cache.disk.etag "/var/lib/lighttpd/cache_etag"
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/doc/mod_debug.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | offers various utilities to aid you debug a problem.
5 |
6 |
7 |
8 | shows a page similar to the one from mod_status, listing all active connections
9 |
10 | By specifying one or more "connection ids" via querystring (parameter "con"), one can request additional debug output for specific connections.
11 |
12 |
13 |
14 | if req.path == "/debug/connections" { debug.show_connections; }
15 |
16 |
17 |
18 |
19 |
20 | dumps all allocated memory to the profiler output file if profiling enabled
21 |
22 |
23 | lighttpd2 needs to be compiled with profiler support, and profiling has to be enabled by setting the environment variable `LIGHTY_PROFILE_MEM` to the path of a target log file.
24 |
25 |
26 |
27 |
28 | shows a plain text list of all events
29 |
30 | this is a very low level debug tool for developers.
31 |
32 |
33 |
34 | if req.path == "/debug/events" { debug.show_events; }
35 |
36 |
37 |
38 |
39 |
40 | time in seconds after start of shutdown to log remaining active events
41 |
42 | timeout after which to display events (default: disabled)
43 |
44 |
45 | timeout after which to repeat displaying events (default: disabled)
46 |
47 |
48 |
49 | this is a very low level debug tool for developers; it shows which event listeners keep lighttpd2 alive when it should stop.
50 |
51 |
52 |
53 |
54 | setup { debug.show_events_after_shutdown 5; }
55 | setup { debug.show_events_after_shutdown 5, 15; }
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/doc/mod_dirlist.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | lists files inside a directory. The output can be customized in various ways from style via css to excluding certain entries.
4 |
5 |
6 | lists file in a directory
7 |
8 |
9 |
10 | string: url to external stylesheet (default: inline internal css)
11 |
12 |
13 | boolean: hide entries beginning with a dot (default: true)
14 |
15 |
16 | boolean: hide entries ending with a tilde (~), often used for backups (default: true)
17 |
18 |
19 | boolean: hide directories from the directory listing (default: false)
20 |
21 |
22 | boolean: include HEADER.txt above the directory listing (default: false)
23 |
24 |
25 | boolean: hide HEADER.txt from the directory listing (default: false)
26 |
27 |
28 | boolean: html-encode HEADER.txt (if included), set to false if it contains real HTML (default: true)
29 |
30 |
31 | boolean: include README.txt below the directory listing (default: true)
32 |
33 |
34 | boolean: hide README.txt from the directory listing (default: false)
35 |
36 |
37 | boolean: html-encode README.txt (if included), set to false if it contains real HTML (default: true)
38 |
39 |
40 | list of strings: hide entries that end with one of the strings supplied (default: empty list)
41 |
42 |
43 | list of strings: hide entries that begin with one of the strings supplied (default: empty list)
44 |
45 |
46 | boolean: output debug information to log (default: false)
47 |
48 |
49 | string: content-type to return in HTTP response headers (default: "text/html; charset=utf-8")
50 |
51 |
52 |
53 |
54 |
55 |
56 | shows a directory listing including the content of HEADER.txt above the list and hiding itself from it; also hides all files ending in ".bak"
57 |
58 |
59 | setup {
60 | module_load ("mod_dirlist");
61 | }
62 |
63 | if req.path =^ "/files/" {
64 | dirlist ("include-header" => true, "hide-header" => true, "hide->suffix" => (".bak"));
65 | }
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/doc/mod_expire.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | add "Expires" and "Cache-Control" headers to the response
4 |
5 | ` if your content changes in specific intervals like every 15 minutes.
11 | ]]>
12 |
13 |
14 | adds an "Expires" header to the response
15 |
16 | the rule to calculate the "Expires" header value with
17 |
18 | [plus] ( )+
22 |
23 | * ` ` is one of "access", "now" or "modification"; "now" being equivalent to "access".
24 | * "`plus`" is optional and does nothing.
25 | * `` is any positive integer.
26 | * `` is one of "seconds", "minutes", "hours", "days", "weeks", "months" or "years".
27 |
28 | The trailing "s" in `` is optional.
29 |
30 | If you use "modification" as ` ` and the file does not exist or cannot be accessed, mod_expire will do nothing and request processing will go on.
31 |
32 | The expire action will overwrite any existing "Expires" header.
33 | It will append the max-age value to any existing "Cache-Control" header.
34 | ]]>
35 |
36 |
37 |
38 | Cache image, css, txt and js files for 1 week.
39 |
40 |
41 | setup {
42 | module_load "mod_expire";
43 | }
44 |
45 | if req.path =~ "\.(jpe?g|png|gif|txt|css|js)$" {
46 | expire "access plus 1 week";
47 | }
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/doc/mod_fastcgi.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | connect to FastCGI backends for generating response content
4 |
5 |
6 | connect to FastCGI backend
7 |
8 | socket to connect to, either "ip:port" or "unix:/path"
9 |
10 |
11 | Don't confuse FastCGI with CGI! Not all CGI backends can be used as FastCGI backends (but you can use [fcgi-cgi](https://redmine.lighttpd.net/projects/fcgi-cgi/wiki) to run CGI backends with lighttpd2).
12 |
13 |
14 |
15 | fastcgi "127.0.0.1:9090"
16 |
17 |
18 |
19 |
20 | Start php for example with spawn-fcgi: `spawn-fcgi -n -s /var/run/lighttpd2/php.sock -- /usr/bin/php5-cgi`
21 |
22 |
23 | setup {
24 | module_load "mod_fastcgi";
25 | }
26 |
27 | if phys.path =$ ".php" and phys.is_file {
28 | fastcgi "unix:/var/run/lighttpd2/php.sock";
29 | }
30 |
31 |
32 |
33 |
34 |
35 | whether to prepend timestamp and other info to FastCGI stderr lines in the "backend" log
36 | false
37 |
38 |
39 |
--------------------------------------------------------------------------------
/doc/mod_flv.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | provides flash pseudo streaming
4 |
5 |
6 | pseudo stream the current file as flash
7 |
8 | Lets flash players seek with the "start" query string parameter to an (byte) offset in the file, and prepends a simple flash header before streaming the file from that offset.
9 |
10 | Uses "video/x-flv" as hard-coded content type.
11 |
12 |
13 |
14 | if phys.path =$ ".flv" {
15 | flv;
16 | }
17 |
18 |
19 |
20 |
21 | Use caching and bandwidth throttling to save traffic. Use a small burst threshold to prevent the player from buffering at the beginning.
22 |
23 | This config will make browsers cache videos for 1 month and limit bandwidth to 150 kilobyte/s after 500 kilobytes.
24 |
25 |
26 | if phys.path =$ ".flv" {
27 | expire "access 1 month";
28 | io.throttle 500kbyte => 150kbyte;
29 | flv;
30 | }
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/doc/mod_fortune.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | loads quotes (aka fortune cookies) from a file and provides actions to add a random quote as response header (X-fortune) or display it as a page.
4 |
5 |
6 | loads cookies from a file, can be called multiple times to load data from multiple files
7 |
8 | the file to load the cookies from
9 |
10 |
11 |
12 |
13 | adds a random quote as response header "X-fortune".
14 |
15 |
16 |
17 | shows a random cookie as response text
18 |
19 |
20 |
21 |
22 | setup {
23 | module_load "mod_fortune";
24 | fortune.load "/var/www/fortunes.txt";
25 | }
26 |
27 | if req.path == "/fortune" {
28 | fortune.page;
29 | } else {
30 | fortune.header;
31 | }
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/doc/mod_proxy.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | connect to HTTP backends for generating response content
4 |
5 |
6 | connect to HTTP backend
7 |
8 | socket to connect to, either "ip:port" or "unix:/path"
9 |
10 |
13 |
14 |
15 | setup {
16 | module_load "mod_proxy";
17 | }
18 |
19 | proxy "127.0.0.1:8080";
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/doc/mod_redirect.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | redirect clients by sending a http status code 301 plus Location header
4 |
5 |
6 | It supports matching [regular expressions](core_regex.html#core_regex) and [substitution](core_pattern.html#core_pattern) with captured substrings as well as other placeholders.
7 |
8 |
9 |
10 | redirect clients
11 |
12 | a simple target string or one rule, mapping a regular expression to a target string, or a list of rules.
13 |
14 |
15 | * The target string is a [pattern](core_pattern.html#core_pattern).
16 | * The [regular expressions](core_regex.html#core_regex) are used to match the request path (always starts with "/"!)
17 | * If a list of rules is given, redirect stops on the first match.
18 | * By default the target string is interpreted as absolute uri; if it starts with '?' it will replace the query string, if it starts with '/' it will replace the current path, and if it starts with './' it is interpreted relative to the current "directory" in the path.
19 |
20 |
21 |
22 | setup {
23 | module_load "mod_redirect";
24 | }
25 | if request.scheme == "http" {
26 | if request.query == "" {
27 | redirect "https://%{request.host}%{enc:request.path}";
28 | } else {
29 | redirect "https://%{request.host}%{enc:request.path}?%{request.query}";
30 | }
31 | }
32 |
33 |
34 |
35 |
36 | setup {
37 | module_load "mod_redirect";
38 | }
39 | if request.host !~ "^www\.(.*)$" {
40 | if request.query == "" {
41 | redirect "http://www.%{request.host}%{enc:request.path}";
42 | } else {
43 | redirect "http://www.%{request.host}%{enc:request.path}?%{request.query}";
44 | }
45 | }
46 |
47 |
48 |
49 |
50 | setup {
51 | module_load "mod_redirect";
52 | }
53 | redirect "^/old_url$" => "http://new.example.tld/url"
54 |
55 |
56 |
57 |
58 |
59 | redirect all non www. requests. for example: foo.tld/bar?x=y to www.foo.tld/bar?x=y
60 |
61 |
62 | if request.host !~ "^www\.(.*)$" {
63 | redirect "." => "http://www.%1/$0?%{request.query}";
64 | }
65 |
66 |
67 |
68 |
69 |
70 | enable debug output
71 | false
72 |
73 |
74 |
--------------------------------------------------------------------------------
/doc/mod_scgi.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | connect to SCGI backends for generating response content
4 |
5 |
6 | connect to SCGI backend
7 |
8 | socket to connect to, either "ip:port" or "unix:/path"
9 |
10 |
11 |
12 | setup {
13 | module_load "mod_scgi";
14 | }
15 |
16 | if req.path =^ "/RPC2" {
17 | scgi "127.0.0.1:5000";
18 | }
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/doc/mod_status.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | displays a page with internal statistics like amount of requests (total or per second), active connections etc.
4 |
5 |
6 | defines the stylesheet to use. available: unset (default), "blue" or any url you wish
7 |
8 | not set
9 |
10 |
11 | status.css = "blue";
12 |
13 |
14 |
15 |
16 |
17 | returns the status page to the client
18 |
19 | (optional) "short"
20 |
21 |
22 | The "short" mode removes connection and runtime details (recommended for "public" status).
23 |
24 | The status page accepts the following query-string parameters:
25 |
26 | * `?mode=runtime`: shows the runtime details
27 | * `format=plain`: shows the "short" stats in plain text format
28 |
29 |
30 |
31 | If /server-status is requested, a page with lighttpd statistics is displayed.
32 |
33 |
34 | setup {
35 | module_load "mod_status";
36 | }
37 |
38 | if req.path == "/server-status" {
39 | status.info;
40 | }
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/doc/mod_throttle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | limits outgoing bandwidth usage
4 |
5 |
6 | All rates are in bytes/sec. The magazines are filled up in fixed intervals (compile time constant; defaults to 200ms).
7 |
8 |
9 |
10 | set the outgoing throttle limits for current connection
11 |
12 | bytes/sec limit
13 |
14 |
15 | optional, defaults to 2*rate
16 |
17 |
18 | `burst` is the initial and maximum value for the `magazine`; doing IO drains the `magazine`, which fills up again over time with the specified `rate`.
19 |
20 |
21 |
22 |
23 | adds the current connection to a throttle pool for outgoing limits
24 |
25 | bytes/sec limit
26 |
27 |
28 | all connections in the same pool are limited as whole. Each `io.throttle_pool` action creates its own pool.
29 |
30 |
31 |
32 | Using the same pool in more than one place:
33 |
34 |
35 | setup {
36 | module_load "mod_throttle";
37 | }
38 | downloadLimit = {
39 | io.throttle_pool 1mbyte;
40 | }
41 | # now use it wherever you need it...
42 | downloadLimit;
43 |
44 |
45 |
46 |
47 |
48 | adds the current connection to an IP-based throttle pool for outgoing limits
49 |
50 | bytes/sec limit
51 |
52 |
53 | all connections from the same IP address in the same pool are limited as whole. Each `io.throttle_ip` action creates its own pool.
54 |
55 |
56 |
57 | Using the same pool in more than one place:
58 |
59 |
60 | setup {
61 | module_load "mod_throttle";
62 | }
63 | downloadLimit = {
64 | io.throttle_ip 200kbyte;
65 | }
66 | # now use it wherever you need it...
67 | downloadLimit;
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/doc/mod_userdir.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | allows you to have user-specific document roots being accessed through http://domain/~user/
4 |
5 |
9 |
10 |
11 | builds the document root by replacing certain placeholders in path with (parts of) the username.
12 |
13 | the path to build the document root with
14 |
15 |
38 |
39 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/include/lighttpd/actions_lua.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_ACTIONS_LUA_H_
2 | #define _LIGHTTPD_ACTIONS_LUA_H_
3 |
4 | #include
5 | #include
6 |
7 | LI_API void li_lua_init_action_mt(liServer *srv, lua_State *L);
8 |
9 | LI_API liAction* li_lua_get_action(lua_State *L, int ndx);
10 | LI_API int li_lua_push_action(liServer *srv, lua_State *L, liAction *a);
11 |
12 | /* create new action from lua function */
13 | LI_API liAction* li_lua_make_action(lua_State *L, int ndx);
14 |
15 | /* either acquire a action ref or makes a new action from a lua function */
16 | LI_API liAction* li_lua_get_action_ref(lua_State *L, int ndx);
17 |
18 | #endif
19 |
--------------------------------------------------------------------------------
/include/lighttpd/angel.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_ANGEL_H_
2 | #define _LIGHTTPD_ANGEL_H_
3 |
4 | typedef void (*liAngelListenCB)(liServer *srv, int fd, gpointer data);
5 |
6 | typedef void (*liAngelLogOpen)(liServer *srv, int fd, gpointer data);
7 |
8 | /* interface to the angel; implementation needs to work without angel too */
9 | LI_API void li_angel_setup(liServer *srv);
10 |
11 | /* listen to a socket (mainloop context) */
12 | LI_API void li_angel_listen(liServer *srv, GString *str, liAngelListenCB cb, gpointer data);
13 |
14 | /* send log messages during startup to angel, frees the string */
15 | LI_API void li_angel_log(liServer *srv, GString *str);
16 |
17 | LI_API void li_angel_log_open_file(liServer *srv, liEventLoop *loop, GString *filename, liAngelLogOpen, gpointer data);
18 |
19 | /* angle_fake definitions, only for internal use */
20 | int li_angel_fake_listen(liServer *srv, GString *str);
21 | gboolean li_angel_fake_log(liServer *srv, GString *str);
22 | int li_angel_fake_log_open_file(liServer *srv, GString *filename);
23 |
24 | #endif
25 |
--------------------------------------------------------------------------------
/include/lighttpd/angel_base.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_ANGEL_BASE_H_
2 | #define _LIGHTTPD_ANGEL_BASE_H_
3 |
4 | #ifdef _LIGHTTPD_BASE_H_
5 | #error Do not mix lighty with angel code
6 | #endif
7 |
8 | #include
9 |
10 | #include
11 |
12 | #include
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | #include
22 |
23 | #include
24 |
25 | #endif
26 |
--------------------------------------------------------------------------------
/include/lighttpd/angel_config_parser.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_ANGEL_CONFIG_PARSER_H_
2 | #define _LIGHTTPD_ANGEL_CONFIG_PARSER_H_
3 |
4 | /* error handling */
5 | #define LI_ANGEL_CONFIG_PARSER_ERROR li_angel_config_parser_error_quark()
6 | LI_API GQuark li_angel_config_parser_error_quark(void);
7 |
8 | typedef enum {
9 | LI_ANGEL_CONFIG_PARSER_ERROR_PARSE, /* parse error */
10 | } liAngelConfigParserError;
11 |
12 | LI_API gboolean li_angel_config_parse_file(liServer *srv, const gchar *filename, GError **err);
13 |
14 | #endif
15 |
--------------------------------------------------------------------------------
/include/lighttpd/angel_data.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_ANGEL_DATA_H_
2 | #define _LIGHTTPD_ANGEL_DATA_H_
3 |
4 | /* write/read data from/to a buffer (GString) (binary)
5 | * this is not meant to be the most performant way to do this,
6 | * as communication with the angel shouldn't happen to often anyway.
7 | *
8 | * Please never send "user" data to the angel (i.e. do not implement
9 | * something like a mod_cgi via sending the request data to the angel;
10 | * instead use the angel to spawn a fastcgi backend (or something similar)
11 | * and send the request via a socket to the backend directly.
12 | */
13 |
14 | /* angel obviously doesn't work across platforms, so we don't need
15 | * to care about endianness
16 | */
17 |
18 | /* The buffer may be bigger of course, but a single string should not
19 | * exceed this length: */
20 | #define LI_ANGEL_DATA_MAX_STR_LEN 1024 /* must fit into a gint32 */
21 |
22 | /* Needed for reading data */
23 | typedef struct liAngelBuffer liAngelBuffer;
24 | struct liAngelBuffer {
25 | GString *data;
26 | gsize pos;
27 | };
28 |
29 | /* error handling */
30 | #define LI_ANGEL_DATA_ERROR li_angel_data_error_quark()
31 | LI_API GQuark li_angel_data_error_quark(void);
32 |
33 | typedef enum {
34 | LI_ANGEL_DATA_ERROR_EOF, /* not enough data to read value */
35 | LI_ANGEL_DATA_ERROR_INVALID_STRING_LENGTH, /* invalid string length read from buffer (< 0 || > max-str-len) */
36 | LI_ANGEL_DATA_ERROR_STRING_TOO_LONG /* string too long (len > max-str-len) */
37 | } liAngelDataError;
38 |
39 | /* write */
40 | LI_API gboolean li_angel_data_write_int32(GString *buf, gint32 i, GError **err);
41 | LI_API gboolean li_angel_data_write_int64(GString *buf, gint64 i, GError **err);
42 | LI_API gboolean li_angel_data_write_char (GString *buf, gchar c, GError **err);
43 | LI_API gboolean li_angel_data_write_str (GString *buf, const GString *str, GError **err);
44 | LI_API gboolean li_angel_data_write_cstr (GString *buf, const gchar *str, gsize len, GError **err);
45 |
46 | /* read:
47 | * - if the val pointer is NULL, the data will be discarded
48 | * - reading strings: if *val != NULL *val will be reused;
49 | * otherwise a new GString* will be created
50 | * - *val will only be modified if no error is returned
51 | */
52 | LI_API gboolean li_angel_data_read_int32(liAngelBuffer *buf, gint32 *val, GError **err);
53 | LI_API gboolean li_angel_data_read_int64(liAngelBuffer *buf, gint64 *val, GError **err);
54 | LI_API gboolean li_angel_data_read_char (liAngelBuffer *buf, gchar *val, GError **err);
55 | LI_API gboolean li_angel_data_read_str (liAngelBuffer *buf, GString **val, GError **err);
56 | LI_API gboolean li_angel_data_read_mem (liAngelBuffer *buf, GString **val, gsize len, GError **err);
57 |
58 | #endif
59 |
--------------------------------------------------------------------------------
/include/lighttpd/angel_log.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_ANGEL_LOG_H_
2 | #define _LIGHTTPD_ANGEL_LOG_H_
3 |
4 | #ifndef _LIGHTTPD_ANGEL_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | #define SEGFAULT(srv, fmt, ...) \
9 | do { \
10 | li_log_write_(srv, LI_LOG_LEVEL_ABORT, LI_LOG_FLAG_TIMESTAMP, "(crashing) %s:%d: "fmt, LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__); \
11 | li_print_backtrace_stderr(); \
12 | abort(); \
13 | } while(0)
14 |
15 | #define ERROR(srv, fmt, ...) \
16 | li_log_write(srv, LI_LOG_LEVEL_ERROR, LI_LOG_FLAG_TIMESTAMP, "error (%s:%d): "fmt, LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
17 |
18 | #define WARNING(srv, fmt, ...) \
19 | li_log_write(srv, LI_LOG_LEVEL_WARNING, LI_LOG_FLAG_TIMESTAMP, "warning (%s:%d): "fmt, LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
20 |
21 | #define INFO(srv, fmt, ...) \
22 | li_log_write(srv, LI_LOG_LEVEL_INFO, LI_LOG_FLAG_TIMESTAMP, "info (%s:%d): "fmt, LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
23 |
24 | #define DEBUG(srv, fmt, ...) \
25 | li_log_write(srv, LI_LOG_LEVEL_DEBUG, LI_LOG_FLAG_TIMESTAMP, "debug (%s:%d): "fmt, LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
26 |
27 | /* log messages from lighty always as ERROR */
28 | #define INSTANCE(srv, inst, msg) \
29 | li_log_write(srv, LI_LOG_LEVEL_ERROR, LI_LOG_FLAG_TIMESTAMP, "lighttpd[%d]: %s", (int) inst->pid, msg)
30 |
31 | #define GERROR(srv, error, fmt, ...) \
32 | li_log_write(srv, LI_LOG_LEVEL_ERROR, LI_LOG_FLAG_TIMESTAMP, "error (%s:%d): " fmt "\n %s", LI_REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__, error ? error->message : "Empty GError")
33 |
34 | #define BACKEND_LINES(srv, txt, ...) \
35 | li_log_split_lines_(srv, LI_LOG_LEVEL_INFO, LI_LOG_FLAG_TIMESTAMP, txt, __VA_ARGS__)
36 |
37 | typedef enum {
38 | LI_LOG_LEVEL_DEBUG,
39 | LI_LOG_LEVEL_INFO,
40 | LI_LOG_LEVEL_WARNING,
41 | LI_LOG_LEVEL_ERROR,
42 | LI_LOG_LEVEL_ABORT
43 | } liLogLevel;
44 |
45 | #define LI_LOG_LEVEL_COUNT (LI_LOG_LEVEL_ABORT+1)
46 |
47 | typedef enum {
48 | LI_LOG_TYPE_STDERR,
49 | LI_LOG_TYPE_FILE,
50 | LI_LOG_TYPE_PIPE,
51 | LI_LOG_TYPE_SYSLOG,
52 | LI_LOG_TYPE_NONE
53 | } liLogType;
54 |
55 | #define LI_LOG_FLAG_NONE (0x0) /* default flag */
56 | #define LI_LOG_FLAG_TIMESTAMP (0x1) /* prepend a timestamp to the log message */
57 |
58 | typedef struct liLog liLog;
59 |
60 | struct liLog {
61 | liLogType type;
62 | gboolean levels[LI_LOG_LEVEL_COUNT];
63 | GString *path;
64 | gint fd;
65 |
66 | time_t last_ts;
67 | GString *ts_cache;
68 |
69 | GString *log_line;
70 | };
71 |
72 | LI_API void li_log_init(liServer *srv);
73 | LI_API void li_log_clean(liServer *srv);
74 |
75 | LI_API void li_log_write(liServer *srv, liLogLevel log_level, guint flags, const gchar *fmt, ...) HEDLEY_PRINTF_FORMAT(4, 5);
76 |
77 | /* replaces '\r' and '\n' with '\0' */
78 | LI_API void li_log_split_lines(liServer *srv, liLogLevel log_level, guint flags, gchar *txt, const gchar *prefix);
79 | LI_API void li_log_split_lines_(liServer *srv, liLogLevel log_level, guint flags, gchar *txt, const gchar *fmt, ...) HEDLEY_PRINTF_FORMAT(5, 6);
80 |
81 | #endif
82 |
--------------------------------------------------------------------------------
/include/lighttpd/angel_plugin_core.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_ANGEL_PLUGIN_CORE_H_
2 | #define _LIGHTTPD_ANGEL_PLUGIN_CORE_H_
3 |
4 | #include
5 |
6 | LI_API gboolean li_plugin_core_init(liServer *srv);
7 |
8 | #endif
9 |
--------------------------------------------------------------------------------
/include/lighttpd/angel_proc.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_ANGEL_PROC_H_
2 | #define _LIGHTTPD_ANGEL_PROC_H_
3 |
4 | #ifndef _LIGHTTPD_ANGEL_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | /* The callback is not allowed to close the epipe */
9 | typedef void (*liErrorPipeCB)(liServer *srv, liErrorPipe *epipe, GString *msg);
10 |
11 | typedef void (*liProcSetupCB)(gpointer ctx);
12 |
13 | struct liErrorPipe {
14 | liServer *srv;
15 | gpointer ctx;
16 | liErrorPipeCB cb;
17 |
18 | int fds[2];
19 | liEventIO fd_watcher;
20 | };
21 |
22 | struct liProc {
23 | liServer *srv;
24 |
25 | pid_t child_pid;
26 | liErrorPipe *epipe;
27 | gchar *appname;
28 | };
29 |
30 | LI_API liErrorPipe* li_error_pipe_new(liServer *srv, liErrorPipeCB cb, gpointer ctx);
31 | LI_API void li_error_pipe_free(liErrorPipe *epipe);
32 |
33 | /** closes out-fd */
34 | LI_API void li_error_pipe_activate(liErrorPipe *epipe);
35 |
36 | /** closes in-fd, moves out-fd to dest_fd */
37 | LI_API void li_error_pipe_use(liErrorPipe *epipe, int dest_fd);
38 |
39 | /** read remaining data from in-fd */
40 | LI_API void li_error_pipe_flush(liErrorPipe *epipe);
41 |
42 | LI_API liProc* li_proc_new(liServer *srv, gchar **args, gchar **env, uid_t uid, gid_t gid, gchar *username, gint64 rlim_core, gint64 rlim_nofile, liProcSetupCB cb, gpointer ctx);
43 | LI_API void li_proc_free(liProc *proc);
44 |
45 | #endif
46 |
--------------------------------------------------------------------------------
/include/lighttpd/angel_server.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_ANGEL_SERVER_H_
2 | #define _LIGHTTPD_ANGEL_SERVER_H_
3 |
4 | #ifndef _LIGHTTPD_ANGEL_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | #ifndef LIGHTTPD_ANGEL_MAGIC
9 | #define LIGHTTPD_ANGEL_MAGIC ((guint)0x3e14ac65)
10 | #endif
11 |
12 | typedef void (*liInstanceResourceFreeCB) (liServer *srv, liInstance *i, liPlugin *p, liInstanceResource *res);
13 |
14 | struct liInstanceConf {
15 | gint refcount;
16 |
17 | gchar **cmd;
18 | gchar **env;
19 | GString *username;
20 | uid_t uid;
21 | gid_t gid;
22 |
23 | gint64 rlim_core, rlim_nofile; /* < 0: don't change, G_MAXINT64: unlimited */
24 | };
25 |
26 | struct liInstance {
27 | gint refcount;
28 |
29 | liServer *srv;
30 | liInstanceConf *ic;
31 |
32 | int pid; /** < remember PID for process as instance ID, even if process is already gone */
33 | liProc *proc;
34 | liEventChild child_watcher;
35 |
36 | liInstanceState s_cur, s_dest;
37 |
38 | liInstance *replace, *replace_by;
39 |
40 | liAngelConnection *acon;
41 |
42 | GPtrArray *resources;
43 | };
44 |
45 | struct liServer {
46 | guint32 magic; /** server magic version, check against LIGHTTPD_ANGEL_MAGIC in plugins */
47 |
48 | liEventLoop loop;
49 | liEventSignal
50 | sig_w_INT,
51 | sig_w_TERM,
52 | sig_w_PIPE;
53 |
54 | liPlugins plugins;
55 |
56 | liLog log;
57 |
58 | gboolean one_shot; /* don't restart instance if it goes down */
59 | };
60 |
61 | struct liInstanceResource {
62 | liInstanceResourceFreeCB free_cb;
63 | liPlugin *plugin; /* may be NULL - we don't care about that */
64 | guint ndx; /* internal array index */
65 |
66 | gpointer data;
67 | };
68 |
69 | LI_API liServer* li_server_new(const gchar *module_dir, gboolean module_resident);
70 | LI_API void li_server_free(liServer* srv);
71 |
72 | LI_API void li_server_stop(liServer *srv);
73 |
74 | LI_API liInstance* li_server_new_instance(liServer *srv, liInstanceConf *ic);
75 | LI_API gboolean li_instance_replace(liInstance *oldi, liInstance *newi);
76 | LI_API void li_instance_set_state(liInstance *i, liInstanceState s);
77 | LI_API void li_instance_state_reached(liInstance *i, liInstanceState s);
78 |
79 | LI_API liInstanceConf* li_instance_conf_new(gchar **cmd, gchar **env, GString *username, uid_t uid, gid_t gid, gint64 rlim_core, gint64 rlim_nofile);
80 | LI_API void li_instance_conf_release(liInstanceConf *ic);
81 | LI_API void li_instance_conf_acquire(liInstanceConf *ic);
82 |
83 | LI_API void li_instance_release(liInstance *i);
84 | LI_API void li_instance_acquire(liInstance *i);
85 |
86 | LI_API void li_instance_add_resource(liInstance *i, liInstanceResource *res, liInstanceResourceFreeCB free_cb, liPlugin *p, gpointer data);
87 | LI_API void li_instance_rem_resource(liInstance *i, liInstanceResource *res);
88 |
89 | #endif
90 |
--------------------------------------------------------------------------------
/include/lighttpd/angel_typedefs.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_ANGEL_TYPEDEFS_H_
2 | #define _LIGHTTPD_ANGEL_TYPEDEFS_H_
3 |
4 | /* angel_proc.h */
5 |
6 | typedef struct liErrorPipe liErrorPipe;
7 | typedef struct liProc liProc;
8 |
9 | /* angel_server.h */
10 |
11 | typedef enum {
12 | LI_INSTANCE_DOWN, /* not started yet */
13 | LI_INSTANCE_SUSPENDED, /* inactive, neither accept nor logs, handle remaining connections */
14 | LI_INSTANCE_WARMUP, /* only accept(), no logging: waiting for another instance to suspend */
15 | LI_INSTANCE_RUNNING, /* everything running */
16 | LI_INSTANCE_SUSPENDING, /* suspended accept(), still logging, handle remaining connections */
17 | LI_INSTANCE_FINISHED /* not running */
18 | } liInstanceState;
19 |
20 | typedef struct liServer liServer;
21 | typedef struct liInstance liInstance;
22 | typedef struct liInstanceConf liInstanceConf;
23 | typedef struct liInstanceResource liInstanceResource;
24 |
25 | #endif
26 |
--------------------------------------------------------------------------------
/include/lighttpd/base.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_BASE_H_
2 | #define _LIGHTTPD_BASE_H_
3 |
4 | #ifdef _LIGHTTPD_ANGEL_BASE_H_
5 | #error Do not mix lighty with angel code
6 | #endif
7 |
8 | #include
9 |
10 | #include
11 | #include
12 |
13 | #include
14 | #include
15 |
16 | #include
17 | #include
18 | #include
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 | #include
46 | #include
47 |
48 | #include
49 |
50 | #include
51 | #include
52 | #include
53 | #include
54 |
55 | #define SERVER_VERSION ((guint) 0x01FF0000)
56 |
57 | #endif
58 |
--------------------------------------------------------------------------------
/include/lighttpd/base_lua.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_BASE_LUA_H_
2 | #define _LIGHTTPD_BASE_LUA_H_
3 |
4 | #ifndef _LIGHTTPD_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | /* this file defines lighttpd <-> lua glue which is always active, even if compiled without lua */
9 |
10 | struct lua_State;
11 |
12 | struct liLuaState {
13 | struct lua_State* L; /** NULL if compiled without Lua */
14 | GStaticRecMutex lualock;
15 | int li_env_ref;
16 | int li_env_default_metatable_ref;
17 | };
18 |
19 | LI_API void li_lua_init(liLuaState* LL, liServer* srv, liWorker* wrk);
20 | LI_API void li_lua_clear(liLuaState* LL);
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/include/lighttpd/buffer.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_BUFFER_H_
2 | #define _LIGHTTPD_BUFFER_H_
3 |
4 | #include
5 |
6 | #include
7 |
8 | typedef struct liBuffer liBuffer;
9 | struct liBuffer {
10 | gchar *addr;
11 | gsize alloc_size;
12 | gsize used;
13 | gint refcount;
14 | liMempoolPtr mptr;
15 | };
16 |
17 | /* shared buffer; free memory after last reference is released */
18 |
19 | /** create new buffer: optimized for short-term buffers which will be released soon, uses mempool */
20 | LI_API liBuffer* li_buffer_new(gsize max_size);
21 | /** create new buffer; optimized for long-term buffers, uses g_slice_alloc */
22 | LI_API liBuffer* li_buffer_new_slice(gsize max_size);
23 |
24 | LI_API void li_buffer_acquire(liBuffer *buf);
25 | LI_API void li_buffer_release(liBuffer *buf);
26 |
27 | #endif
28 |
--------------------------------------------------------------------------------
/include/lighttpd/chunk_parser.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_CHUNK_PARSER_H_
2 | #define _LIGHTTPD_CHUNK_PARSER_H_
3 |
4 | #ifndef _LIGHTTPD_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | struct liChunkParserCtx {
9 | liChunkQueue *cq;
10 |
11 | goffset bytes_in;
12 |
13 | /* current position
14 | * buf is curi[start..start+length)
15 | */
16 | liChunkIter curi;
17 | off_t start, length;
18 | char *buf;
19 |
20 | int cs;
21 | };
22 |
23 | struct liChunkParserMark {
24 | liChunkIter ci;
25 | off_t pos, abs_pos;
26 | };
27 |
28 | LI_API void li_chunk_parser_init(liChunkParserCtx *ctx, liChunkQueue *cq);
29 | LI_API void li_chunk_parser_reset(liChunkParserCtx *ctx);
30 | LI_API liHandlerResult li_chunk_parser_prepare(liChunkParserCtx *ctx);
31 | LI_API liHandlerResult li_chunk_parser_next(liChunkParserCtx *ctx, char **p, char **pe, GError **err);
32 | LI_API void li_chunk_parser_done(liChunkParserCtx *ctx, goffset len);
33 |
34 | /* extract [from..to) */
35 | LI_API gboolean li_chunk_extract_to(liChunkParserMark from, liChunkParserMark to, GString *dest, GError **err);
36 | LI_API GString* li_chunk_extract(liChunkParserMark from, liChunkParserMark to, GError **err);
37 |
38 | INLINE liChunkParserMark li_chunk_parser_getmark(liChunkParserCtx *ctx, const char *fpc);
39 |
40 | /********************
41 | * Inline functions *
42 | ********************/
43 |
44 | INLINE liChunkParserMark li_chunk_parser_getmark(liChunkParserCtx *ctx, const char *fpc) {
45 | liChunkParserMark m;
46 | m.ci = ctx->curi;
47 | m.pos = ctx->start + fpc - ctx->buf;
48 | m.abs_pos = ctx->bytes_in + fpc - ctx->buf;
49 | return m;
50 | }
51 |
52 | #define LI_GETMARK(FPC) (li_chunk_parser_getmark(&ctx->chunk_ctx, FPC))
53 |
54 | #endif
55 |
--------------------------------------------------------------------------------
/include/lighttpd/collect.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_COLLECT_H_
2 | #define _LIGHTTPD_COLLECT_H_
3 |
4 | #ifndef _LIGHTTPD_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | /* executes a function in each worker context */
9 |
10 | /** CollectFunc: the type of functions to execute in each workers context
11 | * - wrk: the current worker
12 | * - fdata: optional user data
13 | * the return value will be placed in the GArray
14 | */
15 | typedef gpointer (*liCollectFuncCB)(liWorker *wrk, gpointer fdata);
16 |
17 | /** CollectCallback: the type of functions to call after a function was called in each workers context
18 | * - cbdata: optional callback data
19 | * depending on the data you should only use it when complete == TRUE
20 | * - fdata : the data the CollectFunc got (this data must be valid until cb is called)
21 | * - result: the return values
22 | * - complete: determines if cbdata is still valid
23 | * if this is FALSE, it may be called from another context than li_collect_start was called
24 | */
25 | typedef void (*liCollectCB)(gpointer cbdata, gpointer fdata, GPtrArray *result, gboolean complete);
26 |
27 | typedef struct liCollectInfo liCollectInfo;
28 |
29 | /** li_collect_start returns NULL if the callback was called directly (e.g. for only one worker and ctx = wrk) */
30 | LI_API liCollectInfo* li_collect_start(liWorker *ctx, liCollectFuncCB func, gpointer fdata, liCollectCB cb, gpointer cbdata);
31 | /** li_collect_start_global uses srv->main_worker to call cb(), and never returns directly */
32 | LI_API liCollectInfo* li_collect_start_global(liServer *srv, liCollectFuncCB func, gpointer fdata, liCollectCB cb, gpointer cbdata);
33 | LI_API void li_collect_break(liCollectInfo* ci); /** this will result in complete == FALSE in the callback; call it if cbdata gets invalid */
34 |
35 | /* internal functions */
36 | LI_API void li_collect_watcher_cb(liEventBase *watcher, int events);
37 |
38 | #endif
39 |
--------------------------------------------------------------------------------
/include/lighttpd/condition_lua.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_CONDITION_LUA_H_
2 | #define _LIGHTTPD_CONDITION_LUA_H_
3 |
4 | #include
5 | #include
6 |
7 | LI_API void li_lua_init_condition_mt(liServer *srv, lua_State *L);
8 |
9 | LI_API liCondition* li_lua_get_condition(lua_State *L, int ndx);
10 | LI_API int li_lua_push_condition(liServer *srv, lua_State *L, liCondition *c);
11 |
12 | LI_API void li_lua_set_global_condition_lvalues(liServer *srv, lua_State *L);
13 |
14 | #endif
15 |
--------------------------------------------------------------------------------
/include/lighttpd/config_lua.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_CONFIG_LUA_H_
2 | #define _LIGHTTPD_CONFIG_LUA_H_
3 |
4 | #include
5 | #include
6 |
7 | LI_API gboolean li_config_lua_load(liLuaState *LL, liServer *srv, liWorker *wrk, const gchar *filename, liAction **pact, gboolean allow_setup, liValue *args);
8 |
9 | LI_API void li_lua_push_action_table(liServer *srv, liWorker *wrk, lua_State *L);
10 | LI_API void li_lua_push_setup_table(liServer *srv, liWorker *wrk, lua_State *L);
11 |
12 | #endif
13 |
--------------------------------------------------------------------------------
/include/lighttpd/config_parser.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_CONFIGPARSER_H_
2 | #define _LIGHTTPD_CONFIGPARSER_H_
3 |
4 | #include
5 |
6 | #define LI_CONFIG_ERROR li_config_error_quark()
7 | LI_API GQuark li_config_error_quark(void);
8 |
9 | LI_API gboolean li_config_parse(liServer *srv, const gchar *config_path);
10 |
11 | /* parse more config snippets at runtime. does not support includes and modifying global vars */
12 | LI_API liAction* li_config_parse_live(liWorker *wrk, const gchar *sourcename, const char *source, gsize sourcelen, GError **error);
13 |
14 | #endif
15 |
--------------------------------------------------------------------------------
/include/lighttpd/encoding.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_ENCODING_H_
2 | #define _LIGHTTPD_ENCODING_H_
3 |
4 | #include
5 |
6 | typedef enum {
7 | LI_ENCODING_HEX, /* a => 61 */
8 | LI_ENCODING_HTML, /* HTML special chars. & => & e.g. */
9 | LI_ENCODING_URI /* relative URI */
10 | } liEncoding;
11 |
12 |
13 | /* encodes special characters in a string and returns the new string */
14 | LI_API GString *li_string_encode_append(const gchar *str, GString *dest, liEncoding encoding);
15 | LI_API GString *li_string_encode(const gchar *str, GString *dest, liEncoding encoding);
16 |
17 | #endif
18 |
--------------------------------------------------------------------------------
/include/lighttpd/environment.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_ENVIRONMENT_H_
2 | #define _LIGHTTPD_ENVIRONMENT_H_
3 |
4 | #ifndef _LIGHTTPD_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | typedef struct liEnvironment liEnvironment;
9 |
10 | typedef struct liEnvironmentDup liEnvironmentDup;
11 |
12 | struct liEnvironment {
13 | GHashTable *table;
14 | };
15 |
16 | /* read only duplicate of a real environment: use it to remember which
17 | env vars you already sent (mod_fastcgi) */
18 | struct liEnvironmentDup {
19 | GHashTable *table;
20 | };
21 |
22 | LI_API void li_environment_init(liEnvironment *env); /* create table */
23 | LI_API void li_environment_reset(liEnvironment *env); /* remove all entries */
24 | LI_API void li_environment_clear(liEnvironment *env); /* destroy table */
25 |
26 | /* overwrite previous value */
27 | LI_API void li_environment_set(liEnvironment *env, const gchar *key, size_t keylen, const gchar *val, size_t valuelen);
28 | /* do not overwrite */
29 | LI_API void li_environment_insert(liEnvironment *env, const gchar *key, size_t keylen, const gchar *val, size_t valuelen);
30 | LI_API void li_environment_remove(liEnvironment *env, const gchar *key, size_t keylen);
31 | LI_API GString* li_environment_get(liEnvironment *env, const gchar *key, size_t keylen);
32 |
33 |
34 | /* create (data) read only copy of a environment; don't modify the real environment
35 | while using the duplicate */
36 | LI_API liEnvironmentDup* li_environment_make_dup(liEnvironment *env);
37 | LI_API void li_environment_dup_free(liEnvironmentDup *envdup);
38 | /* remove an entry (this is allowed - it doesn't modify anything in the original environment);
39 | you must not modify the returned GString */
40 | LI_API GString* li_environment_dup_pop(liEnvironmentDup *envdup, const gchar *key, size_t keylen);
41 |
42 | typedef void (*liAddEnvironmentCB)(gpointer param, const gchar *key, size_t keylen, const gchar *val, size_t valuelen);
43 | /* calls callback for various CGI environment variables to add; if the variable is also present
44 | in envdup, the value from envdup is used instead for the callback and it is popped from envdup.
45 | Also adds all remaining values from envdup via callback, and then frees envdup. */
46 | LI_API void li_environment_dup2cgi(liVRequest *vr, liEnvironmentDup *envdup, liAddEnvironmentCB callback, gpointer param);
47 |
48 | #endif
49 |
--------------------------------------------------------------------------------
/include/lighttpd/etag.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_ETAG_H_
2 | #define _LIGHTTPD_ETAG_H_
3 |
4 | #ifndef _LIGHTTPD_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | LI_API liTristate li_http_response_handle_cachable_etag(liVRequest *vr, GString *etag);
9 | LI_API liTristate li_http_response_handle_cachable_modified(liVRequest *vr, GString *last_modified);
10 | LI_API gboolean li_http_response_handle_cachable(liVRequest *vr);
11 |
12 | /* mut maybe the same as etag */
13 | LI_API void li_etag_mutate(GString *mut, GString *etag);
14 | LI_API void li_etag_set_header(liVRequest *vr, struct stat *st, gboolean *cachable);
15 |
16 | #endif
17 |
--------------------------------------------------------------------------------
/include/lighttpd/filter.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_FILTER_H_
2 | #define _LIGHTTPD_FILTER_H_
3 |
4 | #ifndef _LIGHTTPD_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | typedef liHandlerResult (*liFilterHandlerCB)(liVRequest *vr, liFilter *f);
9 | typedef void (*liFilterFreeCB)(liVRequest *vr, liFilter *f);
10 | typedef void (*liFilterEventCB)(liVRequest *vr, liFilter *f, liStreamEvent event);
11 |
12 | struct liFilter {
13 | liStream stream;
14 |
15 | liChunkQueue *in, *out;
16 |
17 | /* if the handler wasn't able to handle all "in" data it must call li_stream_again(&f->stream) to trigger a new call to handle_data
18 | * vr, in and out can be NULL if the associated vrequest/stream was destroyed
19 | * in handle_data out is never NULL
20 | */
21 | liFilterHandlerCB handle_data;
22 | liFilterFreeCB handle_free;
23 | liFilterEventCB handle_event;
24 | gpointer param;
25 |
26 | liVRequest *vr;
27 | guint filter_ndx;
28 | };
29 |
30 | LI_API liFilter* li_filter_new(liVRequest *vr, liFilterHandlerCB handle_data, liFilterFreeCB handle_free, liFilterEventCB handle_event, gpointer param);
31 |
32 | LI_API liFilter* li_vrequest_add_filter_in(liVRequest *vr, liFilterHandlerCB handle_data, liFilterFreeCB handle_free, liFilterEventCB handle_event, gpointer param);
33 | LI_API liFilter* li_vrequest_add_filter_out(liVRequest *vr, liFilterHandlerCB handle_data, liFilterFreeCB handle_free, liFilterEventCB handle_event, gpointer param);
34 |
35 | LI_API void li_vrequest_filters_init(liVRequest *vr);
36 | LI_API void li_vrequest_filters_clear(liVRequest *vr);
37 | LI_API void li_vrequest_filters_reset(liVRequest *vr);
38 |
39 | #endif
40 |
--------------------------------------------------------------------------------
/include/lighttpd/filter_buffer_on_disk.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_FILTER_BUFFER_ON_DISK_H_
2 | #define _LIGHTTPD_FILTER_BUFFER_ON_DISK_H_
3 |
4 | #include
5 |
6 | /* flush_limit: -1: wait for end-of-stream, n >= 0: if more than n bytes have been written, the next part of the file gets forwarded to out */
7 | /* split_on_file_chunks: start a new file on FILE_CHUNK (those are not written to the file) */
8 | LI_API liStream* li_filter_buffer_on_disk(liVRequest *vr, goffset flush_limit, gboolean split_on_file_chunks);
9 | LI_API void li_filter_buffer_on_disk_stop(liStream *stream);
10 |
11 | #endif
12 |
--------------------------------------------------------------------------------
/include/lighttpd/filter_chunked.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_FILTER_CHUNKED_H_
2 | #define _LIGHTTPD_FILTER_CHUNKED_H_
3 |
4 | #ifndef _LIGHTTPD_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | /* initialize with zero */
9 | typedef struct {
10 | int parse_state;
11 | goffset cur_chunklen;
12 | } liFilterChunkedDecodeState;
13 |
14 | LI_API liHandlerResult li_filter_chunked_encode(liVRequest *vr, liChunkQueue *out, liChunkQueue *in);
15 | LI_API gboolean li_filter_chunked_decode(liVRequest *vr, liChunkQueue *out, liChunkQueue *in, liFilterChunkedDecodeState *state);
16 |
17 | #endif
18 |
--------------------------------------------------------------------------------
/include/lighttpd/http_range_parser.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_HTTP_RANGE_PARSER_H_
2 | #define _LIGHTTPD_HTTP_RANGE_PARSER_H_
3 |
4 | #include
5 |
6 | typedef struct {
7 | /* public */
8 | gboolean last_range;
9 | goffset range_start, range_length, range_end; /* length = end - start + 1; */
10 |
11 | /* private */
12 | GString *data;
13 | goffset limit; /* "file size" */
14 | gboolean found_valid_range;
15 |
16 | int cs;
17 | gchar *data_pos;
18 | } liParseHttpRangeState;
19 |
20 | typedef enum {
21 | LI_PARSE_HTTP_RANGE_OK,
22 | LI_PARSE_HTTP_RANGE_DONE,
23 | LI_PARSE_HTTP_RANGE_INVALID,
24 | LI_PARSE_HTTP_RANGE_NOT_SATISFIABLE
25 | } liParseHttpRangeResult;
26 |
27 | LI_API void li_parse_http_range_init(liParseHttpRangeState* s, const GString *range_str, goffset limit);
28 | LI_API liParseHttpRangeResult li_parse_http_range_next(liParseHttpRangeState* s);
29 | LI_API void li_parse_http_range_clear(liParseHttpRangeState* s);
30 |
31 | #endif
32 |
--------------------------------------------------------------------------------
/include/lighttpd/http_request_parser.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_HTTP_REQUEST_PARSER_H_
2 | #define _LIGHTTPD_HTTP_REQUEST_PARSER_H_
3 |
4 | #ifndef _LIGHTTPD_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | struct liHttpRequestCtx {
9 | liChunkParserCtx chunk_ctx;
10 | liRequest *request;
11 |
12 | liChunkParserMark mark;
13 | GString *h_key, *h_value;
14 | };
15 |
16 | LI_API void li_http_request_parser_init(liHttpRequestCtx* ctx, liRequest *req, liChunkQueue *cq);
17 | LI_API void li_http_request_parser_reset(liHttpRequestCtx* ctx);
18 | LI_API void li_http_request_parser_clear(liHttpRequestCtx *ctx);
19 |
20 | LI_API liHandlerResult li_http_request_parse(liVRequest *vr, liHttpRequestCtx *ctx);
21 |
22 |
23 | #endif
24 |
--------------------------------------------------------------------------------
/include/lighttpd/http_response_parser.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_HTTP_RESPONSE_PARSER_H_
2 | #define _LIGHTTPD_HTTP_RESPONSE_PARSER_H_
3 |
4 | #ifndef _LIGHTTPD_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | struct liHttpResponseCtx {
9 | liChunkParserCtx chunk_ctx;
10 | liResponse *response;
11 |
12 | gboolean accept_cgi, accept_nph;
13 | gboolean drop_header; /* for 1xx responses */
14 |
15 | liHttpVersion http_version;
16 |
17 | liChunkParserMark mark;
18 | GString *h_key, *h_value;
19 | };
20 |
21 | LI_API void li_http_response_parser_init(liHttpResponseCtx* ctx, liResponse *req, liChunkQueue *cq, gboolean accept_cgi, gboolean accept_nph);
22 | LI_API void li_http_response_parser_reset(liHttpResponseCtx* ctx);
23 | LI_API void li_http_response_parser_clear(liHttpResponseCtx *ctx);
24 |
25 | LI_API liHandlerResult li_http_response_parse(liVRequest *vr, liHttpResponseCtx *ctx);
26 |
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/include/lighttpd/idlist.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_IDLIST_H_
2 | #define _LIGHTTPD_IDLIST_H_
3 |
4 | #include
5 |
6 | typedef struct liIDList liIDList;
7 |
8 | struct liIDList {
9 | /* used ids are marked with a "1" in the bitvector (represented as array of gulong) */
10 | GArray *bitvector;
11 |
12 | /* all ids are in the range [0, max_ids[, i.e. 0 <= id < max_ids
13 | * although the type is guint, it has to fit in a gint too, as we
14 | * use gint for the ids in the interface, so we can use -1 as a special value.
15 | */
16 | guint max_ids;
17 |
18 | /* if all ids in [0, used_ids-1] are used, next_free_id is -1
19 | * if not, then all available ids are >= next_free_id,
20 | * so we can start at next_free_id for searching the next free id
21 | */
22 | gint next_free_id;
23 | guint used_ids;
24 | };
25 |
26 | /* create new idlist; the parameter max_ids is "signed" on purpose */
27 | LI_API liIDList* li_idlist_new(gint max_ids);
28 |
29 | /* free idlist */
30 | LI_API void li_idlist_free(liIDList *l);
31 |
32 | /* request new id; return -1 if no id is available, valid ids are always > 0 */
33 | LI_API gint li_idlist_get(liIDList *l);
34 |
35 | /* check whether an id is in use and can be "_put" */
36 | LI_API gboolean li_idlist_is_used(liIDList *l, gint id);
37 |
38 | /* release id. never release an id more than once! */
39 | LI_API void li_idlist_put(liIDList *l, gint id);
40 |
41 | #endif
42 |
--------------------------------------------------------------------------------
/include/lighttpd/ip_parsers.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_IP_PARSERS_H_
2 | #define _LIGHTTPD_IP_PARSERS_H_
3 |
4 | #include
5 |
6 | /** optional parameters are set to default values (netmask all bits, port 0) */
7 | /** parse an IPv4 (if netmask is not NULL with optional cidr netmask, if port is not NULL with optional port) */
8 | LI_API gboolean li_parse_ipv4(const char *str, guint32 *ip, guint32 *netmask, guint16 *port);
9 | /** parse an IPv6 (if network is not NULL with optional cidr network, if port is not NULL with optional port if the ip/cidr part is in [...]) */
10 | LI_API gboolean li_parse_ipv6(const char *str, guint8 *ip, guint *network, guint16 *port);
11 | /** print the ip into dest, return dest */
12 | LI_API GString* li_ipv6_tostring(GString *dest, const guint8 ip[16]);
13 |
14 | #endif
15 |
--------------------------------------------------------------------------------
/include/lighttpd/jobqueue.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_JOBQUEUE_H_
2 | #define _LIGHTTPD_JOBQUEUE_H_
3 |
4 | #ifndef _LIGHTTPD_EVENTS_H_
5 | #error Include lighttpd/events.h instead
6 | #endif
7 |
8 | typedef struct liJob liJob;
9 | typedef struct liJobRef liJobRef;
10 | typedef struct liJobQueue liJobQueue;
11 |
12 | typedef void (*liJobCB)(liJob *job);
13 |
14 | /* All data here is private; use the functions to interact with the job-queue */
15 |
16 | struct liJob {
17 | /* prevent running callback in a loop (delay if job generation == queue generation) */
18 | guint generation;
19 | GList link;
20 | liJobCB callback;
21 | liJobRef *ref;
22 | };
23 |
24 | struct liJobRef {
25 | gint refcount;
26 | liJob *job;
27 | liJobQueue *queue;
28 | };
29 |
30 | struct liJobQueue {
31 | guint generation;
32 |
33 | liEventPrepare prepare_watcher;
34 |
35 | GQueue queue;
36 | liEventTimer queue_watcher;
37 |
38 | GAsyncQueue *async_queue;
39 | liEventAsync async_queue_watcher;
40 | };
41 |
42 | LI_API void li_job_queue_init(liJobQueue *jq, liEventLoop *loop);
43 | LI_API void li_job_queue_clear(liJobQueue *jq); /* runs until all jobs are done */
44 |
45 | LI_API void li_job_init(liJob *job, liJobCB callback);
46 | LI_API void li_job_reset(liJob *job);
47 | /* remove job from queue if active and detach existing references, but doesn't reset loop detection */
48 | LI_API void li_job_stop(liJob *job);
49 | LI_API void li_job_clear(liJob *job);
50 |
51 | /* marks the job for later execution */
52 | LI_API void li_job_later(liJobQueue *jq, liJob *job);
53 | LI_API void li_job_later_ref(liJobRef *jobref); /* NOT thread-safe! */
54 | /* if the job didn't run in this generation yet, run it now; otherwise mark it for later execution */
55 | LI_API void li_job_now(liJobQueue *jq, liJob *job);
56 | LI_API void li_job_now_ref(liJobRef *jobref); /* NOT thread-safe! */
57 |
58 | LI_API void li_job_async(liJobRef *jobref);
59 | /* marks the job for later execution; this is the only threadsafe way to push a job to the queue */
60 |
61 | LI_API liJobRef* li_job_ref(liJobQueue *jq, liJob *job);
62 | LI_API void li_job_ref_release(liJobRef *jobref);
63 | LI_API void li_job_ref_acquire(liJobRef *jobref);
64 |
65 | #endif
66 |
--------------------------------------------------------------------------------
/include/lighttpd/lighttpd-glue.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_LIGHTTPD_GLUE_H_
2 | #define _LIGHTTPD_LIGHTTPD_GLUE_H_
3 |
4 | /* returns the description for a given http status code and sets the len to the length of the returned string */
5 | LI_API gchar *li_http_status_string(guint status_code, guint *len);
6 | /* returns the liHttpMethod enum entry matching the given string */
7 | LI_API liHttpMethod li_http_method_from_string(const gchar *method_str, gssize len);
8 | /* returns the http method as a string and sets len to the length of the returned string */
9 | LI_API gchar *li_http_method_string(liHttpMethod method, guint *len);
10 | /* returns the http version as a string and sets len to the length of the returned string */
11 | LI_API gchar *li_http_version_string(liHttpVersion method, guint *len);
12 | /* converts a given 3 digit http status code to a gchar[3] string. e.g. 403 to {'4','0','3'} */
13 | LI_API void li_http_status_to_str(gint status_code, gchar status_str[]);
14 |
15 | #endif
16 |
--------------------------------------------------------------------------------
/include/lighttpd/memcached.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_MEMCACHED_H_
2 | #define _LIGHTTPD_MEMCACHED_H_
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | typedef struct liMemcachedCon liMemcachedCon;
9 | typedef struct liMemcachedItem liMemcachedItem;
10 | typedef struct liMemcachedRequest liMemcachedRequest;
11 | typedef enum {
12 | LI_MEMCACHED_OK, /* STORED, VALUE, DELETED */
13 | LI_MEMCACHED_NOT_STORED,
14 | LI_MEMCACHED_EXISTS,
15 | LI_MEMCACHED_NOT_FOUND,
16 | LI_MEMCACHED_RESULT_ERROR /* some error occurred */
17 | } liMemcachedResult;
18 |
19 | typedef void (*liMemcachedCB)(liMemcachedRequest *request, liMemcachedResult result, liMemcachedItem *item, GError **err);
20 |
21 | struct liMemcachedItem {
22 | GString *key;
23 | guint32 flags;
24 | li_tstamp ttl;
25 | guint64 cas;
26 | liBuffer *data;
27 | };
28 |
29 | struct liMemcachedRequest {
30 | liMemcachedCB callback;
31 | gpointer cb_data;
32 | };
33 |
34 | /* error handling */
35 | #define LI_MEMCACHED_ERROR li_memcached_error_quark()
36 | LI_API GQuark li_memcached_error_quark(void);
37 |
38 | typedef enum {
39 | LI_MEMCACHED_CONNECTION,
40 | LI_MEMCACHED_BAD_KEY,
41 | LI_MEMCACHED_DISABLED, /* disabled right now */
42 | LI_MEMCACHED_UNKNOWN = 0xff
43 | } liMemcachedError;
44 |
45 | LI_API liMemcachedCon* li_memcached_con_new(liEventLoop *loop, liSocketAddress addr);
46 | LI_API void li_memcached_con_acquire(liMemcachedCon* con);
47 | LI_API void li_memcached_con_release(liMemcachedCon* con); /* thread-safe */
48 |
49 | /* these functions are not thread-safe, i.e. must be called in the same context as "loop" from li_memcached_con_new */
50 | LI_API liMemcachedRequest* li_memcached_get(liMemcachedCon *con, GString *key, liMemcachedCB callback, gpointer cb_data, GError **err);
51 | LI_API liMemcachedRequest* li_memcached_set(liMemcachedCon *con, GString *key, guint32 flags, li_tstamp ttl, liBuffer *data, liMemcachedCB callback, gpointer cb_data, GError **err);
52 |
53 | /* if length(key) <= 250 and all chars x: 0x20 < x < 0x7f the key
54 | * remains untouched; otherwise it gets replaced with its sha1hex hash
55 | * so in most cases the key stays readable, and we have a good fallback
56 | */
57 | LI_API void li_memcached_mutate_key(GString *key);
58 | LI_API gboolean li_memcached_is_key_valid(GString *key);
59 |
60 | #endif
61 |
--------------------------------------------------------------------------------
/include/lighttpd/mempool.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_MEMPOOL_H_
2 | #define _LIGHTTPD_MEMPOOL_H_
3 |
4 | #include
5 |
6 | typedef struct liMempoolPtr liMempoolPtr;
7 | struct liMempoolPtr {
8 | void *priv_data; /* private data for internal management */
9 | void *data; /* real pointer (result of alloc) */
10 | };
11 |
12 | LI_API gsize li_mempool_align_page_size(gsize size);
13 | LI_API liMempoolPtr li_mempool_alloc(gsize size);
14 |
15 | /* you cannot release parts from an allocated chunk; so you _have_ to remember the size from the alloc */
16 | LI_API void li_mempool_free(liMempoolPtr ptr, gsize size);
17 |
18 | LI_API void li_mempool_cleanup(void);
19 |
20 | #endif
21 |
--------------------------------------------------------------------------------
/include/lighttpd/meson.build:
--------------------------------------------------------------------------------
1 | configure_file(output: 'config.h', configuration: conf_data)
2 |
--------------------------------------------------------------------------------
/include/lighttpd/mimetype.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_MIMETYPE_H_
2 | #define _LIGHTTPD_MIMETYPE_H_
3 |
4 | struct liMimetypeNode {
5 | guchar cmin;
6 | guchar cmax;
7 | gpointer *children; /* array of either liMimetypeNode* or GString* */
8 | GString *mimetype;
9 | };
10 | typedef struct liMimetypeNode liMimetypeNode;
11 |
12 | LI_API liMimetypeNode *li_mimetype_node_new(void);
13 | LI_API void li_mimetype_node_free(liMimetypeNode *node);
14 | LI_API void li_mimetype_insert(liMimetypeNode *node, GString *suffix, GString *mimetype);
15 |
16 | /* looks up the mimetype for a filename by comparing suffixes. longest match is returned. do not free the result */
17 | LI_API GString *li_mimetype_get(liVRequest *vr, GString *filename);
18 |
19 | #endif
20 |
--------------------------------------------------------------------------------
/include/lighttpd/network.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_NETWORK_H_
2 | #define _LIGHTTPD_NETWORK_H_
3 |
4 | #ifndef _LIGHTTPD_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | #if defined(USE_LINUX_SENDFILE) || defined(USE_FREEBSD_SENDFILE) || defined(USE_SOLARIS_SENDFILEV) || defined(USE_OSX_SENDFILE)
9 | # define USE_SENDFILE
10 | #endif
11 |
12 | #define LI_NETWORK_ERROR li_network_error_quark()
13 | LI_API GQuark li_network_error_quark(void);
14 |
15 | /** repeats write after EINTR */
16 | LI_API ssize_t li_net_write(int fd, void *buf, ssize_t nbyte);
17 |
18 | /** repeats read after EINTR */
19 | LI_API ssize_t li_net_read(int fd, void *buf, ssize_t nbyte);
20 |
21 | LI_API liNetworkStatus li_network_write(int fd, liChunkQueue *cq, goffset write_max, GError **err);
22 | LI_API liNetworkStatus li_network_read(int fd, liChunkQueue *cq, goffset read_max, liBuffer **buffer, GError **err);
23 |
24 | /* use writev for mem chunks, buffered read/write for files */
25 | LI_API liNetworkStatus li_network_write_writev(int fd, liChunkQueue *cq, goffset *write_max, GError **err);
26 |
27 | #ifdef USE_SENDFILE
28 | /* use sendfile for files, writev for mem chunks */
29 | LI_API liNetworkStatus li_network_write_sendfile(int fd, liChunkQueue *cq, goffset *write_max, GError **err);
30 | #endif
31 |
32 | /* write backends */
33 | LI_API liNetworkStatus li_network_backend_write(int fd, liChunkQueue *cq, goffset *write_max, GError **err);
34 | LI_API liNetworkStatus li_network_backend_writev(int fd, liChunkQueue *cq, goffset *write_max, GError **err);
35 |
36 | #define LI_NETWORK_FALLBACK(f, write_max) do { \
37 | liNetworkStatus res; \
38 | switch(res = f(fd, cq, write_max, err)) { \
39 | case LI_NETWORK_STATUS_SUCCESS: \
40 | break; \
41 | default: \
42 | return res; \
43 | } \
44 | } while(0)
45 |
46 | #endif
47 |
--------------------------------------------------------------------------------
/include/lighttpd/options.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_OPTIONS_H_
2 | #define _LIGHTTPD_OPTIONS_H_
3 |
4 | #ifndef _LIGHTTPD_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | union liOptionValue {
9 | gint64 number;
10 | gboolean boolean;
11 | };
12 |
13 | struct liOptionPtrValue {
14 | gint refcount;
15 |
16 | union {
17 | gpointer ptr;
18 |
19 | /* some common pointer types */
20 | GString *string;
21 | GPtrArray *list;
22 | GHashTable *hash;
23 | liAction *action;
24 | liCondition *cond;
25 | } data;
26 |
27 | liServerOptionPtr *sopt;
28 | };
29 |
30 | struct liOptionSet {
31 | size_t ndx;
32 | liOptionValue value;
33 | };
34 |
35 | struct liOptionPtrSet {
36 | size_t ndx;
37 | liOptionPtrValue *value;
38 | };
39 |
40 | #endif
41 |
--------------------------------------------------------------------------------
/include/lighttpd/pattern.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_PATTERN_H_
2 | #define _LIGHTTPD_PATTERN_H_
3 |
4 | /* liPattern are a parsed representation of a string that can contain various placeholders like $n, %n, %{var} or {enc:var} */
5 |
6 | /* liPattern is a GArray in disguise */
7 | typedef GArray liPattern;
8 |
9 | /* a pattern callback receives an integer index range [from-to] and a data pointer (usually an array) and must return a GString* which gets inserted into the pattern result
10 | * "from" doesn't have to be smaller than "to" (allows reverse ranges)!
11 | */
12 | typedef void (*liPatternCB) (GString *pattern_result, guint from, guint to, gpointer data);
13 |
14 | /* constructs a new liPattern* by parsing the given string, returns NULL on error */
15 | LI_API liPattern *li_pattern_new(liServer *srv, const gchar* str);
16 | LI_API void li_pattern_free(liPattern *pattern);
17 |
18 | /* appends the result to "dest". use (and truncate) vr->wrk->tmp_str as "dest" if possible */
19 | LI_API void li_pattern_eval(liVRequest *vr, GString *dest, liPattern *pattern, liPatternCB nth_callback, gpointer nth_data, liPatternCB nth_prev_callback, gpointer nth_prev_data);
20 |
21 | /* default array callback, expects a GArray* containing GString* elements */
22 | LI_API void li_pattern_array_cb(GString *pattern_result, guint from, guint to, gpointer data);
23 | /* default regex callback, expects a GMatchInfo* */
24 | LI_API void li_pattern_regex_cb(GString *pattern_result, guint from, guint to, gpointer data);
25 |
26 | #endif
27 |
--------------------------------------------------------------------------------
/include/lighttpd/plugin_core.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_PLUGIN_CORE_H_
2 | #define _LIGHTTPD_PLUGIN_CORE_H_
3 |
4 | #include
5 |
6 | typedef enum { LI_ETAG_USE_INODE = 1, LI_ETAG_USE_MTIME = 2, LI_ETAG_USE_SIZE = 4 } liETagFlags;
7 |
8 | enum liCoreOptions {
9 | LI_CORE_OPTION_DEBUG_REQUEST_HANDLING = 0,
10 |
11 | LI_CORE_OPTION_STATIC_RANGE_REQUESTS,
12 |
13 | LI_CORE_OPTION_MAX_KEEP_ALIVE_IDLE,
14 | LI_CORE_OPTION_MAX_KEEP_ALIVE_REQUESTS,
15 |
16 | LI_CORE_OPTION_ETAG_FLAGS,
17 |
18 | LI_CORE_OPTION_ASYNC_STAT,
19 |
20 | LI_CORE_OPTION_BUFFER_ON_DISK_REQUEST_BODY,
21 |
22 | LI_CORE_OPTION_STRICT_POST_CONTENT_LENGTH,
23 | };
24 |
25 | enum liCoreOptionPtrs {
26 | LI_CORE_OPTION_STATIC_FILE_EXCLUDE_EXTENSIONS = 0,
27 |
28 | LI_CORE_OPTION_SERVER_NAME,
29 | LI_CORE_OPTION_SERVER_TAG,
30 |
31 | LI_CORE_OPTION_MIME_TYPES,
32 | };
33 |
34 | /* the core plugin always has base index 0, as it is the first plugin loaded */
35 | #define CORE_OPTION(idx) _CORE_OPTION(vr, idx)
36 | #define _CORE_OPTION(vr, idx) _OPTION_ABS(vr, idx)
37 | #define CORE_OPTIONPTR(idx) _CORE_OPTIONPTR(vr, idx)
38 | #define _CORE_OPTIONPTR(vr, idx) _OPTIONPTR_ABS(vr, idx)
39 |
40 | LI_API void li_plugin_core_init(liServer *srv, liPlugin *p, gpointer userdata);
41 |
42 | #endif
43 |
--------------------------------------------------------------------------------
/include/lighttpd/profiler.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_PROFILER_H_
2 | #define _LIGHTTPD_PROFILER_H_
3 |
4 | extern gboolean li_profiler_enabled; /* read only */
5 |
6 | typedef struct liProfilerMem liProfilerMem;
7 |
8 | struct liProfilerMem {
9 | guint64 inuse_bytes;
10 | guint64 alloc_times;
11 | guint64 alloc_bytes;
12 | guint64 calloc_times;
13 | guint64 calloc_bytes;
14 | guint64 realloc_times;
15 | guint64 realloc_bytes;
16 | guint64 free_times;
17 | guint64 free_bytes;
18 | };
19 |
20 | LI_API void li_profiler_enable(gchar *output_path); /* enables the profiler */
21 | LI_API void li_profiler_finish(void);
22 | LI_API void li_profiler_dump(gint minsize); /* dumps memory statistics to file specified in LI_PROFILE_MEM env var */
23 | LI_API void li_profiler_hashtable_insert(const gpointer addr, gsize size); /* registers an allocated block with the profiler */
24 | LI_API void li_profiler_hashtable_remove(const gpointer addr); /* deregisters an allocated block with the profiler */
25 |
26 | #endif
27 |
--------------------------------------------------------------------------------
/include/lighttpd/radix.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_RADIX_H_
2 | #define _LIGHTTPD_RADIX_H_
3 |
4 | #include
5 |
6 | typedef struct liRadixTree liRadixTree;
7 |
8 | LI_API liRadixTree* li_radixtree_new(void);
9 | LI_API void li_radixtree_free(liRadixTree *tree, GFunc free_func, gpointer free_userdata);
10 |
11 | LI_API gpointer li_radixtree_insert(liRadixTree *tree, const void *key, guint32 bits, gpointer data); /* returns old data after overwrite */
12 | LI_API gpointer li_radixtree_remove(liRadixTree *tree, const void *key, guint32 bits); /* returns data from removed node */
13 | LI_API gpointer li_radixtree_lookup(liRadixTree *tree, const void *key, guint32 bits); /* longest matching prefix */
14 | LI_API gpointer li_radixtree_lookup_exact(liRadixTree *tree, const void *key, guint32 bits);
15 |
16 | LI_API void li_radixtree_foreach(liRadixTree *tree, GFunc func, gpointer userdata);
17 |
18 | #endif
19 |
--------------------------------------------------------------------------------
/include/lighttpd/request.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_REQUEST_H_
2 | #define _LIGHTTPD_REQUEST_H_
3 |
4 | #ifndef _LIGHTTPD_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | struct liRequestUri {
9 | GString *raw; /* may include scheme and authority before path_raw */
10 | GString *raw_path, *raw_orig_path; /* not decoded path with querystring */
11 |
12 | GString *scheme;
13 | GString *authority; /* authority: may include auth and ports and hostname trailing dots */
14 | GString *path;
15 | GString *query;
16 |
17 | GString *host; /* without userinfo and port and trailing dots */
18 | };
19 |
20 | struct liPhysical {
21 | GString *path;
22 | GString *doc_root;
23 | GString *pathinfo;
24 | };
25 |
26 | struct liRequest {
27 | liHttpMethod http_method;
28 | GString *http_method_str;
29 | liHttpVersion http_version;
30 |
31 | liRequestUri uri;
32 |
33 | liHttpHeaders *headers;
34 | /* Parsed headers: */
35 | goffset content_length; /* -1 if not specified; implies chunked transfer-encoding */
36 | };
37 |
38 | LI_API void li_request_init(liRequest *req);
39 | LI_API void li_request_reset(liRequest *req);
40 | LI_API void li_request_clear(liRequest *req);
41 |
42 | LI_API void li_request_copy(liRequest *dest, const liRequest *src);
43 |
44 | LI_API gboolean li_request_validate_header(liConnection *con);
45 |
46 | LI_API void li_physical_init(liPhysical *phys);
47 | LI_API void li_physical_reset(liPhysical *phys);
48 | LI_API void li_physical_clear(liPhysical *phys);
49 |
50 | #endif
51 |
--------------------------------------------------------------------------------
/include/lighttpd/response.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_RESPONSE_H_
2 | #define _LIGHTTPD_RESPONSE_H_
3 |
4 | #ifndef _LIGHTTPD_BASE_H_
5 | #error Please include instead of this file
6 | #endif
7 |
8 | struct liResponse {
9 | liHttpHeaders *headers;
10 | gint http_status;
11 | liTransferEncoding transfer_encoding;
12 | };
13 |
14 | LI_API void li_response_init(liResponse *resp);
15 | LI_API void li_response_reset(liResponse *resp);
16 | LI_API void li_response_clear(liResponse *resp);
17 |
18 | LI_API void li_response_send_headers(liVRequest *vr, liChunkQueue *raw_out, liChunkQueue *response_body, gboolean upgraded);
19 |
20 | #endif
21 |
--------------------------------------------------------------------------------
/include/lighttpd/stream_http_response.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_STREAM_HTTP_RESPONSE_H_
2 | #define _LIGHTTPD_STREAM_HTTP_RESPONSE_H_
3 |
4 | #include
5 |
6 | LI_API liStream* li_stream_http_response_handle(liStream *http_in, liVRequest *vr, gboolean accept_cgi, gboolean accept_nph, gboolean keepalive);
7 |
8 | #endif
9 |
--------------------------------------------------------------------------------
/include/lighttpd/sys_memory.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_SYS_MEMORY_H_
2 | #define _LIGHTTPD_SYS_MEMORY_H_
3 |
4 | /* returns the currently used memory (RSS, resident set size) in bytes or 0 on failure */
5 | LI_API gsize li_memory_usage(void);
6 |
7 | #endif
8 |
--------------------------------------------------------------------------------
/include/lighttpd/tasklet.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_TASKLET_H_
2 | #define _LIGHTTPD_TASKLET_H_
3 |
4 | #include
5 | #include
6 |
7 | typedef struct liTaskletPool liTaskletPool;
8 |
9 | typedef void (*liTaskletFinishedCB)(gpointer data);
10 | typedef void (*liTaskletRunCB)(gpointer data);
11 |
12 | /* if threads = 0: all run callbacks are executed immediately in li_tasklet_push (but finished_cb is delayed)
13 | * if threads < 0: a shared GThreadPool is used
14 | * if threads > 0: a exclusive GThreadPool is used with the specified numbers of threads
15 | */
16 |
17 | /* we do not keep the loop alive! */
18 | LI_API liTaskletPool* li_tasklet_pool_new(liEventLoop *loop, gint threads);
19 |
20 | /* blocks until all tasks are done; calls all finished callbacks;
21 | * you are allowed to call this from finish callbacks, but not more than once!
22 | */
23 | LI_API void li_tasklet_pool_free(liTaskletPool *pool);
24 |
25 | /* this may stop the old pool and wait for all jobs to be finished; doesn't call finished callbacks */
26 | LI_API void li_tasklet_pool_set_threads(liTaskletPool *pool, gint threads);
27 |
28 | LI_API gint li_tasklet_pool_get_threads(liTaskletPool *pool);
29 |
30 | /* the finished callback is executed in the same thread context as the pool lives in;
31 | * it will either be called from li_tasklet_pool_free or the ev-loop handler,
32 | * never from li_tasklet_push
33 | * all tasklets will be executed, you can *not* cancel them!
34 | */
35 | LI_API void li_tasklet_push(liTaskletPool *pool, liTaskletRunCB run, liTaskletFinishedCB finished, gpointer data);
36 |
37 | #endif
38 |
--------------------------------------------------------------------------------
/include/lighttpd/throttle.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_THROTTLE_H_
2 | #define _LIGHTTPD_THROTTLE_H_
3 |
4 | #include
5 |
6 | #define LI_THROTTLE_GRANULARITY 200 /* defines how frequently (in milliseconds) a magazine is refilled */
7 |
8 | typedef void (*liThrottleNotifyCB)(liThrottleState *state, gpointer data);
9 |
10 | LI_API liThrottleState* li_throttle_new(void);
11 | LI_API void li_throttle_set(liWorker *wrk, liThrottleState *state, guint rate, guint burst);
12 | LI_API void li_throttle_free(liWorker *wrk, liThrottleState *state);
13 |
14 | LI_API guint li_throttle_query(liWorker *wrk, liThrottleState *state, guint interested, liThrottleNotifyCB notify_callback, gpointer data);
15 | LI_API void li_throttle_update(liThrottleState *state, guint used);
16 |
17 | LI_API liThrottlePool* li_throttle_pool_new(liServer *srv, guint rate, guint burst);
18 | LI_API void li_throttle_pool_acquire(liThrottlePool *pool);
19 | LI_API void li_throttle_pool_release(liThrottlePool *pool, liServer *srv);
20 |
21 | /* returns whether pool was actually added (otherwise it already was added) */
22 | LI_API gboolean li_throttle_add_pool(liWorker *wrk, liThrottleState *state, liThrottlePool *pool);
23 | LI_API void li_throttle_remove_pool(liWorker *wrk, liThrottleState *state, liThrottlePool *pool);
24 |
25 | /* internal for worker waitqueue setup */
26 | LI_API void li_throttle_waitqueue_cb(liWaitQueue *wq, gpointer data);
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/include/lighttpd/url_parser.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_URL_PARSER_H_
2 | #define _LIGHTTPD_URL_PARSER_H_
3 |
4 | #include
5 |
6 | /* parses uri->raw into all components, which have to be reset/initialized before */
7 | LI_API gboolean li_parse_raw_url(liRequestUri *uri);
8 |
9 | /* parse input into uri->path, uri->raw_path and uri->query, which get truncated before.
10 | * also decodes and simplifies path on success
11 | */
12 | LI_API gboolean li_parse_raw_path(liRequestUri *uri, GString *input);
13 |
14 | LI_API gboolean li_parse_hostname(liRequestUri *uri);
15 |
16 | #endif
17 |
--------------------------------------------------------------------------------
/include/lighttpd/value_lua.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_OPTIONS_LUA_H_
2 | #define _LIGHTTPD_OPTIONS_LUA_H_
3 |
4 | #include
5 | #include
6 |
7 | LI_API void li_lua_init_value_mt(lua_State *L);
8 |
9 | /* converts the top of the stack into an value
10 | * and pops the value
11 | * returns NULL if it couldn't convert the value (still pops it)
12 | */
13 | LI_API liValue* li_value_from_lua(liServer *srv, lua_State *L);
14 |
15 | /* always returns 1, pushes nil on error */
16 | LI_API int li_lua_push_value(lua_State *L, liValue *value);
17 |
18 | LI_API GString* li_lua_togstring(lua_State *L, int ndx);
19 |
20 | #endif
21 |
--------------------------------------------------------------------------------
/include/lighttpd/version.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_VERSION_H_
2 | #define _LIGHTTPD_VERSION_H_
3 |
4 | #ifdef HAVE_VERSION_H
5 | #include
6 | #else
7 | #define REPO_VERSION ""
8 | #endif
9 |
10 | #define PACKAGE_DESC PACKAGE_NAME "/" PACKAGE_VERSION REPO_VERSION
11 |
12 | #endif
13 |
--------------------------------------------------------------------------------
/include/lighttpd/waitqueue.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_WAITQUEUE_H_
2 | #define _LIGHTTPD_WAITQUEUE_H_
3 |
4 | #include
5 | #include
6 |
7 | typedef struct liWaitQueueElem liWaitQueueElem;
8 | typedef struct liWaitQueue liWaitQueue;
9 | typedef void (*liWaitQueueCB) (liWaitQueue *wq, gpointer data);
10 |
11 | struct liWaitQueueElem {
12 | gboolean queued;
13 | li_tstamp ts;
14 | liWaitQueueElem *prev;
15 | liWaitQueueElem *next;
16 | gpointer data;
17 | };
18 |
19 | struct liWaitQueue {
20 | liWaitQueueElem *head;
21 | liWaitQueueElem *tail;
22 | liEventTimer timer;
23 | gdouble delay;
24 |
25 | liWaitQueueCB callback;
26 | gpointer data;
27 | guint length;
28 | };
29 |
30 | /*
31 | * waitqueues are queues used to implement delays for certain tasks in a lightweight, non-blocking way
32 | * they are used for io timeouts or throttling for example
33 | * li_waitqueue_push, li_waitqueue_pop and li_waitqueue_remove have O(1) complexity
34 | */
35 |
36 | /* initializes a waitqueue by creating the timer and initializing the queue. precision is sub-seconds */
37 | LI_API void li_waitqueue_init(liWaitQueue *queue, liEventLoop *loop, const char *waitqueue_name, liWaitQueueCB callback, gdouble delay, gpointer data);
38 |
39 | /* stops the waitqueue. to restart it, simply call li_waitqueue_update */
40 | LI_API void li_waitqueue_stop(liWaitQueue *queue);
41 |
42 | /* updates the delay of the timer. if timer is active, it is stopped and restarted */
43 | LI_API void li_waitqueue_set_delay(liWaitQueue *queue, gdouble delay);
44 |
45 | /* updates the timeout of the waitqueue, you should always call this at the end of your callback */
46 | LI_API void li_waitqueue_update(liWaitQueue *queue);
47 |
48 | /* moves the element to the end of the queue if already queued, appends it to the end otherwise */
49 | LI_API void li_waitqueue_push(liWaitQueue *queue, liWaitQueueElem *elem);
50 |
51 | /* pops the first ready! element from the queue or NULL if none ready yet. this should be called in your callback */
52 | LI_API liWaitQueueElem *li_waitqueue_pop(liWaitQueue *queue);
53 |
54 | /* pops the first element from the queue or NULL if empty. use it to clean your queue */
55 | LI_API liWaitQueueElem *li_waitqueue_pop_force(liWaitQueue *queue);
56 |
57 | /* pops all elements from the queue that are ready or NULL of none ready yet. returns number of elements pop()ed and saves old head in '*head' */
58 | LI_API guint li_waitqueue_pop_ready(liWaitQueue *queue, liWaitQueueElem **head);
59 |
60 | /* removes an element from the queue */
61 | LI_API void li_waitqueue_remove(liWaitQueue *queue, liWaitQueueElem *elem);
62 |
63 | #endif
64 |
--------------------------------------------------------------------------------
/include/meson.build:
--------------------------------------------------------------------------------
1 | inc_dir = include_directories('.', is_system: true)
2 |
3 | subdir('lighttpd')
4 |
--------------------------------------------------------------------------------
/meson_options.txt:
--------------------------------------------------------------------------------
1 | option('lua', type : 'boolean', value : true, description : 'Build with lua; extends core and other modules, and builds mod_lua')
2 | option('ipv6', type : 'boolean', value : true, description : 'Build with IPv6 support')
3 | option('config-parser', type : 'boolean', value : true, description : 'Build with standard config parser')
4 | option('unwind', type : 'boolean', value : true, description : 'Build with (lib)unwind support in asserts to print backtraces')
5 | option('openssl', type : 'boolean', value : true, description : 'Build mod_openssl')
6 | option('gnutls', type : 'boolean', value : true, description : 'Build mod_gnutls')
7 | option('sni', type : 'boolean', value : true, description : 'Build mod_openssl/mod_gnutls with SNI support')
8 | option('bzip2', type : 'boolean', value : true, description : 'Build mod_deflate with bzip2 support')
9 | option('deflate', type : 'boolean', value : true, description : 'Build mod_deflate with zlib (deflate) support')
10 | option('extra-warnings', type : 'boolean', value : true, description : 'Build with extra warnings enabled')
11 | # option('static', type : 'boolean', value : false, description : 'Build static lighttpd with all modules included')
12 | option('profiler', type : 'boolean', value : false, description : 'Build with memory profiler')
13 |
14 | option('search-lib', type : 'array', value : [], description: 'Search libs in additional paths')
15 | option('search-inc', type : 'array', value : [], description: 'Search includes in additional paths')
16 |
--------------------------------------------------------------------------------
/packdist.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # only builds snapshots for now
4 | # tarball name contains date and git short id
5 |
6 | SRCTEST=src/main/lighttpd_worker.c
7 | PACKAGE=lighttpd
8 | REV=${REV}
9 | BASEDOWNLOADURL="https://download.lighttpd.net/lighttpd/snapshots-2.0.x"
10 |
11 | if [ ! -f ${SRCTEST} ]; then
12 | echo "Current directory is not the source directory"
13 | exit 1
14 | fi
15 |
16 | dopack=1
17 | if [ "$1" = "--nopack" ]; then
18 | dopack=0
19 | shift
20 | fi
21 |
22 | append="$1"
23 |
24 | function force() {
25 | "$@" || {
26 | echo "Command failed: $*"
27 | exit 1
28 | }
29 | }
30 |
31 | if [ ${dopack} = "1" ]; then
32 | force ./autogen.sh
33 |
34 | if [ -d distbuild ]; then
35 | # make distcheck may leave readonly files
36 | chmod u+w -R distbuild
37 | rm -rf distbuild
38 | fi
39 |
40 | force mkdir distbuild
41 | force cd distbuild
42 |
43 | force ../configure --prefix=/usr
44 |
45 | # force make
46 | # force make check
47 |
48 | force make distcheck
49 | else
50 | force cd distbuild
51 | fi
52 |
53 | version=`./config.status -V | head -n 1 | cut -d' ' -f3`
54 | name="${PACKAGE}-${version}"
55 | append="-snap-$(date '+%Y%m%d')${REV}-g$(git rev-list --abbrev-commit --abbrev=6 HEAD^..HEAD)"
56 | if [ -n "${append}" ]; then
57 | cp "${name}.tar.gz" "${name}${append}.tar.gz"
58 | cp "${name}.tar.bz2" "${name}${append}.tar.bz2"
59 | name="${name}${append}"
60 | fi
61 |
62 | force sha256sum "${name}.tar."{gz,bz2} > "${name}.sha256sum"
63 |
64 | echo wget "${BASEDOWNLOADURL}/${name}".'{tar.gz,tar.bz2,sha256sum}; sha256sum -c '${name}'.sha256sum'
65 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.pyright]
2 | include = ["tests"]
3 |
4 | [[tool.pyright.executionEnvironments]]
5 | root = "tests"
6 |
7 | [tool.mypy]
8 | warn_unused_configs = true
9 | mypy_path = "tests"
10 | files = "tests"
11 | implicit_reexport = false
12 | show_error_codes = true
13 | follow_imports = "silent"
14 |
--------------------------------------------------------------------------------
/src/angel/angel_log.c:
--------------------------------------------------------------------------------
1 |
2 | #include
3 |
4 | void li_log_init(liServer *srv) {
5 | srv->log.type = LI_LOG_TYPE_STDERR;
6 |
7 | srv->log.levels[LI_LOG_LEVEL_ABORT] = TRUE;
8 | srv->log.levels[LI_LOG_LEVEL_ERROR] = TRUE;
9 | srv->log.levels[LI_LOG_LEVEL_WARNING] = TRUE;
10 |
11 | srv->log.levels[LI_LOG_LEVEL_INFO] = TRUE; /* TODO: remove debug levels */
12 | srv->log.levels[LI_LOG_LEVEL_DEBUG] = TRUE;
13 |
14 | srv->log.fd = -1;
15 | srv->log.ts_cache = g_string_sized_new(0);
16 | srv->log.log_line = g_string_sized_new(0);
17 | }
18 |
19 | void li_log_clean(liServer *srv) {
20 | g_string_free(srv->log.ts_cache, TRUE);
21 | g_string_free(srv->log.log_line, TRUE);
22 | }
23 |
24 | void li_log_write(liServer *srv, liLogLevel log_level, guint flags, const gchar *fmt, ...) {
25 | va_list ap;
26 | GString *log_line = srv->log.log_line;
27 |
28 | if (!srv->log.levels[log_level]) return;
29 |
30 | g_string_truncate(log_line, 0);
31 |
32 | /* for normal error messages, we prepend a timestamp */
33 | if (flags & LI_LOG_FLAG_TIMESTAMP) {
34 | GString *log_ts = srv->log.ts_cache;
35 | time_t li_cur_ts;
36 |
37 | li_cur_ts = (time_t) (li_event_now(&srv->loop));
38 |
39 | if (li_cur_ts != srv->log.last_ts) {
40 | gsize s;
41 | struct tm tm;
42 |
43 | g_string_set_size(log_ts, 255);
44 | #ifdef HAVE_LOCALTIME_R
45 | s = strftime(log_ts->str, log_ts->allocated_len, "%Y-%m-%d %H:%M:%S %Z: ", localtime_r(&li_cur_ts, &tm));
46 | #else
47 | s = strftime(log_ts->str, log_ts->allocated_len, "%Y-%m-%d %H:%M:%S %Z: ", localtime(&li_cur_ts));
48 | #endif
49 |
50 | g_string_set_size(log_ts, s);
51 |
52 | srv->log.last_ts = li_cur_ts;
53 | }
54 |
55 | li_g_string_append_len(log_line, GSTR_LEN(log_ts));
56 | }
57 |
58 | va_start(ap, fmt);
59 | g_string_append_vprintf(log_line, fmt, ap);
60 | va_end(ap);
61 |
62 | li_g_string_append_len(log_line, CONST_STR_LEN("\n"));
63 |
64 | fprintf(stderr, "%s", log_line->str);
65 | }
66 |
67 | void li_log_split_lines(liServer *srv, liLogLevel log_level, guint flags, gchar *txt, const gchar *prefix) {
68 | gchar *start;
69 |
70 | start = txt;
71 | while ('\0' != *txt) {
72 | if ('\r' == *txt || '\n' == *txt) {
73 | *txt = '\0';
74 | if (txt - start > 1) { /* skip empty lines*/
75 | li_log_write(srv, log_level, flags, "%s%s", prefix, start);
76 | }
77 | txt++;
78 | while (*txt == '\n' || *txt == '\r') txt++;
79 | start = txt;
80 | } else {
81 | txt++;
82 | }
83 | }
84 | if (txt - start > 1) { /* skip empty lines*/
85 | li_log_write(srv, log_level, flags, "%s%s", prefix, start);
86 | }
87 | }
88 |
89 | void li_log_split_lines_(liServer *srv, liLogLevel log_level, guint flags, gchar *txt, const gchar *fmt, ...) {
90 | va_list ap;
91 | GString *prefix;
92 |
93 | prefix = g_string_sized_new(0);
94 | va_start(ap, fmt);
95 | g_string_vprintf(prefix, fmt, ap);
96 | va_end(ap);
97 |
98 | li_log_split_lines(srv, log_level, flags, txt, prefix->str);
99 |
100 | g_string_free(prefix, TRUE);
101 | }
102 |
--------------------------------------------------------------------------------
/src/angel/angel_value.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "../common/value_impl.c"
4 |
5 | liValue* li_value_copy(liValue* val) {
6 | return li_common_value_copy_(val);
7 | }
8 |
9 | void li_value_clear(liValue *val) {
10 | li_common_value_clear_(val);
11 | }
12 |
13 | const char* li_valuetype_string(liValueType type) {
14 | return li_common_valuetype_string_(type);
15 | }
16 |
17 | GString *li_value_to_string(liValue *val) {
18 | return li_common_value_to_string_(val);
19 | }
20 |
21 | gpointer li_value_extract_ptr(liValue *val) {
22 | return li_common_value_extract_ptr_(val);
23 | }
24 |
--------------------------------------------------------------------------------
/src/angel/meson.build:
--------------------------------------------------------------------------------
1 | src_angel_shared = [
2 | 'angel_log.c',
3 | 'angel_plugin.c',
4 | 'angel_plugin_core.c',
5 | 'angel_proc.c',
6 | 'angel_server.c',
7 | 'angel_value.c',
8 | ] + ragel_gen.process(
9 | 'angel_config_parser.rl',
10 | )
11 |
12 | lib_shared_angel = library(
13 | 'lighttpd2-sharedangel-' + meson.project_version(),
14 | src_angel_shared,
15 | include_directories: [inc_dir] + search_includes,
16 | dependencies: [
17 | main_deps,
18 | ],
19 | link_with: lib_common,
20 | install: true,
21 | )
22 |
23 | bin_angel = executable(
24 | 'lighttpd2',
25 | 'angel_main.c',
26 | include_directories: [inc_dir] + search_includes,
27 | dependencies: [
28 | main_deps,
29 | ],
30 | link_with: [
31 | lib_common,
32 | lib_shared_angel,
33 | ],
34 | install: true,
35 | install_dir: get_option('sbindir')
36 | )
37 |
--------------------------------------------------------------------------------
/src/common/buffer.c:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 |
5 | static void _buffer_init(liBuffer *buf, gsize alloc_size) {
6 | buf->alloc_size = alloc_size;
7 | buf->used = 0;
8 | buf->mptr = li_mempool_alloc(alloc_size);
9 | buf->addr = buf->mptr.data;
10 | }
11 |
12 | static void _buffer_init_slice(liBuffer *buf, gsize alloc_size) {
13 | buf->alloc_size = alloc_size;
14 | buf->used = 0;
15 | buf->mptr.data = NULL;
16 | buf->addr = g_slice_alloc(alloc_size);
17 | }
18 |
19 | static void _buffer_destroy(liBuffer *buf) {
20 | if (!buf || NULL == buf->addr) return;
21 |
22 | if (NULL == buf->mptr.data) {
23 | g_slice_free1(buf->alloc_size, buf->addr);
24 | } else {
25 | li_mempool_free(buf->mptr, buf->alloc_size);
26 | buf->addr = NULL;
27 | buf->mptr.data = NULL; buf->mptr.priv_data = NULL;
28 | buf->used = buf->alloc_size = 0;
29 | }
30 |
31 | g_slice_free(liBuffer, buf);
32 | }
33 |
34 |
35 | liBuffer* li_buffer_new(gsize max_size) {
36 | liBuffer *buf = g_slice_new0(liBuffer);
37 | _buffer_init(buf, li_mempool_align_page_size(max_size));
38 | buf->refcount = 1;
39 | return buf;
40 | }
41 |
42 | liBuffer* li_buffer_new_slice(gsize max_size) {
43 | liBuffer *buf = g_slice_new0(liBuffer);
44 | _buffer_init_slice(buf, max_size);
45 | buf->refcount = 1;
46 | return buf;
47 | }
48 |
49 | void li_buffer_release(liBuffer *buf) {
50 | if (!buf) return;
51 | LI_FORCE_ASSERT(g_atomic_int_get(&buf->refcount) > 0);
52 | if (g_atomic_int_dec_and_test(&buf->refcount)) {
53 | _buffer_destroy(buf);
54 | }
55 | }
56 |
57 | void li_buffer_acquire(liBuffer *buf) {
58 | LI_FORCE_ASSERT(g_atomic_int_get(&buf->refcount) > 0);
59 | g_atomic_int_inc(&buf->refcount);
60 | }
61 |
--------------------------------------------------------------------------------
/src/common/meson.build:
--------------------------------------------------------------------------------
1 | src_common = [
2 | 'angel_connection.c',
3 | 'angel_data.c',
4 | 'buffer.c',
5 | 'encoding.c',
6 | 'events.c',
7 | 'fetch.c',
8 | 'idlist.c',
9 | 'jobqueue.c',
10 | 'memcached.c',
11 | 'mempool.c',
12 | 'module.c',
13 | 'radix.c',
14 | 'sys_memory.c',
15 | 'sys_socket.c',
16 | 'tasklet.c',
17 | 'utils.c',
18 | 'value.c',
19 | # 'value_impl.c', -- "templated", gets included in main and angel
20 | 'waitqueue.c',
21 | ] + ragel_gen.process('ip_parsers.rl')
22 |
23 | if get_option('profiler')
24 | src_common += ['profiler.c']
25 | endif
26 |
27 | lib_common = library(
28 | 'lighttpd2-common-' + meson.project_version(),
29 | src_common,
30 | include_directories: [inc_dir] + search_includes,
31 | dependencies: [
32 | main_deps,
33 | opt_dep_unwind,
34 | lib_crypt,
35 | lib_kvm,
36 | ],
37 | install: true,
38 | )
39 |
--------------------------------------------------------------------------------
/src/common/sys_memory.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 |
4 | #if defined(LIGHTY_OS_LINUX)
5 | #include
6 |
7 | gsize li_memory_usage(void) {
8 | /* parse /proc/self/stat */
9 | int d;
10 | gchar s[PATH_MAX];
11 | gchar c;
12 | unsigned int u;
13 | long unsigned int lu;
14 | long int ld;
15 | long long unsigned int llu;
16 | gsize rss;
17 | FILE *f;
18 |
19 | f = fopen("/proc/self/stat", "r");
20 | if (!f)
21 | return 0;
22 |
23 | /* fields according to proc(5) */
24 | d = fscanf(
25 | f,
26 | "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu"
27 | " %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld",
28 | &d, s, &c, &d, &d, &d, &d, &d, &u, &lu, &lu, &lu, &lu, &lu, &lu, &ld, &ld, &ld, &ld, &ld, &ld, &lu, &lu,
29 | (long int*)&rss, &lu, &lu, &lu, &lu, &lu, &lu, &lu, &lu, &lu, &lu, &lu, &lu, &lu, &d, &d, &u, &u, &llu, &lu, &ld
30 | );
31 |
32 | fclose(f);
33 |
34 | /* rss is the 24th field */
35 | if (d < 24)
36 | return 0;
37 |
38 | return rss * getpagesize();
39 | }
40 |
41 | #elif defined(LIGHTY_OS_FREEBSD)
42 | #include
43 | #include
44 | #include
45 | #include
46 | #include
47 | #include
48 |
49 | gsize li_memory_usage(void) {
50 | kvm_t *kvm;
51 | struct kinfo_proc *ki_proc;
52 | gint cnt;
53 | gsize rss;
54 |
55 | kvm = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
56 | if (!kvm)
57 | return 0;
58 |
59 | ki_proc = kvm_getprocs(kvm, KERN_PROC_PID, getpid(), &cnt);
60 | if (!ki_proc) {
61 | kvm_close(kvm);
62 | return 0;
63 | }
64 |
65 | rss = ki_proc->ki_rssize * getpagesize();
66 |
67 | kvm_close(kvm);
68 |
69 | return rss;
70 | }
71 | #elif defined(LIGHTY_OS_MACOSX)
72 | #include
73 | #include
74 |
75 | gsize li_memory_usage(void) {
76 | /* info from https://miknight.blogspot.com/2005/11/resident-set-size-in-mac-os-x.html */
77 | struct task_basic_info tbinfo;
78 | mach_msg_type_number_t cnt = TASK_BASIC_INFO_COUNT;
79 |
80 | if (KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t) &tbinfo, &cnt))
81 | return 0;
82 |
83 | return tbinfo.resident_size;
84 | }
85 |
86 | #elif defined(LIGHTY_OS_SOLARIS)
87 |
88 | gsize li_memory_usage(void) {
89 | /* /proc/$pid/psinfo: http://docs.sun.com/app/docs/doc/816-5174/proc-4?l=en&a=view */
90 | gchar path[64];
91 | psinfo_t psinfo;
92 | FILE *f;
93 |
94 | sprintf(path, "/proc/%d/psinfo", getpid());
95 |
96 | f = fopen(path, "r");
97 | if (!f)
98 | return 0;
99 |
100 | if (fread(&psinfo, sizeof(psinfo_t), 1, f) != 1) {
101 | fclose(f);
102 | return 0;
103 | }
104 |
105 | return psinfo.pr_rssize * 1024;
106 | }
107 |
108 | #else
109 |
110 | gsize li_memory_usage(void) {
111 | /* unsupported OS */
112 | return 0;
113 | }
114 |
115 | #endif
116 |
--------------------------------------------------------------------------------
/src/common/sys_socket.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #ifndef HAVE_INET_ATON
5 | /* win32 has inet_addr instead if inet_aton */
6 | # ifdef HAVE_INET_ADDR
7 | int inet_aton(const char *cp, struct in_addr *inp) {
8 | struct in_addr a;
9 |
10 | a.s_addr = inet_addr(cp);
11 |
12 | if (INADDR_NONE == a.s_addr) {
13 | return 0;
14 | }
15 |
16 | inp->s_addr = a.s_addr;
17 |
18 | return 1;
19 | }
20 | # else
21 | # error no inet_aton emulation found
22 | # endif
23 |
24 | #endif
25 |
26 | #ifdef _WIN32
27 |
28 | #include
29 |
30 | /* windows doesn't have inet_ntop */
31 |
32 | /*
33 | I have to look into this more. WSAAddressToString takes a sockaddr structure, which includes
34 | the port number, so I must first test this stuff more carefully. For now, no IPV6 on windows.
35 | You will notice that HAVE_IPV6 is never true for win32.
36 | */
37 |
38 | const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
39 | {
40 | /* WSAAddressToString takes a full sockaddr, while inet_ntop only takes the address */
41 | struct sockaddr_in sock4;
42 | struct sockaddr_in6 sock6;
43 | DWORD addrLen = cnt;
44 | int err = 0;
45 |
46 | /* src is either an in_addr or an in6_addr. */
47 | const struct in_addr *src4 = (const struct in_addr*) src;
48 | const struct in6_addr *src6 = (const struct in6_addr*) src;
49 |
50 | int ipv6 = af == AF_INET6;
51 |
52 | /* DebugBreak(); */
53 |
54 | if ( ipv6 )
55 | {
56 | sock6.sin6_family = AF_INET6;
57 | sock6.sin6_port = 0;
58 | sock6.sin6_addr = *src6;
59 | }
60 | else
61 | {
62 | sock4.sin_family = AF_INET;
63 | sock4.sin_port = 0;
64 | sock4.sin_addr = *src4;
65 | }
66 |
67 | err = WSAAddressToStringA(
68 | ipv6 ? (LPSOCKADDR) &sock6 : (LPSOCKADDR) &sock4,
69 | ipv6 ? sizeof(sock6) : sizeof(sock4),
70 | NULL,
71 | dst, &addrLen );
72 | return err == 0 ? dst : NULL;
73 | }
74 |
75 |
76 | #endif
77 |
--------------------------------------------------------------------------------
/src/lighttpd2.pc.in:
--------------------------------------------------------------------------------
1 | prefix=@prefix@
2 | exec_prefix=@exec_prefix@
3 | libdir=@libdir@
4 | includedir=@includedir@
5 | version=@VERSION@
6 |
7 | INSTALL_MOD=@pkglibdir@
8 |
9 | Name: lighttpd2
10 | Description: modules for lighttpd2
11 | Version: ${version}
12 | Requires: glib-2.0
13 | Libs: -module -export-dynamic -avoid-version -no-undefined -L${libdir} -llighttpd2-common-${version} -llighttpd2-shared-${version} -lev
14 | Cflags: -I${includedir}
15 |
--------------------------------------------------------------------------------
/src/main/base_lua.c:
--------------------------------------------------------------------------------
1 |
2 | #include
3 |
4 | #ifdef HAVE_LUA_H
5 | # include
6 | # include
7 | #endif
8 |
9 | #ifdef HAVE_LUA_H
10 |
11 | void li_lua_init(liLuaState* LL, liServer* srv, liWorker* wrk) {
12 | lua_State *L = LL->L = luaL_newstate();
13 |
14 | lua_pushlightuserdata(L, LL);
15 | lua_setfield(L, LUA_REGISTRYINDEX, LI_LUA_REGISTRY_STATE);
16 |
17 | luaL_openlibs(LL->L);
18 | li_lua_init2(LL, srv, wrk);
19 |
20 | g_static_rec_mutex_init(&LL->lualock);
21 | }
22 |
23 | void li_lua_clear(liLuaState* LL) {
24 | lua_close(LL->L);
25 | LL->L = NULL;
26 |
27 | g_static_rec_mutex_free(&LL->lualock);
28 | }
29 |
30 | #else
31 |
32 | void li_lua_init(liLuaState* LL, liServer* srv, liWorker* wrk) {
33 | UNUSED(srv);
34 | UNUSED(wrk);
35 |
36 | LL->L = NULL;
37 | g_static_rec_mutex_init(&LL->lualock);
38 | }
39 |
40 | void li_lua_clear(liLuaState* LL) {
41 | g_static_rec_mutex_free(&LL->lualock);
42 | }
43 |
44 | #endif
45 |
--------------------------------------------------------------------------------
/src/main/http_range_parser.rl:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 |
5 | #include
6 |
7 | %%{
8 | machine http_range_parser;
9 | variable cs s->cs;
10 | variable p s->data_pos;
11 |
12 | SP = ' ';
13 | HT = '\t';
14 |
15 | ws = SP | HT;
16 |
17 | action int_start {
18 | tmp = 0;
19 | }
20 | action int_step {
21 | int d = fc - '0';
22 | if (tmp > (G_MAXOFFSET-10)/10) {
23 | s->cs = http_range_parser_error;
24 | return LI_PARSE_HTTP_RANGE_INVALID;
25 | }
26 | tmp = 10*tmp + d;
27 | }
28 |
29 | int = (digit digit**) >int_start $int_step ;
30 |
31 | action first_byte {
32 | s->range_start = tmp;
33 | }
34 | action last_byte {
35 | s->range_end = tmp;
36 | found = TRUE;
37 | }
38 | action last_byte_empty {
39 | s->range_end = s->limit - 1;
40 | found = TRUE;
41 | }
42 | action suffix_range {
43 | s->range_end = s->limit - 1;
44 | s->range_start = s->limit - tmp;
45 | found = TRUE;
46 | }
47 | action range_complete {
48 | fbreak;
49 | }
50 |
51 | range = (int %first_byte ws* "-" ws** (int %last_byte | "" %last_byte_empty) | "-" ws* int %suffix_range) ;
52 |
53 | main := ws* "bytes" ws* "=" (ws | ",")* range ( ws* "," >range_complete (ws | ",")* range)** (ws | ",")*;
54 |
55 | write data nofinal;
56 | }%%
57 |
58 | liParseHttpRangeResult li_parse_http_range_next(liParseHttpRangeState* s) {
59 | const char *pe, *eof;
60 | goffset tmp = 0;
61 |
62 | if (s->cs == http_range_parser_error) {
63 | return LI_PARSE_HTTP_RANGE_INVALID;
64 | }
65 |
66 | eof = pe = s->data->str + s->data->len;
67 |
68 | for ( ;; ) {
69 | gboolean found = FALSE;
70 |
71 | if (s->data_pos >= eof) {
72 | return s->found_valid_range ? LI_PARSE_HTTP_RANGE_DONE : LI_PARSE_HTTP_RANGE_NOT_SATISFIABLE;
73 | }
74 |
75 | %% write exec;
76 |
77 | if (s->cs == http_range_parser_error) {
78 | return LI_PARSE_HTTP_RANGE_INVALID;
79 | }
80 |
81 | if (s->data_pos >= eof) {
82 | s->last_range = TRUE;
83 | }
84 |
85 | if (!found) {
86 | return s->found_valid_range ? LI_PARSE_HTTP_RANGE_DONE : LI_PARSE_HTTP_RANGE_NOT_SATISFIABLE;
87 | }
88 |
89 | if (s->range_end >= s->limit) {
90 | s->range_end = s->limit - 1;
91 | }
92 | if (s->range_start < 0) {
93 | s->range_start = 0;
94 | }
95 |
96 | if (s->range_start <= s->range_end) {
97 | s->found_valid_range = TRUE;
98 | s->range_length = s->range_end - s->range_start + 1;
99 | return LI_PARSE_HTTP_RANGE_OK;
100 | }
101 | }
102 | }
103 |
104 | void li_parse_http_range_init(liParseHttpRangeState* s, const GString *range_str, goffset limit) {
105 | s->data = g_string_new_len(GSTR_LEN(range_str));
106 | s->data_pos = s->data->str;
107 | s->limit = limit;
108 | s->last_range = FALSE;
109 | s->found_valid_range = FALSE;
110 |
111 | (void) http_range_parser_en_main;
112 | %% write init;
113 | }
114 |
115 | void li_parse_http_range_clear(liParseHttpRangeState* s) {
116 | if (s->data) {
117 | g_string_free(s->data, TRUE);
118 | s->data = NULL;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/main/meson.build:
--------------------------------------------------------------------------------
1 | src_shared = [
2 | 'angel.c',
3 | 'angel_fake.c',
4 | 'actions.c',
5 | 'base_lua.c',
6 | 'backends.c',
7 | 'chunk.c',
8 | 'chunk_parser.c',
9 | 'collect.c',
10 | 'condition.c',
11 | 'connection.c',
12 | 'environment.c',
13 | 'etag.c',
14 | 'filter.c',
15 | 'filter_chunked.c',
16 | 'filter_buffer_on_disk.c',
17 | 'http_headers.c',
18 | 'lighttpd_glue.c',
19 | 'log.c',
20 | 'mimetype.c',
21 | 'network.c',
22 | 'network_write.c',
23 | 'network_writev.c',
24 | 'network_sendfile.c',
25 | 'options.c',
26 | 'pattern.c',
27 | 'plugin.c',
28 | 'request.c',
29 | 'response.c',
30 | 'server.c',
31 | 'stat_cache.c',
32 | 'stream.c',
33 | 'stream_http_response.c',
34 | 'stream_simple_socket.c',
35 | 'throttle.c',
36 | 'value.c',
37 | 'virtualrequest.c',
38 | 'worker.c',
39 | 'plugin_core.c',
40 | ] + ragel_gen.process(
41 | 'http_range_parser.rl',
42 | 'http_request_parser.rl',
43 | 'http_response_parser.rl',
44 | 'url_parser.rl',
45 | )
46 |
47 | if not get_option('config-parser')
48 | conf_data.set10('WITHOUT_CONFIG_PARSER', true)
49 | else
50 | src_shared += ragel_gen_t0.process('config_parser.rl')
51 | endif
52 |
53 | if get_option('lua')
54 | src_shared += [
55 | 'actions_lua.c',
56 | 'condition_lua.c',
57 | 'config_lua.c',
58 | 'value_lua.c',
59 | 'chunk_lua.c',
60 | 'core_lua.c',
61 | 'environment_lua.c',
62 | 'filters_lua.c',
63 | 'http_headers_lua.c',
64 | 'physical_lua.c',
65 | 'request_lua.c',
66 | 'response_lua.c',
67 | 'stat_lua.c',
68 | # 'subrequest_lua.c',
69 | 'virtualrequest_lua.c',
70 | ]
71 | endif
72 |
73 | lib_shared = library(
74 | 'lighttpd2-shared-' + meson.project_version(),
75 | src_shared,
76 | include_directories: [inc_dir] + search_includes,
77 | dependencies: [
78 | main_deps,
79 | opt_dep_lua,
80 | lib_m, # TODO: fmod in throttle.c
81 | ],
82 | link_with: lib_common,
83 | install: true,
84 | )
85 |
86 | bin_worker = executable(
87 | 'lighttpd2-worker',
88 | 'lighttpd_worker.c',
89 | include_directories: [inc_dir] + search_includes,
90 | dependencies: [
91 | main_deps,
92 | opt_dep_lua,
93 | ],
94 | link_with: [
95 | lib_shared,
96 | lib_common,
97 | ],
98 | install: true,
99 | install_dir: libexec_dir,
100 | )
101 |
--------------------------------------------------------------------------------
/src/main/network_write.c:
--------------------------------------------------------------------------------
1 |
2 | #include
3 |
4 | liNetworkStatus li_network_backend_write(int fd, liChunkQueue *cq, goffset *write_max, GError **err) {
5 | const ssize_t blocksize = 16*1024; /* 16k */
6 | char *block_data;
7 | off_t block_len;
8 | ssize_t r;
9 | gboolean did_write_something = FALSE;
10 | liChunkIter ci;
11 |
12 | do {
13 | if (0 == cq->length)
14 | return did_write_something ? LI_NETWORK_STATUS_SUCCESS : LI_NETWORK_STATUS_FATAL_ERROR;
15 |
16 | ci = li_chunkqueue_iter(cq);
17 | switch (li_chunkiter_read(ci, 0, blocksize, &block_data, &block_len, err)) {
18 | case LI_HANDLER_GO_ON:
19 | break;
20 | case LI_HANDLER_ERROR:
21 | default:
22 | return LI_NETWORK_STATUS_FATAL_ERROR;
23 | }
24 |
25 | if (-1 == (r = li_net_write(fd, block_data, block_len))) {
26 | switch (errno) {
27 | case EAGAIN:
28 | #if EWOULDBLOCK != EAGAIN
29 | case EWOULDBLOCK:
30 | #endif
31 | return did_write_something ? LI_NETWORK_STATUS_SUCCESS : LI_NETWORK_STATUS_WAIT_FOR_EVENT;
32 | case ECONNRESET:
33 | case EPIPE:
34 | case ETIMEDOUT:
35 | return LI_NETWORK_STATUS_CONNECTION_CLOSE;
36 | default:
37 | g_set_error(err, LI_NETWORK_ERROR, 0, "li_network_backend_write: oops, write to fd=%d failed: %s", fd, g_strerror(errno));
38 | return LI_NETWORK_STATUS_FATAL_ERROR;
39 | }
40 | } else if (0 == r) {
41 | return did_write_something ? LI_NETWORK_STATUS_SUCCESS : LI_NETWORK_STATUS_WAIT_FOR_EVENT;
42 | }
43 |
44 | li_chunkqueue_skip(cq, r);
45 | did_write_something = TRUE;
46 | *write_max -= r;
47 | } while (r == block_len && *write_max > 0);
48 |
49 | return LI_NETWORK_STATUS_SUCCESS;
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/options.c:
--------------------------------------------------------------------------------
1 |
2 | #include
3 |
4 |
--------------------------------------------------------------------------------
/src/meson.build:
--------------------------------------------------------------------------------
1 | subdir('common')
2 | subdir('angel')
3 | subdir('main')
4 | subdir('modules')
5 | subdir('unittests')
6 |
--------------------------------------------------------------------------------
/src/modules/fastcgi_stream.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_FASTCGI_STREAM_H_
2 | #define _LIGHTTPD_FASTCGI_STREAM_H_
3 |
4 | #include
5 | #include
6 |
7 | typedef struct liFastCGIBackendCallbacks liFastCGIBackendCallbacks;
8 | typedef struct liFastCGIBackendWait liFastCGIBackendWait;
9 | typedef struct liFastCGIBackendConnection liFastCGIBackendConnection;
10 | typedef struct liFastCGIBackendPool liFastCGIBackendPool;
11 | typedef struct liFastCGIBackendConfig liFastCGIBackendConfig;
12 |
13 | typedef void (*liFastCGIBackendConnectionResetCB)(liVRequest *vr, liFastCGIBackendPool *pool, liFastCGIBackendConnection *bcon);
14 | typedef void (*liFastCGIBackendConnectionEndRequestCB)(liVRequest *vr, liFastCGIBackendPool *pool, liFastCGIBackendConnection *bcon, guint32 appStatus);
15 | typedef void (*liFastCGIBackendConnectionStderrCB)(liVRequest *vr, liFastCGIBackendPool *pool, liFastCGIBackendConnection *bcon, GString *message);
16 |
17 |
18 | struct liFastCGIBackendConnection {
19 | gpointer data;
20 | };
21 |
22 | struct liFastCGIBackendCallbacks {
23 | liFastCGIBackendConnectionResetCB reset_cb;
24 | liFastCGIBackendConnectionEndRequestCB end_request_cb;
25 | liFastCGIBackendConnectionStderrCB fastcgi_stderr_cb;
26 | };
27 |
28 | struct liFastCGIBackendPool {
29 | liBackendPool *subpool;
30 | };
31 |
32 | struct liFastCGIBackendConfig {
33 | const liFastCGIBackendCallbacks *callbacks;
34 |
35 | /* see liBackendConfig */
36 | liSocketAddress sock_addr;
37 | int max_connections;
38 | guint idle_timeout;
39 | guint connect_timeout;
40 | guint wait_timeout;
41 | guint disable_time;
42 | int max_requests;
43 | };
44 |
45 | /* config gets copied, can be freed after this call */
46 | LI_API liFastCGIBackendPool* li_fastcgi_backend_pool_new(const liFastCGIBackendConfig *config);
47 | LI_API void li_fastcgi_backend_pool_free(liFastCGIBackendPool *bpool);
48 |
49 | LI_API liBackendResult li_fastcgi_backend_get(liVRequest *vr, liFastCGIBackendPool *bpool, liFastCGIBackendConnection **pbcon, liFastCGIBackendWait **pbwait);
50 | LI_API void li_fastcgi_backend_wait_stop(liVRequest *vr, liFastCGIBackendPool *bpool, liFastCGIBackendWait **pbwait);
51 |
52 | /* only call from reset or end_request callbacks */
53 | LI_API void li_fastcgi_backend_put(liFastCGIBackendConnection *bcon);
54 |
55 | #endif
56 |
--------------------------------------------------------------------------------
/src/modules/gnutls_filter.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_GNUTLS_FILTER_H_
2 | #define _LIGHTTPD_GNUTLS_FILTER_H_
3 |
4 | #include
5 |
6 | #include
7 |
8 | typedef struct liGnuTLSFilter liGnuTLSFilter;
9 |
10 | typedef void (*liGnuTLSFilterHandshakeCB)(liGnuTLSFilter *f, gpointer data, liStream *plain_source, liStream *plain_drain);
11 | typedef void (*liGnuTLSFilterClosedCB)(liGnuTLSFilter *f, gpointer data);
12 | typedef int (*liGnuTLSFilterPostClientHelloCB)(liGnuTLSFilter *f, gpointer data);
13 |
14 | typedef struct liGnuTLSFilterCallbacks liGnuTLSFilterCallbacks;
15 | struct liGnuTLSFilterCallbacks {
16 | liGnuTLSFilterHandshakeCB handshake_cb; /* called after initial handshake is done */
17 | liGnuTLSFilterClosedCB closed_cb;
18 | liGnuTLSFilterPostClientHelloCB post_client_hello_cb;
19 | };
20 |
21 | LI_API liGnuTLSFilter* li_gnutls_filter_new(
22 | liServer *srv, liWorker *wrk,
23 | const liGnuTLSFilterCallbacks *callbacks, gpointer data,
24 | gnutls_session_t session, liStream *crypt_source, liStream *crypt_drain);
25 |
26 | /* doesn't call closed_cb; but you can call this from closed_cb */
27 | LI_API void li_gnutls_filter_free(liGnuTLSFilter *f);
28 |
29 | #endif
30 |
--------------------------------------------------------------------------------
/src/modules/gnutls_ocsp.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_GNUTLS_OCSP_H_
2 | #define _LIGHTTPD_GNUTLS_OCSP_H_
3 |
4 | #include
5 |
6 | #include
7 |
8 | typedef struct liGnuTLSOCSP liGnuTLSOCSP;
9 |
10 | LI_API liGnuTLSOCSP* li_gnutls_ocsp_new(void);
11 |
12 | /* doesn't call closed_cb; but you can call this from closed_cb */
13 | LI_API void li_gnutls_ocsp_free(liGnuTLSOCSP *ocsp);
14 |
15 | LI_API void li_gnutls_ocsp_use(liGnuTLSOCSP *ocsp, gnutls_certificate_credentials_t creds);
16 |
17 | /* load DER or PEM ("OCSP RESPONSE") encoded ocsp response */
18 | LI_API gboolean li_gnutls_ocsp_add(liServer *srv, liGnuTLSOCSP *ocsp, const char* filename);
19 |
20 | /* search in PEM file for a OCSP RESPONSE block and add it if there is one;
21 | * returns only FALSE if a block was found which COULDN'T be loaded
22 | */
23 | LI_API gboolean li_gnutls_ocsp_search(liServer *srv, liGnuTLSOCSP *ocsp, const char* filename);
24 |
25 | /* search in PEM datum for a OCSP RESPONSE block and add it if there is one;
26 | * returns only FALSE if a block was found which COULDN'T be loaded
27 | */
28 | LI_API gboolean li_gnutls_ocsp_search_datum(liServer *srv, liGnuTLSOCSP *ocsp, gnutls_datum_t const* file);
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/src/modules/meson.build:
--------------------------------------------------------------------------------
1 | modules = {
2 | 'access': {
3 | 'sources': ['mod_access.c'],
4 | },
5 | 'accesslog': {
6 | 'sources': ['mod_accesslog.c'],
7 | },
8 | 'auth': {
9 | 'sources': ['mod_auth.c'],
10 | },
11 | 'balance': {
12 | 'sources': ['mod_balance.c'],
13 | },
14 | 'cache_disk_etag': {
15 | 'sources': ['mod_cache_disk_etag.c'],
16 | },
17 | 'debug': {
18 | 'sources': ['mod_debug.c'],
19 | },
20 | 'deflate': {
21 | 'sources': ['mod_deflate.c'],
22 | 'dependencies': [dep_deflate],
23 | },
24 | 'dirlist': {
25 | 'sources': ['mod_dirlist.c'],
26 | },
27 | 'expire': {
28 | 'sources': ['mod_expire.c'],
29 | },
30 | 'fastcgi': {
31 | 'sources': ['mod_fastcgi.c', 'fastcgi_stream.c'],
32 | },
33 | 'flv': {
34 | 'sources': ['mod_flv.c'],
35 | },
36 | 'fortune': {
37 | 'sources': ['mod_fortune.c'],
38 | },
39 | 'gnutls': {
40 | 'sources': ['mod_gnutls.c', 'gnutls_filter.c', 'gnutls_ocsp.c'],
41 | 'dependencies': [dep_gnutls, opt_dep_idn],
42 | },
43 | 'limit': {
44 | 'sources': ['mod_limit.c'],
45 | },
46 | 'lua': {
47 | 'sources': ['mod_lua.c'],
48 | 'dependencies': [dep_lua],
49 | },
50 | 'memcached': {
51 | 'sources': ['mod_memcached.c'],
52 | 'dependencies': [opt_dep_lua],
53 | },
54 | 'openssl': {
55 | 'sources': ['mod_openssl.c', 'openssl_filter.c'],
56 | 'dependencies': [dep_openssl, opt_dep_idn],
57 | },
58 | 'progress': {
59 | 'sources': ['mod_progress.c'],
60 | },
61 | 'proxy': {
62 | 'sources': ['mod_proxy.c'],
63 | },
64 | 'redirect': {
65 | 'sources': ['mod_redirect.c'],
66 | },
67 | 'rewrite': {
68 | 'sources': ['mod_rewrite.c'],
69 | },
70 | 'scgi': {
71 | 'sources': ['mod_scgi.c'],
72 | },
73 | 'status': {
74 | 'sources': ['mod_status.c'],
75 | },
76 | 'throttle': {
77 | 'sources': ['mod_throttle.c'],
78 | },
79 | 'userdir': {
80 | 'sources': ['mod_userdir.c'],
81 | },
82 | 'vhost': {
83 | 'sources': ['mod_vhost.c'],
84 | },
85 | }
86 |
87 | modules_build_dir = meson.current_build_dir()
88 |
89 | all_modules = []
90 | enabled_modules = []
91 |
92 | foreach name, def: modules
93 | mod_deps = def.get('dependencies', [])
94 | expect_mod = true
95 | foreach dep: mod_deps
96 | if not dep.found()
97 | expect_mod = false
98 | endif
99 | endforeach
100 | mod = shared_module(
101 | 'mod_' + name,
102 | def['sources'],
103 | dependencies: main_deps + mod_deps,
104 | c_args: def.get('c_args', []),
105 | include_directories: [inc_dir] + search_includes,
106 | install: true,
107 | install_dir: modules_dir,
108 | )
109 | all_modules += mod
110 | if expect_mod
111 | enabled_modules += mod
112 | endif
113 | endforeach
114 |
--------------------------------------------------------------------------------
/src/modules/openssl_filter.h:
--------------------------------------------------------------------------------
1 | #ifndef _LIGHTTPD_OPENSSL_FILTER_H_
2 | #define _LIGHTTPD_OPENSSL_FILTER_H_
3 |
4 | #include
5 |
6 | #include
7 |
8 | typedef struct liOpenSSLFilter liOpenSSLFilter;
9 |
10 | typedef void (*liOpenSSLFilterHandshakeCB)(liOpenSSLFilter *f, gpointer data, liStream *plain_source, liStream *plain_drain);
11 | typedef void (*liOpenSSLFilterClosedCB)(liOpenSSLFilter *f, gpointer data);
12 |
13 | typedef struct liOpenSSLFilterCallbacks liOpenSSLFilterCallbacks;
14 | struct liOpenSSLFilterCallbacks {
15 | liOpenSSLFilterHandshakeCB handshake_cb; /* called after initial handshake is done */
16 | liOpenSSLFilterClosedCB closed_cb;
17 | };
18 |
19 | LI_API liOpenSSLFilter* li_openssl_filter_new(
20 | liServer *srv, liWorker *wrk,
21 | const liOpenSSLFilterCallbacks *callbacks, gpointer data,
22 | SSL_CTX *ssl_ctx, liStream *crypt_source, liStream *crypt_drain);
23 |
24 | /* doesn't call closed_cb; but you can call this from closed_cb */
25 | LI_API void li_openssl_filter_free(liOpenSSLFilter *f);
26 |
27 | LI_API SSL* li_openssl_filter_ssl(liOpenSSLFilter *f);
28 |
29 | #endif
30 |
--------------------------------------------------------------------------------
/src/unittests/meson.build:
--------------------------------------------------------------------------------
1 | unittests = {
2 | 'Chunk-UnitTest': {
3 | 'binary': 'test-chunk',
4 | 'sources': ['test-chunk.c'],
5 | },
6 | 'HttpRequestParser-UnitTest': {
7 | 'binary': 'test-http-request-parser',
8 | 'sources': ['test-http-request-parser.c'],
9 | },
10 | 'IpParser-UnitTest': {
11 | 'binary': 'test-ip-parser',
12 | 'sources': ['test-ip-parser.c'],
13 | },
14 | 'Radix-UnitTest': {
15 | 'binary': 'test-radix',
16 | 'sources': ['test-radix.c'],
17 | },
18 | 'RangeParser-UnitTest': {
19 | 'binary': 'test-range-parser',
20 | 'sources': ['test-range-parser.c'],
21 | },
22 | 'Utils-UnitTest': {
23 | 'binary': 'test-utils',
24 | 'sources': ['test-utils.c'],
25 | },
26 | }
27 |
28 | foreach name, def: unittests
29 | test_bin = executable(
30 | def['binary'],
31 | def['sources'],
32 | include_directories: [inc_dir] + search_includes,
33 | dependencies: main_deps + def.get('dependencies', []),
34 | link_with: [
35 | lib_shared,
36 | lib_common,
37 | ],
38 | build_by_default: false,
39 | )
40 | test(
41 | name,
42 | test_bin,
43 | protocol: 'tap',
44 | )
45 | endforeach
46 |
--------------------------------------------------------------------------------
/src/unittests/test-chunk.c:
--------------------------------------------------------------------------------
1 |
2 | #include
3 |
4 | #define perror(msg) g_error("(%s:%i) %s failed: %s", __FILE__, __LINE__, msg, g_strerror(errno))
5 |
6 | #if 0
7 | static liChunkQueue* cq_from_str(const gchar *s, size_t len) {
8 | liChunkQueue *cq = li_chunkqueue_new();
9 | li_chunkqueue_append_mem(cq, s, len);
10 | return cq;
11 | }
12 | #endif
13 |
14 | static void cq_load_str(liChunkQueue *cq, const gchar *s, size_t len) {
15 | li_chunkqueue_reset(cq);
16 | li_chunkqueue_append_mem(cq, s, len);
17 | }
18 |
19 | static void cq_assert_eq(liChunkQueue *cq, const gchar *s, size_t len) {
20 | GString *buf = g_string_sized_new(cq->length);
21 | g_assert(li_chunkqueue_extract_to(cq, cq->length, buf, NULL));
22 | g_assert(0 == memcmp(s, buf->str, len));
23 | g_string_free(buf, TRUE);
24 | }
25 |
26 |
27 | static void test_filter_chunked_decode(void) {
28 | liChunkQueue *cq = li_chunkqueue_new(), *cq2 = li_chunkqueue_new();
29 | liFilterChunkedDecodeState decode_state;
30 |
31 | cq_load_str(cq, CONST_STR_LEN(
32 | "14\r\n"
33 | "01234567890123456789" "\r\n"
34 | "0\r\nrandom foo: xx\r\n\r\n"
35 | "xxx" /* next message */
36 | ));
37 | cq->is_closed = TRUE;
38 | memset(&decode_state, 0, sizeof(decode_state));
39 | li_chunkqueue_reset(cq2);
40 | g_assert(li_filter_chunked_decode(NULL, cq2, cq, &decode_state));
41 | cq_assert_eq(cq2, CONST_STR_LEN(
42 | "01234567890123456789"
43 | ));
44 | g_assert(cq2->is_closed);
45 | cq_assert_eq(cq, CONST_STR_LEN(
46 | "xxx"
47 | ));
48 |
49 | li_chunkqueue_free(cq);
50 | li_chunkqueue_free(cq2);
51 | }
52 |
53 | int main(int argc, char **argv) {
54 | g_test_init(&argc, &argv, NULL);
55 |
56 | g_test_add_func("/chunk/filter_chunked_decode", test_filter_chunked_decode);
57 |
58 | return g_test_run();
59 | }
60 |
--------------------------------------------------------------------------------
/src/unittests/test-http-request-parser.c:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 |
5 | static void test_crlf_newlines(void) {
6 | liRequest req;
7 | liHttpRequestCtx http_req_ctx;
8 | liChunkQueue* cq = li_chunkqueue_new();
9 | liHandlerResult res;
10 |
11 | li_chunkqueue_append_mem(cq, CONST_STR_LEN(
12 | "GET / HTTP/1.0\r\n"
13 | "Host: www.example.com\r\n"
14 | "\r\n"
15 | "\ntrash"));
16 | li_request_init(&req);
17 | li_http_request_parser_init(&http_req_ctx, &req, cq);
18 |
19 | res = li_http_request_parse(NULL, &http_req_ctx);
20 | if (LI_HANDLER_GO_ON != res) g_error("li_http_request_parse didn't finish parsing or failed: %i", res);
21 |
22 | g_assert(6 == cq->length);
23 | g_assert(li_http_header_is(req.headers, CONST_STR_LEN("host"), CONST_STR_LEN("www.example.com")));
24 |
25 | li_chunkqueue_free(cq);
26 | li_http_request_parser_clear(&http_req_ctx);
27 | li_request_clear(&req);
28 | }
29 |
30 | static void test_lf_newlines(void) {
31 | liRequest req;
32 | liHttpRequestCtx http_req_ctx;
33 | liChunkQueue* cq = li_chunkqueue_new();
34 | liHandlerResult res;
35 |
36 | li_chunkqueue_append_mem(cq, CONST_STR_LEN(
37 | "GET / HTTP/1.0\n"
38 | "Host: www.example.com\n"
39 | "\n"
40 | "\rtrash"));
41 | li_request_init(&req);
42 | li_http_request_parser_init(&http_req_ctx, &req, cq);
43 |
44 | res = li_http_request_parse(NULL, &http_req_ctx);
45 | if (LI_HANDLER_GO_ON != res) g_error("li_http_request_parse didn't finish parsing or failed: %i", res);
46 |
47 | g_assert(6 == cq->length);
48 | g_assert(li_http_header_is(req.headers, CONST_STR_LEN("host"), CONST_STR_LEN("www.example.com")));
49 |
50 | li_chunkqueue_free(cq);
51 | li_http_request_parser_clear(&http_req_ctx);
52 | li_request_clear(&req);
53 | }
54 |
55 | int main(int argc, char **argv) {
56 | g_test_init(&argc, &argv, NULL);
57 |
58 | g_test_add_func("/http-request-parser/crlf_newlines", test_crlf_newlines);
59 | g_test_add_func("/http-request-parser/lf_newlines", test_lf_newlines);
60 |
61 | return g_test_run();
62 | }
63 |
--------------------------------------------------------------------------------
/src/unittests/test-ip-parser.c:
--------------------------------------------------------------------------------
1 |
2 | #include
3 |
4 | #define perror(msg) g_error("(%s:%i) %s failed: %s", __FILE__, __LINE__, msg, g_strerror(errno))
5 |
6 |
7 | typedef struct {
8 | struct {
9 | guint32 addr;
10 | guint32 networkmask;
11 | guint16 port;
12 | } ipv4;
13 | struct {
14 | guint8 addr[16];
15 | guint network;
16 | guint16 port;
17 | } ipv6;
18 | struct {
19 | GString *path;
20 | } unix_socket;
21 | } netrange;
22 |
23 | static void test_ipv4_net1(void) {
24 | netrange range;
25 | liSocketAddress addr;
26 | const char str0[] = "0.0.0.0/0:80";
27 | GString str1 = li_const_gstring(CONST_STR_LEN("127.0.0.1"));
28 | struct sockaddr_in *ipv4;
29 |
30 | g_assert(!li_parse_ipv6(str0, range.ipv6.addr, &range.ipv6.network, &range.ipv6.port));
31 | g_assert(li_parse_ipv4(str0, &range.ipv4.addr, &range.ipv4.networkmask, &range.ipv4.port));
32 |
33 | g_assert_cmpuint(range.ipv4.addr, ==, 0);
34 | g_assert_cmpuint(range.ipv4.networkmask, ==, 0);
35 | g_assert_cmpuint(range.ipv4.port, ==, 80);
36 |
37 | addr = li_sockaddr_from_string(&str1, 80);
38 | g_assert(addr.addr_up.raw);
39 |
40 | g_assert_cmpuint(AF_INET, ==, addr.addr_up.plain->sa_family);
41 | ipv4 = addr.addr_up.ipv4;
42 |
43 | g_assert_cmpuint(ipv4->sin_addr.s_addr, ==, htonl(0x7f000001u));
44 |
45 | g_assert(li_ipv4_in_ipv4_net(ipv4->sin_addr.s_addr, range.ipv4.addr, range.ipv4.networkmask));
46 | g_assert_cmpuint(ipv4->sin_port, ==, htons(range.ipv4.port));
47 |
48 | li_sockaddr_clear(&addr);
49 | }
50 |
51 | static void test_ipv6_net1(void) {
52 | netrange range;
53 | liSocketAddress addr;
54 | const char str0[] = "[::/0]:80";
55 | GString str1 = li_const_gstring(CONST_STR_LEN("::1"));
56 | struct sockaddr_in6 *ipv6;
57 |
58 | g_assert(!li_parse_ipv4(str0, &range.ipv4.addr, &range.ipv4.networkmask, &range.ipv4.port));
59 | g_assert(li_parse_ipv6(str0, range.ipv6.addr, &range.ipv6.network, &range.ipv6.port));
60 |
61 | g_assert_cmpuint(range.ipv6.network, ==, 0);
62 | g_assert_cmpuint(range.ipv6.port, ==, 80);
63 |
64 | addr = li_sockaddr_from_string(&str1, 80);
65 | g_assert(addr.addr_up.raw);
66 |
67 | g_assert_cmpuint(AF_INET6, ==, addr.addr_up.plain->sa_family);
68 | ipv6 = addr.addr_up.ipv6;
69 |
70 | g_assert(li_ipv6_in_ipv6_net(ipv6->sin6_addr.s6_addr, range.ipv6.addr, range.ipv6.network));
71 | g_assert_cmpuint(ipv6->sin6_port, ==, htons(range.ipv6.port));
72 |
73 | li_sockaddr_clear(&addr);
74 | }
75 |
76 | int main(int argc, char **argv) {
77 | g_test_init(&argc, &argv, NULL);
78 |
79 | g_test_add_func("/ip-parser/test-localhost-in-all-ipv4-net", test_ipv4_net1);
80 | g_test_add_func("/ip-parser/test-localhost-in-all-ipv6-net", test_ipv6_net1);
81 |
82 | return g_test_run();
83 | }
84 |
--------------------------------------------------------------------------------
/src/unittests/test-radix.c:
--------------------------------------------------------------------------------
1 |
2 | #include
3 |
4 | static void test_radix_insert_lookup(void) {
5 | static const guint magic1 = 4235;
6 | guint value;
7 |
8 | /* 127.0.0.1 */
9 | in_addr_t ip1 = htonl(INADDR_LOOPBACK);
10 | liRadixTree *rd = li_radixtree_new();
11 |
12 | li_radixtree_insert(rd, &ip1, 32, GUINT_TO_POINTER(magic1));
13 |
14 | value = GPOINTER_TO_UINT(li_radixtree_lookup_exact(rd, &ip1, 32));
15 |
16 | g_assert_cmpuint(magic1, ==, value);
17 |
18 | li_radixtree_free(rd, NULL, NULL);
19 | }
20 |
21 | static void test_radix_insert_insert_lookup(void) {
22 | static const guint magic1 = 4235 /* 0x108b */, magic2 = 59234 /* 0xe762 */;
23 | guint value;
24 |
25 | /* 127.0.0.1, 192.168.0.125 */
26 | /* as guint32: 2130706433, 3232235645 */
27 | in_addr_t ip1 = htonl(INADDR_LOOPBACK), ip2 = htonl( (in_addr_t) 0xC0A8007D );
28 | liRadixTree *rd = li_radixtree_new();
29 |
30 | li_radixtree_insert(rd, &ip1, 32, GUINT_TO_POINTER(magic1));
31 | li_radixtree_insert(rd, &ip2, 32, GUINT_TO_POINTER(magic2));
32 |
33 | value = GPOINTER_TO_UINT(li_radixtree_lookup_exact(rd, &ip1, 32));
34 |
35 | g_assert_cmpuint(magic1, ==, value);
36 |
37 | value = GPOINTER_TO_UINT(li_radixtree_lookup_exact(rd, &ip2, 32));
38 |
39 | g_assert_cmpuint(magic2, ==, value);
40 |
41 | li_radixtree_free(rd, NULL, NULL);
42 | }
43 |
44 | static void test_radix_insert_insert_del_lookup(void) {
45 | static const guint magic1 = 4235 /* 0x108b */, magic2 = 59234 /* 0xe762 */;
46 | guint value;
47 |
48 | /* 127.0.0.1, 192.168.0.125 */
49 | /* as guint32: 2130706433, 3232235645 */
50 | in_addr_t ip1 = htonl(INADDR_LOOPBACK), ip2 = htonl( (in_addr_t) 0xC0A8007D );
51 | liRadixTree *rd = li_radixtree_new();
52 |
53 | li_radixtree_insert(rd, &ip1, 32, GUINT_TO_POINTER(magic1));
54 | li_radixtree_insert(rd, &ip2, 32, GUINT_TO_POINTER(magic2));
55 | li_radixtree_remove(rd, &ip2, 32);
56 |
57 | value = GPOINTER_TO_UINT(li_radixtree_lookup_exact(rd, &ip1, 32));
58 |
59 | g_assert_cmpuint(magic1, ==, value);
60 |
61 | li_radixtree_free(rd, NULL, NULL);
62 | }
63 |
64 | int main(int argc, char **argv) {
65 | g_test_init(&argc, &argv, NULL);
66 |
67 | g_test_add_func("/radix/insert-lookup", test_radix_insert_lookup);
68 | g_test_add_func("/radix/insert-insert-lookup", test_radix_insert_insert_lookup);
69 | g_test_add_func("/radix/insert-insert-del-lookup", test_radix_insert_insert_del_lookup);
70 |
71 | return g_test_run();
72 | }
73 |
--------------------------------------------------------------------------------
/tests/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | tmp*
3 |
--------------------------------------------------------------------------------
/tests/CONTRIBUTE.md:
--------------------------------------------------------------------------------
1 | Please run `mypy` and `flake8 tests` in project root and fix errors/lints.
2 |
--------------------------------------------------------------------------------
/tests/autowrapper.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | TESTSRC="$1"
4 | BUILD="$2"
5 |
6 | ARGS="${RUNTEST_ARGS}"
7 |
8 | exec "${TESTSRC}/runtests.py" --angel "${BUILD}/src/angel/lighttpd2" --worker "${BUILD}/src/main/lighttpd2-worker" --plugindir "${BUILD}/src/modules/.libs" $ARGS "$@"
9 |
--------------------------------------------------------------------------------
/tests/ca/ca.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICAzCCAYqgAwIBAgIBATAKBggqhkjOPQQDBDBLMScwJQYDVQQDEx5saWdodHRw
3 | ZDIgdGVzdCBzdWl0ZSBBdXRob3JpdHkxIDAeBgNVBAsTF2xpZ2h0dHBkMiB0ZXN0
4 | IHN1aXRlIENBMB4XDTI1MDEwMTEzMzIyNloXDTM0MTIzMDEzMzIyNlowSzEnMCUG
5 | A1UEAxMebGlnaHR0cGQyIHRlc3Qgc3VpdGUgQXV0aG9yaXR5MSAwHgYDVQQLExds
6 | aWdodHRwZDIgdGVzdCBzdWl0ZSBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABELi
7 | eTNiaScZ2eF/OkuczjC2L2iHw3KtzsiLNxMiBlxhBH0/Lsw96s1pf/FZ5+NR+CTe
8 | 5AnHCizcIdOK7ZUgs4de3jXNsEmuADvc5WAgIhAMewLsbROkCDdMwmN9/8Xnu6NC
9 | MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMEz
10 | tottTkpfEMdgJyKaXwKTAIJrMAoGCCqGSM49BAMEA2cAMGQCMEOSIX2o5l64UiJ1
11 | desOcopAzZYEcQJvEIXwn0OAPLZ2eYBJ7n2tJMpBJALT6gV70wIwd3kFAXMbyC9J
12 | B2kD93IzgHJUaHTUCOCgixVCyuuhcEkH+sosx/3g05oV0yV1zSGR
13 | -----END CERTIFICATE-----
14 |
--------------------------------------------------------------------------------
/tests/ca/ca.key:
--------------------------------------------------------------------------------
1 | Public Key Info:
2 | Public Key Algorithm: EC/ECDSA
3 | Key Security Level: Ultra (384 bits)
4 |
5 | curve: SECP384R1
6 | private key:
7 | 5e:ca:7f:3a:1f:16:b3:1e:7d:e9:e3:b5:cc:0e:fa:74
8 | 8b:2d:46:e7:f1:93:84:73:b7:dd:19:d5:71:ef:b2:89
9 | 06:16:22:b9:73:35:ff:f3:0e:82:4e:56:fd:99:df:31
10 |
11 |
12 | x:
13 | 42:e2:79:33:62:69:27:19:d9:e1:7f:3a:4b:9c:ce:30
14 | b6:2f:68:87:c3:72:ad:ce:c8:8b:37:13:22:06:5c:61
15 | 04:7d:3f:2e:cc:3d:ea:cd:69:7f:f1:59:e7:e3:51:f8
16 |
17 |
18 | y:
19 | 24:de:e4:09:c7:0a:2c:dc:21:d3:8a:ed:95:20:b3:87
20 | 5e:de:35:cd:b0:49:ae:00:3b:dc:e5:60:20:22:10:0c
21 | 7b:02:ec:6d:13:a4:08:37:4c:c2:63:7d:ff:c5:e7:bb
22 |
23 |
24 |
25 | Public Key PIN:
26 | pin-sha256:lMWzBgixjgubOuTReiygfOlYjtIjm+GpneEegi92kAM=
27 | Public Key ID:
28 | sha256:94c5b30608b18e0b9b3ae4d17a2ca07ce9588ed2239be1a99de11e822f769003
29 | sha1:c133b68b6d4e4a5f10c76027229a5f029300826b
30 |
31 | -----BEGIN EC PRIVATE KEY-----
32 | MIGkAgEBBDBeyn86HxazHn3p47XMDvp0iy1G5/GThHO33RnVce+yiQYWIrlzNf/z
33 | DoJOVv2Z3zGgBwYFK4EEACKhZANiAARC4nkzYmknGdnhfzpLnM4wti9oh8Nyrc7I
34 | izcTIgZcYQR9Py7MPerNaX/xWefjUfgk3uQJxwos3CHTiu2VILOHXt41zbBJrgA7
35 | 3OVgICIQDHsC7G0TpAg3TMJjff/F57s=
36 | -----END EC PRIVATE KEY-----
37 |
--------------------------------------------------------------------------------
/tests/ca/ca.pub:
--------------------------------------------------------------------------------
1 | Public Key Information:
2 | Public Key Algorithm: EC/ECDSA
3 | Algorithm Security Level: Ultra (384 bits)
4 | Curve: SECP384R1
5 | X:
6 | 42:e2:79:33:62:69:27:19:d9:e1:7f:3a:4b:9c:ce:30
7 | b6:2f:68:87:c3:72:ad:ce:c8:8b:37:13:22:06:5c:61
8 | 04:7d:3f:2e:cc:3d:ea:cd:69:7f:f1:59:e7:e3:51:f8
9 | Y:
10 | 24:de:e4:09:c7:0a:2c:dc:21:d3:8a:ed:95:20:b3:87
11 | 5e:de:35:cd:b0:49:ae:00:3b:dc:e5:60:20:22:10:0c
12 | 7b:02:ec:6d:13:a4:08:37:4c:c2:63:7d:ff:c5:e7:bb
13 |
14 | Public Key ID:
15 | sha1:c133b68b6d4e4a5f10c76027229a5f029300826b
16 | sha256:94c5b30608b18e0b9b3ae4d17a2ca07ce9588ed2239be1a99de11e822f769003
17 | Public Key PIN:
18 | pin-sha256:lMWzBgixjgubOuTReiygfOlYjtIjm+GpneEegi92kAM=
19 |
20 |
21 | -----BEGIN PUBLIC KEY-----
22 | MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEQuJ5M2JpJxnZ4X86S5zOMLYvaIfDcq3O
23 | yIs3EyIGXGEEfT8uzD3qzWl/8Vnn41H4JN7kCccKLNwh04rtlSCzh17eNc2wSa4A
24 | O9zlYCAiEAx7AuxtE6QIN0zCY33/xee7
25 | -----END PUBLIC KEY-----
26 |
--------------------------------------------------------------------------------
/tests/ca/ca.template:
--------------------------------------------------------------------------------
1 |
2 | dn = "OU=lighttpd2 test suite CA,CN=lighttpd2 test suite Authority"
3 |
4 | serial = 01
5 |
6 | expiration_days = 3650
7 |
8 | ca
9 | cert_signing_key
10 | crl_signing_key
11 |
12 |
--------------------------------------------------------------------------------
/tests/ca/client1.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICRzCCAc6gAwIBAgIUTXuH5LA/Ee7GxPU8psTxrsOB3nMwCgYIKoZIzj0EAwQw
3 | WTEuMCwGA1UEAxMlbGlnaHR0cGQyIHRlc3Qgc3VpdGUgQ2xpZW50IEF1dGhvcml0
4 | eTEnMCUGA1UECxMebGlnaHR0cGQyIHRlc3Qgc3VpdGUgQ2xpZW50IENBMB4XDTI1
5 | MDEwMTEzMzIyNloXDTM0MTIzMDEzMzIyNlowOzEQMA4GA1UEAxMHY2xpZW50MTEn
6 | MCUGA1UECxMebGlnaHR0cGQyIHRlc3Qgc3VpdGUgQ2xpZW50IENBMHYwEAYHKoZI
7 | zj0CAQYFK4EEACIDYgAED0VUvV0QW1TY0qxDrkTsln6WGJcifQdFB+uLXzBCfTwV
8 | SbCXhdY0EdowT2uVZjlDI2xHTAkSdqfSGcrkPJDhSpJYIanX8MbiNSMxQ3kY3ZyF
9 | oGpZ40PhD5O97jX3uvRLo3UwczAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsG
10 | AQUFBwMCMA4GA1UdDwEB/wQEAwIHgDAdBgNVHQ4EFgQU5L/1A0rcCn/DHaFHJnPl
11 | 8hgX8GcwHwYDVR0jBBgwFoAU2hsHrFdo+I7ndox2VLpzaSW3Ws4wCgYIKoZIzj0E
12 | AwQDZwAwZAIwBf9uuyS+5V0f3EROHCcXc73lPHv8BhmPt+u/5yJJhl7PqzRuFRsT
13 | t8BwnRbkm95tAjBpStZOKGgl10T4nk0VBvap7Y8rjcIzVgM5g2ppLkaLUMwmI+tu
14 | aSuQ6gOp73Yshes=
15 | -----END CERTIFICATE-----
16 |
--------------------------------------------------------------------------------
/tests/ca/client1.key:
--------------------------------------------------------------------------------
1 | Public Key Info:
2 | Public Key Algorithm: EC/ECDSA
3 | Key Security Level: Ultra (384 bits)
4 |
5 | curve: SECP384R1
6 | private key:
7 | 00:a9:ce:10:df:bc:99:a8:5b:89:00:e6:16:5c:cc:52
8 | 09:3f:49:07:74:95:21:35:4d:00:25:b8:a4:64:0e:64
9 | 15:f6:52:29:fa:39:77:27:a9:65:90:e7:ec:de:a7:3e
10 | 00:
11 |
12 | x:
13 | 0f:45:54:bd:5d:10:5b:54:d8:d2:ac:43:ae:44:ec:96
14 | 7e:96:18:97:22:7d:07:45:07:eb:8b:5f:30:42:7d:3c
15 | 15:49:b0:97:85:d6:34:11:da:30:4f:6b:95:66:39:43
16 |
17 |
18 | y:
19 | 23:6c:47:4c:09:12:76:a7:d2:19:ca:e4:3c:90:e1:4a
20 | 92:58:21:a9:d7:f0:c6:e2:35:23:31:43:79:18:dd:9c
21 | 85:a0:6a:59:e3:43:e1:0f:93:bd:ee:35:f7:ba:f4:4b
22 |
23 |
24 |
25 | Public Key PIN:
26 | pin-sha256:tiP++hy/M1YPIiNHrKyqWySy8mpf+mrPCwGyI/HOTrs=
27 | Public Key ID:
28 | sha256:b623fefa1cbf33560f222347acacaa5b24b2f26a5ffa6acf0b01b223f1ce4ebb
29 | sha1:e4bff5034adc0a7fc31da1472673e5f21817f067
30 |
31 | -----BEGIN EC PRIVATE KEY-----
32 | MIGlAgEBBDEAqc4Q37yZqFuJAOYWXMxSCT9JB3SVITVNACW4pGQOZBX2Uin6OXcn
33 | qWWQ5+zepz4AoAcGBSuBBAAioWQDYgAED0VUvV0QW1TY0qxDrkTsln6WGJcifQdF
34 | B+uLXzBCfTwVSbCXhdY0EdowT2uVZjlDI2xHTAkSdqfSGcrkPJDhSpJYIanX8Mbi
35 | NSMxQ3kY3ZyFoGpZ40PhD5O97jX3uvRL
36 | -----END EC PRIVATE KEY-----
37 |
--------------------------------------------------------------------------------
/tests/ca/client1.pub:
--------------------------------------------------------------------------------
1 | Public Key Information:
2 | Public Key Algorithm: EC/ECDSA
3 | Algorithm Security Level: Ultra (384 bits)
4 | Curve: SECP384R1
5 | X:
6 | 0f:45:54:bd:5d:10:5b:54:d8:d2:ac:43:ae:44:ec:96
7 | 7e:96:18:97:22:7d:07:45:07:eb:8b:5f:30:42:7d:3c
8 | 15:49:b0:97:85:d6:34:11:da:30:4f:6b:95:66:39:43
9 | Y:
10 | 23:6c:47:4c:09:12:76:a7:d2:19:ca:e4:3c:90:e1:4a
11 | 92:58:21:a9:d7:f0:c6:e2:35:23:31:43:79:18:dd:9c
12 | 85:a0:6a:59:e3:43:e1:0f:93:bd:ee:35:f7:ba:f4:4b
13 |
14 | Public Key ID:
15 | sha1:e4bff5034adc0a7fc31da1472673e5f21817f067
16 | sha256:b623fefa1cbf33560f222347acacaa5b24b2f26a5ffa6acf0b01b223f1ce4ebb
17 | Public Key PIN:
18 | pin-sha256:tiP++hy/M1YPIiNHrKyqWySy8mpf+mrPCwGyI/HOTrs=
19 |
20 |
21 | -----BEGIN PUBLIC KEY-----
22 | MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAED0VUvV0QW1TY0qxDrkTsln6WGJcifQdF
23 | B+uLXzBCfTwVSbCXhdY0EdowT2uVZjlDI2xHTAkSdqfSGcrkPJDhSpJYIanX8Mbi
24 | NSMxQ3kY3ZyFoGpZ40PhD5O97jX3uvRL
25 | -----END PUBLIC KEY-----
26 |
--------------------------------------------------------------------------------
/tests/ca/client1.template:
--------------------------------------------------------------------------------
1 |
2 | dn = "OU=lighttpd2 test suite Client CA,CN=client1"
3 |
4 | expiration_days = 3650
5 |
6 | tls_www_client
7 | signing_key
8 |
--------------------------------------------------------------------------------
/tests/ca/client_ca.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICIDCCAaagAwIBAgIBATAKBggqhkjOPQQDBDBZMS4wLAYDVQQDEyVsaWdodHRw
3 | ZDIgdGVzdCBzdWl0ZSBDbGllbnQgQXV0aG9yaXR5MScwJQYDVQQLEx5saWdodHRw
4 | ZDIgdGVzdCBzdWl0ZSBDbGllbnQgQ0EwHhcNMjUwMTAxMTMzMjI2WhcNMzQxMjMw
5 | MTMzMjI2WjBZMS4wLAYDVQQDEyVsaWdodHRwZDIgdGVzdCBzdWl0ZSBDbGllbnQg
6 | QXV0aG9yaXR5MScwJQYDVQQLEx5saWdodHRwZDIgdGVzdCBzdWl0ZSBDbGllbnQg
7 | Q0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASS3dTmmtjhKfTQw33jA8vGC9LJkGh1
8 | hMH5N2kmE52C46cZFZwH6wZMVkcLmp3EpyASiCfuOi3RvIzUPRkrlXbvY7aL3NkT
9 | /7WhZZtn7cwFaD/NiBO5YWN5zbA6ERatOF6jQjBAMA8GA1UdEwEB/wQFMAMBAf8w
10 | DgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTaGwesV2j4jud2jHZUunNpJbdazjAK
11 | BggqhkjOPQQDBANoADBlAjAsUDPUAQQTNXMCNmxIQ3qba9ZrJSfMIVhZlDO/mUSJ
12 | Vp7nku/3lUdg6VOCCyEnv1kCMQCONCYvNaTMsn7wn6I5Euxyn++S/zwZ+eY3NrCD
13 | xSj8IeL4vDXzU39pNc9Z0nYWKzs=
14 | -----END CERTIFICATE-----
15 |
--------------------------------------------------------------------------------
/tests/ca/client_ca.key:
--------------------------------------------------------------------------------
1 | Public Key Info:
2 | Public Key Algorithm: EC/ECDSA
3 | Key Security Level: Ultra (384 bits)
4 |
5 | curve: SECP384R1
6 | private key:
7 | 48:92:1f:d3:2a:81:6b:7e:08:c7:de:99:26:6a:c2:c2
8 | f5:28:53:01:c5:9d:ae:b7:6a:2d:db:3c:a9:b7:04:f1
9 | 20:5a:0a:35:11:09:90:eb:0c:e3:6a:45:f7:3a:f1:dd
10 |
11 |
12 | x:
13 | 00:92:dd:d4:e6:9a:d8:e1:29:f4:d0:c3:7d:e3:03:cb
14 | c6:0b:d2:c9:90:68:75:84:c1:f9:37:69:26:13:9d:82
15 | e3:a7:19:15:9c:07:eb:06:4c:56:47:0b:9a:9d:c4:a7
16 | 20:
17 |
18 | y:
19 | 12:88:27:ee:3a:2d:d1:bc:8c:d4:3d:19:2b:95:76:ef
20 | 63:b6:8b:dc:d9:13:ff:b5:a1:65:9b:67:ed:cc:05:68
21 | 3f:cd:88:13:b9:61:63:79:cd:b0:3a:11:16:ad:38:5e
22 |
23 |
24 |
25 | Public Key PIN:
26 | pin-sha256:ClC41VsR43G8CaiRcPuncIR9mdMdf8aTr3b2aZKV5Ec=
27 | Public Key ID:
28 | sha256:0a50b8d55b11e371bc09a89170fba770847d99d31d7fc693af76f6699295e447
29 | sha1:da1b07ac5768f88ee7768c7654ba736925b75ace
30 |
31 | -----BEGIN EC PRIVATE KEY-----
32 | MIGkAgEBBDBIkh/TKoFrfgjH3pkmasLC9ShTAcWdrrdqLds8qbcE8SBaCjURCZDr
33 | DONqRfc68d2gBwYFK4EEACKhZANiAASS3dTmmtjhKfTQw33jA8vGC9LJkGh1hMH5
34 | N2kmE52C46cZFZwH6wZMVkcLmp3EpyASiCfuOi3RvIzUPRkrlXbvY7aL3NkT/7Wh
35 | ZZtn7cwFaD/NiBO5YWN5zbA6ERatOF4=
36 | -----END EC PRIVATE KEY-----
37 |
--------------------------------------------------------------------------------
/tests/ca/client_ca.pub:
--------------------------------------------------------------------------------
1 | Public Key Information:
2 | Public Key Algorithm: EC/ECDSA
3 | Algorithm Security Level: Ultra (384 bits)
4 | Curve: SECP384R1
5 | X:
6 | 00:92:dd:d4:e6:9a:d8:e1:29:f4:d0:c3:7d:e3:03:cb
7 | c6:0b:d2:c9:90:68:75:84:c1:f9:37:69:26:13:9d:82
8 | e3:a7:19:15:9c:07:eb:06:4c:56:47:0b:9a:9d:c4:a7
9 | 20
10 | Y:
11 | 12:88:27:ee:3a:2d:d1:bc:8c:d4:3d:19:2b:95:76:ef
12 | 63:b6:8b:dc:d9:13:ff:b5:a1:65:9b:67:ed:cc:05:68
13 | 3f:cd:88:13:b9:61:63:79:cd:b0:3a:11:16:ad:38:5e
14 |
15 | Public Key ID:
16 | sha1:da1b07ac5768f88ee7768c7654ba736925b75ace
17 | sha256:0a50b8d55b11e371bc09a89170fba770847d99d31d7fc693af76f6699295e447
18 | Public Key PIN:
19 | pin-sha256:ClC41VsR43G8CaiRcPuncIR9mdMdf8aTr3b2aZKV5Ec=
20 |
21 |
22 | -----BEGIN PUBLIC KEY-----
23 | MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEkt3U5prY4Sn00MN94wPLxgvSyZBodYTB
24 | +TdpJhOdguOnGRWcB+sGTFZHC5qdxKcgEogn7jot0byM1D0ZK5V272O2i9zZE/+1
25 | oWWbZ+3MBWg/zYgTuWFjec2wOhEWrThe
26 | -----END PUBLIC KEY-----
27 |
--------------------------------------------------------------------------------
/tests/ca/client_ca.template:
--------------------------------------------------------------------------------
1 |
2 | dn = "OU=lighttpd2 test suite Client CA,CN=lighttpd2 test suite Client Authority"
3 |
4 | serial = 01
5 |
6 | expiration_days = 3650
7 |
8 | ca
9 | cert_signing_key
10 | crl_signing_key
11 |
12 |
--------------------------------------------------------------------------------
/tests/ca/createca.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | # (requires gnutls >= 3.2.7 (or >= 3.1.17 and < 3.2.0))
6 |
7 | KEY_TYPE="${KEY_TYPE:-ecc}"
8 | HASH_ALG="${HASH_ALG:-SHA512}"
9 |
10 | function gen_rsa_key() {
11 | local name="$1"
12 | local security="${2:-high}"
13 | local secparam=(--sec-param "${security}")
14 |
15 | echo "Generate RSA key into ${name}.key and ${name}.pub"
16 | certtool -p --rsa --outfile "${name}.key" "${secparam[@]}"
17 | certtool --load-privkey "${name}.key" --pubkey-info --outfile "${name}.pub"
18 | }
19 |
20 | function gen_ecc_key() {
21 | local name="$1"
22 | local security="${2:-ultra}"
23 | local secparam=(--sec-param "${security}")
24 |
25 | echo "Generate ECC key into ${name}.key and ${name}.pub"
26 | certtool -p --ecc --outfile "${name}.key" "${secparam[@]}"
27 | certtool --load-privkey "${name}.key" --pubkey-info --outfile "${name}.pub"
28 | }
29 |
30 | function gen_key() {
31 | case "${KEY_TYPE}" in
32 | rsa) gen_rsa_key "$@" ;;
33 | ecc) gen_ecc_key "$@" ;;
34 | *) echo >&2 "Unknown key type: ${KEY_TYPE}"; exit 1 ;;
35 | esac
36 | }
37 |
38 | function ca_sign_self() {
39 | local ca_name="$1"
40 |
41 | echo "Self signing ${ca_name}"
42 | certtool -s "--hash=${HASH_ALG}" --load-privkey "${ca_name}.key" --outfile "${ca_name}.crt" --template "${ca_name}.template"
43 | }
44 |
45 | function ca_sign() {
46 | local ca_name="$1"
47 | local subject_name="$2"
48 | local key_name="${3:-${subject_name}}"
49 |
50 | echo "Signing ${subject_name} (key ${key_name}) with ${ca_name}"
51 | certtool -c "--hash=${HASH_ALG}" --load-ca-certificate "${ca_name}.crt" --load-ca-privkey "${ca_name}.key" --load-pubkey "${key_name}.pub" --outfile "${subject_name}.crt" --template "${subject_name}.template"
52 | }
53 |
54 | # gen keys
55 | gen_key "ca"
56 | gen_key "intermediate"
57 | gen_key "server"
58 | gen_key "client_ca"
59 | gen_key "client1"
60 |
61 | ca_sign_self "ca"
62 | ca_sign "ca" "intermediate"
63 | ca_sign_self "client_ca"
64 |
65 | for name in test1.ssl test2.ssl; do
66 | ca_sign "intermediate" "server_${name}" "server"
67 |
68 | echo "Generate server_${name}.pem"
69 | cat "server.key" "server_${name}.crt" "intermediate.crt" > "server_${name}.pem"
70 | done
71 |
72 | ca_sign "client_ca" "client1"
73 |
--------------------------------------------------------------------------------
/tests/ca/intermediate.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICPDCCAcOgAwIBAgIURcjH78CmuAoNZVwLZka0+BmM17wwCgYIKoZIzj0EAwQw
3 | SzEnMCUGA1UEAxMebGlnaHR0cGQyIHRlc3Qgc3VpdGUgQXV0aG9yaXR5MSAwHgYD
4 | VQQLExdsaWdodHRwZDIgdGVzdCBzdWl0ZSBDQTAeFw0yNTAxMDExMzMyMjZaFw0z
5 | NDEyMzAxMzMyMjZaMFAxLDAqBgNVBAMTI2xpZ2h0dHBkMiB0ZXN0IHN1aXRlIElu
6 | dGVybWVkaWF0ZSAxMSAwHgYDVQQLExdsaWdodHRwZDIgdGVzdCBzdWl0ZSBDQTB2
7 | MBAGByqGSM49AgEGBSuBBAAiA2IABGAMLbh3AitDqsKwtO3b1qOwve2RzGWGs7z8
8 | qsi4Nye9+r9l6VQTnK0TUxrr/WdYOLdNmeMVtMl3tXb+m6XKnBVH442q8pipYbM7
9 | xSRLTuPDRSpKoJqZTTJcoLC/uhpLu6NjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
10 | HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFIdYZEGTpLS+h8WsSGr4m/7tnnetMB8GA1Ud
11 | IwQYMBaAFMEztottTkpfEMdgJyKaXwKTAIJrMAoGCCqGSM49BAMEA2cAMGQCMDUJ
12 | y41eYkjLnj1x9T1xvy4LPLjhQE4ZdpJ2BwNNnn/+lHgfZtxf8thQtoXbx9uHMgIw
13 | H8cWKviP+rrBLUW4JdnSvv+8voRJYpNswi+EJoee53hShIWsETixdwGM1hRGQtdB
14 | -----END CERTIFICATE-----
15 |
--------------------------------------------------------------------------------
/tests/ca/intermediate.key:
--------------------------------------------------------------------------------
1 | Public Key Info:
2 | Public Key Algorithm: EC/ECDSA
3 | Key Security Level: Ultra (384 bits)
4 |
5 | curve: SECP384R1
6 | private key:
7 | 6c:80:9c:eb:20:30:f0:e5:2e:22:73:0b:32:6f:46:95
8 | 64:9e:fd:14:b6:32:c4:3d:58:24:0f:2c:cf:1f:98:ad
9 | f1:6c:ac:a0:ff:f0:e4:20:66:81:35:fa:f3:f9:50:95
10 |
11 |
12 | x:
13 | 60:0c:2d:b8:77:02:2b:43:aa:c2:b0:b4:ed:db:d6:a3
14 | b0:bd:ed:91:cc:65:86:b3:bc:fc:aa:c8:b8:37:27:bd
15 | fa:bf:65:e9:54:13:9c:ad:13:53:1a:eb:fd:67:58:38
16 |
17 |
18 | y:
19 | 00:b7:4d:99:e3:15:b4:c9:77:b5:76:fe:9b:a5:ca:9c
20 | 15:47:e3:8d:aa:f2:98:a9:61:b3:3b:c5:24:4b:4e:e3
21 | c3:45:2a:4a:a0:9a:99:4d:32:5c:a0:b0:bf:ba:1a:4b
22 | bb:
23 |
24 |
25 | Public Key PIN:
26 | pin-sha256:81OEBDrqLrlq9D3S34OiNpfVp9N9tQyR0O+6KPeXiFs=
27 | Public Key ID:
28 | sha256:f35384043aea2eb96af43dd2df83a23697d5a7d37db50c91d0efba28f797885b
29 | sha1:8758644193a4b4be87c5ac486af89bfeed9e77ad
30 |
31 | -----BEGIN EC PRIVATE KEY-----
32 | MIGkAgEBBDBsgJzrIDDw5S4icwsyb0aVZJ79FLYyxD1YJA8szx+YrfFsrKD/8OQg
33 | ZoE1+vP5UJWgBwYFK4EEACKhZANiAARgDC24dwIrQ6rCsLTt29ajsL3tkcxlhrO8
34 | /KrIuDcnvfq/ZelUE5ytE1Ma6/1nWDi3TZnjFbTJd7V2/pulypwVR+ONqvKYqWGz
35 | O8UkS07jw0UqSqCamU0yXKCwv7oaS7s=
36 | -----END EC PRIVATE KEY-----
37 |
--------------------------------------------------------------------------------
/tests/ca/intermediate.pub:
--------------------------------------------------------------------------------
1 | Public Key Information:
2 | Public Key Algorithm: EC/ECDSA
3 | Algorithm Security Level: Ultra (384 bits)
4 | Curve: SECP384R1
5 | X:
6 | 60:0c:2d:b8:77:02:2b:43:aa:c2:b0:b4:ed:db:d6:a3
7 | b0:bd:ed:91:cc:65:86:b3:bc:fc:aa:c8:b8:37:27:bd
8 | fa:bf:65:e9:54:13:9c:ad:13:53:1a:eb:fd:67:58:38
9 | Y:
10 | 00:b7:4d:99:e3:15:b4:c9:77:b5:76:fe:9b:a5:ca:9c
11 | 15:47:e3:8d:aa:f2:98:a9:61:b3:3b:c5:24:4b:4e:e3
12 | c3:45:2a:4a:a0:9a:99:4d:32:5c:a0:b0:bf:ba:1a:4b
13 | bb
14 |
15 | Public Key ID:
16 | sha1:8758644193a4b4be87c5ac486af89bfeed9e77ad
17 | sha256:f35384043aea2eb96af43dd2df83a23697d5a7d37db50c91d0efba28f797885b
18 | Public Key PIN:
19 | pin-sha256:81OEBDrqLrlq9D3S34OiNpfVp9N9tQyR0O+6KPeXiFs=
20 |
21 |
22 | -----BEGIN PUBLIC KEY-----
23 | MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEYAwtuHcCK0OqwrC07dvWo7C97ZHMZYaz
24 | vPyqyLg3J736v2XpVBOcrRNTGuv9Z1g4t02Z4xW0yXe1dv6bpcqcFUfjjarymKlh
25 | szvFJEtO48NFKkqgmplNMlygsL+6Gku7
26 | -----END PUBLIC KEY-----
27 |
--------------------------------------------------------------------------------
/tests/ca/intermediate.template:
--------------------------------------------------------------------------------
1 |
2 | dn = "OU=lighttpd2 test suite CA,CN=lighttpd2 test suite Intermediate 1"
3 |
4 | expiration_days = 3650
5 |
6 | ca
7 | cert_signing_key
8 | crl_signing_key
9 |
--------------------------------------------------------------------------------
/tests/ca/server.key:
--------------------------------------------------------------------------------
1 | Public Key Info:
2 | Public Key Algorithm: EC/ECDSA
3 | Key Security Level: Ultra (384 bits)
4 |
5 | curve: SECP384R1
6 | private key:
7 | 00:c9:a2:25:88:02:2c:62:f6:11:76:bd:b1:bf:ff:1c
8 | b8:19:5e:49:a3:df:72:d9:d0:2a:83:cc:b0:90:5e:13
9 | f2:29:59:b0:66:07:32:dd:a1:67:12:8d:91:84:9f:64
10 | ca:
11 |
12 | x:
13 | 00:fb:88:39:71:73:b5:7d:c1:17:c5:a3:17:9c:a0:48
14 | af:97:14:92:2e:9b:ff:fb:1b:16:7b:d6:d1:54:54:3e
15 | 49:be:6a:89:3a:44:ef:13:33:6b:ca:84:02:67:6d:65
16 | 16:
17 |
18 | y:
19 | 00:a9:8e:fd:01:17:a6:b7:2c:53:04:e4:d0:99:01:ce
20 | f2:50:43:43:00:66:50:e9:7d:95:c9:0d:55:54:14:93
21 | 7f:63:b8:b7:c1:a5:d9:e4:b9:57:8b:93:96:78:5c:cd
22 | b0:
23 |
24 |
25 | Public Key PIN:
26 | pin-sha256:7nnoskGn5ykPxCscQsd3tPYd2VWvmjZ5Da6yN4hLiBY=
27 | Public Key ID:
28 | sha256:ee79e8b241a7e7290fc42b1c42c777b4f61dd955af9a36790daeb237884b8816
29 | sha1:34ffccbf6c5e5904d8534af3da79f201fddc733d
30 |
31 | -----BEGIN EC PRIVATE KEY-----
32 | MIGlAgEBBDEAyaIliAIsYvYRdr2xv/8cuBleSaPfctnQKoPMsJBeE/IpWbBmBzLd
33 | oWcSjZGEn2TKoAcGBSuBBAAioWQDYgAE+4g5cXO1fcEXxaMXnKBIr5cUki6b//sb
34 | FnvW0VRUPkm+aok6RO8TM2vKhAJnbWUWqY79ARemtyxTBOTQmQHO8lBDQwBmUOl9
35 | lckNVVQUk39juLfBpdnkuVeLk5Z4XM2w
36 | -----END EC PRIVATE KEY-----
37 |
--------------------------------------------------------------------------------
/tests/ca/server.pub:
--------------------------------------------------------------------------------
1 | Public Key Information:
2 | Public Key Algorithm: EC/ECDSA
3 | Algorithm Security Level: Ultra (384 bits)
4 | Curve: SECP384R1
5 | X:
6 | 00:fb:88:39:71:73:b5:7d:c1:17:c5:a3:17:9c:a0:48
7 | af:97:14:92:2e:9b:ff:fb:1b:16:7b:d6:d1:54:54:3e
8 | 49:be:6a:89:3a:44:ef:13:33:6b:ca:84:02:67:6d:65
9 | 16
10 | Y:
11 | 00:a9:8e:fd:01:17:a6:b7:2c:53:04:e4:d0:99:01:ce
12 | f2:50:43:43:00:66:50:e9:7d:95:c9:0d:55:54:14:93
13 | 7f:63:b8:b7:c1:a5:d9:e4:b9:57:8b:93:96:78:5c:cd
14 | b0
15 |
16 | Public Key ID:
17 | sha1:34ffccbf6c5e5904d8534af3da79f201fddc733d
18 | sha256:ee79e8b241a7e7290fc42b1c42c777b4f61dd955af9a36790daeb237884b8816
19 | Public Key PIN:
20 | pin-sha256:7nnoskGn5ykPxCscQsd3tPYd2VWvmjZ5Da6yN4hLiBY=
21 |
22 |
23 | -----BEGIN PUBLIC KEY-----
24 | MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+4g5cXO1fcEXxaMXnKBIr5cUki6b//sb
25 | FnvW0VRUPkm+aok6RO8TM2vKhAJnbWUWqY79ARemtyxTBOTQmQHO8lBDQwBmUOl9
26 | lckNVVQUk39juLfBpdnkuVeLk5Z4XM2w
27 | -----END PUBLIC KEY-----
28 |
--------------------------------------------------------------------------------
/tests/ca/server_test1.ssl.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICdTCCAfygAwIBAgIUcrQcpa5JXvNxkPgRtiMk6atyQJ4wCgYIKoZIzj0EAwQw
3 | UDEsMCoGA1UEAxMjbGlnaHR0cGQyIHRlc3Qgc3VpdGUgSW50ZXJtZWRpYXRlIDEx
4 | IDAeBgNVBAsTF2xpZ2h0dHBkMiB0ZXN0IHN1aXRlIENBMB4XDTI1MDEwMTEzMzIy
5 | NloXDTM0MTIzMDEzMzIyNlowNjESMBAGA1UEAxMJdGVzdDEuc3NsMSAwHgYDVQQL
6 | ExdsaWdodHRwZDIgdGVzdCBzdWl0ZSBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IA
7 | BPuIOXFztX3BF8WjF5ygSK+XFJIum//7GxZ71tFUVD5JvmqJOkTvEzNryoQCZ21l
8 | FqmO/QEXprcsUwTk0JkBzvJQQ0MAZlDpfZXJDVVUFJN/Y7i3waXZ5LlXi5OWeFzN
9 | sKOBsDCBrTAMBgNVHRMBAf8EAjAAMDgGA1UdEQQxMC+CDnRlc3QxLnNzbC50ZXN0
10 | gg4qLm9wZW5zc2wudGVzdIINKi5nbnV0bHMudGVzdDATBgNVHSUEDDAKBggrBgEF
11 | BQcDATAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFDT/zL9sXlkE2FNK89p58gH9
12 | 3HM9MB8GA1UdIwQYMBaAFIdYZEGTpLS+h8WsSGr4m/7tnnetMAoGCCqGSM49BAME
13 | A2cAMGQCMECcU3y8OD+uImStj6IRi7iZPp3bEPdyN2zJOnxwG3kbxguGEZTPZoMe
14 | DMsLdiQSAwIwNc60UE7OKhJJaiNgPnuMybTNvEyksakAP2LfFDpK6/XQyBOnP91J
15 | UZM4P74V6PwR
16 | -----END CERTIFICATE-----
17 |
--------------------------------------------------------------------------------
/tests/ca/server_test1.ssl.pem:
--------------------------------------------------------------------------------
1 | Public Key Info:
2 | Public Key Algorithm: EC/ECDSA
3 | Key Security Level: Ultra (384 bits)
4 |
5 | curve: SECP384R1
6 | private key:
7 | 00:c9:a2:25:88:02:2c:62:f6:11:76:bd:b1:bf:ff:1c
8 | b8:19:5e:49:a3:df:72:d9:d0:2a:83:cc:b0:90:5e:13
9 | f2:29:59:b0:66:07:32:dd:a1:67:12:8d:91:84:9f:64
10 | ca:
11 |
12 | x:
13 | 00:fb:88:39:71:73:b5:7d:c1:17:c5:a3:17:9c:a0:48
14 | af:97:14:92:2e:9b:ff:fb:1b:16:7b:d6:d1:54:54:3e
15 | 49:be:6a:89:3a:44:ef:13:33:6b:ca:84:02:67:6d:65
16 | 16:
17 |
18 | y:
19 | 00:a9:8e:fd:01:17:a6:b7:2c:53:04:e4:d0:99:01:ce
20 | f2:50:43:43:00:66:50:e9:7d:95:c9:0d:55:54:14:93
21 | 7f:63:b8:b7:c1:a5:d9:e4:b9:57:8b:93:96:78:5c:cd
22 | b0:
23 |
24 |
25 | Public Key PIN:
26 | pin-sha256:7nnoskGn5ykPxCscQsd3tPYd2VWvmjZ5Da6yN4hLiBY=
27 | Public Key ID:
28 | sha256:ee79e8b241a7e7290fc42b1c42c777b4f61dd955af9a36790daeb237884b8816
29 | sha1:34ffccbf6c5e5904d8534af3da79f201fddc733d
30 |
31 | -----BEGIN EC PRIVATE KEY-----
32 | MIGlAgEBBDEAyaIliAIsYvYRdr2xv/8cuBleSaPfctnQKoPMsJBeE/IpWbBmBzLd
33 | oWcSjZGEn2TKoAcGBSuBBAAioWQDYgAE+4g5cXO1fcEXxaMXnKBIr5cUki6b//sb
34 | FnvW0VRUPkm+aok6RO8TM2vKhAJnbWUWqY79ARemtyxTBOTQmQHO8lBDQwBmUOl9
35 | lckNVVQUk39juLfBpdnkuVeLk5Z4XM2w
36 | -----END EC PRIVATE KEY-----
37 | -----BEGIN CERTIFICATE-----
38 | MIICdTCCAfygAwIBAgIUcrQcpa5JXvNxkPgRtiMk6atyQJ4wCgYIKoZIzj0EAwQw
39 | UDEsMCoGA1UEAxMjbGlnaHR0cGQyIHRlc3Qgc3VpdGUgSW50ZXJtZWRpYXRlIDEx
40 | IDAeBgNVBAsTF2xpZ2h0dHBkMiB0ZXN0IHN1aXRlIENBMB4XDTI1MDEwMTEzMzIy
41 | NloXDTM0MTIzMDEzMzIyNlowNjESMBAGA1UEAxMJdGVzdDEuc3NsMSAwHgYDVQQL
42 | ExdsaWdodHRwZDIgdGVzdCBzdWl0ZSBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IA
43 | BPuIOXFztX3BF8WjF5ygSK+XFJIum//7GxZ71tFUVD5JvmqJOkTvEzNryoQCZ21l
44 | FqmO/QEXprcsUwTk0JkBzvJQQ0MAZlDpfZXJDVVUFJN/Y7i3waXZ5LlXi5OWeFzN
45 | sKOBsDCBrTAMBgNVHRMBAf8EAjAAMDgGA1UdEQQxMC+CDnRlc3QxLnNzbC50ZXN0
46 | gg4qLm9wZW5zc2wudGVzdIINKi5nbnV0bHMudGVzdDATBgNVHSUEDDAKBggrBgEF
47 | BQcDATAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFDT/zL9sXlkE2FNK89p58gH9
48 | 3HM9MB8GA1UdIwQYMBaAFIdYZEGTpLS+h8WsSGr4m/7tnnetMAoGCCqGSM49BAME
49 | A2cAMGQCMECcU3y8OD+uImStj6IRi7iZPp3bEPdyN2zJOnxwG3kbxguGEZTPZoMe
50 | DMsLdiQSAwIwNc60UE7OKhJJaiNgPnuMybTNvEyksakAP2LfFDpK6/XQyBOnP91J
51 | UZM4P74V6PwR
52 | -----END CERTIFICATE-----
53 | -----BEGIN CERTIFICATE-----
54 | MIICPDCCAcOgAwIBAgIURcjH78CmuAoNZVwLZka0+BmM17wwCgYIKoZIzj0EAwQw
55 | SzEnMCUGA1UEAxMebGlnaHR0cGQyIHRlc3Qgc3VpdGUgQXV0aG9yaXR5MSAwHgYD
56 | VQQLExdsaWdodHRwZDIgdGVzdCBzdWl0ZSBDQTAeFw0yNTAxMDExMzMyMjZaFw0z
57 | NDEyMzAxMzMyMjZaMFAxLDAqBgNVBAMTI2xpZ2h0dHBkMiB0ZXN0IHN1aXRlIElu
58 | dGVybWVkaWF0ZSAxMSAwHgYDVQQLExdsaWdodHRwZDIgdGVzdCBzdWl0ZSBDQTB2
59 | MBAGByqGSM49AgEGBSuBBAAiA2IABGAMLbh3AitDqsKwtO3b1qOwve2RzGWGs7z8
60 | qsi4Nye9+r9l6VQTnK0TUxrr/WdYOLdNmeMVtMl3tXb+m6XKnBVH442q8pipYbM7
61 | xSRLTuPDRSpKoJqZTTJcoLC/uhpLu6NjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
62 | HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFIdYZEGTpLS+h8WsSGr4m/7tnnetMB8GA1Ud
63 | IwQYMBaAFMEztottTkpfEMdgJyKaXwKTAIJrMAoGCCqGSM49BAMEA2cAMGQCMDUJ
64 | y41eYkjLnj1x9T1xvy4LPLjhQE4ZdpJ2BwNNnn/+lHgfZtxf8thQtoXbx9uHMgIw
65 | H8cWKviP+rrBLUW4JdnSvv+8voRJYpNswi+EJoee53hShIWsETixdwGM1hRGQtdB
66 | -----END CERTIFICATE-----
67 |
--------------------------------------------------------------------------------
/tests/ca/server_test1.ssl.template:
--------------------------------------------------------------------------------
1 |
2 | dn = "OU=lighttpd2 test suite CA,CN=test1.ssl"
3 | dns_name = "test1.ssl.test"
4 | dns_name = "*.openssl.test"
5 | dns_name = "*.gnutls.test"
6 |
7 | expiration_days = 3650
8 |
9 | tls_www_server
10 | signing_key
11 | encryption_key
12 |
--------------------------------------------------------------------------------
/tests/ca/server_test2.ssl.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICdjCCAfygAwIBAgIUSthFkk2qsTj4RNfm/uyiQpsDdzAwCgYIKoZIzj0EAwQw
3 | UDEsMCoGA1UEAxMjbGlnaHR0cGQyIHRlc3Qgc3VpdGUgSW50ZXJtZWRpYXRlIDEx
4 | IDAeBgNVBAsTF2xpZ2h0dHBkMiB0ZXN0IHN1aXRlIENBMB4XDTI1MDEwMTEzMzIy
5 | NloXDTM0MTIzMDEzMzIyNlowNjESMBAGA1UEAxMJdGVzdDIuc3NsMSAwHgYDVQQL
6 | ExdsaWdodHRwZDIgdGVzdCBzdWl0ZSBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IA
7 | BPuIOXFztX3BF8WjF5ygSK+XFJIum//7GxZ71tFUVD5JvmqJOkTvEzNryoQCZ21l
8 | FqmO/QEXprcsUwTk0JkBzvJQQ0MAZlDpfZXJDVVUFJN/Y7i3waXZ5LlXi5OWeFzN
9 | sKOBsDCBrTAMBgNVHRMBAf8EAjAAMDgGA1UdEQQxMC+CDnRlc3QyLnNzbC50ZXN0
10 | gg4qLm9wZW5zc2wudGVzdIINKi5nbnV0bHMudGVzdDATBgNVHSUEDDAKBggrBgEF
11 | BQcDATAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFDT/zL9sXlkE2FNK89p58gH9
12 | 3HM9MB8GA1UdIwQYMBaAFIdYZEGTpLS+h8WsSGr4m/7tnnetMAoGCCqGSM49BAME
13 | A2gAMGUCMQDTOUcupCV7GYVaet4uIql6Qgbb5Y7sF8fQ4z9B6nBCde+u54HaijSd
14 | X9vzCKY5UqoCMDzkFiNc0AFrMHvaKUK+7mA2/8P+qiCI/de/UA/Ke7PzVWmLEDEJ
15 | daygZ2t/xp12vw==
16 | -----END CERTIFICATE-----
17 |
--------------------------------------------------------------------------------
/tests/ca/server_test2.ssl.pem:
--------------------------------------------------------------------------------
1 | Public Key Info:
2 | Public Key Algorithm: EC/ECDSA
3 | Key Security Level: Ultra (384 bits)
4 |
5 | curve: SECP384R1
6 | private key:
7 | 00:c9:a2:25:88:02:2c:62:f6:11:76:bd:b1:bf:ff:1c
8 | b8:19:5e:49:a3:df:72:d9:d0:2a:83:cc:b0:90:5e:13
9 | f2:29:59:b0:66:07:32:dd:a1:67:12:8d:91:84:9f:64
10 | ca:
11 |
12 | x:
13 | 00:fb:88:39:71:73:b5:7d:c1:17:c5:a3:17:9c:a0:48
14 | af:97:14:92:2e:9b:ff:fb:1b:16:7b:d6:d1:54:54:3e
15 | 49:be:6a:89:3a:44:ef:13:33:6b:ca:84:02:67:6d:65
16 | 16:
17 |
18 | y:
19 | 00:a9:8e:fd:01:17:a6:b7:2c:53:04:e4:d0:99:01:ce
20 | f2:50:43:43:00:66:50:e9:7d:95:c9:0d:55:54:14:93
21 | 7f:63:b8:b7:c1:a5:d9:e4:b9:57:8b:93:96:78:5c:cd
22 | b0:
23 |
24 |
25 | Public Key PIN:
26 | pin-sha256:7nnoskGn5ykPxCscQsd3tPYd2VWvmjZ5Da6yN4hLiBY=
27 | Public Key ID:
28 | sha256:ee79e8b241a7e7290fc42b1c42c777b4f61dd955af9a36790daeb237884b8816
29 | sha1:34ffccbf6c5e5904d8534af3da79f201fddc733d
30 |
31 | -----BEGIN EC PRIVATE KEY-----
32 | MIGlAgEBBDEAyaIliAIsYvYRdr2xv/8cuBleSaPfctnQKoPMsJBeE/IpWbBmBzLd
33 | oWcSjZGEn2TKoAcGBSuBBAAioWQDYgAE+4g5cXO1fcEXxaMXnKBIr5cUki6b//sb
34 | FnvW0VRUPkm+aok6RO8TM2vKhAJnbWUWqY79ARemtyxTBOTQmQHO8lBDQwBmUOl9
35 | lckNVVQUk39juLfBpdnkuVeLk5Z4XM2w
36 | -----END EC PRIVATE KEY-----
37 | -----BEGIN CERTIFICATE-----
38 | MIICdjCCAfygAwIBAgIUSthFkk2qsTj4RNfm/uyiQpsDdzAwCgYIKoZIzj0EAwQw
39 | UDEsMCoGA1UEAxMjbGlnaHR0cGQyIHRlc3Qgc3VpdGUgSW50ZXJtZWRpYXRlIDEx
40 | IDAeBgNVBAsTF2xpZ2h0dHBkMiB0ZXN0IHN1aXRlIENBMB4XDTI1MDEwMTEzMzIy
41 | NloXDTM0MTIzMDEzMzIyNlowNjESMBAGA1UEAxMJdGVzdDIuc3NsMSAwHgYDVQQL
42 | ExdsaWdodHRwZDIgdGVzdCBzdWl0ZSBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IA
43 | BPuIOXFztX3BF8WjF5ygSK+XFJIum//7GxZ71tFUVD5JvmqJOkTvEzNryoQCZ21l
44 | FqmO/QEXprcsUwTk0JkBzvJQQ0MAZlDpfZXJDVVUFJN/Y7i3waXZ5LlXi5OWeFzN
45 | sKOBsDCBrTAMBgNVHRMBAf8EAjAAMDgGA1UdEQQxMC+CDnRlc3QyLnNzbC50ZXN0
46 | gg4qLm9wZW5zc2wudGVzdIINKi5nbnV0bHMudGVzdDATBgNVHSUEDDAKBggrBgEF
47 | BQcDATAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFDT/zL9sXlkE2FNK89p58gH9
48 | 3HM9MB8GA1UdIwQYMBaAFIdYZEGTpLS+h8WsSGr4m/7tnnetMAoGCCqGSM49BAME
49 | A2gAMGUCMQDTOUcupCV7GYVaet4uIql6Qgbb5Y7sF8fQ4z9B6nBCde+u54HaijSd
50 | X9vzCKY5UqoCMDzkFiNc0AFrMHvaKUK+7mA2/8P+qiCI/de/UA/Ke7PzVWmLEDEJ
51 | daygZ2t/xp12vw==
52 | -----END CERTIFICATE-----
53 | -----BEGIN CERTIFICATE-----
54 | MIICPDCCAcOgAwIBAgIURcjH78CmuAoNZVwLZka0+BmM17wwCgYIKoZIzj0EAwQw
55 | SzEnMCUGA1UEAxMebGlnaHR0cGQyIHRlc3Qgc3VpdGUgQXV0aG9yaXR5MSAwHgYD
56 | VQQLExdsaWdodHRwZDIgdGVzdCBzdWl0ZSBDQTAeFw0yNTAxMDExMzMyMjZaFw0z
57 | NDEyMzAxMzMyMjZaMFAxLDAqBgNVBAMTI2xpZ2h0dHBkMiB0ZXN0IHN1aXRlIElu
58 | dGVybWVkaWF0ZSAxMSAwHgYDVQQLExdsaWdodHRwZDIgdGVzdCBzdWl0ZSBDQTB2
59 | MBAGByqGSM49AgEGBSuBBAAiA2IABGAMLbh3AitDqsKwtO3b1qOwve2RzGWGs7z8
60 | qsi4Nye9+r9l6VQTnK0TUxrr/WdYOLdNmeMVtMl3tXb+m6XKnBVH442q8pipYbM7
61 | xSRLTuPDRSpKoJqZTTJcoLC/uhpLu6NjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
62 | HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFIdYZEGTpLS+h8WsSGr4m/7tnnetMB8GA1Ud
63 | IwQYMBaAFMEztottTkpfEMdgJyKaXwKTAIJrMAoGCCqGSM49BAMEA2cAMGQCMDUJ
64 | y41eYkjLnj1x9T1xvy4LPLjhQE4ZdpJ2BwNNnn/+lHgfZtxf8thQtoXbx9uHMgIw
65 | H8cWKviP+rrBLUW4JdnSvv+8voRJYpNswi+EJoee53hShIWsETixdwGM1hRGQtdB
66 | -----END CERTIFICATE-----
67 |
--------------------------------------------------------------------------------
/tests/ca/server_test2.ssl.template:
--------------------------------------------------------------------------------
1 |
2 | dn = "OU=lighttpd2 test suite CA,CN=test2.ssl"
3 | dns_name = "test2.ssl.test"
4 | dns_name = "*.openssl.test"
5 | dns_name = "*.gnutls.test"
6 |
7 | expiration_days = 3650
8 |
9 | tls_www_server
10 | signing_key
11 | encryption_key
12 |
--------------------------------------------------------------------------------
/tests/meson.build:
--------------------------------------------------------------------------------
1 | runtest_file = files('runtests.py')
2 |
3 | test(
4 | 'http',
5 | runtest_file,
6 | args: [
7 | '--angel', bin_angel.full_path(),
8 | '--worker', bin_worker.full_path(),
9 | '--plugindir', modules_build_dir,
10 | ],
11 | depends: [
12 | bin_angel,
13 | bin_worker,
14 | enabled_modules,
15 | ],
16 | )
17 |
--------------------------------------------------------------------------------
/tests/pylt/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lighttpd/lighttpd2/c6d66b2084a60324f9a4d48960c8d268a0fc3b31/tests/pylt/__init__.py
--------------------------------------------------------------------------------
/tests/pylt/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lighttpd/lighttpd2/c6d66b2084a60324f9a4d48960c8d268a0fc3b31/tests/pylt/tests/__init__.py
--------------------------------------------------------------------------------
/tests/pylt/tests/t-alias.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from pylt.requests import CurlRequest, TEST_TXT
4 |
5 |
6 | class TestAlias1(CurlRequest):
7 | URL = "/alias1"
8 | EXPECT_RESPONSE_BODY = TEST_TXT
9 | EXPECT_RESPONSE_CODE = 200
10 | EXPECT_RESPONSE_HEADERS = [("Content-Type", "text/plain; charset=utf-8")]
11 | config = """
12 | alias "/alias1" => var.default_docroot + "/test.txt";
13 | """
14 |
15 |
16 | class TestAlias2(CurlRequest):
17 | URL = "/alias2"
18 | EXPECT_RESPONSE_BODY = TEST_TXT
19 | EXPECT_RESPONSE_CODE = 200
20 | EXPECT_RESPONSE_HEADERS = [("Content-Type", "text/plain; charset=utf-8")]
21 | config = """
22 | alias "/alias1" => "/nothing", "/alias2" => var.default_docroot + "/test.txt";
23 | """
24 |
25 |
26 | class TestAlias3(CurlRequest):
27 | URL = "/alias3/test.txt"
28 | EXPECT_RESPONSE_BODY = TEST_TXT
29 | EXPECT_RESPONSE_CODE = 200
30 | EXPECT_RESPONSE_HEADERS = [("Content-Type", "text/plain; charset=utf-8")]
31 | config = """
32 | alias "/alias3" => var.default_docroot + "/";
33 | """
34 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-basic-docroot.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from pylt.base import ModuleTest
4 | from pylt.requests import CurlRequest
5 |
6 |
7 | class TestSimple(CurlRequest):
8 | vhost = "xyz.abc.basic-docroot"
9 | URL = "/?simple"
10 | EXPECT_RESPONSE_BODY = "/var/www/xyz.abc.basic-docroot/htdocs"
11 | EXPECT_RESPONSE_CODE = 200
12 |
13 |
14 | class TestSubdir(CurlRequest):
15 | vhost = "xyz.abc.basic-docroot"
16 | URL = "/?subdir"
17 | EXPECT_RESPONSE_BODY = "/var/www/basic-docroot/xyz.abc.basic-docroot/htdocs"
18 | EXPECT_RESPONSE_CODE = 200
19 |
20 |
21 | class TestSubdirOpenRange(CurlRequest):
22 | vhost = "test.xyz.abc.basic-docroot"
23 | URL = "/?subdir-open-range"
24 | EXPECT_RESPONSE_BODY = "/var/www/basic-docroot/test.xyz.abc/htdocs"
25 | EXPECT_RESPONSE_CODE = 200
26 |
27 |
28 | class TestSubdirFixedRange(CurlRequest):
29 | vhost = "test.xyz.abc.basic-docroot"
30 | URL = "/?subdir-fixed-range"
31 | EXPECT_RESPONSE_BODY = "/var/www/basic-docroot/xyz.abc/htdocs"
32 | EXPECT_RESPONSE_CODE = 200
33 |
34 |
35 | class TestCascade(CurlRequest):
36 | URL = "/?cascade"
37 | EXPECT_RESPONSE_BODY = "/"
38 | EXPECT_RESPONSE_CODE = 200
39 |
40 |
41 | class TestCascadeFallback(CurlRequest):
42 | URL = "/?cascade-fallback"
43 | EXPECT_RESPONSE_BODY = "/var/www/fallback/htdocs"
44 | EXPECT_RESPONSE_CODE = 200
45 |
46 |
47 | class Test(ModuleTest):
48 | vhost = "basic-docroot"
49 | subdomains = True
50 | config = """
51 |
52 | if req.query == "simple" {
53 | docroot "/var/www/$0/htdocs";
54 | } else if req.query == "subdir" {
55 | docroot "/var/www/$[1]/$[0]/htdocs";
56 | } else if req.query == "subdir-open-range" {
57 | docroot "/var/www/$1/$[2-]/htdocs";
58 | } else if req.query == "subdir-fixed-range" {
59 | docroot "/var/www/$1/$[2-3]/htdocs";
60 | } else if req.query == "cascade" {
61 | docroot ("/","/var/www/fallback/htdocs");
62 | } else if req.query == "cascade-fallback" {
63 | docroot ("_","/var/www/fallback/htdocs");
64 | }
65 |
66 | env.set "INFO" => "%{phys.docroot}";
67 | show_env_info;
68 |
69 | """
70 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-deflate.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from pylt.base import ModuleTest
4 | from pylt.requests import CurlRequest, TEST_TXT
5 |
6 |
7 | class DeflateRequest(CurlRequest):
8 | _NO_REGISTER = True # used in metaclass
9 |
10 | URL = "/test.txt"
11 | EXPECT_RESPONSE_BODY = TEST_TXT
12 | EXPECT_RESPONSE_CODE = 200
13 |
14 | EXPECT_RESPONSE_HEADERS = [("Vary", "Accept-Encoding")]
15 |
16 | def prepare_test(self) -> None:
17 | self.EXPECT_RESPONSE_HEADERS = (
18 | self.EXPECT_RESPONSE_HEADERS
19 | + [("Content-Encoding", self.ACCEPT_ENCODING)]
20 | )
21 |
22 |
23 | class TestGzip(DeflateRequest):
24 | ACCEPT_ENCODING = 'gzip'
25 |
26 |
27 | class TestXGzip(DeflateRequest):
28 | ACCEPT_ENCODING = 'x-gzip'
29 |
30 |
31 | class TestDeflate(DeflateRequest):
32 | ACCEPT_ENCODING = 'deflate'
33 |
34 |
35 | # not supported
36 | ### class TestCompress(DeflateRequest):
37 | ### ACCEPT_ENCODING = 'compress'
38 |
39 |
40 | class TestBzip2(DeflateRequest):
41 | ACCEPT_ENCODING = 'bzip2'
42 |
43 |
44 | class TestXBzip2(DeflateRequest):
45 | ACCEPT_ENCODING = 'x-bzip2'
46 |
47 |
48 | class TestDisableDeflate(CurlRequest):
49 | URL = "/test.txt?nodeflate"
50 | EXPECT_RESPONSE_BODY = TEST_TXT
51 | EXPECT_RESPONSE_CODE = 200
52 |
53 | EXPECT_RESPONSE_HEADERS = [("Content-Encoding", None)]
54 |
55 |
56 | class Test(ModuleTest):
57 | def prepare_test(self) -> None:
58 | # deflate is enabled global too; force it here anyway
59 | self.config = """
60 | defaultaction;
61 | if req.query == "nodeflate" { req_header.remove "Accept-Encoding"; } static; do_deflate;
62 | """
63 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-dirlist.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from pylt.base import ModuleTest
4 | from pylt.requests import CurlRequest
5 |
6 |
7 | class TestDirlist(CurlRequest):
8 | URL = "/foo/"
9 | EXPECT_RESPONSE_CODE = 200
10 | EXPECT_RESPONSE_HEADERS = [("Content-Type", "text/html; charset=utf-8")]
11 |
12 |
13 | class TestRedirectDir(CurlRequest):
14 | URL = "/foo"
15 | EXPECT_RESPONSE_CODE = 301
16 | EXPECT_RESPONSE_HEADERS = [("Location", "http://dirlist.test/foo/")]
17 |
18 |
19 | class TestRedirectDirWithQuery(CurlRequest):
20 | URL = "/foo?bar=baz"
21 | EXPECT_RESPONSE_CODE = 301
22 | EXPECT_RESPONSE_HEADERS = [("Location", "http://dirlist.test/foo/?bar=baz")]
23 |
24 |
25 | class TestRedirectDirWithQueryAndSpecialChars(CurlRequest):
26 | URL = "/f%3f%20o?bar=baz"
27 | EXPECT_RESPONSE_CODE = 301
28 | EXPECT_RESPONSE_HEADERS = [("Location", "http://dirlist.test/f%3f%20o/?bar=baz")]
29 |
30 |
31 | class Test(ModuleTest):
32 | config = """
33 | setup { module_load "mod_dirlist"; }
34 | dirlist;
35 | """
36 |
37 | def prepare_test(self) -> None:
38 | self.prepare_dir("www/vhosts/dirlist.test/foo")
39 | self.prepare_file("www/vhosts/dirlist.test/foo/test.txt", "abc")
40 | self.prepare_dir("www/vhosts/dirlist.test/f? o")
41 | self.prepare_file("www/vhosts/dirlist.test/f? o/test.txt", "abc")
42 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-env-set.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from pylt.requests import CurlRequest
4 |
5 |
6 | class TestPatternCapture(CurlRequest):
7 | # use capture from previous regex conditional
8 | config = """
9 | if req.path =~ "(.*)" {
10 | env.set "INFO" => "%1";
11 | show_env_info;
12 | }
13 | """
14 | URL = "/path/?a_simple_query"
15 | EXPECT_RESPONSE_BODY = "/path/"
16 | EXPECT_RESPONSE_CODE = 200
17 |
18 |
19 | class TestPatternCaptureRange(CurlRequest):
20 | # use capture from previous regex conditional
21 | config = """
22 | if req.path =~ "/([^/]*)/(.*)" {
23 | env.set "INFO" => "%[1-2]";
24 | show_env_info;
25 | }
26 | """
27 | URL = "/path/xyz"
28 | EXPECT_RESPONSE_BODY = "pathxyz"
29 | EXPECT_RESPONSE_CODE = 200
30 |
31 |
32 | class TestPatternCaptureRevRange(CurlRequest):
33 | # use capture from previous regex conditional
34 | config = """
35 | if req.path =~ "/([^/]*)/(.*)" {
36 | env.set "INFO" => "%[2-1]";
37 | show_env_info;
38 | }
39 | """
40 | URL = "/path/xyz"
41 | EXPECT_RESPONSE_BODY = "xyzpath"
42 | EXPECT_RESPONSE_CODE = 200
43 |
44 |
45 | class TestPatternEncodingPath(CurlRequest):
46 | # encoding path
47 | config = """
48 | env.set "INFO" => "%{enc:req.path}";
49 | show_env_info;
50 | """
51 | URL = "/complicated%3fpath%3d%20%24"
52 | EXPECT_RESPONSE_BODY = "/complicated%3fpath%3d%20%24"
53 | EXPECT_RESPONSE_CODE = 200
54 |
55 |
56 | class TestPatternCombine(CurlRequest):
57 | # combine several pieces
58 | config = """
59 | env.set "INFO" => "Abc:%{enc:req.path}:%{req.query}:%{req.host}";
60 | show_env_info;
61 | """
62 | URL = "/complicated%3fpath%3d%20%24?a_simple_query"
63 | EXPECT_RESPONSE_CODE = 200
64 |
65 | def prepare_test(self):
66 | self.EXPECT_RESPONSE_BODY = "Abc:/complicated%3fpath%3d%20%24:a_simple_query:" + self.vhost
67 |
68 |
69 | class TestPatternEscape(CurlRequest):
70 | config = r"""
71 | env.set "INFO" => "\\%\\?\\$\\%{req.path}";
72 | show_env_info;
73 | """
74 | URL = "/abc"
75 | EXPECT_RESPONSE_BODY = "%?$%{req.path}"
76 | EXPECT_RESPONSE_CODE = 200
77 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-gnutls.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from pylt.requests import CurlRequest, TEST_TXT
4 |
5 |
6 | class TestSimpleRequest(CurlRequest):
7 | PORT_OFFSET = 1
8 | SCHEME = "https"
9 | URL = "/test.txt"
10 | EXPECT_RESPONSE_BODY = TEST_TXT
11 | EXPECT_RESPONSE_CODE = 200
12 | EXPECT_RESPONSE_HEADERS = [("Content-Type", "text/plain; charset=utf-8")]
13 | vhost = "test1.ssl.test"
14 |
15 |
16 | class TestSNI(CurlRequest):
17 | PORT_OFFSET = 1
18 | SCHEME = "https"
19 | URL = "/test.txt"
20 | EXPECT_RESPONSE_BODY = TEST_TXT
21 | EXPECT_RESPONSE_CODE = 200
22 | EXPECT_RESPONSE_HEADERS = [("Content-Type", "text/plain; charset=utf-8")]
23 | vhost = "test2.ssl.test"
24 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-header-modify.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from pylt.base import eprint, log
4 | from pylt.requests import CurlRequest
5 |
6 |
7 | class TestHeaderAdd(CurlRequest):
8 | # use capture from previous regex conditional
9 | config = """
10 | header.add "Test-Header" => "%{req.query}";
11 | header.add "Test-Header" => "%{req.path}";
12 | respond;
13 | """
14 | URL = "/path?simple_query"
15 |
16 | def CheckResponse(self) -> bool:
17 | h = self.response.get_all_headers("Test-Header")
18 | if len(h) != 2 or h[0] != "simple_query" or h[1] != "/path":
19 | eprint(repr(h))
20 | raise Exception("Unexpected headers 'Test-Header'")
21 | return True
22 |
23 |
24 | class TestHeaderAppend(CurlRequest):
25 | # use capture from previous regex conditional
26 | config = """
27 | header.append "Test-Header" => "%{req.query}";
28 | header.append "Test-Header" => "%{req.path}";
29 | respond;
30 | """
31 | URL = "/path?simple_query"
32 |
33 | def CheckResponse(self) -> bool:
34 | h = self.response.get_all_headers("Test-Header")
35 | if len(h) != 1 or h[0] != "simple_query, /path":
36 | log(repr(h))
37 | raise Exception("Unexpected headers 'Test-Header'")
38 | return True
39 |
40 |
41 | class TestHeaderOverwrite(CurlRequest):
42 | # use capture from previous regex conditional
43 | config = """
44 | header.overwrite "Test-Header" => "%{req.query}";
45 | header.overwrite "Test-Header" => "%{req.path}";
46 | respond;
47 | """
48 | URL = "/path?simple_query"
49 |
50 | def CheckResponse(self) -> bool:
51 | h = self.response.get_all_headers("Test-Header")
52 | if len(h) != 1 or h[0] != "/path":
53 | log(repr(h))
54 | raise Exception("Unexpected headers 'Test-Header'")
55 | return True
56 |
57 |
58 | class TestHeaderRemove(CurlRequest):
59 | # use capture from previous regex conditional
60 | config = """
61 | header.add "Test-Header" => "%{req.query}";
62 | header.remove "Test-Header";
63 | respond;
64 | """
65 | URL = "/path?simple_query"
66 |
67 | def CheckResponse(self) -> bool:
68 | h = self.response.get_all_headers("Test-Header")
69 | if len(h) != 0:
70 | log(repr(h))
71 | raise Exception("Unexpected headers 'Test-Header'")
72 | return True
73 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-lua.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from pylt.base import ModuleTest, TestBase
4 | from pylt.requests import CurlRequest
5 |
6 |
7 | LUA_STATE_ENV_INFO = """
8 | -- globals should be reset after loading
9 | info = "global info"
10 |
11 | -- tostring(custom_obj) should throw an error, but log functions should handle it
12 | local custom_obj = {["data"] = "test string"}
13 | setmetatable(custom_obj, {["__tostring"] = function(obj) return nil .. obj["data"] end})
14 |
15 | print("bar", "custom_obj=", custom_obj)
16 |
17 | local function extract_info(vr)
18 | vr:error("extract_info: info=" .. (info or ""), "nil=", nil, "custom_obj=", custom_obj)
19 | -- simple globals should be "per handler" (and request)
20 | info = (info or "") .. "handler global"
21 | -- special `REQ` allows request-global state across handlers
22 | REQ.info = (REQ.info or "") .. "request global:" .. vr.env["INFO"]
23 | end
24 |
25 | local function show_info(vr)
26 | lighty.error("show_info: info=" .. (info or "") .. "; REQ.info=" .. (REQ.info or ""))
27 | if vr:handle_direct() then
28 | vr.resp.status = 200
29 | vr.resp.headers["Content-Type"] = "text/plain"
30 | vr.out:add((info or "") .. (REQ.info or ""))
31 | end
32 | end
33 |
34 | actions = action.list({extract_info, show_info})
35 | """
36 |
37 |
38 | class TestLuaStateInfo1(CurlRequest):
39 | URL = "/?a_simple_query"
40 | EXPECT_RESPONSE_BODY = "request global:a_simple_query"
41 | EXPECT_RESPONSE_CODE = 200
42 |
43 | config = """
44 | env.set "INFO" => "%{req.query}";
45 | lua_state_env_info;
46 | """
47 |
48 | class TestLuaStateInfo2(CurlRequest):
49 | URL = "/?b_simple_query"
50 | EXPECT_RESPONSE_BODY = "request global:b_simple_query"
51 | EXPECT_RESPONSE_CODE = 200
52 |
53 | config = """
54 | env.set "INFO" => "%{req.query}";
55 | lua_state_env_info;
56 | """
57 |
58 | class TestLuaWorkerStateInfo1(CurlRequest):
59 | URL = "/?a_simple_query"
60 | EXPECT_RESPONSE_BODY = "request global:a_simple_query"
61 | EXPECT_RESPONSE_CODE = 200
62 |
63 | config = """
64 | env.set "INFO" => "%{req.query}";
65 | worker_lua_state_env_info;
66 | """
67 |
68 | class TestLuaWorkerStateInfo2(CurlRequest):
69 | URL = "/?b_simple_query"
70 | EXPECT_RESPONSE_BODY = "request global:b_simple_query"
71 | EXPECT_RESPONSE_CODE = 200
72 |
73 | config = """
74 | env.set "INFO" => "%{req.query}";
75 | worker_lua_state_env_info;
76 | """
77 |
78 | class Test(ModuleTest):
79 | def prepare_test(self) -> None:
80 | show_env_info_lua = self.prepare_file("lua/lua_state_env_info.lua", LUA_STATE_ENV_INFO)
81 | self.plain_config = f"""
82 | lua_state_env_info = {{
83 | include_lua "{show_env_info_lua}";
84 | }};
85 | worker_lua_state_env_info = {{
86 | lua.handler "{show_env_info_lua}";
87 | }};
88 | """
89 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-map-cidr.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from pylt.requests import CurlRequest
4 |
5 |
6 | class TestSimpleCidrMap(CurlRequest):
7 | URL = "/test.txt"
8 | EXPECT_RESPONSE_BODY = "abc"
9 | EXPECT_RESPONSE_CODE = 200
10 | config = """
11 | map_cidr [
12 | "127.0.0.0/8" => {
13 | },
14 | default => {
15 | respond 402 => "";
16 | },
17 | ];
18 | respond 200 => "abc";
19 | """
20 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-memcached.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import socket
4 | import os
5 | import time
6 |
7 | from pylt import base
8 | from pylt.requests import CurlRequest
9 | from pylt.service import Service
10 |
11 |
12 | class Memcached(Service):
13 | name = "memcached"
14 | binary: list[str] = []
15 |
16 | def __init__(self, *, tests: base.Tests) -> None:
17 | super().__init__(tests=tests)
18 | self.sockfile = os.path.join(self.tests.env.dir, "tmp", "sockets", self.name + ".sock")
19 | self.binary = [os.path.join(self.tests.env.sourcedir, "tests", "run-memcached.py")]
20 |
21 | def prepare_service(self) -> None:
22 | assert self.tests
23 | self.tests.install_dir(os.path.join("tmp", "sockets"))
24 | sock = self.bind_unix_socket(sockfile=self.sockfile)
25 | self.fork(*self.binary, inp=sock)
26 |
27 | def cleanup_service(self) -> None:
28 | assert self.tests
29 | try:
30 | os.remove(self.sockfile)
31 | except Exception as e:
32 | base.eprint(f"Couldn't delete socket {self.sockfile!r}: {e}")
33 | self.tests.remove_dir(os.path.join("tmp", "sockets"))
34 |
35 |
36 | class TestStore1(CurlRequest):
37 | URL = "/"
38 | EXPECT_RESPONSE_BODY = "Hello World!"
39 | EXPECT_RESPONSE_CODE = 200
40 | EXPECT_RESPONSE_HEADERS = [("X-Memcached-Hit", "false")]
41 |
42 |
43 | class TestLookup1(CurlRequest):
44 | URL = "/"
45 | EXPECT_RESPONSE_BODY = "Hello World!"
46 | EXPECT_RESPONSE_CODE = 200
47 | EXPECT_RESPONSE_HEADERS = [("X-Memcached-Hit", "true")]
48 |
49 | def run_test(self) -> bool:
50 | # storing might take some time: only after the request is actually
51 | # finished does lighttpd start the memcache connection to store it
52 | time.sleep(0.2)
53 | return super().run_test()
54 |
55 |
56 | class Test(base.ModuleTest):
57 | config = """
58 | memcache;
59 | """
60 |
61 | def __init__(self, *, tests: base.Tests) -> None:
62 | super().__init__(tests=tests)
63 |
64 | memcached = Memcached(tests=self.tests)
65 | self.plain_config = f"""
66 | setup {{ module_load "mod_memcached"; }}
67 |
68 | memcache = {{
69 | memcached.lookup (( "server" => "unix:{memcached.sockfile}" ), {{
70 | header.add "X-Memcached-Hit" => "true";
71 | }}, {{
72 | header.add "X-Memcached-Hit" => "false";
73 | respond 200 => "Hello World!";
74 | memcached.store ( "server" => "unix:{memcached.sockfile}" );
75 | }});
76 | }};
77 | """
78 | self.tests.add_service(memcached)
79 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-mime-type.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from pylt.base import ModuleTest
4 | from pylt.requests import CurlRequest
5 |
6 |
7 | class TestMimeType1(CurlRequest):
8 | URL = "/test.txt"
9 | EXPECT_RESPONSE_BODY = ""
10 | EXPECT_RESPONSE_CODE = 200
11 | EXPECT_RESPONSE_HEADERS = [("Content-Type", "text/plain; charset=utf-8")]
12 |
13 |
14 | class TestMimeType2(CurlRequest):
15 | URL = "/test.xt"
16 | EXPECT_RESPONSE_BODY = ""
17 | EXPECT_RESPONSE_CODE = 200
18 | EXPECT_RESPONSE_HEADERS = [("Content-Type", "text/plain")]
19 |
20 |
21 | class TestMimeType3(CurlRequest):
22 | URL = "/test.rxt"
23 | EXPECT_RESPONSE_BODY = ""
24 | EXPECT_RESPONSE_CODE = 200
25 | EXPECT_RESPONSE_HEADERS = [("Content-Type", "text/strange")]
26 |
27 |
28 | class Test(ModuleTest):
29 | def prepare_test(self) -> None:
30 | self.prepare_vhost_file("test.txt", "")
31 | self.prepare_vhost_file("test.xt", "")
32 | self.prepare_vhost_file("test.rxt", "")
33 | self.config = """
34 | mime_types (
35 | ".txt" => "text/plain; charset=utf-8",
36 | ".xt" => "text/plain",
37 | ".rxt" => "text/strange",
38 | "xt" => "should-not-trigger"
39 | );
40 | """
41 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-mod-lua.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from pylt.base import ModuleTest
4 | from pylt.requests import CurlRequest
5 |
6 |
7 | LUA_TEST_OPTIONS = """
8 |
9 | local function settag(tag)
10 | setup["server.tag"](tag)
11 | end
12 |
13 | local function changetag(tag)
14 | return action["server.tag"](tag)
15 | end
16 |
17 | actions = {
18 | ["lua.changetag"] = changetag
19 | }
20 | setups = {
21 | ["lua.settag"] = settag
22 | }
23 |
24 | """
25 |
26 |
27 | class TestSetupOption(CurlRequest):
28 | URL = "/"
29 | EXPECT_RESPONSE_HEADERS = [("Server", "lighttpd 2.0 with lua")]
30 |
31 |
32 | class TestChangeOption(CurlRequest):
33 | URL = "/?change"
34 | EXPECT_RESPONSE_HEADERS = [("Server", "lighttpd 2.0 with modified lua")]
35 |
36 |
37 | class Test(ModuleTest):
38 | def prepare_test(self) -> None:
39 | test_options_lua = self.prepare_file("lua/test_options.lua", LUA_TEST_OPTIONS)
40 | self.plain_config = f"""
41 | setup {{
42 | lua.plugin "{test_options_lua}";
43 | lua.settag "lighttpd 2.0 with lua";
44 | }}
45 | """
46 | self.config = """
47 | if req.query == "change" {
48 | lua.changetag "lighttpd 2.0 with modified lua";
49 | }
50 | """
51 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-openssl.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from pylt.requests import CurlRequest, TEST_TXT
4 |
5 |
6 | class TestSimpleRequest(CurlRequest):
7 | PORT_OFFSET = 2
8 | SCHEME = "https"
9 | URL = "/test.txt"
10 | EXPECT_RESPONSE_BODY = TEST_TXT
11 | EXPECT_RESPONSE_CODE = 200
12 | EXPECT_RESPONSE_HEADERS = [("Content-Type", "text/plain; charset=utf-8")]
13 | vhost = "test1.ssl.test"
14 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-redirect.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from pylt.base import ModuleTest
4 | from pylt.requests import CurlRequest, TEST_TXT
5 |
6 |
7 | class TestRewrite1(CurlRequest):
8 | URL = "/somefile"
9 | EXPECT_RESPONSE_BODY = TEST_TXT
10 | EXPECT_RESPONSE_CODE = 200
11 | EXPECT_RESPONSE_HEADERS = [("Content-Type", "text/plain; charset=utf-8")]
12 | config = """
13 | rewrite "^/somefile$" => "/test.txt";
14 | defaultaction;
15 | """
16 |
17 |
18 | class TestRewrite2(CurlRequest):
19 | URL = "/somefile"
20 | EXPECT_RESPONSE_BODY = TEST_TXT
21 | EXPECT_RESPONSE_CODE = 200
22 | EXPECT_RESPONSE_HEADERS = [("Content-Type", "text/plain; charset=utf-8")]
23 | config = """
24 | rewrite "/somethingelse" => "/nothing", "^/somefile$" => "/test.txt";
25 | defaultaction;
26 | """
27 |
28 |
29 | class Test(ModuleTest):
30 | plain_config = """
31 | setup { module_load "mod_rewrite"; }
32 | """
33 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-rewrite.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from pylt.base import ModuleTest
4 | from pylt.requests import CurlRequest, TEST_TXT
5 |
6 |
7 | class TestRewrite1(CurlRequest):
8 | URL = "/somefile"
9 | EXPECT_RESPONSE_BODY = TEST_TXT
10 | EXPECT_RESPONSE_CODE = 200
11 | EXPECT_RESPONSE_HEADERS = [("Content-Type", "text/plain; charset=utf-8")]
12 | config = """
13 | rewrite "^/somefile$" => "/test.txt";
14 | defaultaction;
15 | """
16 |
17 |
18 | class TestRewrite2(CurlRequest):
19 | URL = "/somefile"
20 | EXPECT_RESPONSE_BODY = TEST_TXT
21 | EXPECT_RESPONSE_CODE = 200
22 | EXPECT_RESPONSE_HEADERS = [("Content-Type", "text/plain; charset=utf-8")]
23 | config = """
24 | rewrite "/somethingelse" => "/nothing", "^/somefile$" => "/test.txt";
25 | defaultaction;
26 | """
27 |
28 |
29 | # match decoded and simplified paths by default
30 | class TestRewrite3(CurlRequest):
31 | URL = "/http://some%2Ffile"
32 | EXPECT_RESPONSE_BODY = "/dest/file"
33 | EXPECT_RESPONSE_CODE = 200
34 | config = """
35 | rewrite "/http:/some(/.*)" => "/dest$1";
36 | respond 200 => "%{req.path}";
37 | """
38 |
39 |
40 | # match raw paths and simplify path
41 | class TestRewrite4(CurlRequest):
42 | URL = "/http://some%2Ffile"
43 | EXPECT_RESPONSE_BODY = "/dest/http:/some/file"
44 | EXPECT_RESPONSE_CODE = 200
45 | config = """
46 | rewrite_raw "(/http://some%2F.*)" => "/dest$1";
47 | respond 200 => "%{req.path}";
48 | """
49 |
50 |
51 | # match and write raw paths
52 | class TestRewrite5(CurlRequest):
53 | URL = "/http://some%2Ffile"
54 | EXPECT_RESPONSE_BODY = "/dest/http://some%2Ffile"
55 | EXPECT_RESPONSE_CODE = 200
56 | config = """
57 | rewrite_raw "(/http://some%2F.*)" => "/dest$1";
58 | respond 200 => "%{req.raw_path}";
59 | """
60 |
61 |
62 | # raw match and write query string
63 | class TestRewrite6(CurlRequest):
64 | URL = "/http://some%2Ffile"
65 | EXPECT_RESPONSE_BODY = "/http://some%2Ffile"
66 | EXPECT_RESPONSE_CODE = 200
67 | config = """
68 | rewrite_raw "(/http://some%2F.*)" => "/dest?$1";
69 | respond 200 => "%{req.query}";
70 | """
71 |
72 |
73 | class Test(ModuleTest):
74 | plain_config = """
75 | setup { module_load "mod_rewrite"; }
76 | """
77 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-scgi.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import socket
4 | import os
5 |
6 | from pylt import base
7 | from pylt.requests import CurlRequest
8 | from pylt.service import Service
9 |
10 |
11 | class SCGI(Service):
12 | name = "scgi"
13 | binary: list[str] = []
14 |
15 | def __init__(self, *, tests: base.Tests) -> None:
16 | super().__init__(tests=tests)
17 | self.sockfile = os.path.join(self.tests.env.dir, "tmp", "sockets", self.name + ".sock")
18 | self.binary = [os.path.join(self.tests.env.sourcedir, "tests", "run-scgi-envcheck.py")]
19 |
20 | def prepare_service(self) -> None:
21 | assert self.tests
22 | self.tests.install_dir(os.path.join("tmp", "sockets"))
23 | sock = self.bind_unix_socket(sockfile=self.sockfile)
24 | self.fork(*self.binary, inp=sock)
25 |
26 | def cleanup_service(self) -> None:
27 | assert self.tests
28 | try:
29 | os.remove(self.sockfile)
30 | except Exception as e:
31 | base.eprint(f"Couldn't delete socket {self.sockfile}: {e}")
32 | self.tests.remove_dir(os.path.join("tmp", "sockets"))
33 |
34 |
35 | class TestPathInfo1(CurlRequest):
36 | URL = "/scgi/abc/xyz?PATH_INFO"
37 | EXPECT_RESPONSE_BODY = "/abc/xyz"
38 | EXPECT_RESPONSE_CODE = 200
39 |
40 |
41 | class TestRequestUri1(CurlRequest):
42 | URL = "/scgi/abc/xyz?REQUEST_URI"
43 | EXPECT_RESPONSE_BODY = "/scgi/abc/xyz?REQUEST_URI"
44 | EXPECT_RESPONSE_CODE = 200
45 |
46 |
47 | class Test(base.ModuleTest):
48 | config = """
49 | run_scgi;
50 | """
51 |
52 | def __init__(self, *, tests: base.Tests) -> None:
53 | super().__init__(tests=tests)
54 |
55 | scgi = SCGI(tests=self.tests)
56 | self.plain_config = f"""
57 | setup {{ module_load "mod_scgi"; }}
58 |
59 | run_scgi = {{
60 | core.wsgi ( "/scgi", {{ scgi "unix:{scgi.sockfile}"; }} );
61 | }};
62 | """
63 | self.tests.add_service(scgi)
64 |
--------------------------------------------------------------------------------
/tests/pylt/tests/t-secdownload.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import time
4 | import typing
5 | from hashlib import md5
6 |
7 | from pylt.base import ModuleTest
8 | from pylt.requests import CurlRequest, TEST_TXT
9 |
10 |
11 | def securl(prefix: str, path: str, secret: str, tstamp: typing.Optional[float] = None) -> str:
12 | if tstamp is None:
13 | tstamp = time.time()
14 | hex_tstamp = f'{int(tstamp):x}'
15 | md5content = secret + path + hex_tstamp
16 | if prefix[-1] != '/':
17 | prefix += '/'
18 | return prefix + md5(md5content.encode()).hexdigest() + '/' + hex_tstamp + path
19 |
20 |
21 | class SecdownloadFail(CurlRequest):
22 | URL = "/test.txt"
23 | EXPECT_RESPONSE_CODE = 403
24 |
25 |
26 | class SecdownloadSuccess(CurlRequest):
27 | EXPECT_RESPONSE_BODY = TEST_TXT
28 | EXPECT_RESPONSE_CODE = 200
29 |
30 | def run_test(self) -> bool:
31 | self.URL = securl('/', '/test.txt', 'abc')
32 | return super().run_test()
33 |
34 |
35 | class SecdownloadGone(CurlRequest):
36 | EXPECT_RESPONSE_CODE = 410
37 |
38 | def run_test(self) -> bool:
39 | self.URL = securl('/', '/test.txt', 'abc', time.time() - 800)
40 | return super().run_test()
41 |
42 |
43 | class Test(ModuleTest):
44 | config = """
45 | secdownload ( "prefix" => "/", "document-root" => var.default_docroot, "secret" => "abc", "timeout" => 600 );
46 | """
47 | no_docroot = True
48 |
--------------------------------------------------------------------------------
/tests/run-scgi-envcheck.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import asyncio
5 | import dataclasses
6 | import socket
7 | import traceback
8 |
9 |
10 | @dataclasses.dataclass
11 | class ScgiRequest:
12 | headers: dict[bytes, bytes]
13 | body: bytes
14 |
15 |
16 | async def parse_scgi_request(reader: asyncio.StreamReader) -> ScgiRequest:
17 | hlen = int((await reader.readuntil(b':'))[:-1])
18 | header_raw = await reader.readexactly(hlen + 1)
19 | assert len(header_raw) >= 16, "invalid request: too short (< 16)"
20 | assert header_raw[-2:] == b'\0,', \
21 | fr"Invalid request: missing header/netstring terminator '\x00,', got {header_raw[-2:]!r}"
22 | header_list = header_raw[:-2].split(b'\0')
23 | assert len(header_list) % 2 == 0, \
24 | f"Invalid request: odd numbers of header entries (must be pairs), got {len(header_list)}"
25 | assert header_list[0] == b'CONTENT_LENGTH', \
26 | f"Invalid request: first header entry must be 'CONTENT_LENGTH', got {header_list[0]!r}"
27 | clen = int(header_list[1])
28 | headers = {}
29 | i = 0
30 | while i < len(header_list):
31 | key = header_list[i]
32 | value = header_list[i+1]
33 | i += 2
34 | assert not key in headers, f"Invalid request: duplicate header key {key!r}"
35 | headers[key] = value
36 | assert headers.get(b'SCGI') == b'1', "Invalid request: missing SCGI=1 header"
37 | body = await reader.readexactly(clen)
38 | return ScgiRequest(headers=headers, body=body)
39 |
40 |
41 | async def handle_scgi(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
42 | print("scgi-envcheck: Incoming connection", flush=True)
43 | try:
44 | req = await parse_scgi_request(reader)
45 | envvar = req.headers[b'QUERY_STRING']
46 | result = req.headers[envvar]
47 | except KeyboardInterrupt:
48 | raise
49 | except Exception as e:
50 | print(traceback.format_exc())
51 | writer.write(b"Status: 500\r\nContent-Type: text/plain\r\n\r\n" + str(e).encode())
52 | else:
53 | writer.write(b"Status: 200\r\nContent-Type: text/plain\r\n\r\n" + result)
54 | await writer.drain()
55 | writer.close()
56 | await writer.wait_closed()
57 |
58 |
59 | async def main() -> None:
60 | sock = socket.socket(fileno=0)
61 |
62 | if sock.type == socket.AF_UNIX:
63 | server = await asyncio.start_unix_server(handle_scgi, sock=sock, start_serving=False)
64 | else:
65 | server = await asyncio.start_server(handle_scgi, sock=sock, start_serving=False)
66 |
67 | addr = server.sockets[0].getsockname()
68 | print(f'Serving on {addr}', flush=True)
69 |
70 | async with server:
71 | await server.serve_forever()
72 |
73 |
74 | try:
75 | asyncio.run(main())
76 | except KeyboardInterrupt:
77 | pass
78 |
--------------------------------------------------------------------------------
/tests/runtests.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import os.path
5 | import sys
6 |
7 | sys.path.append(os.path.dirname(__file__))
8 |
9 | import pylt.run
10 |
11 | pylt.run.main()
12 |
--------------------------------------------------------------------------------