diff options
Diffstat (limited to '')
87 files changed, 10519 insertions, 0 deletions
diff --git a/debian/NEWS b/debian/NEWS new file mode 100644 index 0000000..6a9f209 --- /dev/null +++ b/debian/NEWS @@ -0,0 +1,47 @@ +haproxy (2.6.8-2) unstable; urgency=medium + + Starting with haproxy 2.6, the "ssl-engine" keyword has been removed. You will + need to remove this setting for your previous config to continue to work. + + Previously, clients sending an invalid request header like "Version: rtsp/1.1" + would still get their request being served. Starting with haproxy 2.6, this + will result in a 502 response. If you depend on the old, buggy behaviour, set + "option accept-invalid-http-requests" in the relevant config section. + + -- Lee Garrett <debian@rocketjump.eu> Tue, 31 Jan 2023 22:57:05 +0100 + +haproxy (1.8.0-1) experimental; urgency=medium + + In order to upgrade to the HAProxy 1.8 new process model, a full service + restart will be performed automatically on upgrade from pre-1.8 versions + when running under systemd. This incurs (minimal) service downtime and + will only be performed once; future upgrades will reload haproxy seamlessly. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Tue, 28 Nov 2017 23:44:01 +0200 + +haproxy (1.4.23-1) unstable; urgency=low + + As of 1.4.23-1, the Debian package ships an rsyslog snippet to allow logging + via /dev/log from chrooted HAProxy processes. If you are using rsyslog, you + should restart rsyslog after installing this package to enable HAProxy to log + via rsyslog. See /usr/share/doc/haproxy/README.Debian for more details. + + Also note that as of 1.4.23-1, chrooting the HAProxy process is enabled in the + default Debian configuration. + + -- Apollon Oikonomopoulos <apoikos@gmail.com> Thu, 25 Apr 2013 23:26:35 +0300 + +haproxy (1.4.13-1) unstable; urgency=low + + Maintainer of this package has changed. + + -- Christo Buschek <crito@30loops.net> Mon, 10 Mar 2011 22:07:10 +0100 + +haproxy (1.3.14.2-1) unstable; urgency=low + + Configuration has moved to /etc/haproxy/haproxy.cfg. This allows to add the + configurable /etc/haproxy/errors directory. + The haproxy binary was also moved to /usr/sbin rather than /usr/bin, update + your init script or reinstall the one provided with the package. + + -- Arnaud Cornet <acornet@debian.org> Mon, 21 Jan 2008 23:38:15 +0100 diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..05c35e8 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,2534 @@ +haproxy (2.6.12-1+deb12u1) bookworm-security; urgency=high + + * Non-maintainer upload by the Security Team. + * REORG: http: move has_forbidden_char() from h2.c to http.h + * BUG/MAJOR: h3: reject header values containing invalid chars + * BUG/MAJOR: http: reject any empty content-length header value + (CVE-2023-40225) (Closes: #1043502) + * MINOR: ist: add new function ist_find_range() to find a character range + * MINOR: http: add new function http_path_has_forbidden_char() + * MINOR: h2: pass accept-invalid-http-request down the request parser + * REGTESTS: http-rules: add accept-invalid-http-request for normalize-uri + tests + * BUG/MINOR: h1: do not accept '#' as part of the URI component + (CVE-2023-45539) + * BUG/MINOR: h2: reject more chars from the :path pseudo header + * BUG/MINOR: h3: reject more chars from the :path pseudo header + * REGTESTS: http-rules: verify that we block '#' by default for + normalize-uri + * DOC: clarify the handling of URL fragments in requests + + -- Salvatore Bonaccorso <carnil@debian.org> Sat, 16 Dec 2023 17:41:30 +0100 + +haproxy (2.6.12-1) unstable; urgency=medium + + * New upstream version. + + -- Vincent Bernat <bernat@debian.org> Sat, 01 Apr 2023 11:05:57 +0200 + +haproxy (2.6.11-1) unstable; urgency=medium + + * New upstream version. + + -- Vincent Bernat <bernat@debian.org> Sat, 18 Mar 2023 14:37:13 +0100 + +haproxy (2.6.10-1) unstable; urgency=medium + + * New upstream version. + + -- Vincent Bernat <bernat@debian.org> Sat, 11 Mar 2023 12:59:22 +0100 + +haproxy (2.6.9-1) unstable; urgency=medium + + * New upstream version. + + -- Vincent Bernat <bernat@debian.org> Wed, 15 Feb 2023 21:45:50 +0100 + +haproxy (2.6.8-2) unstable; urgency=medium + + * Add a NEWS entry for incompatibilities introduced in HAProxy 2.6. + Closes: #1030173. + * BUG/CRITICAL: http: properly reject empty http header field names + (CVE-2023-25725) + + -- Vincent Bernat <bernat@debian.org> Mon, 13 Feb 2023 20:16:13 +0100 + +haproxy (2.6.8-1) unstable; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Tue, 24 Jan 2023 11:57:14 +0100 + +haproxy (2.6.7-1) unstable; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Fri, 02 Dec 2022 22:20:15 +0100 + +haproxy (2.6.6-2) unstable; urgency=medium + + * Upload to unstable. + + -- Vincent Bernat <bernat@debian.org> Sat, 22 Oct 2022 10:19:03 +0200 + +haproxy (2.6.6-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Thu, 22 Sep 2022 20:22:23 +0200 + +haproxy (2.6.5-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Sat, 03 Sep 2022 19:33:51 +0200 + +haproxy (2.6.4-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Mon, 22 Aug 2022 19:01:25 +0200 + +haproxy (2.6.3-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Fri, 19 Aug 2022 19:16:11 +0200 + +haproxy (2.6.2-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Fri, 22 Jul 2022 18:21:43 +0200 + +haproxy (2.6.1-1) experimental; urgency=medium + + [ Lucas Kanashiro ] + * d/t/utils: add helper functions to be re-used in tests + * d/t/proxy-localhost: refactor to use the check_index_file helper function + * d/t/proxy-ssl-termination: add test for the SSL termination proxy feature + * d/t/proxy-ssl-pass-through: add test for the SSL Pass-Through proxy feature + + [ Vincent Bernat ] + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Wed, 22 Jun 2022 20:06:08 +0200 + +haproxy (2.6.0-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Thu, 02 Jun 2022 08:49:38 +0200 + +haproxy (2.5.7-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Sat, 14 May 2022 12:01:07 +0200 + +haproxy (2.5.6-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Tue, 26 Apr 2022 17:59:23 +0200 + +haproxy (2.5.5-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Mon, 14 Mar 2022 19:26:46 +0100 + +haproxy (2.5.4-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Fri, 25 Feb 2022 17:39:11 +0100 + +haproxy (2.5.3-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Fri, 18 Feb 2022 20:22:25 +0100 + +haproxy (2.5.2-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Wed, 16 Feb 2022 19:09:04 +0100 + +haproxy (2.5.1-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Tue, 11 Jan 2022 19:23:50 +0100 + +haproxy (2.5.0-1) experimental; urgency=medium + + * New upstream release. + * d/patches: patch to make logging work without rsyslog with systemd + + -- Vincent Bernat <bernat@debian.org> Thu, 25 Nov 2021 21:20:30 +0100 + +haproxy (2.4.19-1) unstable; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Fri, 30 Sep 2022 09:07:13 +0200 + +haproxy (2.4.18-1) unstable; urgency=medium + + [ Lucas Kanashiro ] + * d/t/utils: add helper functions to be re-used in tests + * d/t/proxy-localhost: refactor to use the check_index_file helper function + * d/t/proxy-ssl-termination: add test for the SSL termination proxy feature + * d/t/proxy-ssl-pass-through: add test for the SSL Pass-Through proxy feature + + [ Vincent Bernat ] + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Wed, 27 Jul 2022 15:59:36 +0200 + +haproxy (2.4.17-1) unstable; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Sat, 14 May 2022 14:27:20 +0200 + +haproxy (2.4.16-1) unstable; urgency=medium + + * New upstream release. + * d/install: do not install halog explicitely. + + -- Vincent Bernat <bernat@debian.org> Fri, 29 Apr 2022 17:42:42 +0200 + +haproxy (2.4.15-1) unstable; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Mon, 14 Mar 2022 20:17:04 +0100 + +haproxy (2.4.14-1) unstable; urgency=medium + + * New upstream release. + - Fix compilation with OpenSSL 3.0. Closes: #996423, #1006007. + + -- Vincent Bernat <bernat@debian.org> Fri, 25 Feb 2022 18:38:27 +0100 + +haproxy (2.4.13-1) unstable; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Thu, 17 Feb 2022 10:03:46 +0100 + +haproxy (2.4.12-1) unstable; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Tue, 11 Jan 2022 12:06:17 +0100 + +haproxy (2.4.11-1) unstable; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Fri, 07 Jan 2022 17:25:51 +0100 + +haproxy (2.4.10-1) unstable; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Thu, 23 Dec 2021 19:13:26 +0100 + +haproxy (2.4.9-1) unstable; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Wed, 24 Nov 2021 19:42:28 +0100 + +haproxy (2.4.8-3) unstable; urgency=medium + + * d/logrotate: only use rsyslog-rotate if present. Closes: #1000436. + + -- Vincent Bernat <bernat@debian.org> Wed, 24 Nov 2021 09:29:54 +0100 + +haproxy (2.4.8-2) unstable; urgency=medium + + * Non-maintainer upload. + * Enable OpenTracing support. + + -- Stephen Gelman <ssgelm@debian.org> Tue, 09 Nov 2021 23:06:46 -0600 + +haproxy (2.4.8-1) unstable; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Thu, 04 Nov 2021 08:36:56 +0100 + +haproxy (2.4.7-2) unstable; urgency=medium + + * Upload to unstable. + + -- Vincent Bernat <bernat@debian.org> Sat, 16 Oct 2021 20:43:13 +0200 + +haproxy (2.4.7-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Thu, 07 Oct 2021 09:08:09 +0200 + +haproxy (2.4.4-1) experimental; urgency=medium + + * New upstream release. + * d/patches: remove patches applied upstream. + + -- Vincent Bernat <bernat@debian.org> Wed, 08 Sep 2021 08:38:05 +0200 + +haproxy (2.4.3-2) experimental; urgency=high + + * d/patches: fix missing header name length check in HTX (CVE-2021-40346). + + -- Vincent Bernat <bernat@debian.org> Sat, 04 Sep 2021 11:56:31 +0200 + +haproxy (2.4.3-1) experimental; urgency=medium + + * New upstream release. + * d/patches: remove patches applied upstream. + * d/patches: h2: match absolute-path not path-absolute for :path. + + -- Vincent Bernat <bernat@debian.org> Sat, 21 Aug 2021 16:32:25 +0200 + +haproxy (2.4.2-2) experimental; urgency=medium + + * Fix HTTP request smuggling via HTTP/2 desync attacks. + + -- Vincent Bernat <bernat@debian.org> Fri, 13 Aug 2021 16:12:31 +0200 + +haproxy (2.4.2-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Wed, 07 Jul 2021 21:47:17 +0200 + +haproxy (2.4.1-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Thu, 17 Jun 2021 13:57:57 +0200 + +haproxy (2.4.0-1) experimental; urgency=medium + + * New upstream release. + * d/rules: switch to SLZ instead of zlib + * d/rules: update build for contrib → admin + * d/rules: remove use of USE_REGPARM (outdated) + * d/rules: remove hack around gcc_s + * d/copyright: update + + -- Vincent Bernat <bernat@debian.org> Tue, 18 May 2021 22:00:05 +0200 + +haproxy (2.3.10-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Sat, 24 Apr 2021 18:22:41 +0200 + +haproxy (2.3.9-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Tue, 30 Mar 2021 19:50:42 +0200 + +haproxy (2.3.8-1) experimental; urgency=medium + + * New upstream release. + * d/logrotate: reduce log retention to 7 days. Closes: #985441. + + -- Vincent Bernat <bernat@debian.org> Thu, 25 Mar 2021 18:17:18 +0100 + +haproxy (2.3.7-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Tue, 16 Mar 2021 18:41:25 +0100 + +haproxy (2.3.6-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Thu, 04 Mar 2021 13:57:49 +0100 + +haproxy (2.3.5-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Sat, 06 Feb 2021 17:12:53 +0100 + +haproxy (2.3.4-1) experimental; urgency=medium + + * New upstream release: + - Revert "BUG/MINOR: dns: SRV records ignores duplicated AR records" + + -- Vincent Bernat <bernat@debian.org> Fri, 15 Jan 2021 14:13:28 +0100 + +haproxy (2.3.3-1) experimental; urgency=medium + + * d/tests: sleep before test to let Apache2 start. + Closes: #976997. + * New upstream release: + - BUG/MAJOR: ring: tcp forward on ring can break the reader counter. + - BUG/MAJOR: spoa/python: Fixing return None + - BUG/MEDIUM: local log format regression. Closes: #974977. + + -- Vincent Bernat <bernat@debian.org> Sat, 09 Jan 2021 15:18:10 +0100 + +haproxy (2.3.2-1) experimental; urgency=medium + + * New upstream release. + - BUG/MAJOR: connection: reset conn->owner when detaching from session + list + - BUG/MAJOR: filters: Always keep all offsets up to date during data + filtering + - BUG/MAJOR: peers: fix partial message decoding + - BUG/MAJOR: tcpcheck: Allocate input and output buffers from the buffer + pool + + -- Vincent Bernat <bernat@debian.org> Sat, 28 Nov 2020 20:25:34 +0100 + +haproxy (2.3.1-1) experimental; urgency=medium + + * New upstream release. + - BUG/MAJOR: spoe: Be sure to remove all references on a released spoe + applet + * d/patches: remove patches applied upstream. + + -- Vincent Bernat <bernat@debian.org> Sat, 14 Nov 2020 23:17:20 +0100 + +haproxy (2.3.0-1) experimental; urgency=medium + + * New upstream release. + * d/gbp, d/watch: prepare for 2.3.0 release + + -- Vincent Bernat <bernat@debian.org> Wed, 11 Nov 2020 16:30:10 +0100 + +haproxy (2.2.17-1) unstable; urgency=medium + + * New upstream release. + * d/patches: remove upstream-applied patch. + + -- Vincent Bernat <bernat@debian.org> Thu, 09 Sep 2021 19:42:08 +0200 + +haproxy (2.2.16-3) unstable; urgency=high + + * d/patches: fix missing header name length check in HTX (CVE-2021-40346). + + -- Vincent Bernat <bernat@debian.org> Sat, 04 Sep 2021 16:14:51 +0200 + +haproxy (2.2.16-2) unstable; urgency=medium + + * d/patches: h2: match absolute-path not path-absolute for :path + + -- Vincent Bernat <bernat@debian.org> Sat, 21 Aug 2021 16:19:52 +0200 + +haproxy (2.2.16-1) unstable; urgency=high + + * New upstream release. + * Fix CVE-2021-39240, CVE-2021-39241, CVE-2021-39242. + * d/patches: remove upstream-applied patch. + + -- Vincent Bernat <bernat@debian.org> Thu, 19 Aug 2021 07:22:05 +0200 + +haproxy (2.2.15-1) UNRELEASED; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Fri, 16 Jul 2021 11:18:32 +0200 + +haproxy (2.2.14-1) UNRELEASED; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Thu, 29 Apr 2021 15:32:49 +0200 + +haproxy (2.2.13-1) UNRELEASED; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Fri, 02 Apr 2021 21:18:28 +0200 + +haproxy (2.2.12-1) UNRELEASED; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Wed, 31 Mar 2021 20:31:24 +0200 + +haproxy (2.2.11-1) UNRELEASED; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Thu, 18 Mar 2021 21:34:40 +0100 + +haproxy (2.2.10-1) UNRELEASED; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Thu, 04 Mar 2021 19:08:41 +0100 + +haproxy (2.2.9-2) unstable; urgency=medium + + * d/patches: fix agent-check regression putting down servers. + Closes: #988779. + + -- Vincent Bernat <bernat@debian.org> Thu, 27 May 2021 15:00:01 +0200 + +haproxy (2.2.9-1) unstable; urgency=medium + + * New upstream release. + - BUG/MAJOR: connection: reset conn->owner when detaching from session + list + + -- Vincent Bernat <bernat@debian.org> Sat, 06 Feb 2021 18:52:20 +0100 + +haproxy (2.2.8-1) unstable; urgency=medium + + * New upstream release. + - Revert "BUG/MINOR: dns: SRV records ignores duplicated AR records" + + -- Vincent Bernat <bernat@debian.org> Thu, 14 Jan 2021 11:48:52 +0100 + +haproxy (2.2.7-1) unstable; urgency=medium + + * New upstream release. + - BUG/MAJOR: ring: tcp forward on ring can break the reader counter. + - BUG/MAJOR: spoa/python: Fixing return None + + -- Vincent Bernat <bernat@debian.org> Sat, 09 Jan 2021 15:31:08 +0100 + +haproxy (2.2.6-2) unstable; urgency=medium + + * d/tests: sleep before test to let Apache2 start. + Closes: #976997. + + -- Vincent Bernat <bernat@debian.org> Thu, 07 Jan 2021 07:56:14 +0100 + +haproxy (2.2.6-1) unstable; urgency=medium + + * New upstream release. + - BUG/MAJOR: filters: Always keep all offsets up to date during data + filtering + - BUG/MAJOR: peers: fix partial message decoding + - BUG/MAJOR: spoe: Be sure to remove all references on a released spoe + applet + - BUG/MAJOR: tcpcheck: Allocate input and output buffers from the buffer + pool + * d/patches: remove patches applied upstream + + -- Vincent Bernat <bernat@debian.org> Mon, 30 Nov 2020 20:02:49 +0100 + +haproxy (2.2.5-2) unstable; urgency=medium + + * Upload to unstable. + + -- Vincent Bernat <bernat@debian.org> Wed, 11 Nov 2020 16:21:12 +0100 + +haproxy (2.2.5-1) experimental; urgency=medium + + * New upstream release. + - BUG/MAJOR: mux-h2: Don't try to send data if we know it is no longer + possible + * d/patches: warn if payload of an errorfile doesn't match the C-L + + -- Vincent Bernat <bernat@debian.org> Sun, 08 Nov 2020 19:12:02 +0100 + +haproxy (2.2.4-1) experimental; urgency=medium + + * New upstream release. + * d/patches: drop patch for ARM32 + + -- Vincent Bernat <bernat@debian.org> Fri, 02 Oct 2020 21:29:56 +0200 + +haproxy (2.2.3-2) experimental; urgency=medium + + * d/patches: add upstream patch to fix build on ARM32 + + -- Vincent Bernat <bernat@debian.org> Wed, 09 Sep 2020 19:38:52 +0200 + +haproxy (2.2.3-1) experimental; urgency=medium + + * New upstream version. + - BUG/MAJOR: dns: disabled servers through SRV records never recover + + -- Vincent Bernat <bernat@debian.org> Tue, 08 Sep 2020 23:12:05 +0200 + +haproxy (2.2.2-1) experimental; urgency=medium + + * New upstream version. + - BUG/MAJOR: dns: don't treat Authority records as an error + - BUG/MAJOR: dns: fix null pointer dereference in + snr_update_srv_status + + -- Vincent Bernat <bernat@debian.org> Sat, 01 Aug 2020 17:06:42 +0200 + +haproxy (2.2.1-1) experimental; urgency=medium + + * New upstream version. + - BUG/MAJOR: tasks: don't requeue global tasks into the local + queue + - BUG/MAJOR: dns: Make the do-resolve action thread-safe + + -- Vincent Bernat <bernat@debian.org> Thu, 23 Jul 2020 13:39:14 +0200 + +haproxy (2.2.0-1) experimental; urgency=medium + + * New upstream version. + * Upload to experimental + * Update d/watch to look for 2.2 stable releases + * d/gbp.conf: set branch names for 2.2 + * d/patches: refresh patches + + -- Vincent Bernat <bernat@debian.org> Tue, 14 Jul 2020 16:53:23 +0200 + +haproxy (2.1.7-1) experimental; urgency=medium + + * New upstream version. + + -- Vincent Bernat <bernat@debian.org> Fri, 12 Jun 2020 07:50:48 +0200 + +haproxy (2.1.5-1) experimental; urgency=medium + + * New upstream version. + - BUG/MAJOR: mux-fcgi: Stop sending loop if FCGI stream is blocked for + any reason + - Revert "BUG/MINOR: connection: always send address-less LOCAL PROXY + connections" + - Revert "BUG/MINOR: connection: make sure to correctly tag local + PROXY connections" + + -- Vincent Bernat <bernat@debian.org> Mon, 01 Jun 2020 08:52:56 +0200 + +haproxy (2.1.4-1) experimental; urgency=medium + + * New upstream version. + - BUG/CRITICAL: hpack: never index a header into the headroom after + wrapping + - BUG/MAJOR: http-ana: Always abort the request when a tarpit is + triggered + - BUG/MAJOR: list: fix invalid element address calculation + - BUG/MAJOR: proxy_protocol: Properly validate TLV lengths + * d/control: fix maintainer address. Closes: #955553. + + -- Vincent Bernat <bernat@debian.org> Sun, 12 Apr 2020 13:29:54 +0200 + +haproxy (2.1.3-3) experimental; urgency=medium + + * d/copryight: document OpenSSL exception. Closes: #951782. + * d/haproxy.cfg: use "ssl-min-ver" to set minimum version. + * d/patches: fix an overflow in HTTP/2 header handling. + Fix CVE-2020-11100. + + -- Vincent Bernat <bernat@debian.org> Wed, 01 Apr 2020 21:18:57 +0200 + +haproxy (2.1.3-2) experimental; urgency=medium + + * d/dconv: use Python 3 to build the documentation. + Closes: #948296, #950435. + * d/dconv: replace cgi.escape by html.escape. Closes: #951416. + + -- Vincent Bernat <bernat@debian.org> Wed, 19 Feb 2020 07:53:53 +0100 + +haproxy (2.1.3-1) experimental; urgency=medium + + * New upstream version. + - BUG/MAJOR: hashes: fix the signedness of the hash inputs + - BUG/MAJOR: memory: Don't forget to unlock the rwlock if the pool is + empty. + + -- Vincent Bernat <bernat@debian.org> Mon, 20 Jan 2020 06:53:23 +0100 + +haproxy (2.1.2-1) experimental; urgency=medium + + * New upstream version 2.1.2. + - BUG/MAJOR: task: add a new TASK_SHARED_WQ flag to fix foreign requeuing + * d/logrotate.conf: use rsyslog helper instead of SysV init script. + Closes: #946973. + + -- Vincent Bernat <bernat@debian.org> Fri, 20 Dec 2019 08:20:33 +0100 + +haproxy (2.1.1-1) experimental; urgency=medium + + * New upstream version 2.1.1. + - BUG/MAJOR: dns: add minimalist error processing on the Rx path + + -- Vincent Bernat <bernat@debian.org> Sat, 14 Dec 2019 11:20:32 +0100 + +haproxy (2.1.0-2) experimental; urgency=medium + + * Link against libatomic on riscv64 + + -- Apollon Oikonomopoulos <apoikos@debian.org> Fri, 29 Nov 2019 14:03:49 +0200 + +haproxy (2.1.0-1) experimental; urgency=medium + + * New upstream version 2.1.0 + * Upload to experimental + * Update d/watch to look for 2.1 stable releases + * d/gbp.conf: set branch names for 2.1 + * Bump Standards-Version to 4.4.1; no changes needed + * Bump dh compat level to 12 + + B-D on debhelper-compat and remove debian/compat + + Override dh_installsystemd with the same args as dh_installinit + + Add ${misc:Pre-Depends} to haproxy's Pre-Depends + + -- Apollon Oikonomopoulos <apoikos@debian.org> Wed, 27 Nov 2019 23:30:30 +0200 + +haproxy (2.0.19-1) unstable; urgency=medium + + * New upstream release. + - BUG/MAJOR: mux-h2: Don't try to send data if we know it is no longer + possible + + -- Vincent Bernat <bernat@debian.org> Fri, 06 Nov 2020 19:33:59 +0100 + +haproxy (2.0.18-1) unstable; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Wed, 30 Sep 2020 13:41:09 +0200 + +haproxy (2.0.17-1) unstable; urgency=medium + + * New upstream release. + - BUG/MAJOR: dns: Make the do-resolve action thread-safe + + -- Vincent Bernat <bernat@debian.org> Sat, 01 Aug 2020 20:05:01 +0200 + +haproxy (2.0.16-1) unstable; urgency=medium + + * New upstream release. + - BUG/MAJOR: stream: Mark the server address as unset on new outgoing + connection + * d/patches: refresh patches. + + -- Vincent Bernat <bernat@debian.org> Sat, 18 Jul 2020 13:50:56 +0200 + +haproxy (2.0.15-1) unstable; urgency=medium + + * New upstream release. + - BUG/MAJOR: stream-int: always detach a faulty endpoint on connect + failure + + -- Vincent Bernat <bernat@debian.org> Sat, 13 Jun 2020 18:48:25 +0200 + +haproxy (2.0.14-1) unstable; urgency=medium + + * New upstream release. + - BUG/CRITICAL: hpack: never index a header into the headroom after + wrapping + - BUG/MAJOR: http-ana: Always abort the request when a tarpit is + triggered + - BUG/MAJOR: list: fix invalid element address calculation + - BUG/MAJOR: proxy_protocol: Properly validate TLV lengths + * d/control: fix maintainer address. Closes: #955553. + + -- Vincent Bernat <bernat@debian.org> Thu, 16 Apr 2020 18:34:22 +0200 + +haproxy (2.0.13-2) unstable; urgency=medium + + * d/dconv: replace cgi.escape by html.escape. Closes: #951416. + * d/copryight: document OpenSSL exception. Closes: #951782. + * d/haproxy.cfg: use "ssl-min-ver" to set minimum version. + * Apply one patch to fix an overflow in HTTP/2 header handling. + Fix CVE-2020-11100. + + -- Vincent Bernat <bernat@debian.org> Wed, 01 Apr 2020 21:49:32 +0200 + +haproxy (2.0.13-1) unstable; urgency=medium + + * New upstream release. + - BUG/MAJOR: hashes: fix the signedness of the hash inputs + - BUG/MAJOR: memory: Don't forget to unlock the rwlock if the pool is + empty. + * d/dconv: use Python 3 to build the documentation. + Closes: #948296, #950435. + + -- Vincent Bernat <bernat@debian.org> Sat, 15 Feb 2020 15:32:32 +0100 + +haproxy (2.0.12-1) unstable; urgency=medium + + * New upstream version. + - BUG/MAJOR: task: add a new TASK_SHARED_WQ flag to fix foreign requeuing + * d/logrotate.conf: use rsyslog helper instead of SysV init script. + Closes: #946973. + + -- Vincent Bernat <bernat@debian.org> Fri, 20 Dec 2019 08:20:33 +0100 + +haproxy (2.0.11-1) unstable; urgency=medium + + * New upstream release. + - BUG/MAJOR: dns: add minimalist error processing on the Rx path + + -- Vincent Bernat <bernat@debian.org> Fri, 13 Dec 2019 19:22:03 +0100 + +haproxy (2.0.10-1) unstable; urgency=medium + + * New upstream release. + - BUG/MAJOR: h2: make header field name filtering stronger + - BUG/MAJOR: h2: reject header values containing invalid chars + - BUG/MAJOR: mux-h2: don't try to decode a response HEADERS frame in + idle state + + -- Vincent Bernat <bernat@debian.org> Tue, 26 Nov 2019 13:22:17 +0100 + +haproxy (2.0.9-1) unstable; urgency=medium + + * New upstream release. + - BUG/MAJOR: stream-int: Don't receive data from mux until SI_ST_EST + is reached + + -- Vincent Bernat <bernat@debian.org> Sat, 16 Nov 2019 17:38:51 +0100 + +haproxy (2.0.8-1) unstable; urgency=medium + + * New upstream release. + - BUG/MAJOR: idle conns: schedule the cleanup task on the correct + threads + + -- Vincent Bernat <bernat@debian.org> Wed, 23 Oct 2019 08:55:55 +0200 + +haproxy (2.0.7-1) unstable; urgency=medium + + * New upstream release. + - BUG/MAJOR: mux-h2: Handle HEADERS frames received after a RST_STREAM + frame + - BUG/MAJOR: mux_h2: Don't consume more payload than received for + skipped frames + - BUG/MEDIUM: checks: make sure the connection is ready before trying + to recv + + -- Vincent Bernat <bernat@debian.org> Fri, 27 Sep 2019 19:14:12 +0200 + +haproxy (2.0.6-2) unstable; urgency=medium + + * d/patches: fix regression with checks. + + -- Vincent Bernat <bernat@debian.org> Wed, 18 Sep 2019 08:02:53 +0200 + +haproxy (2.0.6-1) unstable; urgency=medium + + * New upstream release. + - BUG/MAJOR: ssl: ssl_sock was not fully initialized. + + -- Vincent Bernat <bernat@debian.org> Fri, 13 Sep 2019 21:25:38 +0200 + +haproxy (2.0.5-1) unstable; urgency=medium + + * New upstream release. + - BUG/MEDIUM: mux_h1: Don't bother subscribing in recv if we're not + connected. + - BUG/MEDIUM: mux_pt: Don't call unsubscribe if we did not subscribe. + - BUG/MEDIUM: proxy: Don't forget the SF_HTX flag when upgrading + TCP=>H1+HTX. + - BUG/MEDIUM: proxy: Don't use cs_destroy() when freeing the + conn_stream. + - BUG/MEDIUM: stick-table: Wrong stick-table backends parsing. + + -- Vincent Bernat <bernat@debian.org> Fri, 16 Aug 2019 19:51:24 +0200 + +haproxy (2.0.4-1) unstable; urgency=medium + + * New upstream release. Upload to unstable. + - BUG/MAJOR: http/sample: use a static buffer for raw -> htx + conversion + - BUG/MAJOR: queue/threads: avoid an AB/BA locking issue in + process_srv_queue() + * d/haproxy.cfg: update default cipher lists to more secure defaults. + TLSv1.0 and TLSv1.1 are disabled, as well as TLS tickets (they are + breaking forward secrecy unless correctly rotated). + Closes: #932763. + + -- Vincent Bernat <bernat@debian.org> Fri, 09 Aug 2019 14:22:23 +0200 + +haproxy (2.0.3-1) experimental; urgency=medium + + * New upstream version. + - BUG/CRITICAL: http_ana: Fix parsing of malformed cookies which start by + a delimiter (CVE-2019-14241) + - BUG/MEDIUM: checks: Don't attempt to receive data if we already + subscribed. + - BUG/MEDIUM: http/htx: unbreak option http_proxy + - DOC: htx: Update comments in HTX files + - BUG/MEDIUM: mux-h1: Trim excess server data at the end of a transaction + - BUG/MEDIUM: tcp-checks: do not dereference inexisting conn_stream + * Bump Standards-Version to 4.4.0; no changes needed + + -- Apollon Oikonomopoulos <apoikos@debian.org> Tue, 23 Jul 2019 13:31:31 -0300 + +haproxy (2.0.2-1) experimental; urgency=medium + + * New upstream version. + - BUG/MAJOR: listener: fix thread safety in resume_listener() + + -- Vincent Bernat <bernat@debian.org> Wed, 17 Jul 2019 12:19:54 +0200 + +haproxy (2.0.1-1) experimental; urgency=medium + + * New upstream version. + - BUG/MAJOR: sample: Wrong stick-table name parsing in "if/unless" ACL + condition. + - BUG/MAJOR: mux-h1: Don't crush trash chunk area when outgoing + message is formatted + * d/rules: fix crash during reload due to libgcc_s.so missing when + chrooted. + + -- Vincent Bernat <bernat@debian.org> Mon, 24 Jun 2019 19:28:26 +0200 + +haproxy (2.0.0-1) experimental; urgency=medium + + * New upstream version. + * d/watch: update to follow 2.0. + * d/gbp.conf: update for 2.0 and experimental. + * d/rules: update to use linux-glibc target. + * d/rules: enable prometheus exporter. + * d/patches: refresh patches. + * d/vim-haproxy.install: update path to vim syntax file. + * d/README.Debian: remove outdated information. + + -- Vincent Bernat <bernat@debian.org> Thu, 20 Jun 2019 11:40:19 +0200 + +haproxy (1.9.8-1) experimental; urgency=medium + + * New upstream version. + - BUG/MAJOR: map/acl: real fix segfault during show map/acl on CLI + - BUG/MAJOR: mux-h2: do not add a stream twice to the send list + + -- Vincent Bernat <bernat@debian.org> Thu, 16 May 2019 01:50:10 +0200 + +haproxy (1.9.7-1) experimental; urgency=medium + + * New upstream version. + - BUG/MAJOR: http_fetch: Get the channel depending on the keyword used + - BUG/MAJOR: lb/threads: fix AB/BA locking issue in round-robin LB + - BUG/MAJOR: lb/threads: fix insufficient locking on round-robin LB + - BUG/MAJOR: muxes: Use the HTX mode to find the best mux for HTTP + proxies only + - BUG/MAJOR: task: make sure never to delete a queued task + + -- Vincent Bernat <bernat@debian.org> Sun, 28 Apr 2019 17:37:04 +0200 + +haproxy (1.9.6-1) experimental; urgency=medium + + * New upstream version. + - BUG/MAJOR: checks: segfault during tcpcheck_main + + -- Vincent Bernat <bernat@debian.org> Sat, 30 Mar 2019 12:43:33 +0100 + +haproxy (1.9.5-1) experimental; urgency=medium + + * New upstream version. + - BUG/MAJOR: cache/htx: Set the start-line offset when a cached object + is served + - BUG/MAJOR: fd/threads, task/threads: ensure all spin locks are + unlocked + - BUG/MAJOR: listener: Make sure the listener exist before using it. + - BUG/MAJOR: mux-h2: fix race condition between close on both ends + - BUG/MAJOR: spoe: Don't try to get agent config during SPOP + healthcheck + - BUG/MAJOR: spoe: Fix initialization of thread-dependent fields + - BUG/MAJOR: stats: Fix how huge POST data are read from the channel + - BUG/MAJOR: stream: avoid double free on unique_id + - BUG/MAJOR: tasks: Use the TASK_GLOBAL flag to know if we're in the + global rq. + + -- Vincent Bernat <bernat@debian.org> Tue, 19 Mar 2019 20:13:48 +0100 + +haproxy (1.9.4-1) experimental; urgency=medium + + * New upstream version. + - BUG/MAJOR: config: verify that targets of track-sc and stick rules + are present + - BUG/MAJOR: htx/backend: Make all tests on HTTP messages compatible + with HTX + - BUG/MAJOR: spoe: verify that backends used by SPOE cover all their + callers' processes + + -- Vincent Bernat <bernat@debian.org> Thu, 07 Feb 2019 12:48:42 +0100 + +haproxy (1.9.3-1) experimental; urgency=medium + + * New upstream version. + - BUG/MAJOR: mux-h2: don't destroy the stream on failed allocation in + h2_snd_buf() + - BUG/MEDIUM: checks: fix recent regression on agent-check making it + crash + - BUG/MEDIUM: ssl: Fix handling of TLS 1.3 KeyUpdate messages + + -- Vincent Bernat <bernat@debian.org> Tue, 29 Jan 2019 12:59:10 +0100 + +haproxy (1.9.2-1) experimental; urgency=medium + + * New upstream version. + - BUG/MAJOR: cache: fix confusion between zero and uninitialized cache + key + - BUG/MEDIUM: checks: Avoid having an associated server for email + checks. + - BUG/MEDIUM: connection: properly unregister the mux on failed + initialization + - BUG/MEDIUM: h1: Get the h1m state when restarting the headers + parsing + - BUG/MEDIUM: h1: Make sure we destroy an inactive connectin that did + shutw. + - BUG/MEDIUM: init: Initialize idle_orphan_conns for first server in + server-template + - BUG/MEDIUM: mux-h2: decode trailers in HEADERS frames + - BUG/MEDIUM: ssl: Disable anti-replay protection and set max data + with 0RTT. + - BUG/MEDIUM: ssl: missing allocation failure checks loading tls key + file + - BUG/MEDIUM: stats: Get the right scope pointer depending on HTX is + used or not + * d/patches: removal of CVE-2018-20615.patch (applied upstream) + + -- Vincent Bernat <bernat@debian.org> Thu, 17 Jan 2019 19:19:27 +0100 + +haproxy (1.9.0-2) experimental; urgency=medium + + * Fix out-of-bounds read in HTTP2 mux (CVE-2018-20615). + Possible crash in H2 HEADERS frame decoder when the PRIORITY flag + is present, due to a missing frame size check. + * Bump Standards-Version to 4.3.0; no changes needed. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Thu, 03 Jan 2019 12:41:02 +0200 + +haproxy (1.9.0-1) experimental; urgency=medium + + * New upstream version 1.9.0. + See https://www.haproxy.com/blog/haproxy-1-9-has-arrived/. + * d/watch: update to follow 1.9. + * d/gbp.conf: update for 1.9 and experimental. + * d/rules: do not override CFLAGS, hijack DEBUG_CFLAGS for this instead. + * d/patches: add regression fix for DNS. + + -- Vincent Bernat <bernat@debian.org> Fri, 21 Dec 2018 11:13:41 +0100 + +haproxy (1.8.15-1) unstable; urgency=high + + [ Vincent Bernat ] + * d/rules: switch to pcre2. Closes: #911933. + + [ Apollon Oikonomopoulos ] + * New upstream version 1.8.15 + - BUG: dns: Fix off-by-one write in dns_validate_dns_response() ( + - BUG: dns: Fix out-of-bounds read via signedness error in + dns_validate_dns_response() + - BUG: dns: Prevent out-of-bounds read in dns_read_name() + - BUG: dns: Prevent out-of-bounds read in dns_validate_dns_response() + (CVE-2018-20102, closes: #916308) + - BUG: dns: Prevent stack-exhaustion via recursion loop in dns_read_name + (CVE-2018-20103, closes: #916307) + - BUG/MAJOR: http: http_txn_get_path() may deference an inexisting buffer + + -- Apollon Oikonomopoulos <apoikos@debian.org> Fri, 14 Dec 2018 15:31:04 +0200 + +haproxy (1.8.14-1) unstable; urgency=medium + + * New upstream version. + - BUG/CRITICAL: hpack: fix improper sign check on the header index + value (already fixed in 1.8.13-2) + - BUG/MAJOR: kqueue: Don't reset the changes number by accident. + - BUG/MAJOR: thread: lua: Wrong SSL context initialization. + + -- Vincent Bernat <bernat@debian.org> Sun, 23 Sep 2018 12:25:03 +0200 + +haproxy (1.8.13-2) unstable; urgency=high + + * Fix improper sign check on the HPACK header index value (CVE-2018-14645) + * Bump Standards-Version to 4.2.1; no changes needed + + -- Apollon Oikonomopoulos <apoikos@debian.org> Wed, 19 Sep 2018 22:46:58 +0300 + +haproxy (1.8.13-1) unstable; urgency=medium + + * New upstream version. + - BUG/MEDIUM: h2: don't accept new streams if conn_streams are still + in excess + - BUG/MEDIUM: h2: make sure the last stream closes the connection + after a timeout + - BUG/MEDIUM: h2: never leave pending data in the output buffer on close + - BUG/MEDIUM: h2: prevent orphaned streams from blocking a connection + forever + - BUG/MEDIUM: stats: don't ask for more data as long as we're responding + - BUG/MEDIUM: stream-int: don't immediately enable reading when the + buffer was reportedly full + - BUG/MEDIUM: threads/sync: use sched_yield when available + - BUG/MEDIUM: threads: Fix the exit condition of the thread barrier + - BUG/MEDIUM: threads: properly fix nbthreads == MAX_THREADS + - BUG/MEDIUM: threads: unbreak "bind" referencing an incorrect thread + number + * d/patches: drop systemd exit status patch (applied upstream). + + -- Vincent Bernat <bernat@debian.org> Wed, 01 Aug 2018 11:36:20 +0200 + +haproxy (1.8.12-1) unstable; urgency=medium + + * New upstream version. + - BUG/MAJOR: stick_table: Complete incomplete SEGV fix + + -- Vincent Bernat <bernat@debian.org> Wed, 27 Jun 2018 20:05:50 +0200 + +haproxy (1.8.11-1) unstable; urgency=medium + + * New upstream version. + - BUG/MAJOR: Stick-tables crash with segfault when the key is not in + the stick-table + + -- Vincent Bernat <bernat@debian.org> Tue, 26 Jun 2018 18:26:05 +0200 + +haproxy (1.8.10-1) unstable; urgency=medium + + * New upstream version. + - BUG/MAJOR: lua: Dead lock with sockets + - BUG/MAJOR: map: fix a segfault when using http-request set-map + - BUG/MAJOR: ssl: OpenSSL context is stored in non-reserved memory slot + - BUG/MAJOR: ssl: Random crash with cipherlist capture + - BUG/MEDIUM: cache: don't cache when an Authorization header is present + - BUG/MEDIUM: dns: Delay the attempt to run a DNS resolution on check + failure. + - BUG/MEDIUM: fd: Don't modify the update_mask in fd_dodelete(). + - BUG/MEDIUM: fd: Only check update_mask against all_threads_mask. + - BUG/MEDIUM: servers: Add srv_addr default placeholder to the state file + - BUG/MEDIUM: stick-tables: Decrement ref_cnt in table_* converters + - BUG/MEDIUM: threads: Use the sync point to check active jobs and exit + - BUG/MEDIUM: threads: handle signal queue only in thread 0 + * Remove patch from CVE. Included upstream. + * d/patches: add a patch for clean stop with systemd. + + -- Vincent Bernat <bernat@debian.org> Fri, 22 Jun 2018 20:21:37 +0200 + +haproxy (1.8.9-2) unstable; urgency=high + + * d/patches: fix CVE-2018-11469: do not cache when an Authorization + header is present. Closes: #900084. + + -- Vincent Bernat <bernat@debian.org> Sat, 26 May 2018 16:05:07 +0200 + +haproxy (1.8.9-1) unstable; urgency=medium + + * New upstream version. + - BUG/MAJOR: channel: Fix crash when trying to read from a closed socket + - BUG/MEDIUM: h2: implement missing support for chunked encoded uploads + - BUG/MEDIUM: http: don't always abort transfers on CF_SHUTR + - BUG/MEDIUM: lua: Fix segmentation fault if a Lua task exits + - BUG/MEDIUM: pollers: Use a global list for fd shared between threads + - BUG/MEDIUM: ssl: properly protect SSL cert generation + - BUG/MEDIUM: task: Don't free a task that is about to be run + - BUG/MEDIUM: threads: Fix the sync point for more than 32 threads + * d/rsyslog.conf: use modern syntax and statements, thanks to Guillem + Jover. Closes: #897914. + + -- Vincent Bernat <bernat@debian.org> Sat, 19 May 2018 15:00:17 +0200 + +haproxy (1.8.8-1) unstable; urgency=high + + * New upstream version. + - BUG/CRITICAL: h2: fix incorrect frame length check + + -- Vincent Bernat <bernat@debian.org> Thu, 19 Apr 2018 17:51:55 +0200 + +haproxy (1.8.7-1) unstable; urgency=medium + + * New upstream version. + - BUG/MAJOR: cache: always initialize newly created objects + * d/control: switch maintainer address to tracker.debian.org. + + -- Vincent Bernat <bernat@debian.org> Sat, 07 Apr 2018 07:58:34 +0200 + +haproxy (1.8.6-1) unstable; urgency=medium + + * New upstream version. + - BUG/MAJOR: cache: fix random crashes caused by incorrect delete() on + non-first blocks + - BUG/MAJOR: h2: remove orphaned streams from the send list before closing + - BUG/MEDIUM: h2/threads: never release the task outside of the task + handler + - BUG/MEDIUM: h2: always add a stream to the send or fctl list when + blocked + - BUG/MEDIUM: h2: don't consider pending data on detach if connection + is in error + + -- Vincent Bernat <bernat@debian.org> Thu, 05 Apr 2018 21:08:12 +0200 + +haproxy (1.8.5-1) unstable; urgency=medium + + * New upstream version. + - BUG/MAJOR: threads/queue: Fix thread-safety issues on the queues + management + - BUG/MEDIUM: buffer: Fix the wrapping case in bi_putblk + - BUG/MEDIUM: buffer: Fix the wrapping case in bo_putblk + - BUG/MEDIUM: fix a 100% cpu usage with cpu-map and nbthread/nbproc + - BUG/MEDIUM: h2: also arm the h2 timeout when sending + - BUG/MEDIUM: h2: always consume any trailing data after end of output + buffers + - BUG/MEDIUM: h2: properly account for DATA padding in flow control + - BUG/MEDIUM: http: Switch the HTTP response in tunnel mode as earlier + as possible + - BUG/MEDIUM: spoe: Remove idle applets from idle list when HAProxy is + stopping + - BUG/MEDIUM: ssl/sample: ssl_bc_* fetch keywords are broken. + - BUG/MEDIUM: ssl: Don't always treat SSL_ERROR_SYSCALL as + unrecovarable. + - BUG/MEDIUM: ssl: Shutdown the connection for reading on + SSL_ERROR_SYSCALL + - BUG/MEDIUM: tcp-check: single connect rule can't detect DOWN servers + - BUG/MEDIUM: threads/queue: wake up other threads upon dequeue + - BUG/MEDIUM: threads/unix: Fix a deadlock when a listener is + temporarily disabled + * Upload to unstable. + * d/control: update Vcs-* fields to salsa.debian.org. + + -- Vincent Bernat <bernat@debian.org> Sun, 25 Mar 2018 11:31:25 +0200 + +haproxy (1.8.4-1) experimental; urgency=medium + + * New upstream stable release. + * d/patches: document why dconv patch is not in series. + * d/docs: ship NOTICE file in haproxy-doc. + + -- Vincent Bernat <bernat@debian.org> Sat, 10 Feb 2018 08:43:36 +0100 + +haproxy (1.8.3-1) experimental; urgency=medium + + * New upstream stable release. + * Change default configuration of stats socket to support hitless + reload. + + -- Vincent Bernat <bernat@debian.org> Tue, 02 Jan 2018 18:48:24 +0100 + +haproxy (1.8.2-1) experimental; urgency=medium + + * New upstream stable release + * Refresh patches + * Bump Standards-Version to 4.1.2; no changes needed + + -- Apollon Oikonomopoulos <apoikos@debian.org> Sun, 24 Dec 2017 14:28:28 +0200 + +haproxy (1.8.1-1) experimental; urgency=medium + + * New upstream stable release. + * Enable PCRE JIT. + * systemd: replace Wants/After=syslog.service with After=rsyslog.service + (Closes: #882610) + + -- Apollon Oikonomopoulos <apoikos@debian.org> Sun, 03 Dec 2017 23:59:03 +0200 + +haproxy (1.8.0-2) experimental; urgency=medium + + * Use libatomic on platforms without 64-bit atomics. Fixes FTBFS on armel, + mips, mipsel, powerpc, powerpcspe, sh4 and m68k. + * d/rules: use variables defined in architecture.mk and buildflags.mk + * d/rules: drop unreachable else case. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Wed, 29 Nov 2017 01:21:40 +0200 + +haproxy (1.8.0-1) experimental; urgency=medium + + * New upstream stable series. Notable new features include: + + HTTP/2 support + + Support for multiple worker threads to allow scalability across CPUs + (e.g. for SSL termination) + + Seamless reloads + + HTTP small object caching + + Dynamic backend server configuration + See https://www.haproxy.com/blog/whats-new-haproxy-1-8/ and + https://www.mail-archive.com/haproxy@formilux.org/msg28004.html for more + detailed descriptions of the new features. + * Upload to experimental + * Refresh all patches. + * d/watch: switch to the 1.8.x upstream stable series + * Bump Standards to 4.1.1 + + Switch haproxy-doc to Priority: optional from extra. + * Bump compat to 10: + + B-D on debhelper (>= 10) + + Drop explicit dh-systemd dependency and invocation + + Replace --no-restart-on-upgrade with --no-restart-after-upgrade + --no-stop-on-upgrade to make up for DH 10 defaults. + * B-D on libsystemd-dev and enable sd_notify() support on Linux. + * B-D on python3-sphinx instead of python-sphinx. + * d/rules: do not call dpkg-parsechangelog directly. + * d/copyright: drop obsolete section. + * Drop obsolete lintian overrides. + * Do a full-service restart when upgrading from pre-1.8 versions and running + under systemd, to migrate to the new process model and service type. + + Document this in d/NEWS as well. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Tue, 28 Nov 2017 22:25:11 +0200 + +haproxy (1.7.10-1) unstable; urgency=medium + + * New upstream version release (see CHANGELOG): + - BUG/MAJOR: stream-int: don't re-arm recv if send fails + - BUG/MAJOR: stream: ensure analysers are always called upon close + - BUG/MEDIUM: compression: Fix check on txn in smp_fetch_res_comp_algo + - BUG/MEDIUM: connection: remove useless flag CO_FL_DATA_RD_SH + - BUG/MEDIUM: deinit: correctly deinitialize the proxy and global + listener tasks + - BUG/MEDIUM: deviceatlas: ignore not valuable HTTP request data + - BUG/MEDIUM: epoll: ensure we always consider HUP and ERR + - BUG/MEDIUM: http: Close streams for connections closed before a + redirect + - BUG/MEDIUM: http: Fix a regression bug when a HTTP response is in + TUNNEL mode + - BUG/MEDIUM: http: Return an error when url_dec sample converter + failed + - BUG/MEDIUM: http: don't automatically forward request close + - BUG/MEDIUM: http: don't disable lingering on requests with tunnelled + responses + - BUG/MEDIUM: kqueue: Don't bother closing the kqueue after fork. + - BUG/MEDIUM: lua: HTTP services must take care of body-less status + codes + - BUG/MEDIUM: lua: fix crash when using bogus mode in + register_service() + - BUG/MEDIUM: peers: set NOLINGER on the outgoing stream interface + - BUG/MEDIUM: prevent buffers being overwritten during build_logline() + execution + - BUG/MEDIUM: ssl: fix OCSP expiry calculation + - BUG/MEDIUM: stream: don't ignore res.analyse_exp anymore + - BUG/MEDIUM: stream: properly set the required HTTP analysers on + use-service + - BUG/MEDIUM: tcp-check: don't call tcpcheck_main() from the I/O + handlers! + - BUG/MEDIUM: tcp-check: properly indicate polling state before + performing I/O + - BUG/MEDIUM: tcp/http: set-dst-port action broken + * Fix VERDATE build argument to really use changelog date. + * Bump compat to 10. + * d/control: B-D on python3-sphinx instead of python-sphinx. + * d/control: make haproxy-doc Priority: optional. + * d/rules: enable PCRE JIT. + * d/rules: use variables defined in *.mk. + * d/patches: refresh and replace Wants/After=syslog.service with + After=rsyslog.service. Closes: #882610. + + -- Vincent Bernat <bernat@debian.org> Wed, 03 Jan 2018 08:29:48 +0100 + +haproxy (1.7.9-1) unstable; urgency=medium + + * New upstream version release (see CHANGELOG): + - BUG/MAJOR: lua/socket: resources not destroyed when the socket is + aborted + - BUG/MEDIUM: lua: bad memory access + - BUG/MEDIUM: http: Switch HTTP responses in TUNNEL mode when body + length is undefined + + -- Vincent Bernat <bernat@debian.org> Sat, 19 Aug 2017 12:05:02 +0200 + +haproxy (1.7.8-1) unstable; urgency=medium + + * New upstream version release (see CHANGELOG): + - BUG/MAJOR: cli: fix custom io_release was crushed by NULL. + - BUG/MAJOR: compression: Be sure to release the compression state in + all cases + - BUG/MAJOR: map: fix segfault during 'show map/acl' on cli. + - BUG/MEDIUM: filters: Be sure to call flt_end_analyze for both + channels + - BUG/MEDIUM: map/acl: fix unwanted flags inheritance. + * Bump Standards-Version to 4.0.0. No changes needed. + * Update d/watch to use https. + + -- Vincent Bernat <bernat@debian.org> Sat, 08 Jul 2017 08:24:35 +0200 + +haproxy (1.7.7-1) unstable; urgency=medium + + * New upstream version release (see CHANGELOG): + - BUG/MEDIUM: http: Drop the connection establishment when a redirect + is performed + - BUG/MEDIUM: cfgparse: Check if tune.http.maxhdr is in the range + 1..32767 + + -- Vincent Bernat <bernat@debian.org> Mon, 26 Jun 2017 14:06:48 +0200 + +haproxy (1.7.6-1) unstable; urgency=medium + + * New upstream version release (see CHANGELOG): + - BUG/MAJOR: Use -fwrapv. + - BUG/MAJOR: http: call manage_client_side_cookies() before erasing + the buffer + - BUG/MAJOR: server: Segfault after parsing server state file. + - BUG/MEDIUM: acl: don't free unresolved args in prune_acl_expr() + - BUG/MEDIUM: acl: proprely release unused args in prune_acl_expr() + - BUG/MEDIUM: arg: ensure that we properly unlink unresolved arguments + on error + - BUG/MEDIUM: lua: memory leak + - BUG/MEDIUM: lua: segfault if a converter or a sample doesn't return + anything + - BUG/MEDIUM: peers: Peers CLOSE_WAIT issue. + - BUG/MEDIUM: unix: never unlink a unix socket from the file system + + -- Vincent Bernat <bernat@debian.org> Sun, 18 Jun 2017 12:34:40 +0200 + +haproxy (1.7.5-2) unstable; urgency=medium + + * Enable getaddrinfo() support, allowing resolution of hostnames to IPv6 + addresses (Closes: #862780). Thanks to Anton Eliasson + <devel@antoneliasson.se>! + + -- Apollon Oikonomopoulos <apoikos@debian.org> Wed, 17 May 2017 13:01:45 +0300 + +haproxy (1.7.5-1) unstable; urgency=medium + + * New upstream version release (see CHANGELOG): + - BUG/MEDIUM: peers: fix buffer overflow control in intdecode. + - BUG/MEDIUM: buffers: Fix how input/output data are injected into buffers + - BUG/MEDIUM: http: Fix blocked HTTP/1.0 responses when compression is + enabled + + -- Apollon Oikonomopoulos <apoikos@debian.org> Tue, 04 Apr 2017 14:25:38 +0300 + +haproxy (1.7.4-1) unstable; urgency=medium + + * New upstream release (see CHANGELOG): + - BUG/MAJOR: connection: update CO_FL_CONNECTED before calling the + data layer + - BUG/MAJOR: http: fix typo in http_apply_redirect_rule + - BUG/MAJOR: stream-int: do not depend on connection flags to detect + connection + - BUG/MEDIUM: cli: Prevent double free in CLI ACL lookup + - BUG/MEDIUM: connection: ensure to always report the end of handshakes + - BUG/MEDIUM: listener: do not try to rebind another process' socket + - BUG/MEDIUM: stream: fix client-fin/server-fin handling + - BUG/MEDIUM: tcp: don't require privileges to bind to device + + -- Vincent Bernat <bernat@debian.org> Fri, 31 Mar 2017 11:01:14 +0200 + +haproxy (1.7.3-1) unstable; urgency=medium + + * New upstream release (see CHANGELOG): + - BUG/MAJOR: lua segmentation fault when the request is like 'GET + ?arg=val HTTP/1.1' + - BUG/MAJOR: dns: restart sockets after fork() + - BUG/MEDIUM: tcp: don't poll for write when connect() succeeds + - BUG/MEDIUM: http: prevent redirect from overwriting a buffer + - BUG/MEDIUM: filters: Do not truncate HTTP response when body length + is undefined + - BUG/MEDIUM: http: Prevent replace-header from overwriting a buffer + - BUG/MEDIUM: config: reject anything but "if" or "unless" after a + use-backend rule + + -- Vincent Bernat <bernat@debian.org> Wed, 01 Mar 2017 20:03:12 +0100 + +haproxy (1.7.2-1) unstable; urgency=medium + + * New upstream release (see CHANGELOG): + + Fix a regression whereby fragmented requests were randomly flagged as + bad requests depending on previous buffer contents; this was noticable + under low load with authenticated requests. + + Fix dynamic address resolution for IPv6-only hosts. + + Make sure SSL sessions are not reused when the SNI changes. This makes + SNI and SSL health checks play nice together. + + Minor improvements: + - Add the ability to perform actions on multiple servers via the stats + page. + - Add the ability to specify a custom HTTP reason field in generated + responses. + - New sample fetch function, `fc_rcvd_proxy', indicating wheter the + PROXY protocol was used on the frontend for a connection or not. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Fri, 13 Jan 2017 14:49:05 +0200 + +haproxy (1.7.1-1) unstable; urgency=medium + + * New upstream stable release. + * Upload to unstable. + * Notable new features since 1.6: + + SPOE (stream processing offload engine) : ability to delegate some + slow, unreliable or dangerous processing to external processes. + + More statistics in the CSV output. + + Support of directories for config files: if the argument to -f + is a directory, all files found there are loaded in alphabetical order. + + It is now possible to set/unset/preset environment variables directly in + the global section and query them through the CLI. + + The CLI makes it possible to change a server's address, port, maxconn, + check address and port at runtime, without reloading haproxy. + + Support for multiple certificates: different certificates for the same + domain so that the best one can be picked according to browser support. + The main use is to be able to deliver ECDSA certificates to clients + supporting them, without breaking compatibility with older clients. + + SO_REUSEPORT is now configurable and can be disabled. + + Updates to the Lua API, including new classes to access many internal + objects like listeners, servers, proxies etc. + + Support for a new type of maps consisting of regular expressions with + replacement values. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Tue, 13 Dec 2016 12:32:32 +0200 + +haproxy (1.7.0-1) experimental; urgency=medium + + * New upstream stable series. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Fri, 25 Nov 2016 18:00:55 +0200 + +haproxy (1.7~dev6-1) experimental; urgency=medium + + * New upstream development release (Closes: #828337) + * Upload to experimental + * d/watch: look for 1.7 + * B-D on zlib1g-dev + * haproxy: Depend on lsb-base for the initscript + * Ship additional plain-text documentation + * haproxy-doc: ship HTML version of management.txt + * Update the default SSL cipher list and add a link to Mozilla's SSL + configuration generator (Closes: #840735) + * d/rules: use SUBVERS to pass the Debian revision to HAPROXY_VERSION + + -- Apollon Oikonomopoulos <apoikos@debian.org> Thu, 10 Nov 2016 16:02:27 +0200 + +haproxy (1.6.10-1) unstable; urgency=medium + + * New upstream release (see CHANGELOG): + + Fix retransmits in proxy mode and rare cases of unkillable tasks. + + systemd wrapper: do not leave old processes behind when reloading too + fast. + + systemd wrapper: correctly set the status code. + + Fix two bugs in the peers' task management possibly causing some + CLOSE_WAIT connection after some rare race conditions. + + Make SO_REUSEPORT use configurable via the "-dR" command line switch + or the "noreuseport" config option in the global section. + * B-D on libssl1.0-dev (Closes: #828337); upstream does not currently + support OpenSSL 1.1 for the 1.6 series. + * haproxy: depend on lsb-base for the initscript's use of + /lib/lsb/init-functions. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Mon, 21 Nov 2016 11:46:16 +0200 + +haproxy (1.6.9-2) unstable; urgency=medium + + * Enable Linux namespace support. + * Pass the full Debian version and package release date from d/changelog to + the build system. + * initscript: reorder the reload command arguments to always parse EXTRAOPTS + properly. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Wed, 28 Sep 2016 10:45:43 +0300 + +haproxy (1.6.9-1) unstable; urgency=medium + + * New upstream release (see CHANGELOG): + + BUG/MAJOR: stream: properly mark the server address as unset on + connect retry + + -- Vincent Bernat <bernat@debian.org> Wed, 31 Aug 2016 07:44:27 +0200 + +haproxy (1.6.8-1) unstable; urgency=medium + + * New upstream release (see CHANGELOG): + + BUG/MAJOR: compression: initialize avail_in/next_in even during + flush + + BUG/MAJOR: server: the "sni" directive could randomly cause trouble + + BUG/MAJOR: stick-counters: possible crash when using sc_trackers + with wrong table + + -- Vincent Bernat <bernat@debian.org> Sun, 14 Aug 2016 14:17:08 +0200 + +haproxy (1.6.7-1) unstable; urgency=medium + + * New upstream release (see CHANGELOG): + + BUG/MAJOR: fix use-after-free crash on start + + BUG/MEDIUM: dns: fix alignment issues in the DNS response parser + + -- Vincent Bernat <bernat@debian.org> Thu, 14 Jul 2016 08:29:43 +0200 + +haproxy (1.6.6-1) unstable; urgency=medium + + * New upstream release (see CHANGELOG): + + BUG/MAJOR: fix listening IP address storage for frontends + + BUG/MAJOR: http: fix breakage of "reqdeny" causing random crashes + + BUG/MEDIUM: stick-tables: fix breakage in table converters + + BUG/MEDIUM: dns: unbreak DNS resolver after header fix + + BUG/MEDIUM: stats: show servers state may show an servers from another + backend + + BUG/MEDIUM: fix risk of segfault with "show tls-keys" + + BUG/MEDIUM: sticktables: segfault in some configuration error cases + + BUG/MEDIUM: lua: converters doesn't work + + BUG/MEDIUM: http: add-header: buffer overwritten + + BUG/MEDIUM: external-checks: close all FDs right after the fork() + + BUG/MAJOR: external-checks: use asynchronous signal delivery + * Drop haproxy.service-check-config-before-reload.patch. Applied + upstream. + + -- Vincent Bernat <bernat@debian.org> Tue, 28 Jun 2016 10:13:33 +0200 + +haproxy (1.6.5-2) unstable; urgency=high + + * Add a patch to fix CVE-2016-5360. Closes: #826869. + + BUG/MAJOR: http: fix breakage of "reqdeny" causing random crashes + + -- Vincent Bernat <bernat@debian.org> Sat, 11 Jun 2016 22:23:50 +0200 + +haproxy (1.6.5-1) unstable; urgency=medium + + * New upstream release (see CHANGELOG): + + BUG/MAJOR: channel: fix miscalculation of available buffer space + + BUG/MAJOR: Fix crash in http_get_fhdr with exactly MAX_HDR_HISTORY + headers + + BUG/MEDIUM: channel: don't allow to overwrite the reserve until + connected + + BUG/MEDIUM: channel: fix inconsistent handling of 4GB-1 transfers + + BUG/MEDIUM: channel: incorrect polling condition may delay event + delivery + + BUG/MEDIUM: dns: fix alignment issue when building DNS queries + + BUG/MEDIUM: fix maxaccept computation on per-process listeners + + BUG/MEDIUM: Fix RFC5077 resumption when more than TLS_TICKETS_NO are + present + + BUG/MEDIUM: http: fix risk of CPU spikes with pipelined requests from + dead client + + BUG/MEDIUM: log: fix risk of segfault when logging HTTP fields in TCP + mode + + BUG/MEDIUM: lua: protects the upper boundary of the argument list for + converters/fetches. + + BUG/MEDIUM: peers: fix incorrect age in frequency counters + + BUG/MEDIUM: sample: initialize the pointer before parse_binary call. + + BUG/MEDIUM: stats: show backend may show an empty or incomplete result + + BUG/MEDIUM: stats: show servers state may show an empty or incomplete + result + + BUG/MEDIUM: stick-tables: some sample-fetch doesn't work in the + connection state. + + BUG/MEDIUM: stream: ensure the SI_FL_DONT_WAKE flag is properly cleared + + BUG/MEDIUM: trace.c: rdtsc() is defined in two files + + MEDIUM: unblock signals on startup. + * Bump standards to 3.9.8; no changes needed. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Wed, 11 May 2016 11:07:24 +0300 + +haproxy (1.6.4-3) unstable; urgency=medium + + * d/init: remove support for dynamic script name. This enable haproxy to + be started on boot. + + -- Vincent Bernat <bernat@debian.org> Thu, 24 Mar 2016 20:36:08 +0100 + +haproxy (1.6.4-2) unstable; urgency=medium + + * d/init: fix SysV init script w/ respect to handling EXTRAOPTS on check. + * d/control: add Pre-Depends for dpkg-maintscript-helper support of + dir_to_symlink. + + -- Vincent Bernat <bernat@debian.org> Sat, 19 Mar 2016 16:35:20 +0100 + +haproxy (1.6.4-1) unstable; urgency=medium + + * New upstream release (see CHANGELOG): + + BUG/MAJOR: http-reuse: fix risk of orphaned connections. + + BUG/MAJOR: lua: applets can't sleep. + + BUG/MAJOR: samples: check smp->strm before using it. + + BUG/MAJOR: servers state: server port is erased when dns resolution is + enabled on a server. + + BUG/MAJOR: vars: always retrieve the stream and session from the sample + + BUG/MEDIUM: buffers: do not round up buffer size during allocation + + BUG/MEDIUM: dns: no DNS resolution happens if no ports provided to the + nameserver + + BUG/MEDIUM: servers state: server port is used uninitialized + + BUG/MEDIUM: config: Adding validation to stick-table expire value. + + BUG/MEDIUM: sample: http_date() doesn't provide the right day of the + week + + BUG/MEDIUM: channel: fix miscalculation of available buffer space. + + BUG/MEDIUM: http-reuse: do not share private connections across backends + + BUG/MEDIUM: ssl: fix off-by-one in ALPN list allocation + + BUG/MEDIUM: ssl: fix off-by-one in NPN list allocation + + BUG/MEDIUM: stats: stats bind-process doesn't propagate the process mask + correctly + + BUG/MEDIUM: chunks: always reject negative-length chunks + + BUG/MEDIUM: cfgparse: wrong argument offset after parsing server "sni" + keyword + + [ Vincent Bernat ] + * haproxy.init: append ${EXTRAOPTS} when verifying configuration file. + * haproxy.init: move EXTRAOPTS after all other parameters. + * haproxy.init: management of multiple HAProxy instances with SysV + init.d script, courtesy of Ivan Savcic. + + [ Apollon Oikonomopoulos ] + * Bump standards to 3.9.7: + + haproxy-doc: move the additional documentation from + /usr/share/doc/haproxy-doc to /usr/share/doc/haproxy, as per the + recommendation in Policy §12.3. + + Add compatibility symlinks from /usr/share/doc/haproxy-doc to + /usr/share/doc/haproxy. + * Enable all hardening flags. + * d/control: use HTTPS for Vcs-* + * Use www.haproxy.org as the project's homepage in d/control and + d/copyright. + * d/copyright: adjust debian/* years. + * Add basic DEP-8 tests. + * Drop the haproxy-dbg binary package in favor of ddebs. + * haproxy-doc: + + Use dpkg-maintscript-helper dir_to_symlink for the compatibility + symlinks. + + Add Lua documentation doc-base entry. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Tue, 15 Mar 2016 21:04:11 +0200 + +haproxy (1.6.3-1) unstable; urgency=medium + + [ Apollon Oikonomopoulos ] + * haproxy.init: use s-s-d's --pidfile option. + Thanks to Louis Bouchard (Closes: 804530) + + [ Vincent Bernat ] + * watch: fix d/watch to look for 1.6 version + * Imported Upstream version 1.6.3 + + -- Vincent Bernat <bernat@debian.org> Thu, 31 Dec 2015 08:10:10 +0100 + +haproxy (1.6.2-2) unstable; urgency=medium + + * Enable USE_REGPARM on amd64 as well. + + -- Vincent Bernat <bernat@debian.org> Tue, 03 Nov 2015 21:21:30 +0100 + +haproxy (1.6.2-1) unstable; urgency=medium + + * New upstream release. + - BUG/MAJOR: dns: first DNS response packet not matching queried + hostname may lead to a loop + - BUG/MAJOR: http: don't requeue an idle connection that is already + queued + * Upload to unstable. + + -- Vincent Bernat <bernat@debian.org> Tue, 03 Nov 2015 13:36:22 +0100 + +haproxy (1.6.1-2) experimental; urgency=medium + + * Build the Lua manpage in -arch, fixes FTBFS in binary-only builds. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Thu, 22 Oct 2015 12:19:41 +0300 + +haproxy (1.6.1-1) experimental; urgency=medium + + [ Vincent Bernat ] + * New upstream release. + - BUG/MAJOR: ssl: free the generated SSL_CTX if the LRU cache is + disabled + * Drop 0001-BUILD-install-only-relevant-and-existing-documentati.patch. + + [ Apollon Oikonomopoulos ] + * Ship and generate Lua API documentation. + + -- Vincent Bernat <bernat@debian.org> Thu, 22 Oct 2015 10:45:55 +0200 + +haproxy (1.6.0+ds1-1) experimental; urgency=medium + + * New upstream release! + * Add a patch to fix documentation installation: + + 0001-BUILD-install-only-relevant-and-existing-documentati.patch + * Update HAProxy documentation converter to a more recent version. + + -- Vincent Bernat <bernat@debian.org> Wed, 14 Oct 2015 17:29:19 +0200 + +haproxy (1.6~dev7-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Tue, 06 Oct 2015 16:01:26 +0200 + +haproxy (1.6~dev5-1) experimental; urgency=medium + + * New upstream release. + + -- Vincent Bernat <bernat@debian.org> Mon, 14 Sep 2015 15:50:28 +0200 + +haproxy (1.6~dev4-1) experimental; urgency=medium + + * New upstream release. + * Refresh debian/copyright. + + -- Vincent Bernat <bernat@debian.org> Sun, 30 Aug 2015 23:54:10 +0200 + +haproxy (1.6~dev3-1) experimental; urgency=medium + + * New upstream release. + * Enable Lua support. + + -- Vincent Bernat <bernat@debian.org> Sat, 15 Aug 2015 17:51:29 +0200 + +haproxy (1.5.15-1) unstable; urgency=medium + + * New upstream stable release including the following fix: + - BUG/MAJOR: http: don't call http_send_name_header() after an error + + -- Vincent Bernat <bernat@debian.org> Mon, 02 Nov 2015 07:34:19 +0100 + +haproxy (1.5.14-1) unstable; urgency=high + + * New upstream version. Fix an information leak (CVE-2015-3281): + - BUG/MAJOR: buffers: make the buffer_slow_realign() function + respect output data. + * Add $named as a dependency for init script. Closes: #790638. + + -- Vincent Bernat <bernat@debian.org> Fri, 03 Jul 2015 19:49:02 +0200 + +haproxy (1.5.13-1) unstable; urgency=medium + + * New upstream stable release including the following fixes: + - MAJOR: peers: allow peers section to be used with nbproc > 1 + - BUG/MAJOR: checks: always check for end of list before proceeding + - MEDIUM: ssl: replace standards DH groups with custom ones + - BUG/MEDIUM: ssl: fix tune.ssl.default-dh-param value being overwritten + - BUG/MEDIUM: cfgparse: segfault when userlist is misused + - BUG/MEDIUM: stats: properly initialize the scope before dumping stats + - BUG/MEDIUM: http: don't forward client shutdown without NOLINGER + except for tunnels + - BUG/MEDIUM: checks: do not dereference head of a tcp-check at the end + - BUG/MEDIUM: checks: do not dereference a list as a tcpcheck struct + - BUG/MEDIUM: peers: apply a random reconnection timeout + - BUG/MEDIUM: config: properly compute the default number of processes + for a proxy + + -- Vincent Bernat <bernat@debian.org> Sat, 27 Jun 2015 20:52:07 +0200 + +haproxy (1.5.12-1) unstable; urgency=medium + + * New upstream stable release including the following fixes: + - BUG/MAJOR: http: don't read past buffer's end in http_replace_value + - BUG/MAJOR: http: prevent risk of reading past end with balance + url_param + - BUG/MEDIUM: Do not consider an agent check as failed on L7 error + - BUG/MEDIUM: patern: some entries are not deleted with case + insensitive match + - BUG/MEDIUM: buffer: one byte miss in buffer free space check + - BUG/MEDIUM: http: thefunction "(req|res)-replace-value" doesn't + respect the HTTP syntax + - BUG/MEDIUM: peers: correctly configure the client timeout + - BUG/MEDIUM: http: hdr_cnt would not count any header when called + without name + - BUG/MEDIUM: listener: don't report an error when resuming unbound + listeners + - BUG/MEDIUM: init: don't limit cpu-map to the first 32 processes only + - BUG/MEDIUM: stream-int: always reset si->ops when si->end is + nullified + - BUG/MEDIUM: http: remove content-length from chunked messages + - BUG/MEDIUM: http: do not restrict parsing of transfer-encoding to + HTTP/1.1 + - BUG/MEDIUM: http: incorrect transfer-coding in the request is a bad + request + - BUG/MEDIUM: http: remove content-length form responses with bad + transfer-encoding + - BUG/MEDIUM: http: wait for the exact amount of body bytes in + wait_for_request_body + + -- Vincent Bernat <bernat@debian.org> Sat, 02 May 2015 16:38:28 +0200 + +haproxy (1.5.11-2) unstable; urgency=medium + + * Upload to unstable. + + -- Vincent Bernat <bernat@debian.org> Sun, 26 Apr 2015 17:46:58 +0200 + +haproxy (1.5.11-1) experimental; urgency=medium + + * New upstream stable release including the following fixes: + - BUG/MAJOR: log: don't try to emit a log if no logger is set + - BUG/MEDIUM: backend: correctly detect the domain when + use_domain_only is used + - BUG/MEDIUM: Do not set agent health to zero if server is disabled + in config + - BUG/MEDIUM: Only explicitly report "DOWN (agent)" if the agent health + is zero + - BUG/MEDIUM: http: fix header removal when previous header ends with + pure LF + - BUG/MEDIUM: channel: fix possible integer overflow on reserved size + computation + - BUG/MEDIUM: channel: don't schedule data in transit for leaving until + connected + - BUG/MEDIUM: http: make http-request set-header compute the string + before removal + * Upload to experimental. + + -- Vincent Bernat <bernat@debian.org> Sun, 01 Feb 2015 09:22:27 +0100 + +haproxy (1.5.10-1) experimental; urgency=medium + + * New upstream stable release including the following fixes: + - BUG/MAJOR: stream-int: properly check the memory allocation return + - BUG/MEDIUM: sample: fix random number upper-bound + - BUG/MEDIUM: patterns: previous fix was incomplete + - BUG/MEDIUM: payload: ensure that a request channel is available + - BUG/MEDIUM: tcp-check: don't rely on random memory contents + - BUG/MEDIUM: tcp-checks: disable quick-ack unless next rule is an expect + - BUG/MEDIUM: config: do not propagate processes between stopped + processes + - BUG/MEDIUM: memory: fix freeing logic in pool_gc2() + - BUG/MEDIUM: compression: correctly report zlib_mem + * Upload to experimental. + + -- Vincent Bernat <bernat@debian.org> Sun, 04 Jan 2015 13:17:56 +0100 + +haproxy (1.5.9-1) experimental; urgency=medium + + * New upstream stable release including the following fixes: + - BUG/MAJOR: sessions: unlink session from list on out + of memory + - BUG/MEDIUM: pattern: don't load more than once a pattern + list. + - BUG/MEDIUM: connection: sanitize PPv2 header length before + parsing address information + - BUG/MAJOR: frontend: initialize capture pointers earlier + - BUG/MEDIUM: checks: fix conflicts between agent checks and + ssl healthchecks + - BUG/MEDIUM: ssl: force a full GC in case of memory shortage + - BUG/MEDIUM: ssl: fix bad ssl context init can cause + segfault in case of OOM. + * Upload to experimental. + + -- Vincent Bernat <bernat@debian.org> Sun, 07 Dec 2014 16:37:36 +0100 + +haproxy (1.5.8-3) unstable; urgency=medium + + * Remove RC4 from the default cipher string shipped in configuration. + + -- Vincent Bernat <bernat@debian.org> Fri, 27 Feb 2015 11:29:23 +0100 + +haproxy (1.5.8-2) unstable; urgency=medium + + * Cherry-pick the following patches from 1.5.9 release: + - 8a0b93bde77e BUG/MAJOR: sessions: unlink session from list on out + of memory + - bae03eaad40a BUG/MEDIUM: pattern: don't load more than once a pattern + list. + - 93637b6e8503 BUG/MEDIUM: connection: sanitize PPv2 header length before + parsing address information + - 8ba50128832b BUG/MAJOR: frontend: initialize capture pointers earlier + - 1f96a87c4e14 BUG/MEDIUM: checks: fix conflicts between agent checks and + ssl healthchecks + - 9bcc01ae2598 BUG/MEDIUM: ssl: force a full GC in case of memory shortage + - 909514970089 BUG/MEDIUM: ssl: fix bad ssl context init can cause + segfault in case of OOM. + * Cherry-pick the following patches from future 1.5.10 release: + - 1e89acb6be9b BUG/MEDIUM: payload: ensure that a request channel is + available + - bad3c6f1b6d7 BUG/MEDIUM: patterns: previous fix was incomplete + + -- Vincent Bernat <bernat@debian.org> Sun, 07 Dec 2014 11:11:21 +0100 + +haproxy (1.5.8-1) unstable; urgency=medium + + * New upstream stable release including the following fixes: + + + BUG/MAJOR: buffer: check the space left is enough or not when input + data in a buffer is wrapped + + BUG/MINOR: ssl: correctly initialize ssl ctx for invalid certificates + + BUG/MEDIUM: tcp: don't use SO_ORIGINAL_DST on non-AF_INET sockets + + BUG/MEDIUM: regex: fix pcre_study error handling + + BUG/MEDIUM: tcp: fix outgoing polling based on proxy protocol + + BUG/MINOR: log: fix request flags when keep-alive is enabled + + BUG/MAJOR: cli: explicitly call cli_release_handler() upon error + + BUG/MEDIUM: http: don't dump debug headers on MSG_ERROR + * Also includes the following new features: + + MINOR: ssl: add statement to force some ssl options in global. + + MINOR: ssl: add fetchs 'ssl_c_der' and 'ssl_f_der' to return DER + formatted certs + * Disable SSLv3 in the default configuration file. + + -- Vincent Bernat <bernat@debian.org> Fri, 31 Oct 2014 13:48:19 +0100 + +haproxy (1.5.6-1) unstable; urgency=medium + + * New upstream stable release including the following fixes: + + BUG/MEDIUM: systemd: set KillMode to 'mixed' + + MINOR: systemd: Check configuration before start + + BUG/MEDIUM: config: avoid skipping disabled proxies + + BUG/MINOR: config: do not accept more track-sc than configured + + BUG/MEDIUM: backend: fix URI hash when a query string is present + * Drop systemd patches: + + haproxy.service-also-check-on-start.patch + + haproxy.service-set-killmode-to-mixed.patch + * Refresh other patches. + + -- Vincent Bernat <bernat@debian.org> Mon, 20 Oct 2014 18:10:21 +0200 + +haproxy (1.5.5-1) unstable; urgency=medium + + [ Vincent Bernat ] + * initscript: use start-stop-daemon to reliably terminate all haproxy + processes. Also treat stopping a non-running haproxy as success. + (Closes: #762608, LP: #1038139) + + [ Apollon Oikonomopoulos ] + * New upstream stable release including the following fixes: + + DOC: Address issue where documentation is excluded due to a gitignore + rule. + + MEDIUM: Improve signal handling in systemd wrapper. + + BUG/MINOR: config: don't propagate process binding for dynamic + use_backend + + MINOR: Also accept SIGHUP/SIGTERM in systemd-wrapper + + DOC: clearly state that the "show sess" output format is not fixed + + MINOR: stats: fix minor typo fix in stats_dump_errors_to_buffer() + + DOC: indicate in the doc that track-sc* can wait if data are missing + + MEDIUM: http: enable header manipulation for 101 responses + + BUG/MEDIUM: config: propagate frontend to backend process binding again. + + MEDIUM: config: properly propagate process binding between proxies + + MEDIUM: config: make the frontends automatically bind to the listeners' + processes + + MEDIUM: config: compute the exact bind-process before listener's + maxaccept + + MEDIUM: config: only warn if stats are attached to multi-process bind + directives + + MEDIUM: config: report it when tcp-request rules are misplaced + + MINOR: config: detect the case where a tcp-request content rule has no + inspect-delay + + MEDIUM: systemd-wrapper: support multiple executable versions and names + + BUG/MEDIUM: remove debugging code from systemd-wrapper + + BUG/MEDIUM: http: adjust close mode when switching to backend + + BUG/MINOR: config: don't propagate process binding on fatal errors. + + BUG/MEDIUM: check: rule-less tcp-check must detect connect failures + + BUG/MINOR: tcp-check: report the correct failed step in the status + + DOC: indicate that weight zero is reported as DRAIN + * Add a new patch (haproxy.service-set-killmode-to-mixed.patch) to fix the + systemctl stop action conflicting with the systemd wrapper now catching + SIGTERM. + * Bump standards to 3.9.6; no changes needed. + * haproxy-doc: link to tracker.debian.org instead of packages.qa.debian.org. + * d/copyright: move debian/dconv/* paragraph after debian/*, so that it + actually matches the files it is supposed to. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Wed, 08 Oct 2014 12:34:53 +0300 + +haproxy (1.5.4-1) unstable; urgency=high + + * New upstream version. + + Fix a critical bug that, under certain unlikely conditions, allows a + client to crash haproxy. + * Prefix rsyslog configuration file to ensure to log only to + /var/log/haproxy. Thanks to Paul Bourke for the patch. + + -- Vincent Bernat <bernat@debian.org> Tue, 02 Sep 2014 19:14:38 +0200 + +haproxy (1.5.3-1) unstable; urgency=medium + + * New upstream stable release, fixing the following issues: + + Memory corruption when building a proxy protocol v2 header + + Memory leak in SSL DHE key exchange + + -- Apollon Oikonomopoulos <apoikos@debian.org> Fri, 25 Jul 2014 10:41:36 +0300 + +haproxy (1.5.2-1) unstable; urgency=medium + + * New upstream stable release. Important fixes: + + A few sample fetch functions when combined in certain ways would return + malformed results, possibly crashing the HAProxy process. + + Hash-based load balancing and http-send-name-header would fail for + requests which contain a body which starts to be forwarded before the + data is used. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Mon, 14 Jul 2014 00:42:32 +0300 + +haproxy (1.5.1-1) unstable; urgency=medium + + * New upstream stable release: + + Fix a file descriptor leak for clients that disappear before connecting. + + Do not staple expired OCSP responses. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Tue, 24 Jun 2014 12:56:30 +0300 + +haproxy (1.5.0-1) unstable; urgency=medium + + * New upstream stable series. Notable changes since the 1.4 series: + + Native SSL support on both sides with SNI/NPN/ALPN and OCSP stapling. + + IPv6 and UNIX sockets are supported everywhere + + End-to-end HTTP keep-alive for better support of NTLM and improved + efficiency in static farms + + HTTP/1.1 response compression (deflate, gzip) to save bandwidth + + PROXY protocol versions 1 and 2 on both sides + + Data sampling on everything in request or response, including payload + + ACLs can use any matching method with any input sample + + Maps and dynamic ACLs updatable from the CLI + + Stick-tables support counters to track activity on any input sample + + Custom format for logs, unique-id, header rewriting, and redirects + + Improved health checks (SSL, scripted TCP, check agent, ...) + + Much more scalable configuration supports hundreds of thousands of + backends and certificates without sweating + + * Upload to unstable, merge all 1.5 work from experimental. Most important + packaging changes since 1.4.25-1 include: + + systemd support. + + A more sane default config file. + + Zero-downtime upgrades between 1.5 releases by gracefully reloading + HAProxy during upgrades. + + HTML documentation shipped in the haproxy-doc package. + + kqueue support for kfreebsd. + + * Packaging changes since 1.5~dev26-2: + + Drop patches merged upstream: + o Fix-reference-location-in-manpage.patch + o 0001-BUILD-stats-workaround-stupid-and-bogus-Werror-forma.patch + + d/watch: look for stable 1.5 releases + + systemd: respect CONFIG and EXTRAOPTS when specified in + /etc/default/haproxy. + + initscript: test the configuration before start or reload. + + initscript: remove the ENABLED flag and logic. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Fri, 20 Jun 2014 11:05:17 +0300 + +haproxy (1.5~dev26-2) experimental; urgency=medium + + * initscript: start should not fail when haproxy is already running + + Fixes upgrades from post-1.5~dev24-1 installations + + -- Apollon Oikonomopoulos <apoikos@debian.org> Wed, 04 Jun 2014 13:20:39 +0300 + +haproxy (1.5~dev26-1) experimental; urgency=medium + + * New upstream development version. + + Add a patch to fix compilation with -Werror=format-security + + -- Vincent Bernat <bernat@debian.org> Wed, 28 May 2014 20:32:10 +0200 + +haproxy (1.5~dev25-1) experimental; urgency=medium + + [ Vincent Bernat ] + * New upstream development version. + * Rename "contimeout", "clitimeout" and "srvtimeout" in the default + configuration file to "timeout connection", "timeout client" and + "timeout server". + + [ Apollon Oikonomopoulos ] + * Build on kfreebsd using the "freebsd" target; enables kqueue support. + + -- Vincent Bernat <bernat@debian.org> Thu, 15 May 2014 00:20:11 +0200 + +haproxy (1.5~dev24-2) experimental; urgency=medium + + * New binary package: haproxy-doc + + Contains the HTML documentation built using a version of Cyril Bonté's + haproxy-dconv (https://github.com/cbonte/haproxy-dconv). + + Add Build-Depends-Indep on python and python-mako + + haproxy Suggests: haproxy-doc + * systemd: check config file for validity on reload. + * haproxy.cfg: + + Enable the stats socket by default and bind it to + /run/haproxy/admin.sock, which is accessible by the haproxy group. + /run/haproxy creation is handled by the initscript for sysv-rc and a + tmpfiles.d config for systemd. + + Set the default locations for CA and server certificates to + /etc/ssl/certs and /etc/ssl/private respectively. + + Set the default cipher list to be used on listening SSL sockets to + enable PFS, preferring ECDHE ciphers by default. + * Gracefully reload HAProxy on upgrade instead of performing a full restart. + * debian/rules: split build into binary-arch and binary-indep. + * Build-depend on debhelper >= 9, set compat to 9. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Sun, 27 Apr 2014 13:37:17 +0300 + +haproxy (1.5~dev24-1) experimental; urgency=medium + + * New upstream development version, fixes major regressions introduced in + 1.5~dev23: + + + Forwarding of a message body (request or response) would automatically + stop after the transfer timeout strikes, and with no error. + + Redirects failed to update the msg->next offset after consuming the + request, so if they were made with keep-alive enabled and starting with + a slash (relative location), then the buffer was shifted by a negative + amount of data, causing a crash. + + The code to standardize DH parameters caused an important performance + regression for, so it was temporarily reverted for the time needed to + understand the cause and to fix it. + + For a complete release announcement, including other bugfixes and feature + enhancements, see http://deb.li/yBVA. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Sun, 27 Apr 2014 11:09:37 +0300 + +haproxy (1.5~dev23-1) experimental; urgency=medium + + * New upstream development version; notable changes since 1.5~dev22: + + SSL record size optimizations to speed up both, small and large + transfers. + + Dynamic backend name support in use_backend. + + Compressed chunked transfer encoding support. + + Dynamic ACL manipulation via the CLI. + + New "language" converter for extracting language preferences from + Accept-Language headers. + * Remove halog source and systemd unit files from + /usr/share/doc/haproxy/contrib, they are built and shipped in their + appropriate locations since 1.5~dev19-2. + + -- Apollon Oikonomopoulos <apoikos@debian.org> Wed, 23 Apr 2014 11:12:34 +0300 + +haproxy (1.5~dev22-1) experimental; urgency=medium + + * New upstream development version + * watch: use the source page and not the main one + + -- Apollon Oikonomopoulos <apoikos@debian.org> Mon, 03 Feb 2014 17:45:51 +0200 + +haproxy (1.5~dev21+20140118-1) experimental; urgency=medium + + * New upstream development snapshot, with the following fixes since + 1.5-dev21: + + 00b0fb9 BUG/MAJOR: ssl: fix breakage caused by recent fix abf08d9 + + 410f810 BUG/MEDIUM: map: segmentation fault with the stats's socket + command "set map ..." + + abf08d9 BUG/MAJOR: connection: fix mismatch between rcv_buf's API and + usage + + 35249cb BUG/MINOR: pattern: pattern comparison executed twice + + c920096 BUG/MINOR: http: don't clear the SI_FL_DONT_WAKE flag between + requests + + b800623 BUG/MEDIUM: stats: fix HTTP/1.0 breakage introduced in previous + patch + + 61f7f0a BUG/MINOR: stream-int: do not clear the owner upon unregister + + 983eb31 BUG/MINOR: channel: CHN_INFINITE_FORWARD must be unsigned + + a3ae932 BUG/MEDIUM: stats: the web interface must check the tracked + servers before enabling + + e24d963 BUG/MEDIUM: checks: unchecked servers could not be enabled + anymore + + 7257550 BUG/MINOR: http: always disable compression on HTTP/1.0 + + 9f708ab BUG/MINOR: checks: successful check completion must not + re-enable MAINT servers + + ff605db BUG/MEDIUM: backend: do not re-initialize the connection's + context upon reuse + + ea90063 BUG/MEDIUM: stream-int: fix the keep-alive idle connection + handler + * Update debian/copyright to reflect the license of ebtree/ + (closes: #732614) + * Synchronize debian/copyright with source + * Add Documentation field to the systemd unit file + + -- Apollon Oikonomopoulos <apoikos@debian.org> Mon, 20 Jan 2014 10:07:34 +0200 + +haproxy (1.5~dev21-1) experimental; urgency=low + + [ Prach Pongpanich ] + * Bump Standards-Version to 3.9.5 + + [ Thomas Bechtold ] + * debian/control: Add haproxy-dbg binary package for debug symbols. + + [ Apollon Oikonomopoulos ] + * New upstream development version. + * Require syslog to be operational before starting. Closes: #726323. + + -- Vincent Bernat <bernat@debian.org> Tue, 17 Dec 2013 01:38:04 +0700 + +haproxy (1.5~dev19-2) experimental; urgency=low + + [ Vincent Bernat ] + * Really enable systemd support by using dh-systemd helper. + * Don't use -L/usr/lib and rely on default search path. Closes: #722777. + + [ Apollon Oikonomopoulos ] + * Ship halog. + + -- Vincent Bernat <bernat@debian.org> Thu, 12 Sep 2013 21:58:05 +0200 + +haproxy (1.5~dev19-1) experimental; urgency=high + + [ Vincent Bernat ] + * New upstream version. + + CVE-2013-2175: fix a possible crash when using negative header + occurrences. + + Drop 0002-Fix-typo-in-src-haproxy.patch: applied upstream. + * Enable gzip compression feature. + + [ Prach Pongpanich ] + * Drop bashism patch. It seems useless to maintain a patch to convert + example scripts from /bin/bash to /bin/sh. + * Fix reload/restart action of init script (LP: #1187469) + + -- Vincent Bernat <bernat@debian.org> Mon, 17 Jun 2013 22:03:58 +0200 + +haproxy (1.5~dev18-1) experimental; urgency=low + + [ Apollon Oikonomopoulos ] + * New upstream development version + + [ Vincent Bernat ] + * Add support for systemd. Currently, /etc/default/haproxy is not used + when using systemd. + + -- Vincent Bernat <bernat@debian.org> Sun, 26 May 2013 12:33:00 +0200 + +haproxy (1.4.25-1) unstable; urgency=medium + + [ Prach Pongpanich ] + * New upstream version. + * Update watch file to use the source page. + * Bump Standards-Version to 3.9.5. + + [ Thomas Bechtold ] + * debian/control: Add haproxy-dbg binary package for debug symbols. + + [ Apollon Oikonomopoulos ] + * Require syslog to be operational before starting. Closes: #726323. + * Document how to bind non-local IPv6 addresses. + * Add a reference to configuration.txt.gz to the manpage. + * debian/copyright: synchronize with source. + + -- Prach Pongpanich <prachpub@gmail.com> Fri, 28 Mar 2014 09:35:09 +0700 + +haproxy (1.4.24-2) unstable; urgency=low + + [ Apollon Oikonomopoulos ] + * Ship contrib/halog as /usr/bin/halog. + + [ Vincent Bernat ] + * Don't use -L/usr/lib and rely on default search path. Closes: #722777. + + -- Vincent Bernat <bernat@debian.org> Sun, 15 Sep 2013 14:36:27 +0200 + +haproxy (1.4.24-1) unstable; urgency=high + + [ Vincent Bernat ] + * New upstream version. + + CVE-2013-2175: fix a possible crash when using negative header + occurrences. + + [ Prach Pongpanich ] + * Drop bashism patch. It seems useless to maintain a patch to convert + example scripts from /bin/bash to /bin/sh. + * Fix reload/restart action of init script (LP: #1187469). + + -- Vincent Bernat <bernat@debian.org> Mon, 17 Jun 2013 21:56:26 +0200 + +haproxy (1.4.23-1) unstable; urgency=low + + [ Apollon Oikonomopoulos ] + * New upstream version (Closes: #643650, #678953) + + This fixes CVE-2012-2942 (Closes: #674447) + + This fixes CVE-2013-1912 (Closes: #704611) + * Ship vim addon as vim-haproxy (Closes: #702893) + * Check for the configuration file after sourcing /etc/default/haproxy + (Closes: #641762) + * Use /dev/log for logging by default (Closes: #649085) + + [ Vincent Bernat ] + * debian/control: + + add Vcs-* fields + + switch maintenance to Debian HAProxy team. (Closes: #706890) + + drop dependency to quilt: 3.0 (quilt) format is in use. + * debian/rules: + + don't explicitly call dh_installchangelog. + + use dh_installdirs to install directories. + + use dh_install to install error and configuration files. + + switch to `linux2628` Makefile target for Linux. + * debian/postrm: + + remove haproxy user and group on purge. + * Ship a more minimal haproxy.cfg file: no `listen` blocks but `global` + and `defaults` block with appropriate configuration to use chroot and + logging in the expected way. + + [ Prach Pongpanich ] + * debian/copyright: + + add missing copyright holders + + update years of copyright + * debian/rules: + + build with -Wl,--as-needed to get rid of unnecessary depends + * Remove useless files in debian/haproxy.{docs,examples} + * Update debian/watch file, thanks to Bart Martens + + -- Vincent Bernat <bernat@debian.org> Mon, 06 May 2013 20:02:14 +0200 + +haproxy (1.4.15-1) unstable; urgency=low + + * New upstream release with critical bug fix (Closes: #631351) + + -- Christo Buschek <crito@30loops.net> Thu, 14 Jul 2011 18:17:05 +0200 + +haproxy (1.4.13-1) unstable; urgency=low + + * New maintainer upload (Closes: #615246) + * New upstream release + * Standards-version goes 3.9.1 (no change) + * Added patch bashism (Closes: #581109) + * Added a README.source file. + + -- Christo Buschek <crito@30loops.net> Thu, 11 Mar 2011 12:41:59 +0000 + +haproxy (1.4.8-1) unstable; urgency=low + + * New upstream release. + + -- Arnaud Cornet <acornet@debian.org> Fri, 18 Jun 2010 00:42:53 +0100 + +haproxy (1.4.4-1) unstable; urgency=low + + * New upstream release + * Add splice and tproxy support + * Add regparm optimization on i386 + * Switch to dpkg-source 3.0 (quilt) format + + -- Arnaud Cornet <acornet@debian.org> Thu, 15 Apr 2010 20:00:34 +0100 + +haproxy (1.4.2-1) unstable; urgency=low + + * New upstream release + * Remove debian/patches/haproxy.1-hyphen.patch gone upstream + * Tighten quilt build dep (Closes: #567087) + * standards-version goes 3.8.4 (no change) + * Add $remote_fs to init.d script required start and stop + + -- Arnaud Cornet <acornet@debian.org> Sat, 27 Mar 2010 15:19:48 +0000 + +haproxy (1.3.22-1) unstable; urgency=low + + * New upstream bugfix release + + -- Arnaud Cornet <acornet@debian.org> Mon, 19 Oct 2009 22:31:45 +0100 + +haproxy (1.3.21-1) unstable; urgency=low + + [ Michael Shuler ] + * New Upstream Version (Closes: #538992) + * Added override for example shell scripts in docs (Closes: #530096) + * Added upstream changelog to docs + * Added debian/watch + * Updated debian/copyright format + * Added haproxy.1-hyphen.patch, to fix hyphen in man page + * Upgrade Standards-Version to 3.8.3 (no change needed) + * Upgrade debian/compat to 7 (no change needed) + + [ Arnaud Cornet ] + * New upstream version. + * Merge Michael's work, few changelog fixes + * Add debian/README.source to point to quilt doc + * Depend on debhelper >= 7.0.50~ and use overrides in debian/rules + + -- Arnaud Cornet <acornet@debian.org> Sun, 18 Oct 2009 14:01:29 +0200 + +haproxy (1.3.18-1) unstable; urgency=low + + * New Upstream Version (Closes: #534583). + * Add contrib directory in docs + + -- Arnaud Cornet <acornet@debian.org> Fri, 26 Jun 2009 00:11:01 +0200 + +haproxy (1.3.15.7-2) unstable; urgency=low + + * Fix build without debian/patches directory (Closes: #515682) using + /usr/share/quilt/quilt.make. + + -- Arnaud Cornet <acornet@debian.org> Tue, 17 Feb 2009 08:55:12 +0100 + +haproxy (1.3.15.7-1) unstable; urgency=low + + * New Upstream Version. + * Remove upstream patches: + -use_backend-consider-unless.patch + -segfault-url_param+check_post.patch + -server-timeout.patch + -closed-fd-remove.patch + -connection-slot-during-retry.patch + -srv_dynamic_maxconn.patch + -do-not-pause-backends-on-reload.patch + -acl-in-default.patch + -cookie-capture-check.patch + -dead-servers-queue.patch + + -- Arnaud Cornet <acornet@debian.org> Mon, 16 Feb 2009 11:20:21 +0100 + +haproxy (1.3.15.2-2~lenny1) testing-proposed-updates; urgency=low + + * Rebuild for lenny to circumvent pcre3 shlibs bump. + + -- Arnaud Cornet <acornet@debian.org> Wed, 14 Jan 2009 11:28:36 +0100 + +haproxy (1.3.15.2-2) unstable; urgency=low + + * Add stable branch bug fixes from upstream (Closes: #510185). + - use_backend-consider-unless.patch: consider "unless" in use_backend + - segfault-url_param+check_post.patch: fix segfault with url_param + + check_post + - server-timeout.patch: consider server timeout in all circumstances + - closed-fd-remove.patch: drop info about closed file descriptors + - connection-slot-during-retry.patch: do not release the connection slot + during a retry + - srv_dynamic_maxconn.patch: dynamic connection throttling api fix + - do-not-pause-backends-on-reload.patch: make reload reliable + - acl-in-default.patch: allow acl-related keywords in defaults sections + - cookie-capture-check.patch: cookie capture is declared in the frontend + but checked on the backend + - dead-servers-queue.patch: make dead servers not suck pending connections + * Add quilt build-dependancy. Use quilt in debian/rules to apply + patches. + + -- Arnaud Cornet <acornet@debian.org> Wed, 31 Dec 2008 08:50:21 +0100 + +haproxy (1.3.15.2-1) unstable; urgency=low + + * New Upstream Version (Closes: #497186). + + -- Arnaud Cornet <acornet@debian.org> Sat, 30 Aug 2008 18:06:31 +0200 + +haproxy (1.3.15.1-1) unstable; urgency=low + + * New Upstream Version + * Upgrade standards version to 3.8.0 (no change needed). + * Build with TARGET=linux26 on linux, TARGET=generic on other systems. + + -- Arnaud Cornet <acornet@debian.org> Fri, 20 Jun 2008 00:38:50 +0200 + +haproxy (1.3.14.5-1) unstable; urgency=low + + * New Upstream Version (Closes: #484221) + * Use debhelper 7, drop CDBS. + + -- Arnaud Cornet <acornet@debian.org> Wed, 04 Jun 2008 19:21:56 +0200 + +haproxy (1.3.14.3-1) unstable; urgency=low + + * New Upstream Version + * Add status argument support to init-script to conform to LSB. + * Cleanup pidfile after stop in init script. Init script return code fixups. + + -- Arnaud Cornet <acornet@debian.org> Sun, 09 Mar 2008 21:30:29 +0100 + +haproxy (1.3.14.2-3) unstable; urgency=low + + * Add init script support for nbproc > 1 in configuration. That is, + multiple haproxy processes. + * Use 'option redispatch' instead of redispatch in debian default + config. + + -- Arnaud Cornet <acornet@debian.org> Sun, 03 Feb 2008 18:22:28 +0100 + +haproxy (1.3.14.2-2) unstable; urgency=low + + * Fix init scripts's reload function to use -sf instead of -st (to wait for + active session to finish cleanly). Also support dash. Thanks to + Jean-Baptiste Quenot for noticing. + + -- Arnaud Cornet <acornet@debian.org> Thu, 24 Jan 2008 23:47:26 +0100 + +haproxy (1.3.14.2-1) unstable; urgency=low + + * New Upstream Version + * Simplify DEB_MAKE_INVOKE, as upstream now supports us overriding + CFLAGS. + * Move haproxy to usr/sbin. + + -- Arnaud Cornet <acornet@debian.org> Mon, 21 Jan 2008 22:42:51 +0100 + +haproxy (1.3.14.1-1) unstable; urgency=low + + * New upstream release. + * Drop dfsg list and hash code rewrite (merged upstream). + * Add a HAPROXY variable in init script. + * Drop makefile patch, fix debian/rules accordingly. Drop build-dependancy + on quilt. + * Manpage now upstream. Ship upstream's and drop ours. + + -- Arnaud Cornet <acornet@debian.org> Tue, 01 Jan 2008 22:50:09 +0100 + +haproxy (1.3.12.dfsg2-1) unstable; urgency=low + + * New upstream bugfix release. + * Use new Homepage tag. + * Bump standards-version (no change needed). + * Add build-depend on quilt and add patch to allow proper CFLAGS passing to + make. + + -- Arnaud Cornet <acornet@debian.org> Tue, 25 Dec 2007 21:52:59 +0100 + +haproxy (1.3.12.dfsg-1) unstable; urgency=low + + * Initial release (Closes: #416397). + * The DFSG removes files with GPL-incompabitle license and adds a + re-implementation by me. + + -- Arnaud Cornet <acornet@debian.org> Fri, 17 Aug 2007 09:33:41 +0200 diff --git a/debian/clean b/debian/clean new file mode 100644 index 0000000..8d9fe01 --- /dev/null +++ b/debian/clean @@ -0,0 +1,3 @@ +doc/configuration.html +doc/intro.html +doc/management.html diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..5ce2aef --- /dev/null +++ b/debian/control @@ -0,0 +1,58 @@ +Source: haproxy +Section: net +Priority: optional +Maintainer: Debian HAProxy Maintainers <team+haproxy@tracker.debian.org> +Uploaders: Apollon Oikonomopoulos <apoikos@debian.org>, + Prach Pongpanich <prach@debian.org>, + Vincent Bernat <bernat@debian.org> +Standards-Version: 4.4.1 +Build-Depends: debhelper-compat (= 12), + libpcre2-dev, + libssl-dev, + liblua5.3-dev, + libsystemd-dev [linux-any], + python3-sphinx, + libopentracing-c-wrapper-dev, + pkg-config +Build-Depends-Indep: python3, python3-mako +Homepage: http://www.haproxy.org/ +Vcs-Git: https://salsa.debian.org/haproxy-team/haproxy.git +Vcs-Browser: https://salsa.debian.org/haproxy-team/haproxy + +Package: haproxy +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, adduser, lsb-base (>= 3.0-6) +Pre-Depends: dpkg (>= 1.17.14), ${misc:Pre-Depends} +Suggests: vim-haproxy, haproxy-doc +Description: fast and reliable load balancing reverse proxy + HAProxy is a TCP/HTTP reverse proxy which is particularly suited for high + availability environments. It features connection persistence through HTTP + cookies, load balancing, header addition, modification, deletion both ways. It + has request blocking capabilities and provides interface to display server + status. + +Package: haproxy-doc +Section: doc +Architecture: all +Depends: ${misc:Depends}, libjs-bootstrap (<< 4), libjs-jquery, + ${sphinxdoc:Depends} +Pre-Depends: dpkg (>= 1.17.14) +Description: fast and reliable load balancing reverse proxy (HTML documentation) + HAProxy is a TCP/HTTP reverse proxy which is particularly suited for high + availability environments. It features connection persistence through HTTP + cookies, load balancing, header addition, modification, deletion both ways. It + has request blocking capabilities and provides interface to display server + status. + . + This package contains the HTML documentation for haproxy. + +Package: vim-haproxy +Architecture: all +Depends: ${misc:Depends} +Recommends: vim-addon-manager +Description: syntax highlighting for HAProxy configuration files + The vim-haproxy package provides filetype detection and syntax highlighting + for HAProxy configuration files. + . + As per the Debian vim policy, installed addons are not activated + automatically, but the "vim-addon-manager" tool can be used for this purpose. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..7eb0d9a --- /dev/null +++ b/debian/copyright @@ -0,0 +1,941 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: haproxy +Upstream-Contact: Willy Tarreau <w@1wt.eu> +Source: http://www.haproxy.org/ + +Files: * +Copyright: Copyright 2000-2021 Willy Tarreau <w@1wt.eu>. +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: .github/matrix.py +Copyright: 2020, Tim Duesterhus <tim@bastelstu.be> + 2019, Ilya Shipitsin <chipitsine@gmail.com> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: addons/51degrees/dummy/* +Copyright: 51Degrees Mobile Experts Limited. / 2019, 51Degrees Mobile Experts Limited, 5 Charlotte Close +License: MPL-2.0 +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: addons/ot/* +Copyright: 2017, 2020, HAProxy Technologies +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: addons/promex/service-prometheus.c +Copyright: 2018, 2019, Christopher Faulet <cfaulet@haproxy.com> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: addons/wurfl/dummy/* +Copyright: ScientiaMobile, Inc. +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: addons/wurfl/dummy/Makefile +Copyright: Copyright 2000-2021 Willy Tarreau <w@1wt.eu>. +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: admin/halog/fgets2.c +Copyright: 2000-2012, Willy Tarreau <w@1wt.eu> +License: LGPL-2.1 +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: admin/halog/halog.c +Copyright: 2000-2020, Willy Tarreau <w@1wt.eu> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: admin/iprange/* +Copyright: 2000-2021, Willy Tarreau <w@1wt.eu> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: admin/netsnmp-perl/* +Copyright: 2007-2010, Krzysztof Piotr Oledzki <ole@ans.pl> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: admin/release-estimator/release-estimator.py +Copyright: 2020, HAProxy Technologies, Daniel Corbett <dcorbett@haproxy.com> +License: GPL-3+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: admin/wireshark-dissectors/peers/packet-happp.c +Copyright: 2016, Frédéric Lécaille <flecaille@haproxy.com> + 1998, Gerald Combs +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: debian/* +Copyright: Copyright (C) 2007-2011, Arnaud Cornet <acornet@debian.org> + Copyright (C) 2011, Christo Buschek <crito@30loops.net> + Copyright (C) 2013, Prach Pongpanich <prachpub@gmail.com> + Copyright (C) 2013-2016, Apollon Oikonomopoulos <apoikos@debian.org> + Copyright (C) 2013-2016, Vincent Bernat <bernat@debian.org> +License: GPL-2 + +Files: debian/dconv/* +Copyright: 2012, Cyril Bonté +License: Apache-2.0 +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: debian/dconv/js/* +Copyright: 2013-2015, Twitter, Inc. and other contributors; Licensed MIT +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: debian/dconv/js/typeahead.bundle.js +Copyright: Copyright 2013-2015 Twitter, Inc. and other contributors +License: Expat + +Files: dev/base64/* +Copyright: 2009, 2010, Krzysztof Piotr Oledzki <ole@ans.pl> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: dev/tcploop/tcploop.c +Copyright: 2012-2017, Willy Tarreau <w@1wt.eu> +License: Expat +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: include/* +Copyright: 2000-2020, Willy Tarreau - w@1wt.eu +License: LGPL-2.1 + +Files: include/haproxy/api-t.h + include/haproxy/api.h + include/haproxy/buf-t.h + include/haproxy/buf.h + include/haproxy/bug.h + include/haproxy/initcall.h + include/haproxy/istbuf.h +Copyright: 2000-2020, Willy Tarreau - w@1wt.eu +License: Expat + +Files: include/haproxy/arg-t.h + include/haproxy/arg.h + include/haproxy/protobuf-t.h + include/haproxy/protobuf.h +Copyright: 2012, Willy Tarreau <w@1wt.eu> +License: LGPL-2.1 + +Files: include/haproxy/atomic.h + include/haproxy/thread-t.h + include/haproxy/thread.h +Copyright: 2020, Willy Tarreau - w@1wt.eu + 2017, Christopher Faulet - cfaulet@haproxy.com +License: LGPL-2.1 + +Files: include/haproxy/auth-t.h + include/haproxy/auth.h +Copyright: 2009, 2010, Krzysztof Piotr Oledzki <ole@ans.pl> +License: GPL-2+ + +Files: include/haproxy/base64.h + include/haproxy/signal-t.h + include/haproxy/signal.h + include/haproxy/uri_auth-t.h + include/haproxy/uri_auth.h +Copyright: 2000-2020, Willy Tarreau <w@1wt.eu> +License: GPL-2+ + +Files: include/haproxy/check-t.h +Copyright: 2008, 2009, Krzysztof Piotr Oledzki <ole@ans.pl> + 2000-2020, Willy Tarreau - w@1wt.eu +License: GPL-2+ + +Files: include/haproxy/compression-t.h +Copyright: 2012, Exceliance, David Du Colombier <dducolombier@exceliance.fr> +License: LGPL-2.1 + +Files: include/haproxy/compression.h +Copyright: 2012, (C) Exceliance, David Du Colombier <dducolombier@exceliance.fr> +License: LGPL-2.1 + +Files: include/haproxy/counters-t.h +Copyright: 2011-2014, Willy Tarreau <w@1wt.eu> + 2008, 2009, Krzysztof Piotr Oledzki <ole@ans.pl> +License: LGPL-2.1 + +Files: include/haproxy/dgram-t.h + include/haproxy/dgram.h + include/haproxy/dns-t.h + include/haproxy/fix-t.h + include/haproxy/fix.h + include/haproxy/mqtt-t.h + include/haproxy/mqtt.h + include/haproxy/resolvers-t.h + include/haproxy/resolvers.h +Copyright: 2014, 2020, Baptiste Assmann <bedis9@gmail.com> +License: LGPL-2.1 + +Files: include/haproxy/dict-t.h + include/haproxy/dict.h +Copyright: 2019, Frédéric Lécaille <flecaille@haproxy.com> +License: Expat + +Files: include/haproxy/dns.h +Copyright: 2020, HAProxy Technologies +License: LGPL-2.1 + +Files: include/haproxy/extcheck.h +Copyright: 2014, Horms Solutions Ltd, Simon Horman <horms@verge.net.au> + 2000-2009, 2020, Willy Tarreau <w@1wt.eu> +License: LGPL-2.1 + +Files: include/haproxy/fcgi-app-t.h + include/haproxy/fcgi-app.h + include/haproxy/fcgi.h + include/haproxy/h1_htx.h + include/haproxy/http_htx-t.h + include/haproxy/http_htx.h + include/haproxy/htx-t.h + include/haproxy/htx.h + include/haproxy/spoe-t.h + include/haproxy/spoe.h +Copyright: 2017-2019, HAProxy Technologies, Christopher Faulet <cfaulet@haproxy.com> +License: LGPL-2.1 + +Files: include/haproxy/filters-t.h + include/haproxy/filters.h + include/haproxy/flt_http_comp.h +Copyright: 2015, Qualys Inc., Christopher Faulet <cfaulet@qualys.com> +License: LGPL-2.1 + +Files: include/haproxy/h2.h +Copyright: 2017, HAProxy Technologies + 2000-2017, Willy Tarreau - w@1wt.eu +License: Expat + +Files: include/haproxy/hlua-t.h + include/haproxy/hlua.h + include/haproxy/hlua_fcn.h +Copyright: 2015, 2016, Thierry Fournier <tfournier@arpalert.org> +License: LGPL-2.1 + +Files: include/haproxy/hpack-dec.h + include/haproxy/hpack-enc.h + include/haproxy/hpack-huff.h + include/haproxy/hpack-tbl-t.h + include/haproxy/hpack-tbl.h + include/haproxy/http-hdr-t.h + include/haproxy/http-hdr.h +Copyright: 2017, HAProxy Technologies + 2014-2020, Willy Tarreau <willy@haproxy.org> +License: Expat + +Files: include/haproxy/mailers-t.h +Copyright: 2015, Horms Solutions Ltd., Simon Horman <horms@verge.net.au> + 2010, EXCELIANCE, Emeric Brun <ebrun@exceliance.fr> +License: LGPL-2.1 + +Files: include/haproxy/mailers.h +Copyright: 2020, Willy Tarreau <w@1wt.eu> + 2015, Horms Solutions Ltd., Simon Horman <horms@verge.net.au> + 2010, EXCELIANCE, Emeric Brun <ebrun@exceliance.fr> +License: LGPL-2.1 + +Files: include/haproxy/mworker-t.h + include/haproxy/mworker.h +Copyright: HAProxy Technologies 2019, - William Lallemand <wlallemand@haproxy.com> +License: GPL-2+ + +Files: include/haproxy/namespace-t.h + include/haproxy/namespace.h +Copyright: 2015-2020, Willy Tarreau + 2014, Tamas Kovacs, Sarkozi Laszlo, Krisztian Kovacs +License: LGPL-2.1 + +Files: include/haproxy/net_helper.h +Copyright: 2017-2020, Willy Tarreau + 2017, Olivier Houchard +License: Expat + +Files: include/haproxy/openssl-compat.h +Copyright: Copyright 2000-2013 Willy Tarreau - w@1wt.eu +License: LGPL-2.1 + +Files: include/haproxy/peers-t.h + include/haproxy/peers.h + include/haproxy/ssl_sock-t.h + include/haproxy/ssl_sock.h +Copyright: 2010, 2012, EXCELIANCE, Emeric Brun <ebrun@exceliance.fr> +License: LGPL-2.1 + +Files: include/haproxy/proto_quic.h + include/haproxy/quic_sock.h +Copyright: 2020, Frédéric Lécaille <flecaille@haproxy.com> +License: LGPL-2.1 + +Files: include/haproxy/proto_sockpair.h +Copyright: HAProxy Technologies - William Lallemand <wlallemand@haproxy.com> +License: LGPL-2.1 + +Files: include/haproxy/proto_udp.h + include/haproxy/quic_cc-t.h + include/haproxy/quic_cc.h + include/haproxy/quic_frame-t.h + include/haproxy/quic_frame.h + include/haproxy/quic_loss-t.h + include/haproxy/quic_loss.h + include/haproxy/xprt_quic-t.h + include/haproxy/xprt_quic.h +Copyright: 2019, 2020, HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com> +License: LGPL-2.1 + +Files: include/haproxy/qpack-tbl-t.h +Copyright: 2020, HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com> +License: Expat + +Files: include/haproxy/quic_tls-t.h + include/haproxy/quic_tls.h +Copyright: 2019, 2020, HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com> +License: GPL-2+ + +Files: include/haproxy/sample-t.h + include/haproxy/sample.h + include/haproxy/sample_data-t.h + include/haproxy/stick_table-t.h + include/haproxy/stick_table.h +Copyright: 2010, 2012, 2013, 2020, Willy Tarreau <w@1wt.eu> + 2009, 2010, EXCELIANCE, Emeric Brun <ebrun@exceliance.fr> +License: LGPL-2.1 + +Files: include/haproxy/shctx-t.h + include/haproxy/shctx.h +Copyright: 2011, 2012, EXCELIANCE +License: GPL-2+ + +Files: include/haproxy/ssl_ckch-t.h + include/haproxy/ssl_ckch.h + include/haproxy/ssl_crtlist-t.h + include/haproxy/ssl_crtlist.h +Copyright: 2020, HAProxy Technologies, William Lallemand <wlallemand@haproxy.com> +License: LGPL-2.1 + +Files: include/haproxy/ssl_utils.h +Copyright: 2020, HAProxy Technologies, William Lallemand <wlallemand@haproxy.com> + 2012, EXCELIANCE, Emeric Brun <ebrun@exceliance.fr> +License: LGPL-2.1 + +Files: include/haproxy/tcpcheck-t.h +Copyright: 2020, Gaetan Rivet <grive@u256.net> + 2020, Christopher Faulet <cfaulet@haproxy.com> + 2013, Baptiste Assmann <bedis9@gmail.com> + 2007-2010, Krzysztof Piotr Oledzki <ole@ans.pl> + 2000-2009, 2020, Willy Tarreau <w@1wt.eu> +License: GPL-2+ + +Files: include/haproxy/tcpcheck.h +Copyright: 2020, Gaetan Rivet <grive@u256.net> + 2020, Christopher Faulet <cfaulet@haproxy.com> + 2013, Baptiste Assmann <bedis9@gmail.com> + 2007-2010, Krzysztof Piotr Oledzki <ole@ans.pl> + 2000-2009, 2020, Willy Tarreau <w@1wt.eu> +License: LGPL-2.1 + +Files: include/haproxy/uri_normalizer-t.h + include/haproxy/uri_normalizer.h +Copyright: 2021, Tim Duesterhus <tim@bastelstu.be> +License: GPL-2+ + +Files: include/haproxy/vars-t.h + include/haproxy/vars.h +Copyright: 2015, Thierry FOURNIER <tfournier@arpalert.org> +License: LGPL-2.1 + +Files: include/haproxy/xref-t.h + include/haproxy/xref.h +Copyright: 2020, Willy Tarreau - w@1wt.eu + 2017, Thierry Fournier <thierry.fournier@ozon.io> +License: Expat + +Files: include/import/* +Copyright: 2002-2011, - Willy Tarreau <w@1wt.eu> +License: LGPL-2.1 + +Files: include/import/atomic-ops.h +Copyright: Copyright 2000-2013 Willy Tarreau - w@1wt.eu +License: LGPL-2.1 + +Files: include/import/eb32sctree.h +Copyright: 2002-2017, - Willy Tarreau <w@1wt.eu> +License: LGPL-2.1 + +Files: include/import/ist.h +Copyright: 2000-2020, Willy Tarreau - w@1wt.eu +License: Expat + +Files: include/import/lru.h + include/import/plock.h + include/import/slz.h +Copyright: 2012-2017, Willy Tarreau <w@1wt.eu> +License: Expat + +Files: include/import/mjson.h +Copyright: 2018-2020, Cesanta Software Limited +License: Expat + +Files: include/import/sha1.h +Copyright: 2009-2015, Linus Torvalds and others. +License: LGPL-2.1 + +Files: include/import/xxhash.h +Copyright: 2012-2020, Yann Collet +License: BSD-2-clause + +Files: src/* +Copyright: 2000-2020, Willy Tarreau <w@1wt.eu> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/action.c + src/fcgi-app.c + src/flt_spoe.c + src/h1_htx.c + src/http_ana.c + src/http_htx.c + src/htx.c + src/mux_fcgi.c + src/server_state.c +Copyright: 2016-2019, 2021, HAProxy Technologies, Christopher Faulet <cfaulet@haproxy.com> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/auth.c +Copyright: 2009, 2010, Krzysztof Piotr Oledzki <ole@ans.pl> +License: GPL-2+ + +Files: src/base64.c + src/server.c + src/stats.c +Copyright: 2007-2010, Krzysztof Piotr Oledzki <ole@ans.pl> + 2000-2012, Willy Tarreau <w@1wt.eu> +License: GPL-2+ + +Files: src/cache.c +Copyright: 2017, 2020, HAProxy Technologies +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/cfgparse-global.c + src/cfgparse-listen.c + src/dict.c + src/namespace.c + src/vars.c + src/version.c +Copyright: Copyright 2000-2015 Willy Tarreau <w@1wt.eu>. +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/cfgparse-ssl.c + src/ssl_sample.c + src/ssl_utils.c +Copyright: 2020, HAProxy Technologies, William Lallemand <wlallemand@haproxy.com> + 2012, EXCELIANCE, Emeric Brun <ebrun@exceliance.fr> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/check.c + src/cli.c +Copyright: 2007-2010, Krzysztof Piotr Oledzki <ole@ans.pl> + 2000-2012, Willy Tarreau <w@1wt.eu> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/compression.c +Copyright: 2012, Exceliance, David Du Colombier <dducolombier@exceliance.fr> +License: GPL-2+ + +Files: src/debug.c + src/haproxy.c + src/wdt.c +Copyright: 2000-2021, Willy Tarreau <willy@haproxy.org>. +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/dgram.c + src/fix.c + src/mqtt.c + src/resolvers.c +Copyright: 2014, 2020, Baptiste Assmann <bedis9@gmail.com> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/dns.c +Copyright: 2017, 2020, HAProxy Technologies +License: GPL-2+ + +Files: src/eb32sctree.c + src/eb32tree.c + src/eb64tree.c + src/ebimtree.c + src/ebistree.c + src/ebmbtree.c + src/ebpttree.c + src/ebsttree.c + src/ebtree.c +Copyright: 2002-2011, - Willy Tarreau <w@1wt.eu> +License: LGPL-2.1 +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/ev_evports.c +Copyright: 2018, Joyent, Inc. +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/extcheck.c +Copyright: 2014, Horms Solutions Ltd, Simon Horman <horms@verge.net.au> + 2000-2009, 2020, Willy Tarreau <w@1wt.eu> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/fcgi.c +Copyright: 2019, HAProxy Technologies, Christopher Faulet <cfaulet@haproxy.com> +License: Expat +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/filters.c + src/flt_http_comp.c + src/flt_trace.c +Copyright: 2015, Qualys Inc., Christopher Faulet <cfaulet@qualys.com> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/h2.c +Copyright: 2017, Willy Tarreau <w@1wt.eu> + 2017, HAProxy Technologies +License: Expat +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/hlua.c + src/hlua_fcn.c +Copyright: 2015, 2016, Thierry Fournier <tfournier@arpalert.org> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/hpack-dec.c + src/hpack-enc.c + src/hpack-huff.c + src/hpack-tbl.c +Copyright: 2017, HAProxy Technologies + 2014-2020, Willy Tarreau <willy@haproxy.org> +License: Expat +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/lru.c +Copyright: 2012-2017, Willy Tarreau <w@1wt.eu> +License: Expat + +Files: src/mailers.c +Copyright: 2020, Willy Tarreau <w@1wt.eu> + 2015, Horms Solutions Ltd, Simon Horman <horms@verge.net.au> +License: GPL-2+ + +Files: src/mjson.c +Copyright: 2018-2020, Cesanta Software Limited +License: Expat +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/mux_h1.c +Copyright: 2018, 2019, Christopher Faulet <cfaulet@haproxy.com> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/mworker-prog.c + src/proto_sockpair.c +Copyright: HAProxy Technologies - William Lallemand <wlallemand@haproxy.com> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/mworker.c +Copyright: HAProxy Technologies 2019, - William Lallemand <wlallemand@haproxy.com> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/peers.c + src/ssl_sock.c +Copyright: 2010, 2012, EXCELIANCE, Emeric Brun <ebrun@exceliance.fr> +License: GPL-2+ + +Files: src/proto_quic.c +Copyright: 2020, Frédéric Lécaille <flecaille@haproxy.com> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/proto_udp.c + src/quic_frame.c + src/quic_sock.c + src/xprt_quic.c +Copyright: 2019, 2020, HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/proto_uxdg.c +Copyright: 2020, HAProxy Technologies, Emeric Brun <ebrun@haproxy.com> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/qpack-tbl.c +Copyright: 2020, HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com> +License: Expat +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/quic_cc.c + src/quic_cc_newreno.c +Copyright: 2019, 2020, HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com> +License: LGPL-2.1 +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/ring.c + src/sink.c + src/trace.c +Copyright: 2000-2020, Willy Tarreau - w@1wt.eu +License: LGPL-2.1 +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/sample.c + src/stick_table.c +Copyright: 2010, 2012, Willy Tarreau <w@1wt.eu> + 2009, 2010, EXCELIANCE, Emeric Brun <ebrun@exceliance.fr> +License: GPL-2+ + +Files: src/sha1.c +Copyright: 2009-2015, Linus Torvalds and others. +License: LGPL-2.1 +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/shctx.c +Copyright: 2011, 2012, EXCELIANCE +License: GPL-2+ + +Files: src/slz.c +Copyright: 2012-2017, Willy Tarreau <w@1wt.eu> +License: Expat +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/ssl_ckch.c + src/ssl_crtlist.c +Copyright: 2020, HAProxy Technologies, William Lallemand <wlallemand@haproxy.com> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/tcpcheck.c +Copyright: 2020, Gaetan Rivet <grive@u256.net> + 2020, Christopher Faulet <cfaulet@haproxy.com> + 2013, Baptiste Assmann <bedis9@gmail.com> + 2007-2010, Krzysztof Piotr Oledzki <ole@ans.pl> + 2000-2009, 2020, Willy Tarreau <w@1wt.eu> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/thread.c +Copyright: 2017, Christopher Fauet - cfaulet@haproxy.com +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/uri_normalizer.c +Copyright: 2021, Tim Duesterhus <tim@bastelstu.be> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: src/xprt_handshake.c +Copyright: 2019, HAProxy Technologies, Olivier Houchard <ohouchard@haproxy.com> +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +Files: tests/exp/filltab25.c +Copyright: 2007, willy tarreau. +License: GPL-2+ +Comment: + An OpenSSL exception is present in the LICENSE file: "This program is + released under the GPL with the additional exemption that compiling, + linking, and/or using OpenSSL is allowed." + +License: Apache-2.0 + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + . + http://www.apache.org/licenses/LICENSE-2.0 + . + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + . + On Debian systems, the full text of the Apache License version 2.0 can be + found in the file `/usr/share/common-licenses/Apache-2.0'. + +License: BSD-2-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + . + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License: Expat + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + . + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +License: GPL-2 + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation. + . + On Debian systems, the complete text of the GNU General Public License, version + 2, can be found in /usr/share/common-licenses/GPL-2. + +License: GPL-2+ + This program is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later + version. + . + This program is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the GNU General Public License for more + details. + . + You should have received a copy of the GNU General Public + License along with this package; if not, write to the Free + Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301 USA + . + On Debian systems, the full text of the GNU General Public + License version 2 can be found in the file + `/usr/share/common-licenses/GPL-2'. + +License: GPL-3+ + This software is Copyright (c) 2020 by X. Ample. + . + This is free software, licensed under: + . + The GNU General Public License, Version 3, June 2007 + . + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 3 dated June, 2007, or (at + your option) any later version. + On Debian systems, the complete text of version 3 of the GNU General + Public License can be found in '/usr/share/common-licenses/GPL-3'. + +License: LGPL-2.1 + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + . + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + . + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the complete text of the GNU Lesser General Public License, + version 2.1, can be found in /usr/share/common-licenses/LGPL-2.1. + +License: MPL-2.0 + This software is Copyright (c) 2020 by X. Ample. + . + This is free software, licensed under: + . + Mozilla Public License Version 2.0 + . + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. + On Debian systems, the complete text of Mozilla Public License v 2.0 + can be found in '/usr/share/common-licenses/MPL-2.0'. diff --git a/debian/dconv/LICENSE b/debian/dconv/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/debian/dconv/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/debian/dconv/NOTICE b/debian/dconv/NOTICE new file mode 100644 index 0000000..c9575a7 --- /dev/null +++ b/debian/dconv/NOTICE @@ -0,0 +1,13 @@ +Copyright 2012 Cyril Bonté + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/debian/dconv/README.md b/debian/dconv/README.md new file mode 100644 index 0000000..4ca89b2 --- /dev/null +++ b/debian/dconv/README.md @@ -0,0 +1,21 @@ +# HAProxy Documentation Converter + +Made to convert the HAProxy documentation into HTML. + +More than HTML, the main goal is to provide easy navigation. + +## Documentations + +A bot periodically fetches last commits for HAProxy 1.4 and 1.5 to produce up-to-date documentations. + +Converted documentations are then stored online : +- HAProxy 1.4 Configuration Manual : [stable](http://cbonte.github.com/haproxy-dconv/configuration-1.4.html) / [snapshot](http://cbonte.github.com/haproxy-dconv/snapshot/configuration-1.4.html) +- HAProxy 1.5 Configuration Manual : [stable](http://cbonte.github.com/haproxy-dconv/configuration-1.5.html) / [snapshot](http://cbonte.github.com/haproxy-dconv/snapshot/configuration-1.5.html) +- HAProxy 1.6 Configuration Manual : [stable](http://cbonte.github.com/haproxy-dconv/configuration-1.6.html) / [snapshot](http://cbonte.github.com/haproxy-dconv/snapshot/configuration-1.6.html) + + +## Contribute + +The project now lives by itself, as it is sufficiently useable. But I'm sure we can do even better. +Feel free to report feature requests or to provide patches ! + diff --git a/debian/dconv/css/check.png b/debian/dconv/css/check.png Binary files differnew file mode 100644 index 0000000..a7fab32 --- /dev/null +++ b/debian/dconv/css/check.png diff --git a/debian/dconv/css/cross.png b/debian/dconv/css/cross.png Binary files differnew file mode 100644 index 0000000..24f5064 --- /dev/null +++ b/debian/dconv/css/cross.png diff --git a/debian/dconv/css/page.css b/debian/dconv/css/page.css new file mode 100644 index 0000000..b48fdd2 --- /dev/null +++ b/debian/dconv/css/page.css @@ -0,0 +1,223 @@ +/* Global Styles */ + +body { + margin-top: 50px; + background: #eee; +} + +a.anchor { + display: block; position: relative; top: -50px; visibility: hidden; +} + +/* ------------------------------- */ + +/* Wrappers */ + +/* ------------------------------- */ + +#wrapper { + width: 100%; +} + +#page-wrapper { + padding: 0 15px 50px; + width: 740px; + background-color: #fff; + margin-left: 250px; +} + +#sidebar { + position: fixed; + width: 250px; + top: 50px; + bottom: 0; + padding: 15px; + background: #f5f5f5; + border-right: 1px solid #ccc; +} + + +/* ------------------------------- */ + +/* Twitter typeahead.js */ + +/* ------------------------------- */ + +.twitter-typeahead { + width: 100%; +} +.typeahead, +.tt-query, +.tt-hint { + width: 100%; + padding: 8px 12px; + border: 2px solid #ccc; + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + border-radius: 8px; + outline: none; +} + +.typeahead { + background-color: #fff; +} + +.typeahead:focus { + border: 2px solid #0097cf; +} + +.tt-query { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.tt-hint { + color: #999 +} + +.tt-menu { + width: 100%; + margin-top: 4px; + padding: 8px 0; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + border-radius: 8px; + -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); + -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); + box-shadow: 0 5px 10px rgba(0,0,0,.2); +} + +.tt-suggestion { + padding: 3px 8px; + line-height: 24px; +} + +.tt-suggestion:hover { + cursor: pointer; + color: #fff; + background-color: #0097cf; +} + +.tt-suggestion.tt-cursor { + color: #fff; + background-color: #0097cf; + +} + +.tt-suggestion p { + margin: 0; +} + +#searchKeyword { + width: 100%; + margin: 0; +} + +#searchKeyword .tt-menu { + max-height: 300px; + overflow-y: auto; +} + +/* ------------------------------- */ + +/* Misc */ + +/* ------------------------------- */ + +.well-small ul { + padding: 0px; +} +.table th, +.table td.pagination-centered { + text-align: center; +} + +pre { + overflow: visible; /* Workaround for dropdown menus */ +} + +pre.text { + padding: 0; + font-size: 13px; + color: #000; + background: transparent; + border: none; + margin-bottom: 18px; +} +pre.arguments { + font-size: 13px; + color: #000; + background: transparent; +} + +.comment { + color: #888; +} +small, .small { + color: #888; +} +.level1 { + font-size: 125%; +} +.sublevels { + border-left: 1px solid #ccc; + padding-left: 10px; +} +.tab { + padding-left: 20px; +} +.keyword { + font-family: Menlo, Monaco, "Courier New", monospace; + white-space: pre; + background: #eee; + border-top: 1px solid #fff; + border-bottom: 1px solid #ccc; +} + +.label-see-also { + background-color: #999; +} +.label-disabled { + background-color: #ccc; +} +h5 { + text-decoration: underline; +} + +.example-desc { + border-bottom: 1px solid #ccc; + margin-bottom: 18px; +} +.noheight { + min-height: 0 !important; +} +.separator { + margin-bottom: 18px; +} + +div { + word-wrap: break-word; +} + +html, body { + width: 100%; + min-height: 100%: +} + +.dropdown-menu > li { + white-space: nowrap; +} +/* TEMPORARILY HACKS WHILE PRE TAGS ARE USED +-------------------------------------------------- */ + +h5, +.unpre, +.example-desc, +.dropdown-menu { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + white-space: normal; +} diff --git a/debian/dconv/haproxy-dconv.py b/debian/dconv/haproxy-dconv.py new file mode 100755 index 0000000..ec800cf --- /dev/null +++ b/debian/dconv/haproxy-dconv.py @@ -0,0 +1,534 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright 2012 Cyril Bonté +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +''' +TODO : ability to split chapters into several files +TODO : manage keyword locality (server/proxy/global ; ex : maxconn) +TODO : Remove global variables where possible +''' +import os +import subprocess +import sys +import html +import re +import time +import datetime + +from optparse import OptionParser + +from mako.template import Template +from mako.lookup import TemplateLookup +from mako.exceptions import TopLevelLookupException + +from parser import PContext +from parser import remove_indent +from parser import * + +from urllib.parse import quote + +VERSION = "" +HAPROXY_GIT_VERSION = False + +def main(): + global VERSION, HAPROXY_GIT_VERSION + + usage="Usage: %prog --infile <infile> --outfile <outfile>" + + optparser = OptionParser(description='Generate HTML Document from HAProxy configuation.txt', + version=VERSION, + usage=usage) + optparser.add_option('--infile', '-i', help='Input file mostly the configuration.txt') + optparser.add_option('--outfile','-o', help='Output file') + optparser.add_option('--base','-b', default = '', help='Base directory for relative links') + (option, args) = optparser.parse_args() + + if not (option.infile and option.outfile) or len(args) > 0: + optparser.print_help() + exit(1) + + option.infile = os.path.abspath(option.infile) + option.outfile = os.path.abspath(option.outfile) + + os.chdir(os.path.dirname(__file__)) + + VERSION = get_git_version() + if not VERSION: + sys.exit(1) + + HAPROXY_GIT_VERSION = get_haproxy_git_version(os.path.dirname(option.infile)) + + convert(option.infile, option.outfile, option.base) + + +# Temporarily determine the version from git to follow which commit generated +# the documentation +def get_git_version(): + if not os.path.isdir(".git"): + print("This does not appear to be a Git repository.", file=sys.stderr) + return + try: + p = subprocess.Popen(["git", "describe", "--tags", "--match", "v*"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + except EnvironmentError: + print("Unable to run git", file=sys.stderr) + return + version = p.communicate()[0] + if p.returncode != 0: + print("Unable to run git", file=sys.stderr) + return + + if len(version) < 2: + return + + version = version[1:].strip() + version = re.sub(r'-g.*', '', version) + return version + +def get_haproxy_git_version(path): + try: + p = subprocess.Popen(["git", "describe", "--tags", "--match", "v*"], cwd=path, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + except EnvironmentError: + return False + version = p.communicate()[0] + + if p.returncode != 0: + return False + + if len(version) < 2: + return False + + version = version[1:].strip() + version = re.sub(r'-g.*', '', version) + return version + +def getTitleDetails(string): + array = string.split(".") + + title = array.pop().strip() + chapter = ".".join(array) + level = max(1, len(array)) + if array: + toplevel = array[0] + else: + toplevel = False + + return { + "title" : title, + "chapter" : chapter, + "level" : level, + "toplevel": toplevel + } + +# Parse the whole document to insert links on keywords +def createLinks(): + global document, keywords, keywordsCount, keyword_conflicts, chapters + + print("Generating keywords links...", file=sys.stderr) + + delimiters = [ + dict(start='"', end='"', multi=True ), + dict(start='- ' , end='\n' , multi=False), + ] + + for keyword in keywords: + keywordsCount[keyword] = 0 + for delimiter in delimiters: + keywordsCount[keyword] += document.count(delimiter['start'] + keyword + delimiter['end']) + if (keyword in keyword_conflicts) and (not keywordsCount[keyword]): + # The keyword is never used, we can remove it from the conflicts list + del keyword_conflicts[keyword] + + if keyword in keyword_conflicts: + chapter_list = "" + for chapter in keyword_conflicts[keyword]: + chapter_list += '<li><a href="#%s">%s</a></li>' % (quote("%s (%s)" % (keyword, chapters[chapter]['title'])), chapters[chapter]['title']) + for delimiter in delimiters: + if delimiter['multi']: + document = document.replace(delimiter['start'] + keyword + delimiter['end'], + delimiter['start'] + '<span class="dropdown">' + + '<a class="dropdown-toggle" data-toggle="dropdown" href="#">' + + keyword + + '<span class="caret"></span>' + + '</a>' + + '<ul class="dropdown-menu">' + + '<li class="dropdown-header">This keyword is available in sections :</li>' + + chapter_list + + '</ul>' + + '</span>' + delimiter['end']) + else: + document = document.replace(delimiter['start'] + keyword + delimiter['end'], delimiter['start'] + '<a href="#' + quote(keyword) + '">' + keyword + '</a>' + delimiter['end']) + else: + for delimiter in delimiters: + document = document.replace(delimiter['start'] + keyword + delimiter['end'], delimiter['start'] + '<a href="#' + quote(keyword) + '">' + keyword + '</a>' + delimiter['end']) + if keyword.startswith("option "): + shortKeyword = keyword[len("option "):] + keywordsCount[shortKeyword] = 0 + for delimiter in delimiters: + keywordsCount[keyword] += document.count(delimiter['start'] + shortKeyword + delimiter['end']) + if (shortKeyword in keyword_conflicts) and (not keywordsCount[shortKeyword]): + # The keyword is never used, we can remove it from the conflicts list + del keyword_conflicts[shortKeyword] + for delimiter in delimiters: + document = document.replace(delimiter['start'] + shortKeyword + delimiter['start'], delimiter['start'] + '<a href="#' + quote(keyword) + '">' + shortKeyword + '</a>' + delimiter['end']) + +def documentAppend(text, retline = True): + global document + document += text + if retline: + document += "\n" + +def init_parsers(pctxt): + return [ + underline.Parser(pctxt), + arguments.Parser(pctxt), + seealso.Parser(pctxt), + example.Parser(pctxt), + table.Parser(pctxt), + underline.Parser(pctxt), + keyword.Parser(pctxt), + ] + +# The parser itself +def convert(infile, outfile, base=''): + global document, keywords, keywordsCount, chapters, keyword_conflicts + + if len(base) > 0 and base[:-1] != '/': + base += '/' + + hasSummary = False + + data = [] + fd = open(infile,"r") + for line in fd: + line.replace("\t", " " * 8) + line = line.rstrip() + data.append(line) + fd.close() + + pctxt = PContext( + TemplateLookup( + directories=[ + 'templates' + ] + ) + ) + + parsers = init_parsers(pctxt) + + pctxt.context = { + 'headers': {}, + 'document': "", + 'base': base, + } + + sections = [] + currentSection = { + "details": getTitleDetails(""), + "content": "", + } + + chapters = {} + + keywords = {} + keywordsCount = {} + + specialSections = { + "default": { + "hasKeywords": True, + }, + "4.1": { + "hasKeywords": True, + }, + } + + pctxt.keywords = keywords + pctxt.keywordsCount = keywordsCount + pctxt.chapters = chapters + + print("Importing %s..." % infile, file=sys.stderr) + + nblines = len(data) + i = j = 0 + while i < nblines: + line = data[i].rstrip() + if i < nblines - 1: + next = data[i + 1].rstrip() + else: + next = "" + if (line == "Summary" or re.match("^[0-9].*", line)) and (len(next) > 0) and (next[0] == '-') \ + and ("-" * len(line)).startswith(next): # Fuzzy underline length detection + sections.append(currentSection) + currentSection = { + "details": getTitleDetails(line), + "content": "", + } + j = 0 + i += 1 # Skip underline + while not data[i + 1].rstrip(): + i += 1 # Skip empty lines + + else: + if len(line) > 80: + print("Line `%i' exceeds 80 columns" % (i + 1), file=sys.stderr) + + currentSection["content"] = currentSection["content"] + line + "\n" + j += 1 + if currentSection["details"]["title"] == "Summary" and line != "": + hasSummary = True + # Learn chapters from the summary + details = getTitleDetails(line) + if details["chapter"]: + chapters[details["chapter"]] = details + i += 1 + sections.append(currentSection) + + chapterIndexes = sorted(chapters.keys()) + + document = "" + + # Complete the summary + for section in sections: + details = section["details"] + title = details["title"] + if title: + fulltitle = title + if details["chapter"]: + #documentAppend("<a name=\"%s\"></a>" % details["chapter"]) + fulltitle = details["chapter"] + ". " + title + if not details["chapter"] in chapters: + print("Adding '%s' to the summary" % details["title"], file=sys.stderr) + chapters[details["chapter"]] = details + chapterIndexes = sorted(chapters.keys()) + + for section in sections: + details = section["details"] + pctxt.details = details + level = details["level"] + title = details["title"] + content = section["content"].rstrip() + + print("Parsing chapter %s..." % title, file=sys.stderr) + + if (title == "Summary") or (title and not hasSummary): + summaryTemplate = pctxt.templates.get_template('summary.html') + documentAppend(summaryTemplate.render( + pctxt = pctxt, + chapters = chapters, + chapterIndexes = chapterIndexes, + )) + if title and not hasSummary: + hasSummary = True + else: + continue + + if title: + documentAppend('<a class="anchor" id="%s" name="%s"></a>' % (details["chapter"], details["chapter"])) + if level == 1: + documentAppend("<div class=\"page-header\">", False) + documentAppend('<h%d id="chapter-%s" data-target="%s"><small><a class="small" href="#%s">%s.</a></small> %s</h%d>' % (level, details["chapter"], details["chapter"], details["chapter"], details["chapter"], html.escape(title, True), level)) + if level == 1: + documentAppend("</div>", False) + + if content: + if False and title: + # Display a navigation bar + documentAppend('<ul class="well pager">') + documentAppend('<li><a href="#top">Top</a></li>', False) + index = chapterIndexes.index(details["chapter"]) + if index > 0: + documentAppend('<li class="previous"><a href="#%s">Previous</a></li>' % chapterIndexes[index - 1], False) + if index < len(chapterIndexes) - 1: + documentAppend('<li class="next"><a href="#%s">Next</a></li>' % chapterIndexes[index + 1], False) + documentAppend('</ul>', False) + content = html.escape(content, True) + content = re.sub(r'section ([0-9]+(.[0-9]+)*)', r'<a href="#\1">section \1</a>', content) + + pctxt.set_content(content) + + if not title: + lines = pctxt.get_lines() + pctxt.context['headers'] = { + 'title': '', + 'subtitle': '', + 'version': '', + 'author': '', + 'date': '' + } + if re.match("^-+$", pctxt.get_line().strip()): + # Try to analyze the header of the file, assuming it follows + # those rules : + # - it begins with a "separator line" (several '-' chars) + # - then the document title + # - an optional subtitle + # - a new separator line + # - the version + # - the author + # - the date + pctxt.next() + pctxt.context['headers']['title'] = pctxt.get_line().strip() + pctxt.next() + subtitle = "" + while not re.match("^-+$", pctxt.get_line().strip()): + subtitle += " " + pctxt.get_line().strip() + pctxt.next() + pctxt.context['headers']['subtitle'] += subtitle.strip() + if not pctxt.context['headers']['subtitle']: + # No subtitle, try to guess one from the title if it + # starts with the word "HAProxy" + if pctxt.context['headers']['title'].startswith('HAProxy '): + pctxt.context['headers']['subtitle'] = pctxt.context['headers']['title'][8:] + pctxt.context['headers']['title'] = 'HAProxy' + pctxt.next() + pctxt.context['headers']['version'] = pctxt.get_line().strip() + pctxt.next() + pctxt.context['headers']['author'] = pctxt.get_line().strip() + pctxt.next() + pctxt.context['headers']['date'] = pctxt.get_line().strip() + pctxt.next() + if HAPROXY_GIT_VERSION: + pctxt.context['headers']['version'] = 'version ' + HAPROXY_GIT_VERSION + + # Skip header lines + pctxt.eat_lines() + pctxt.eat_empty_lines() + + documentAppend('<div>', False) + + delay = [] + while pctxt.has_more_lines(): + try: + specialSection = specialSections[details["chapter"]] + except: + specialSection = specialSections["default"] + + line = pctxt.get_line() + if i < nblines - 1: + nextline = pctxt.get_line(1) + else: + nextline = "" + + oldline = line + pctxt.stop = False + for parser in parsers: + line = parser.parse(line) + if pctxt.stop: + break + if oldline == line: + # nothing has changed, + # delays the rendering + if delay or line != "": + delay.append(line) + pctxt.next() + elif pctxt.stop: + while delay and delay[-1].strip() == "": + del delay[-1] + if delay: + remove_indent(delay) + documentAppend('<pre class="text">%s\n</pre>' % "\n".join(delay), False) + delay = [] + documentAppend(line, False) + else: + while delay and delay[-1].strip() == "": + del delay[-1] + if delay: + remove_indent(delay) + documentAppend('<pre class="text">%s\n</pre>' % "\n".join(delay), False) + delay = [] + documentAppend(line, True) + pctxt.next() + + while delay and delay[-1].strip() == "": + del delay[-1] + if delay: + remove_indent(delay) + documentAppend('<pre class="text">%s\n</pre>' % "\n".join(delay), False) + delay = [] + documentAppend('</div>') + + if not hasSummary: + summaryTemplate = pctxt.templates.get_template('summary.html') + print(chapters) + document = summaryTemplate.render( + pctxt = pctxt, + chapters = chapters, + chapterIndexes = chapterIndexes, + ) + document + + + # Log warnings for keywords defined in several chapters + keyword_conflicts = {} + for keyword in keywords: + keyword_chapters = list(keywords[keyword]) + keyword_chapters.sort() + if len(keyword_chapters) > 1: + print('Multi section keyword : "%s" in chapters %s' % (keyword, list(keyword_chapters)), file=sys.stderr) + keyword_conflicts[keyword] = keyword_chapters + + keywords = list(keywords) + keywords.sort() + + createLinks() + + # Add the keywords conflicts to the keywords list to make them available in the search form + # And remove the original keyword which is now useless + for keyword in keyword_conflicts: + sections = keyword_conflicts[keyword] + offset = keywords.index(keyword) + for section in sections: + keywords.insert(offset, "%s (%s)" % (keyword, chapters[section]['title'])) + offset += 1 + keywords.remove(keyword) + + print("Exporting to %s..." % outfile, file=sys.stderr) + + template = pctxt.templates.get_template('template.html') + try: + footerTemplate = pctxt.templates.get_template('footer.html') + footer = footerTemplate.render( + pctxt = pctxt, + headers = pctxt.context['headers'], + document = document, + chapters = chapters, + chapterIndexes = chapterIndexes, + keywords = keywords, + keywordsCount = keywordsCount, + keyword_conflicts = keyword_conflicts, + version = VERSION, + date = datetime.datetime.now().strftime("%Y/%m/%d"), + ) + except TopLevelLookupException: + footer = "" + + fd = open(outfile,'w') + + print(template.render( + pctxt = pctxt, + headers = pctxt.context['headers'], + base = base, + document = document, + chapters = chapters, + chapterIndexes = chapterIndexes, + keywords = keywords, + keywordsCount = keywordsCount, + keyword_conflicts = keyword_conflicts, + version = VERSION, + date = datetime.datetime.now().strftime("%Y/%m/%d"), + footer = footer + ), file=fd) + fd.close() + +if __name__ == '__main__': + main() diff --git a/debian/dconv/img/logo-med.png b/debian/dconv/img/logo-med.png Binary files differnew file mode 100644 index 0000000..1be03b2 --- /dev/null +++ b/debian/dconv/img/logo-med.png diff --git a/debian/dconv/js/typeahead.bundle.js b/debian/dconv/js/typeahead.bundle.js new file mode 100644 index 0000000..bb0c8ae --- /dev/null +++ b/debian/dconv/js/typeahead.bundle.js @@ -0,0 +1,2451 @@ +/*! + * typeahead.js 0.11.1 + * https://github.com/twitter/typeahead.js + * Copyright 2013-2015 Twitter, Inc. and other contributors; Licensed MIT + */ + +(function(root, factory) { + if (typeof define === "function" && define.amd) { + define("bloodhound", [ "jquery" ], function(a0) { + return root["Bloodhound"] = factory(a0); + }); + } else if (typeof exports === "object") { + module.exports = factory(require("jquery")); + } else { + root["Bloodhound"] = factory(jQuery); + } +})(this, function($) { + var _ = function() { + "use strict"; + return { + isMsie: function() { + return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false; + }, + isBlankString: function(str) { + return !str || /^\s*$/.test(str); + }, + escapeRegExChars: function(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + }, + isString: function(obj) { + return typeof obj === "string"; + }, + isNumber: function(obj) { + return typeof obj === "number"; + }, + isArray: $.isArray, + isFunction: $.isFunction, + isObject: $.isPlainObject, + isUndefined: function(obj) { + return typeof obj === "undefined"; + }, + isElement: function(obj) { + return !!(obj && obj.nodeType === 1); + }, + isJQuery: function(obj) { + return obj instanceof $; + }, + toStr: function toStr(s) { + return _.isUndefined(s) || s === null ? "" : s + ""; + }, + bind: $.proxy, + each: function(collection, cb) { + $.each(collection, reverseArgs); + function reverseArgs(index, value) { + return cb(value, index); + } + }, + map: $.map, + filter: $.grep, + every: function(obj, test) { + var result = true; + if (!obj) { + return result; + } + $.each(obj, function(key, val) { + if (!(result = test.call(null, val, key, obj))) { + return false; + } + }); + return !!result; + }, + some: function(obj, test) { + var result = false; + if (!obj) { + return result; + } + $.each(obj, function(key, val) { + if (result = test.call(null, val, key, obj)) { + return false; + } + }); + return !!result; + }, + mixin: $.extend, + identity: function(x) { + return x; + }, + clone: function(obj) { + return $.extend(true, {}, obj); + }, + getIdGenerator: function() { + var counter = 0; + return function() { + return counter++; + }; + }, + templatify: function templatify(obj) { + return $.isFunction(obj) ? obj : template; + function template() { + return String(obj); + } + }, + defer: function(fn) { + setTimeout(fn, 0); + }, + debounce: function(func, wait, immediate) { + var timeout, result; + return function() { + var context = this, args = arguments, later, callNow; + later = function() { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + } + }; + callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) { + result = func.apply(context, args); + } + return result; + }; + }, + throttle: function(func, wait) { + var context, args, timeout, result, previous, later; + previous = 0; + later = function() { + previous = new Date(); + timeout = null; + result = func.apply(context, args); + }; + return function() { + var now = new Date(), remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0) { + clearTimeout(timeout); + timeout = null; + previous = now; + result = func.apply(context, args); + } else if (!timeout) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }, + stringify: function(val) { + return _.isString(val) ? val : JSON.stringify(val); + }, + noop: function() {} + }; + }(); + var VERSION = "0.11.1"; + var tokenizers = function() { + "use strict"; + return { + nonword: nonword, + whitespace: whitespace, + obj: { + nonword: getObjTokenizer(nonword), + whitespace: getObjTokenizer(whitespace) + } + }; + function whitespace(str) { + str = _.toStr(str); + return str ? str.split(/\s+/) : []; + } + function nonword(str) { + str = _.toStr(str); + return str ? str.split(/\W+/) : []; + } + function getObjTokenizer(tokenizer) { + return function setKey(keys) { + keys = _.isArray(keys) ? keys : [].slice.call(arguments, 0); + return function tokenize(o) { + var tokens = []; + _.each(keys, function(k) { + tokens = tokens.concat(tokenizer(_.toStr(o[k]))); + }); + return tokens; + }; + }; + } + }(); + var LruCache = function() { + "use strict"; + function LruCache(maxSize) { + this.maxSize = _.isNumber(maxSize) ? maxSize : 100; + this.reset(); + if (this.maxSize <= 0) { + this.set = this.get = $.noop; + } + } + _.mixin(LruCache.prototype, { + set: function set(key, val) { + var tailItem = this.list.tail, node; + if (this.size >= this.maxSize) { + this.list.remove(tailItem); + delete this.hash[tailItem.key]; + this.size--; + } + if (node = this.hash[key]) { + node.val = val; + this.list.moveToFront(node); + } else { + node = new Node(key, val); + this.list.add(node); + this.hash[key] = node; + this.size++; + } + }, + get: function get(key) { + var node = this.hash[key]; + if (node) { + this.list.moveToFront(node); + return node.val; + } + }, + reset: function reset() { + this.size = 0; + this.hash = {}; + this.list = new List(); + } + }); + function List() { + this.head = this.tail = null; + } + _.mixin(List.prototype, { + add: function add(node) { + if (this.head) { + node.next = this.head; + this.head.prev = node; + } + this.head = node; + this.tail = this.tail || node; + }, + remove: function remove(node) { + node.prev ? node.prev.next = node.next : this.head = node.next; + node.next ? node.next.prev = node.prev : this.tail = node.prev; + }, + moveToFront: function(node) { + this.remove(node); + this.add(node); + } + }); + function Node(key, val) { + this.key = key; + this.val = val; + this.prev = this.next = null; + } + return LruCache; + }(); + var PersistentStorage = function() { + "use strict"; + var LOCAL_STORAGE; + try { + LOCAL_STORAGE = window.localStorage; + LOCAL_STORAGE.setItem("~~~", "!"); + LOCAL_STORAGE.removeItem("~~~"); + } catch (err) { + LOCAL_STORAGE = null; + } + function PersistentStorage(namespace, override) { + this.prefix = [ "__", namespace, "__" ].join(""); + this.ttlKey = "__ttl__"; + this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix)); + this.ls = override || LOCAL_STORAGE; + !this.ls && this._noop(); + } + _.mixin(PersistentStorage.prototype, { + _prefix: function(key) { + return this.prefix + key; + }, + _ttlKey: function(key) { + return this._prefix(key) + this.ttlKey; + }, + _noop: function() { + this.get = this.set = this.remove = this.clear = this.isExpired = _.noop; + }, + _safeSet: function(key, val) { + try { + this.ls.setItem(key, val); + } catch (err) { + if (err.name === "QuotaExceededError") { + this.clear(); + this._noop(); + } + } + }, + get: function(key) { + if (this.isExpired(key)) { + this.remove(key); + } + return decode(this.ls.getItem(this._prefix(key))); + }, + set: function(key, val, ttl) { + if (_.isNumber(ttl)) { + this._safeSet(this._ttlKey(key), encode(now() + ttl)); + } else { + this.ls.removeItem(this._ttlKey(key)); + } + return this._safeSet(this._prefix(key), encode(val)); + }, + remove: function(key) { + this.ls.removeItem(this._ttlKey(key)); + this.ls.removeItem(this._prefix(key)); + return this; + }, + clear: function() { + var i, keys = gatherMatchingKeys(this.keyMatcher); + for (i = keys.length; i--; ) { + this.remove(keys[i]); + } + return this; + }, + isExpired: function(key) { + var ttl = decode(this.ls.getItem(this._ttlKey(key))); + return _.isNumber(ttl) && now() > ttl ? true : false; + } + }); + return PersistentStorage; + function now() { + return new Date().getTime(); + } + function encode(val) { + return JSON.stringify(_.isUndefined(val) ? null : val); + } + function decode(val) { + return $.parseJSON(val); + } + function gatherMatchingKeys(keyMatcher) { + var i, key, keys = [], len = LOCAL_STORAGE.length; + for (i = 0; i < len; i++) { + if ((key = LOCAL_STORAGE.key(i)).match(keyMatcher)) { + keys.push(key.replace(keyMatcher, "")); + } + } + return keys; + } + }(); + var Transport = function() { + "use strict"; + var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, sharedCache = new LruCache(10); + function Transport(o) { + o = o || {}; + this.cancelled = false; + this.lastReq = null; + this._send = o.transport; + this._get = o.limiter ? o.limiter(this._get) : this._get; + this._cache = o.cache === false ? new LruCache(0) : sharedCache; + } + Transport.setMaxPendingRequests = function setMaxPendingRequests(num) { + maxPendingRequests = num; + }; + Transport.resetCache = function resetCache() { + sharedCache.reset(); + }; + _.mixin(Transport.prototype, { + _fingerprint: function fingerprint(o) { + o = o || {}; + return o.url + o.type + $.param(o.data || {}); + }, + _get: function(o, cb) { + var that = this, fingerprint, jqXhr; + fingerprint = this._fingerprint(o); + if (this.cancelled || fingerprint !== this.lastReq) { + return; + } + if (jqXhr = pendingRequests[fingerprint]) { + jqXhr.done(done).fail(fail); + } else if (pendingRequestsCount < maxPendingRequests) { + pendingRequestsCount++; + pendingRequests[fingerprint] = this._send(o).done(done).fail(fail).always(always); + } else { + this.onDeckRequestArgs = [].slice.call(arguments, 0); + } + function done(resp) { + cb(null, resp); + that._cache.set(fingerprint, resp); + } + function fail() { + cb(true); + } + function always() { + pendingRequestsCount--; + delete pendingRequests[fingerprint]; + if (that.onDeckRequestArgs) { + that._get.apply(that, that.onDeckRequestArgs); + that.onDeckRequestArgs = null; + } + } + }, + get: function(o, cb) { + var resp, fingerprint; + cb = cb || $.noop; + o = _.isString(o) ? { + url: o + } : o || {}; + fingerprint = this._fingerprint(o); + this.cancelled = false; + this.lastReq = fingerprint; + if (resp = this._cache.get(fingerprint)) { + cb(null, resp); + } else { + this._get(o, cb); + } + }, + cancel: function() { + this.cancelled = true; + } + }); + return Transport; + }(); + var SearchIndex = window.SearchIndex = function() { + "use strict"; + var CHILDREN = "c", IDS = "i"; + function SearchIndex(o) { + o = o || {}; + if (!o.datumTokenizer || !o.queryTokenizer) { + $.error("datumTokenizer and queryTokenizer are both required"); + } + this.identify = o.identify || _.stringify; + this.datumTokenizer = o.datumTokenizer; + this.queryTokenizer = o.queryTokenizer; + this.reset(); + } + _.mixin(SearchIndex.prototype, { + bootstrap: function bootstrap(o) { + this.datums = o.datums; + this.trie = o.trie; + }, + add: function(data) { + var that = this; + data = _.isArray(data) ? data : [ data ]; + _.each(data, function(datum) { + var id, tokens; + that.datums[id = that.identify(datum)] = datum; + tokens = normalizeTokens(that.datumTokenizer(datum)); + _.each(tokens, function(token) { + var node, chars, ch; + node = that.trie; + chars = token.split(""); + while (ch = chars.shift()) { + node = node[CHILDREN][ch] || (node[CHILDREN][ch] = newNode()); + node[IDS].push(id); + } + }); + }); + }, + get: function get(ids) { + var that = this; + return _.map(ids, function(id) { + return that.datums[id]; + }); + }, + search: function search(query) { + var that = this, tokens, matches; + tokens = normalizeTokens(this.queryTokenizer(query)); + _.each(tokens, function(token) { + var node, chars, ch, ids; + if (matches && matches.length === 0) { + return false; + } + node = that.trie; + chars = token.split(""); + while (node && (ch = chars.shift())) { + node = node[CHILDREN][ch]; + } + if (node && chars.length === 0) { + ids = node[IDS].slice(0); + matches = matches ? getIntersection(matches, ids) : ids; + } else { + matches = []; + return false; + } + }); + return matches ? _.map(unique(matches), function(id) { + return that.datums[id]; + }) : []; + }, + all: function all() { + var values = []; + for (var key in this.datums) { + values.push(this.datums[key]); + } + return values; + }, + reset: function reset() { + this.datums = {}; + this.trie = newNode(); + }, + serialize: function serialize() { + return { + datums: this.datums, + trie: this.trie + }; + } + }); + return SearchIndex; + function normalizeTokens(tokens) { + tokens = _.filter(tokens, function(token) { + return !!token; + }); + tokens = _.map(tokens, function(token) { + return token.toLowerCase(); + }); + return tokens; + } + function newNode() { + var node = {}; + node[IDS] = []; + node[CHILDREN] = {}; + return node; + } + function unique(array) { + var seen = {}, uniques = []; + for (var i = 0, len = array.length; i < len; i++) { + if (!seen[array[i]]) { + seen[array[i]] = true; + uniques.push(array[i]); + } + } + return uniques; + } + function getIntersection(arrayA, arrayB) { + var ai = 0, bi = 0, intersection = []; + arrayA = arrayA.sort(); + arrayB = arrayB.sort(); + var lenArrayA = arrayA.length, lenArrayB = arrayB.length; + while (ai < lenArrayA && bi < lenArrayB) { + if (arrayA[ai] < arrayB[bi]) { + ai++; + } else if (arrayA[ai] > arrayB[bi]) { + bi++; + } else { + intersection.push(arrayA[ai]); + ai++; + bi++; + } + } + return intersection; + } + }(); + var Prefetch = function() { + "use strict"; + var keys; + keys = { + data: "data", + protocol: "protocol", + thumbprint: "thumbprint" + }; + function Prefetch(o) { + this.url = o.url; + this.ttl = o.ttl; + this.cache = o.cache; + this.prepare = o.prepare; + this.transform = o.transform; + this.transport = o.transport; + this.thumbprint = o.thumbprint; + this.storage = new PersistentStorage(o.cacheKey); + } + _.mixin(Prefetch.prototype, { + _settings: function settings() { + return { + url: this.url, + type: "GET", + dataType: "json" + }; + }, + store: function store(data) { + if (!this.cache) { + return; + } + this.storage.set(keys.data, data, this.ttl); + this.storage.set(keys.protocol, location.protocol, this.ttl); + this.storage.set(keys.thumbprint, this.thumbprint, this.ttl); + }, + fromCache: function fromCache() { + var stored = {}, isExpired; + if (!this.cache) { + return null; + } + stored.data = this.storage.get(keys.data); + stored.protocol = this.storage.get(keys.protocol); + stored.thumbprint = this.storage.get(keys.thumbprint); + isExpired = stored.thumbprint !== this.thumbprint || stored.protocol !== location.protocol; + return stored.data && !isExpired ? stored.data : null; + }, + fromNetwork: function(cb) { + var that = this, settings; + if (!cb) { + return; + } + settings = this.prepare(this._settings()); + this.transport(settings).fail(onError).done(onResponse); + function onError() { + cb(true); + } + function onResponse(resp) { + cb(null, that.transform(resp)); + } + }, + clear: function clear() { + this.storage.clear(); + return this; + } + }); + return Prefetch; + }(); + var Remote = function() { + "use strict"; + function Remote(o) { + this.url = o.url; + this.prepare = o.prepare; + this.transform = o.transform; + this.transport = new Transport({ + cache: o.cache, + limiter: o.limiter, + transport: o.transport + }); + } + _.mixin(Remote.prototype, { + _settings: function settings() { + return { + url: this.url, + type: "GET", + dataType: "json" + }; + }, + get: function get(query, cb) { + var that = this, settings; + if (!cb) { + return; + } + query = query || ""; + settings = this.prepare(query, this._settings()); + return this.transport.get(settings, onResponse); + function onResponse(err, resp) { + err ? cb([]) : cb(that.transform(resp)); + } + }, + cancelLastRequest: function cancelLastRequest() { + this.transport.cancel(); + } + }); + return Remote; + }(); + var oParser = function() { + "use strict"; + return function parse(o) { + var defaults, sorter; + defaults = { + initialize: true, + identify: _.stringify, + datumTokenizer: null, + queryTokenizer: null, + sufficient: 5, + sorter: null, + local: [], + prefetch: null, + remote: null + }; + o = _.mixin(defaults, o || {}); + !o.datumTokenizer && $.error("datumTokenizer is required"); + !o.queryTokenizer && $.error("queryTokenizer is required"); + sorter = o.sorter; + o.sorter = sorter ? function(x) { + return x.sort(sorter); + } : _.identity; + o.local = _.isFunction(o.local) ? o.local() : o.local; + o.prefetch = parsePrefetch(o.prefetch); + o.remote = parseRemote(o.remote); + return o; + }; + function parsePrefetch(o) { + var defaults; + if (!o) { + return null; + } + defaults = { + url: null, + ttl: 24 * 60 * 60 * 1e3, + cache: true, + cacheKey: null, + thumbprint: "", + prepare: _.identity, + transform: _.identity, + transport: null + }; + o = _.isString(o) ? { + url: o + } : o; + o = _.mixin(defaults, o); + !o.url && $.error("prefetch requires url to be set"); + o.transform = o.filter || o.transform; + o.cacheKey = o.cacheKey || o.url; + o.thumbprint = VERSION + o.thumbprint; + o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax; + return o; + } + function parseRemote(o) { + var defaults; + if (!o) { + return; + } + defaults = { + url: null, + cache: true, + prepare: null, + replace: null, + wildcard: null, + limiter: null, + rateLimitBy: "debounce", + rateLimitWait: 300, + transform: _.identity, + transport: null + }; + o = _.isString(o) ? { + url: o + } : o; + o = _.mixin(defaults, o); + !o.url && $.error("remote requires url to be set"); + o.transform = o.filter || o.transform; + o.prepare = toRemotePrepare(o); + o.limiter = toLimiter(o); + o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax; + delete o.replace; + delete o.wildcard; + delete o.rateLimitBy; + delete o.rateLimitWait; + return o; + } + function toRemotePrepare(o) { + var prepare, replace, wildcard; + prepare = o.prepare; + replace = o.replace; + wildcard = o.wildcard; + if (prepare) { + return prepare; + } + if (replace) { + prepare = prepareByReplace; + } else if (o.wildcard) { + prepare = prepareByWildcard; + } else { + prepare = idenityPrepare; + } + return prepare; + function prepareByReplace(query, settings) { + settings.url = replace(settings.url, query); + return settings; + } + function prepareByWildcard(query, settings) { + settings.url = settings.url.replace(wildcard, encodeURIComponent(query)); + return settings; + } + function idenityPrepare(query, settings) { + return settings; + } + } + function toLimiter(o) { + var limiter, method, wait; + limiter = o.limiter; + method = o.rateLimitBy; + wait = o.rateLimitWait; + if (!limiter) { + limiter = /^throttle$/i.test(method) ? throttle(wait) : debounce(wait); + } + return limiter; + function debounce(wait) { + return function debounce(fn) { + return _.debounce(fn, wait); + }; + } + function throttle(wait) { + return function throttle(fn) { + return _.throttle(fn, wait); + }; + } + } + function callbackToDeferred(fn) { + return function wrapper(o) { + var deferred = $.Deferred(); + fn(o, onSuccess, onError); + return deferred; + function onSuccess(resp) { + _.defer(function() { + deferred.resolve(resp); + }); + } + function onError(err) { + _.defer(function() { + deferred.reject(err); + }); + } + }; + } + }(); + var Bloodhound = function() { + "use strict"; + var old; + old = window && window.Bloodhound; + function Bloodhound(o) { + o = oParser(o); + this.sorter = o.sorter; + this.identify = o.identify; + this.sufficient = o.sufficient; + this.local = o.local; + this.remote = o.remote ? new Remote(o.remote) : null; + this.prefetch = o.prefetch ? new Prefetch(o.prefetch) : null; + this.index = new SearchIndex({ + identify: this.identify, + datumTokenizer: o.datumTokenizer, + queryTokenizer: o.queryTokenizer + }); + o.initialize !== false && this.initialize(); + } + Bloodhound.noConflict = function noConflict() { + window && (window.Bloodhound = old); + return Bloodhound; + }; + Bloodhound.tokenizers = tokenizers; + _.mixin(Bloodhound.prototype, { + __ttAdapter: function ttAdapter() { + var that = this; + return this.remote ? withAsync : withoutAsync; + function withAsync(query, sync, async) { + return that.search(query, sync, async); + } + function withoutAsync(query, sync) { + return that.search(query, sync); + } + }, + _loadPrefetch: function loadPrefetch() { + var that = this, deferred, serialized; + deferred = $.Deferred(); + if (!this.prefetch) { + deferred.resolve(); + } else if (serialized = this.prefetch.fromCache()) { + this.index.bootstrap(serialized); + deferred.resolve(); + } else { + this.prefetch.fromNetwork(done); + } + return deferred.promise(); + function done(err, data) { + if (err) { + return deferred.reject(); + } + that.add(data); + that.prefetch.store(that.index.serialize()); + deferred.resolve(); + } + }, + _initialize: function initialize() { + var that = this, deferred; + this.clear(); + (this.initPromise = this._loadPrefetch()).done(addLocalToIndex); + return this.initPromise; + function addLocalToIndex() { + that.add(that.local); + } + }, + initialize: function initialize(force) { + return !this.initPromise || force ? this._initialize() : this.initPromise; + }, + add: function add(data) { + this.index.add(data); + return this; + }, + get: function get(ids) { + ids = _.isArray(ids) ? ids : [].slice.call(arguments); + return this.index.get(ids); + }, + search: function search(query, sync, async) { + var that = this, local; + local = this.sorter(this.index.search(query)); + sync(this.remote ? local.slice() : local); + if (this.remote && local.length < this.sufficient) { + this.remote.get(query, processRemote); + } else if (this.remote) { + this.remote.cancelLastRequest(); + } + return this; + function processRemote(remote) { + var nonDuplicates = []; + _.each(remote, function(r) { + !_.some(local, function(l) { + return that.identify(r) === that.identify(l); + }) && nonDuplicates.push(r); + }); + async && async(nonDuplicates); + } + }, + all: function all() { + return this.index.all(); + }, + clear: function clear() { + this.index.reset(); + return this; + }, + clearPrefetchCache: function clearPrefetchCache() { + this.prefetch && this.prefetch.clear(); + return this; + }, + clearRemoteCache: function clearRemoteCache() { + Transport.resetCache(); + return this; + }, + ttAdapter: function ttAdapter() { + return this.__ttAdapter(); + } + }); + return Bloodhound; + }(); + return Bloodhound; +}); + +(function(root, factory) { + if (typeof define === "function" && define.amd) { + define("typeahead.js", [ "jquery" ], function(a0) { + return factory(a0); + }); + } else if (typeof exports === "object") { + module.exports = factory(require("jquery")); + } else { + factory(jQuery); + } +})(this, function($) { + var _ = function() { + "use strict"; + return { + isMsie: function() { + return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false; + }, + isBlankString: function(str) { + return !str || /^\s*$/.test(str); + }, + escapeRegExChars: function(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + }, + isString: function(obj) { + return typeof obj === "string"; + }, + isNumber: function(obj) { + return typeof obj === "number"; + }, + isArray: $.isArray, + isFunction: $.isFunction, + isObject: $.isPlainObject, + isUndefined: function(obj) { + return typeof obj === "undefined"; + }, + isElement: function(obj) { + return !!(obj && obj.nodeType === 1); + }, + isJQuery: function(obj) { + return obj instanceof $; + }, + toStr: function toStr(s) { + return _.isUndefined(s) || s === null ? "" : s + ""; + }, + bind: $.proxy, + each: function(collection, cb) { + $.each(collection, reverseArgs); + function reverseArgs(index, value) { + return cb(value, index); + } + }, + map: $.map, + filter: $.grep, + every: function(obj, test) { + var result = true; + if (!obj) { + return result; + } + $.each(obj, function(key, val) { + if (!(result = test.call(null, val, key, obj))) { + return false; + } + }); + return !!result; + }, + some: function(obj, test) { + var result = false; + if (!obj) { + return result; + } + $.each(obj, function(key, val) { + if (result = test.call(null, val, key, obj)) { + return false; + } + }); + return !!result; + }, + mixin: $.extend, + identity: function(x) { + return x; + }, + clone: function(obj) { + return $.extend(true, {}, obj); + }, + getIdGenerator: function() { + var counter = 0; + return function() { + return counter++; + }; + }, + templatify: function templatify(obj) { + return $.isFunction(obj) ? obj : template; + function template() { + return String(obj); + } + }, + defer: function(fn) { + setTimeout(fn, 0); + }, + debounce: function(func, wait, immediate) { + var timeout, result; + return function() { + var context = this, args = arguments, later, callNow; + later = function() { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + } + }; + callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) { + result = func.apply(context, args); + } + return result; + }; + }, + throttle: function(func, wait) { + var context, args, timeout, result, previous, later; + previous = 0; + later = function() { + previous = new Date(); + timeout = null; + result = func.apply(context, args); + }; + return function() { + var now = new Date(), remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0) { + clearTimeout(timeout); + timeout = null; + previous = now; + result = func.apply(context, args); + } else if (!timeout) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }, + stringify: function(val) { + return _.isString(val) ? val : JSON.stringify(val); + }, + noop: function() {} + }; + }(); + var WWW = function() { + "use strict"; + var defaultClassNames = { + wrapper: "twitter-typeahead", + input: "tt-input", + hint: "tt-hint", + menu: "tt-menu", + dataset: "tt-dataset", + suggestion: "tt-suggestion", + selectable: "tt-selectable", + empty: "tt-empty", + open: "tt-open", + cursor: "tt-cursor", + highlight: "tt-highlight" + }; + return build; + function build(o) { + var www, classes; + classes = _.mixin({}, defaultClassNames, o); + www = { + css: buildCss(), + classes: classes, + html: buildHtml(classes), + selectors: buildSelectors(classes) + }; + return { + css: www.css, + html: www.html, + classes: www.classes, + selectors: www.selectors, + mixin: function(o) { + _.mixin(o, www); + } + }; + } + function buildHtml(c) { + return { + wrapper: '<span class="' + c.wrapper + '"></span>', + menu: '<div class="' + c.menu + '"></div>' + }; + } + function buildSelectors(classes) { + var selectors = {}; + _.each(classes, function(v, k) { + selectors[k] = "." + v; + }); + return selectors; + } + function buildCss() { + var css = { + wrapper: { + position: "relative", + display: "inline-block" + }, + hint: { + position: "absolute", + top: "0", + left: "0", + borderColor: "transparent", + boxShadow: "none", + opacity: "1" + }, + input: { + position: "relative", + verticalAlign: "top", + backgroundColor: "transparent" + }, + inputWithNoHint: { + position: "relative", + verticalAlign: "top" + }, + menu: { + position: "absolute", + top: "100%", + left: "0", + zIndex: "100", + display: "none" + }, + ltr: { + left: "0", + right: "auto" + }, + rtl: { + left: "auto", + right: " 0" + } + }; + if (_.isMsie()) { + _.mixin(css.input, { + backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)" + }); + } + return css; + } + }(); + var EventBus = function() { + "use strict"; + var namespace, deprecationMap; + namespace = "typeahead:"; + deprecationMap = { + render: "rendered", + cursorchange: "cursorchanged", + select: "selected", + autocomplete: "autocompleted" + }; + function EventBus(o) { + if (!o || !o.el) { + $.error("EventBus initialized without el"); + } + this.$el = $(o.el); + } + _.mixin(EventBus.prototype, { + _trigger: function(type, args) { + var $e; + $e = $.Event(namespace + type); + (args = args || []).unshift($e); + this.$el.trigger.apply(this.$el, args); + return $e; + }, + before: function(type) { + var args, $e; + args = [].slice.call(arguments, 1); + $e = this._trigger("before" + type, args); + return $e.isDefaultPrevented(); + }, + trigger: function(type) { + var deprecatedType; + this._trigger(type, [].slice.call(arguments, 1)); + if (deprecatedType = deprecationMap[type]) { + this._trigger(deprecatedType, [].slice.call(arguments, 1)); + } + } + }); + return EventBus; + }(); + var EventEmitter = function() { + "use strict"; + var splitter = /\s+/, nextTick = getNextTick(); + return { + onSync: onSync, + onAsync: onAsync, + off: off, + trigger: trigger + }; + function on(method, types, cb, context) { + var type; + if (!cb) { + return this; + } + types = types.split(splitter); + cb = context ? bindContext(cb, context) : cb; + this._callbacks = this._callbacks || {}; + while (type = types.shift()) { + this._callbacks[type] = this._callbacks[type] || { + sync: [], + async: [] + }; + this._callbacks[type][method].push(cb); + } + return this; + } + function onAsync(types, cb, context) { + return on.call(this, "async", types, cb, context); + } + function onSync(types, cb, context) { + return on.call(this, "sync", types, cb, context); + } + function off(types) { + var type; + if (!this._callbacks) { + return this; + } + types = types.split(splitter); + while (type = types.shift()) { + delete this._callbacks[type]; + } + return this; + } + function trigger(types) { + var type, callbacks, args, syncFlush, asyncFlush; + if (!this._callbacks) { + return this; + } + types = types.split(splitter); + args = [].slice.call(arguments, 1); + while ((type = types.shift()) && (callbacks = this._callbacks[type])) { + syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args)); + asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args)); + syncFlush() && nextTick(asyncFlush); + } + return this; + } + function getFlush(callbacks, context, args) { + return flush; + function flush() { + var cancelled; + for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) { + cancelled = callbacks[i].apply(context, args) === false; + } + return !cancelled; + } + } + function getNextTick() { + var nextTickFn; + if (window.setImmediate) { + nextTickFn = function nextTickSetImmediate(fn) { + setImmediate(function() { + fn(); + }); + }; + } else { + nextTickFn = function nextTickSetTimeout(fn) { + setTimeout(function() { + fn(); + }, 0); + }; + } + return nextTickFn; + } + function bindContext(fn, context) { + return fn.bind ? fn.bind(context) : function() { + fn.apply(context, [].slice.call(arguments, 0)); + }; + } + }(); + var highlight = function(doc) { + "use strict"; + var defaults = { + node: null, + pattern: null, + tagName: "strong", + className: null, + wordsOnly: false, + caseSensitive: false + }; + return function hightlight(o) { + var regex; + o = _.mixin({}, defaults, o); + if (!o.node || !o.pattern) { + return; + } + o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ]; + regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly); + traverse(o.node, hightlightTextNode); + function hightlightTextNode(textNode) { + var match, patternNode, wrapperNode; + if (match = regex.exec(textNode.data)) { + wrapperNode = doc.createElement(o.tagName); + o.className && (wrapperNode.className = o.className); + patternNode = textNode.splitText(match.index); + patternNode.splitText(match[0].length); + wrapperNode.appendChild(patternNode.cloneNode(true)); + textNode.parentNode.replaceChild(wrapperNode, patternNode); + } + return !!match; + } + function traverse(el, hightlightTextNode) { + var childNode, TEXT_NODE_TYPE = 3; + for (var i = 0; i < el.childNodes.length; i++) { + childNode = el.childNodes[i]; + if (childNode.nodeType === TEXT_NODE_TYPE) { + i += hightlightTextNode(childNode) ? 1 : 0; + } else { + traverse(childNode, hightlightTextNode); + } + } + } + }; + function getRegex(patterns, caseSensitive, wordsOnly) { + var escapedPatterns = [], regexStr; + for (var i = 0, len = patterns.length; i < len; i++) { + escapedPatterns.push(_.escapeRegExChars(patterns[i])); + } + regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")"; + return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i"); + } + }(window.document); + var Input = function() { + "use strict"; + var specialKeyCodeMap; + specialKeyCodeMap = { + 9: "tab", + 27: "esc", + 37: "left", + 39: "right", + 13: "enter", + 38: "up", + 40: "down" + }; + function Input(o, www) { + o = o || {}; + if (!o.input) { + $.error("input is missing"); + } + www.mixin(this); + this.$hint = $(o.hint); + this.$input = $(o.input); + this.query = this.$input.val(); + this.queryWhenFocused = this.hasFocus() ? this.query : null; + this.$overflowHelper = buildOverflowHelper(this.$input); + this._checkLanguageDirection(); + if (this.$hint.length === 0) { + this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop; + } + } + Input.normalizeQuery = function(str) { + return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " "); + }; + _.mixin(Input.prototype, EventEmitter, { + _onBlur: function onBlur() { + this.resetInputValue(); + this.trigger("blurred"); + }, + _onFocus: function onFocus() { + this.queryWhenFocused = this.query; + this.trigger("focused"); + }, + _onKeydown: function onKeydown($e) { + var keyName = specialKeyCodeMap[$e.which || $e.keyCode]; + this._managePreventDefault(keyName, $e); + if (keyName && this._shouldTrigger(keyName, $e)) { + this.trigger(keyName + "Keyed", $e); + } + }, + _onInput: function onInput() { + this._setQuery(this.getInputValue()); + this.clearHintIfInvalid(); + this._checkLanguageDirection(); + }, + _managePreventDefault: function managePreventDefault(keyName, $e) { + var preventDefault; + switch (keyName) { + case "up": + case "down": + preventDefault = !withModifier($e); + break; + + default: + preventDefault = false; + } + preventDefault && $e.preventDefault(); + }, + _shouldTrigger: function shouldTrigger(keyName, $e) { + var trigger; + switch (keyName) { + case "tab": + trigger = !withModifier($e); + break; + + default: + trigger = true; + } + return trigger; + }, + _checkLanguageDirection: function checkLanguageDirection() { + var dir = (this.$input.css("direction") || "ltr").toLowerCase(); + if (this.dir !== dir) { + this.dir = dir; + this.$hint.attr("dir", dir); + this.trigger("langDirChanged", dir); + } + }, + _setQuery: function setQuery(val, silent) { + var areEquivalent, hasDifferentWhitespace; + areEquivalent = areQueriesEquivalent(val, this.query); + hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false; + this.query = val; + if (!silent && !areEquivalent) { + this.trigger("queryChanged", this.query); + } else if (!silent && hasDifferentWhitespace) { + this.trigger("whitespaceChanged", this.query); + } + }, + bind: function() { + var that = this, onBlur, onFocus, onKeydown, onInput; + onBlur = _.bind(this._onBlur, this); + onFocus = _.bind(this._onFocus, this); + onKeydown = _.bind(this._onKeydown, this); + onInput = _.bind(this._onInput, this); + this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown); + if (!_.isMsie() || _.isMsie() > 9) { + this.$input.on("input.tt", onInput); + } else { + this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) { + if (specialKeyCodeMap[$e.which || $e.keyCode]) { + return; + } + _.defer(_.bind(that._onInput, that, $e)); + }); + } + return this; + }, + focus: function focus() { + this.$input.focus(); + }, + blur: function blur() { + this.$input.blur(); + }, + getLangDir: function getLangDir() { + return this.dir; + }, + getQuery: function getQuery() { + return this.query || ""; + }, + setQuery: function setQuery(val, silent) { + this.setInputValue(val); + this._setQuery(val, silent); + }, + hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() { + return this.query !== this.queryWhenFocused; + }, + getInputValue: function getInputValue() { + return this.$input.val(); + }, + setInputValue: function setInputValue(value) { + this.$input.val(value); + this.clearHintIfInvalid(); + this._checkLanguageDirection(); + }, + resetInputValue: function resetInputValue() { + this.setInputValue(this.query); + }, + getHint: function getHint() { + return this.$hint.val(); + }, + setHint: function setHint(value) { + this.$hint.val(value); + }, + clearHint: function clearHint() { + this.setHint(""); + }, + clearHintIfInvalid: function clearHintIfInvalid() { + var val, hint, valIsPrefixOfHint, isValid; + val = this.getInputValue(); + hint = this.getHint(); + valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0; + isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow(); + !isValid && this.clearHint(); + }, + hasFocus: function hasFocus() { + return this.$input.is(":focus"); + }, + hasOverflow: function hasOverflow() { + var constraint = this.$input.width() - 2; + this.$overflowHelper.text(this.getInputValue()); + return this.$overflowHelper.width() >= constraint; + }, + isCursorAtEnd: function() { + var valueLength, selectionStart, range; + valueLength = this.$input.val().length; + selectionStart = this.$input[0].selectionStart; + if (_.isNumber(selectionStart)) { + return selectionStart === valueLength; + } else if (document.selection) { + range = document.selection.createRange(); + range.moveStart("character", -valueLength); + return valueLength === range.text.length; + } + return true; + }, + destroy: function destroy() { + this.$hint.off(".tt"); + this.$input.off(".tt"); + this.$overflowHelper.remove(); + this.$hint = this.$input = this.$overflowHelper = $("<div>"); + } + }); + return Input; + function buildOverflowHelper($input) { + return $('<pre aria-hidden="true"></pre>').css({ + position: "absolute", + visibility: "hidden", + whiteSpace: "pre", + fontFamily: $input.css("font-family"), + fontSize: $input.css("font-size"), + fontStyle: $input.css("font-style"), + fontVariant: $input.css("font-variant"), + fontWeight: $input.css("font-weight"), + wordSpacing: $input.css("word-spacing"), + letterSpacing: $input.css("letter-spacing"), + textIndent: $input.css("text-indent"), + textRendering: $input.css("text-rendering"), + textTransform: $input.css("text-transform") + }).insertAfter($input); + } + function areQueriesEquivalent(a, b) { + return Input.normalizeQuery(a) === Input.normalizeQuery(b); + } + function withModifier($e) { + return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey; + } + }(); + var Dataset = function() { + "use strict"; + var keys, nameGenerator; + keys = { + val: "tt-selectable-display", + obj: "tt-selectable-object" + }; + nameGenerator = _.getIdGenerator(); + function Dataset(o, www) { + o = o || {}; + o.templates = o.templates || {}; + o.templates.notFound = o.templates.notFound || o.templates.empty; + if (!o.source) { + $.error("missing source"); + } + if (!o.node) { + $.error("missing node"); + } + if (o.name && !isValidName(o.name)) { + $.error("invalid dataset name: " + o.name); + } + www.mixin(this); + this.highlight = !!o.highlight; + this.name = o.name || nameGenerator(); + this.limit = o.limit || 5; + this.displayFn = getDisplayFn(o.display || o.displayKey); + this.templates = getTemplates(o.templates, this.displayFn); + this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source; + this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async; + this._resetLastSuggestion(); + this.$el = $(o.node).addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name); + } + Dataset.extractData = function extractData(el) { + var $el = $(el); + if ($el.data(keys.obj)) { + return { + val: $el.data(keys.val) || "", + obj: $el.data(keys.obj) || null + }; + } + return null; + }; + _.mixin(Dataset.prototype, EventEmitter, { + _overwrite: function overwrite(query, suggestions) { + suggestions = suggestions || []; + if (suggestions.length) { + this._renderSuggestions(query, suggestions); + } else if (this.async && this.templates.pending) { + this._renderPending(query); + } else if (!this.async && this.templates.notFound) { + this._renderNotFound(query); + } else { + this._empty(); + } + this.trigger("rendered", this.name, suggestions, false); + }, + _append: function append(query, suggestions) { + suggestions = suggestions || []; + if (suggestions.length && this.$lastSuggestion.length) { + this._appendSuggestions(query, suggestions); + } else if (suggestions.length) { + this._renderSuggestions(query, suggestions); + } else if (!this.$lastSuggestion.length && this.templates.notFound) { + this._renderNotFound(query); + } + this.trigger("rendered", this.name, suggestions, true); + }, + _renderSuggestions: function renderSuggestions(query, suggestions) { + var $fragment; + $fragment = this._getSuggestionsFragment(query, suggestions); + this.$lastSuggestion = $fragment.children().last(); + this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions)); + }, + _appendSuggestions: function appendSuggestions(query, suggestions) { + var $fragment, $lastSuggestion; + $fragment = this._getSuggestionsFragment(query, suggestions); + $lastSuggestion = $fragment.children().last(); + this.$lastSuggestion.after($fragment); + this.$lastSuggestion = $lastSuggestion; + }, + _renderPending: function renderPending(query) { + var template = this.templates.pending; + this._resetLastSuggestion(); + template && this.$el.html(template({ + query: query, + dataset: this.name + })); + }, + _renderNotFound: function renderNotFound(query) { + var template = this.templates.notFound; + this._resetLastSuggestion(); + template && this.$el.html(template({ + query: query, + dataset: this.name + })); + }, + _empty: function empty() { + this.$el.empty(); + this._resetLastSuggestion(); + }, + _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) { + var that = this, fragment; + fragment = document.createDocumentFragment(); + _.each(suggestions, function getSuggestionNode(suggestion) { + var $el, context; + context = that._injectQuery(query, suggestion); + $el = $(that.templates.suggestion(context)).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable); + fragment.appendChild($el[0]); + }); + this.highlight && highlight({ + className: this.classes.highlight, + node: fragment, + pattern: query + }); + return $(fragment); + }, + _getFooter: function getFooter(query, suggestions) { + return this.templates.footer ? this.templates.footer({ + query: query, + suggestions: suggestions, + dataset: this.name + }) : null; + }, + _getHeader: function getHeader(query, suggestions) { + return this.templates.header ? this.templates.header({ + query: query, + suggestions: suggestions, + dataset: this.name + }) : null; + }, + _resetLastSuggestion: function resetLastSuggestion() { + this.$lastSuggestion = $(); + }, + _injectQuery: function injectQuery(query, obj) { + return _.isObject(obj) ? _.mixin({ + _query: query + }, obj) : obj; + }, + update: function update(query) { + var that = this, canceled = false, syncCalled = false, rendered = 0; + this.cancel(); + this.cancel = function cancel() { + canceled = true; + that.cancel = $.noop; + that.async && that.trigger("asyncCanceled", query); + }; + this.source(query, sync, async); + !syncCalled && sync([]); + function sync(suggestions) { + if (syncCalled) { + return; + } + syncCalled = true; + suggestions = (suggestions || []).slice(0, that.limit); + rendered = suggestions.length; + that._overwrite(query, suggestions); + if (rendered < that.limit && that.async) { + that.trigger("asyncRequested", query); + } + } + function async(suggestions) { + suggestions = suggestions || []; + if (!canceled && rendered < that.limit) { + that.cancel = $.noop; + rendered += suggestions.length; + that._append(query, suggestions.slice(0, that.limit - rendered)); + that.async && that.trigger("asyncReceived", query); + } + } + }, + cancel: $.noop, + clear: function clear() { + this._empty(); + this.cancel(); + this.trigger("cleared"); + }, + isEmpty: function isEmpty() { + return this.$el.is(":empty"); + }, + destroy: function destroy() { + this.$el = $("<div>"); + } + }); + return Dataset; + function getDisplayFn(display) { + display = display || _.stringify; + return _.isFunction(display) ? display : displayFn; + function displayFn(obj) { + return obj[display]; + } + } + function getTemplates(templates, displayFn) { + return { + notFound: templates.notFound && _.templatify(templates.notFound), + pending: templates.pending && _.templatify(templates.pending), + header: templates.header && _.templatify(templates.header), + footer: templates.footer && _.templatify(templates.footer), + suggestion: templates.suggestion || suggestionTemplate + }; + function suggestionTemplate(context) { + return $("<div>").text(displayFn(context)); + } + } + function isValidName(str) { + return /^[_a-zA-Z0-9-]+$/.test(str); + } + }(); + var Menu = function() { + "use strict"; + function Menu(o, www) { + var that = this; + o = o || {}; + if (!o.node) { + $.error("node is required"); + } + www.mixin(this); + this.$node = $(o.node); + this.query = null; + this.datasets = _.map(o.datasets, initializeDataset); + function initializeDataset(oDataset) { + var node = that.$node.find(oDataset.node).first(); + oDataset.node = node.length ? node : $("<div>").appendTo(that.$node); + return new Dataset(oDataset, www); + } + } + _.mixin(Menu.prototype, EventEmitter, { + _onSelectableClick: function onSelectableClick($e) { + this.trigger("selectableClicked", $($e.currentTarget)); + }, + _onRendered: function onRendered(type, dataset, suggestions, async) { + this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); + this.trigger("datasetRendered", dataset, suggestions, async); + }, + _onCleared: function onCleared() { + this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); + this.trigger("datasetCleared"); + }, + _propagate: function propagate() { + this.trigger.apply(this, arguments); + }, + _allDatasetsEmpty: function allDatasetsEmpty() { + return _.every(this.datasets, isDatasetEmpty); + function isDatasetEmpty(dataset) { + return dataset.isEmpty(); + } + }, + _getSelectables: function getSelectables() { + return this.$node.find(this.selectors.selectable); + }, + _removeCursor: function _removeCursor() { + var $selectable = this.getActiveSelectable(); + $selectable && $selectable.removeClass(this.classes.cursor); + }, + _ensureVisible: function ensureVisible($el) { + var elTop, elBottom, nodeScrollTop, nodeHeight; + elTop = $el.position().top; + elBottom = elTop + $el.outerHeight(true); + nodeScrollTop = this.$node.scrollTop(); + nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10); + if (elTop < 0) { + this.$node.scrollTop(nodeScrollTop + elTop); + } else if (nodeHeight < elBottom) { + this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight)); + } + }, + bind: function() { + var that = this, onSelectableClick; + onSelectableClick = _.bind(this._onSelectableClick, this); + this.$node.on("click.tt", this.selectors.selectable, onSelectableClick); + _.each(this.datasets, function(dataset) { + dataset.onSync("asyncRequested", that._propagate, that).onSync("asyncCanceled", that._propagate, that).onSync("asyncReceived", that._propagate, that).onSync("rendered", that._onRendered, that).onSync("cleared", that._onCleared, that); + }); + return this; + }, + isOpen: function isOpen() { + return this.$node.hasClass(this.classes.open); + }, + open: function open() { + this.$node.addClass(this.classes.open); + }, + close: function close() { + this.$node.removeClass(this.classes.open); + this._removeCursor(); + }, + setLanguageDirection: function setLanguageDirection(dir) { + this.$node.attr("dir", dir); + }, + selectableRelativeToCursor: function selectableRelativeToCursor(delta) { + var $selectables, $oldCursor, oldIndex, newIndex; + $oldCursor = this.getActiveSelectable(); + $selectables = this._getSelectables(); + oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1; + newIndex = oldIndex + delta; + newIndex = (newIndex + 1) % ($selectables.length + 1) - 1; + newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex; + return newIndex === -1 ? null : $selectables.eq(newIndex); + }, + setCursor: function setCursor($selectable) { + this._removeCursor(); + if ($selectable = $selectable && $selectable.first()) { + $selectable.addClass(this.classes.cursor); + this._ensureVisible($selectable); + } + }, + getSelectableData: function getSelectableData($el) { + return $el && $el.length ? Dataset.extractData($el) : null; + }, + getActiveSelectable: function getActiveSelectable() { + var $selectable = this._getSelectables().filter(this.selectors.cursor).first(); + return $selectable.length ? $selectable : null; + }, + getTopSelectable: function getTopSelectable() { + var $selectable = this._getSelectables().first(); + return $selectable.length ? $selectable : null; + }, + update: function update(query) { + var isValidUpdate = query !== this.query; + if (isValidUpdate) { + this.query = query; + _.each(this.datasets, updateDataset); + } + return isValidUpdate; + function updateDataset(dataset) { + dataset.update(query); + } + }, + empty: function empty() { + _.each(this.datasets, clearDataset); + this.query = null; + this.$node.addClass(this.classes.empty); + function clearDataset(dataset) { + dataset.clear(); + } + }, + destroy: function destroy() { + this.$node.off(".tt"); + this.$node = $("<div>"); + _.each(this.datasets, destroyDataset); + function destroyDataset(dataset) { + dataset.destroy(); + } + } + }); + return Menu; + }(); + var DefaultMenu = function() { + "use strict"; + var s = Menu.prototype; + function DefaultMenu() { + Menu.apply(this, [].slice.call(arguments, 0)); + } + _.mixin(DefaultMenu.prototype, Menu.prototype, { + open: function open() { + !this._allDatasetsEmpty() && this._show(); + return s.open.apply(this, [].slice.call(arguments, 0)); + }, + close: function close() { + this._hide(); + return s.close.apply(this, [].slice.call(arguments, 0)); + }, + _onRendered: function onRendered() { + if (this._allDatasetsEmpty()) { + this._hide(); + } else { + this.isOpen() && this._show(); + } + return s._onRendered.apply(this, [].slice.call(arguments, 0)); + }, + _onCleared: function onCleared() { + if (this._allDatasetsEmpty()) { + this._hide(); + } else { + this.isOpen() && this._show(); + } + return s._onCleared.apply(this, [].slice.call(arguments, 0)); + }, + setLanguageDirection: function setLanguageDirection(dir) { + this.$node.css(dir === "ltr" ? this.css.ltr : this.css.rtl); + return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0)); + }, + _hide: function hide() { + this.$node.hide(); + }, + _show: function show() { + this.$node.css("display", "block"); + } + }); + return DefaultMenu; + }(); + var Typeahead = function() { + "use strict"; + function Typeahead(o, www) { + var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged; + o = o || {}; + if (!o.input) { + $.error("missing input"); + } + if (!o.menu) { + $.error("missing menu"); + } + if (!o.eventBus) { + $.error("missing event bus"); + } + www.mixin(this); + this.eventBus = o.eventBus; + this.minLength = _.isNumber(o.minLength) ? o.minLength : 1; + this.input = o.input; + this.menu = o.menu; + this.enabled = true; + this.active = false; + this.input.hasFocus() && this.activate(); + this.dir = this.input.getLangDir(); + this._hacks(); + this.menu.bind().onSync("selectableClicked", this._onSelectableClicked, this).onSync("asyncRequested", this._onAsyncRequested, this).onSync("asyncCanceled", this._onAsyncCanceled, this).onSync("asyncReceived", this._onAsyncReceived, this).onSync("datasetRendered", this._onDatasetRendered, this).onSync("datasetCleared", this._onDatasetCleared, this); + onFocused = c(this, "activate", "open", "_onFocused"); + onBlurred = c(this, "deactivate", "_onBlurred"); + onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed"); + onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed"); + onEscKeyed = c(this, "isActive", "_onEscKeyed"); + onUpKeyed = c(this, "isActive", "open", "_onUpKeyed"); + onDownKeyed = c(this, "isActive", "open", "_onDownKeyed"); + onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed"); + onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed"); + onQueryChanged = c(this, "_openIfActive", "_onQueryChanged"); + onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged"); + this.input.bind().onSync("focused", onFocused, this).onSync("blurred", onBlurred, this).onSync("enterKeyed", onEnterKeyed, this).onSync("tabKeyed", onTabKeyed, this).onSync("escKeyed", onEscKeyed, this).onSync("upKeyed", onUpKeyed, this).onSync("downKeyed", onDownKeyed, this).onSync("leftKeyed", onLeftKeyed, this).onSync("rightKeyed", onRightKeyed, this).onSync("queryChanged", onQueryChanged, this).onSync("whitespaceChanged", onWhitespaceChanged, this).onSync("langDirChanged", this._onLangDirChanged, this); + } + _.mixin(Typeahead.prototype, { + _hacks: function hacks() { + var $input, $menu; + $input = this.input.$input || $("<div>"); + $menu = this.menu.$node || $("<div>"); + $input.on("blur.tt", function($e) { + var active, isActive, hasActive; + active = document.activeElement; + isActive = $menu.is(active); + hasActive = $menu.has(active).length > 0; + if (_.isMsie() && (isActive || hasActive)) { + $e.preventDefault(); + $e.stopImmediatePropagation(); + _.defer(function() { + $input.focus(); + }); + } + }); + $menu.on("mousedown.tt", function($e) { + $e.preventDefault(); + }); + }, + _onSelectableClicked: function onSelectableClicked(type, $el) { + this.select($el); + }, + _onDatasetCleared: function onDatasetCleared() { + this._updateHint(); + }, + _onDatasetRendered: function onDatasetRendered(type, dataset, suggestions, async) { + this._updateHint(); + this.eventBus.trigger("render", suggestions, async, dataset); + }, + _onAsyncRequested: function onAsyncRequested(type, dataset, query) { + this.eventBus.trigger("asyncrequest", query, dataset); + }, + _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) { + this.eventBus.trigger("asynccancel", query, dataset); + }, + _onAsyncReceived: function onAsyncReceived(type, dataset, query) { + this.eventBus.trigger("asyncreceive", query, dataset); + }, + _onFocused: function onFocused() { + this._minLengthMet() && this.menu.update(this.input.getQuery()); + }, + _onBlurred: function onBlurred() { + if (this.input.hasQueryChangedSinceLastFocus()) { + this.eventBus.trigger("change", this.input.getQuery()); + } + }, + _onEnterKeyed: function onEnterKeyed(type, $e) { + var $selectable; + if ($selectable = this.menu.getActiveSelectable()) { + this.select($selectable) && $e.preventDefault(); + } + }, + _onTabKeyed: function onTabKeyed(type, $e) { + var $selectable; + if ($selectable = this.menu.getActiveSelectable()) { + this.select($selectable) && $e.preventDefault(); + } else if ($selectable = this.menu.getTopSelectable()) { + this.autocomplete($selectable) && $e.preventDefault(); + } + }, + _onEscKeyed: function onEscKeyed() { + this.close(); + }, + _onUpKeyed: function onUpKeyed() { + this.moveCursor(-1); + }, + _onDownKeyed: function onDownKeyed() { + this.moveCursor(+1); + }, + _onLeftKeyed: function onLeftKeyed() { + if (this.dir === "rtl" && this.input.isCursorAtEnd()) { + this.autocomplete(this.menu.getTopSelectable()); + } + }, + _onRightKeyed: function onRightKeyed() { + if (this.dir === "ltr" && this.input.isCursorAtEnd()) { + this.autocomplete(this.menu.getTopSelectable()); + } + }, + _onQueryChanged: function onQueryChanged(e, query) { + this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty(); + }, + _onWhitespaceChanged: function onWhitespaceChanged() { + this._updateHint(); + }, + _onLangDirChanged: function onLangDirChanged(e, dir) { + if (this.dir !== dir) { + this.dir = dir; + this.menu.setLanguageDirection(dir); + } + }, + _openIfActive: function openIfActive() { + this.isActive() && this.open(); + }, + _minLengthMet: function minLengthMet(query) { + query = _.isString(query) ? query : this.input.getQuery() || ""; + return query.length >= this.minLength; + }, + _updateHint: function updateHint() { + var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match; + $selectable = this.menu.getTopSelectable(); + data = this.menu.getSelectableData($selectable); + val = this.input.getInputValue(); + if (data && !_.isBlankString(val) && !this.input.hasOverflow()) { + query = Input.normalizeQuery(val); + escapedQuery = _.escapeRegExChars(query); + frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i"); + match = frontMatchRegEx.exec(data.val); + match && this.input.setHint(val + match[1]); + } else { + this.input.clearHint(); + } + }, + isEnabled: function isEnabled() { + return this.enabled; + }, + enable: function enable() { + this.enabled = true; + }, + disable: function disable() { + this.enabled = false; + }, + isActive: function isActive() { + return this.active; + }, + activate: function activate() { + if (this.isActive()) { + return true; + } else if (!this.isEnabled() || this.eventBus.before("active")) { + return false; + } else { + this.active = true; + this.eventBus.trigger("active"); + return true; + } + }, + deactivate: function deactivate() { + if (!this.isActive()) { + return true; + } else if (this.eventBus.before("idle")) { + return false; + } else { + this.active = false; + this.close(); + this.eventBus.trigger("idle"); + return true; + } + }, + isOpen: function isOpen() { + return this.menu.isOpen(); + }, + open: function open() { + if (!this.isOpen() && !this.eventBus.before("open")) { + this.menu.open(); + this._updateHint(); + this.eventBus.trigger("open"); + } + return this.isOpen(); + }, + close: function close() { + if (this.isOpen() && !this.eventBus.before("close")) { + this.menu.close(); + this.input.clearHint(); + this.input.resetInputValue(); + this.eventBus.trigger("close"); + } + return !this.isOpen(); + }, + setVal: function setVal(val) { + this.input.setQuery(_.toStr(val)); + }, + getVal: function getVal() { + return this.input.getQuery(); + }, + select: function select($selectable) { + var data = this.menu.getSelectableData($selectable); + if (data && !this.eventBus.before("select", data.obj)) { + this.input.setQuery(data.val, true); + this.eventBus.trigger("select", data.obj); + this.close(); + return true; + } + return false; + }, + autocomplete: function autocomplete($selectable) { + var query, data, isValid; + query = this.input.getQuery(); + data = this.menu.getSelectableData($selectable); + isValid = data && query !== data.val; + if (isValid && !this.eventBus.before("autocomplete", data.obj)) { + this.input.setQuery(data.val); + this.eventBus.trigger("autocomplete", data.obj); + return true; + } + return false; + }, + moveCursor: function moveCursor(delta) { + var query, $candidate, data, payload, cancelMove; + query = this.input.getQuery(); + $candidate = this.menu.selectableRelativeToCursor(delta); + data = this.menu.getSelectableData($candidate); + payload = data ? data.obj : null; + cancelMove = this._minLengthMet() && this.menu.update(query); + if (!cancelMove && !this.eventBus.before("cursorchange", payload)) { + this.menu.setCursor($candidate); + if (data) { + this.input.setInputValue(data.val); + } else { + this.input.resetInputValue(); + this._updateHint(); + } + this.eventBus.trigger("cursorchange", payload); + return true; + } + return false; + }, + destroy: function destroy() { + this.input.destroy(); + this.menu.destroy(); + } + }); + return Typeahead; + function c(ctx) { + var methods = [].slice.call(arguments, 1); + return function() { + var args = [].slice.call(arguments); + _.each(methods, function(method) { + return ctx[method].apply(ctx, args); + }); + }; + } + }(); + (function() { + "use strict"; + var old, keys, methods; + old = $.fn.typeahead; + keys = { + www: "tt-www", + attrs: "tt-attrs", + typeahead: "tt-typeahead" + }; + methods = { + initialize: function initialize(o, datasets) { + var www; + datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1); + o = o || {}; + www = WWW(o.classNames); + return this.each(attach); + function attach() { + var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, typeahead, MenuConstructor; + _.each(datasets, function(d) { + d.highlight = !!o.highlight; + }); + $input = $(this); + $wrapper = $(www.html.wrapper); + $hint = $elOrNull(o.hint); + $menu = $elOrNull(o.menu); + defaultHint = o.hint !== false && !$hint; + defaultMenu = o.menu !== false && !$menu; + defaultHint && ($hint = buildHintFromInput($input, www)); + defaultMenu && ($menu = $(www.html.menu).css(www.css.menu)); + $hint && $hint.val(""); + $input = prepInput($input, www); + if (defaultHint || defaultMenu) { + $wrapper.css(www.css.wrapper); + $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint); + $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null); + } + MenuConstructor = defaultMenu ? DefaultMenu : Menu; + eventBus = new EventBus({ + el: $input + }); + input = new Input({ + hint: $hint, + input: $input + }, www); + menu = new MenuConstructor({ + node: $menu, + datasets: datasets + }, www); + typeahead = new Typeahead({ + input: input, + menu: menu, + eventBus: eventBus, + minLength: o.minLength + }, www); + $input.data(keys.www, www); + $input.data(keys.typeahead, typeahead); + } + }, + isEnabled: function isEnabled() { + var enabled; + ttEach(this.first(), function(t) { + enabled = t.isEnabled(); + }); + return enabled; + }, + enable: function enable() { + ttEach(this, function(t) { + t.enable(); + }); + return this; + }, + disable: function disable() { + ttEach(this, function(t) { + t.disable(); + }); + return this; + }, + isActive: function isActive() { + var active; + ttEach(this.first(), function(t) { + active = t.isActive(); + }); + return active; + }, + activate: function activate() { + ttEach(this, function(t) { + t.activate(); + }); + return this; + }, + deactivate: function deactivate() { + ttEach(this, function(t) { + t.deactivate(); + }); + return this; + }, + isOpen: function isOpen() { + var open; + ttEach(this.first(), function(t) { + open = t.isOpen(); + }); + return open; + }, + open: function open() { + ttEach(this, function(t) { + t.open(); + }); + return this; + }, + close: function close() { + ttEach(this, function(t) { + t.close(); + }); + return this; + }, + select: function select(el) { + var success = false, $el = $(el); + ttEach(this.first(), function(t) { + success = t.select($el); + }); + return success; + }, + autocomplete: function autocomplete(el) { + var success = false, $el = $(el); + ttEach(this.first(), function(t) { + success = t.autocomplete($el); + }); + return success; + }, + moveCursor: function moveCursoe(delta) { + var success = false; + ttEach(this.first(), function(t) { + success = t.moveCursor(delta); + }); + return success; + }, + val: function val(newVal) { + var query; + if (!arguments.length) { + ttEach(this.first(), function(t) { + query = t.getVal(); + }); + return query; + } else { + ttEach(this, function(t) { + t.setVal(newVal); + }); + return this; + } + }, + destroy: function destroy() { + ttEach(this, function(typeahead, $input) { + revert($input); + typeahead.destroy(); + }); + return this; + } + }; + $.fn.typeahead = function(method) { + if (methods[method]) { + return methods[method].apply(this, [].slice.call(arguments, 1)); + } else { + return methods.initialize.apply(this, arguments); + } + }; + $.fn.typeahead.noConflict = function noConflict() { + $.fn.typeahead = old; + return this; + }; + function ttEach($els, fn) { + $els.each(function() { + var $input = $(this), typeahead; + (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input); + }); + } + function buildHintFromInput($input, www) { + return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop("readonly", true).removeAttr("id name placeholder required").attr({ + autocomplete: "off", + spellcheck: "false", + tabindex: -1 + }); + } + function prepInput($input, www) { + $input.data(keys.attrs, { + dir: $input.attr("dir"), + autocomplete: $input.attr("autocomplete"), + spellcheck: $input.attr("spellcheck"), + style: $input.attr("style") + }); + $input.addClass(www.classes.input).attr({ + autocomplete: "off", + spellcheck: false + }); + try { + !$input.attr("dir") && $input.attr("dir", "auto"); + } catch (e) {} + return $input; + } + function getBackgroundStyles($el) { + return { + backgroundAttachment: $el.css("background-attachment"), + backgroundClip: $el.css("background-clip"), + backgroundColor: $el.css("background-color"), + backgroundImage: $el.css("background-image"), + backgroundOrigin: $el.css("background-origin"), + backgroundPosition: $el.css("background-position"), + backgroundRepeat: $el.css("background-repeat"), + backgroundSize: $el.css("background-size") + }; + } + function revert($input) { + var www, $wrapper; + www = $input.data(keys.www); + $wrapper = $input.parent().filter(www.selectors.wrapper); + _.each($input.data(keys.attrs), function(val, key) { + _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val); + }); + $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input); + if ($wrapper.length) { + $input.detach().insertAfter($wrapper); + $wrapper.remove(); + } + } + function $elOrNull(obj) { + var isValid, $el; + isValid = _.isJQuery(obj) || _.isElement(obj); + $el = isValid ? $(obj).first() : []; + return $el.length ? $el : null; + } + })(); +});
\ No newline at end of file diff --git a/debian/dconv/parser/__init__.py b/debian/dconv/parser/__init__.py new file mode 100644 index 0000000..82b8522 --- /dev/null +++ b/debian/dconv/parser/__init__.py @@ -0,0 +1,81 @@ +__all__ = [ + 'arguments', + 'example', + 'keyword', + 'seealso', + 'table', + 'underline' +] + + +class Parser: + def __init__(self, pctxt): + self.pctxt = pctxt + + def parse(self, line): + return line + +class PContext: + def __init__(self, templates = None): + self.set_content_list([]) + self.templates = templates + + def set_content(self, content): + self.set_content_list(content.split("\n")) + + def set_content_list(self, content): + self.lines = content + self.nblines = len(self.lines) + self.i = 0 + self.stop = False + + def get_lines(self): + return self.lines + + def eat_lines(self): + count = 0 + while self.has_more_lines() and self.lines[self.i].strip(): + count += 1 + self.next() + return count + + def eat_empty_lines(self): + count = 0 + while self.has_more_lines() and not self.lines[self.i].strip(): + count += 1 + self.next() + return count + + def next(self, count=1): + self.i += count + + def has_more_lines(self, offset=0): + return self.i + offset < self.nblines + + def get_line(self, offset=0): + return self.lines[self.i + offset].rstrip() + + +# Get the indentation of a line +def get_indent(line): + indent = 0 + length = len(line) + while indent < length and line[indent] == ' ': + indent += 1 + return indent + + +# Remove unneeded indentation +def remove_indent(list): + # Detect the minimum indentation in the list + min_indent = -1 + for line in list: + if not line.strip(): + continue + indent = get_indent(line) + if min_indent < 0 or indent < min_indent: + min_indent = indent + # Realign the list content to remove the minimum indentation + if min_indent > 0: + for index, line in enumerate(list): + list[index] = line[min_indent:] diff --git a/debian/dconv/parser/arguments.py b/debian/dconv/parser/arguments.py new file mode 100644 index 0000000..096b269 --- /dev/null +++ b/debian/dconv/parser/arguments.py @@ -0,0 +1,132 @@ +import sys +import re +import parser + +''' +TODO: Allow inner data parsing (this will allow to parse the examples provided in an arguments block) +''' +class Parser(parser.Parser): + def __init__(self, pctxt): + parser.Parser.__init__(self, pctxt) + #template = pctxt.templates.get_template("parser/arguments.tpl") + #self.replace = template.render().strip() + + def parse(self, line): + #return re.sub(r'(Arguments *:)', self.replace, line) + pctxt = self.pctxt + + result = re.search(r'(Arguments? *:)', line) + if result: + label = result.group(0) + content = [] + + desc_indent = False + desc = re.sub(r'.*Arguments? *:', '', line).strip() + + indent = parser.get_indent(line) + + pctxt.next() + pctxt.eat_empty_lines() + + arglines = [] + if desc != "none": + add_empty_lines = 0 + while pctxt.has_more_lines() and (parser.get_indent(pctxt.get_line()) > indent): + for j in range(0, add_empty_lines): + arglines.append("") + arglines.append(pctxt.get_line()) + pctxt.next() + add_empty_lines = pctxt.eat_empty_lines() + ''' + print line + + if parser.get_indent(line) == arg_indent: + argument = re.sub(r' *([^ ]+).*', r'\1', line) + if argument: + #content.append("<b>%s</b>" % argument) + arg_desc = [line.replace(argument, " " * len(self.unescape(argument)), 1)] + #arg_desc = re.sub(r'( *)([^ ]+)(.*)', r'\1<b>\2</b>\3', line) + arg_desc_indent = parser.get_indent(arg_desc[0]) + arg_desc[0] = arg_desc[0][arg_indent:] + pctxt.next() + add_empty_lines = 0 + while pctxt.has_more_lines and parser.get_indent(pctxt.get_line()) >= arg_indent: + for i in range(0, add_empty_lines): + arg_desc.append("") + arg_desc.append(pctxt.get_line()[arg_indent:]) + pctxt.next() + add_empty_lines = pctxt.eat_empty_lines() + # TODO : reduce space at the beginnning + content.append({ + 'name': argument, + 'desc': arg_desc + }) + ''' + + if arglines: + new_arglines = [] + #content = self.parse_args(arglines) + parser.remove_indent(arglines) + ''' + pctxt2 = parser.PContext(pctxt.templates) + pctxt2.set_content_list(arglines) + while pctxt2.has_more_lines(): + new_arglines.append(parser.example.Parser(pctxt2).parse(pctxt2.get_line())) + pctxt2.next() + arglines = new_arglines + ''' + + pctxt.stop = True + + template = pctxt.templates.get_template("parser/arguments.tpl") + return template.render( + pctxt=pctxt, + label=label, + desc=desc, + content=arglines + #content=content + ) + return line + + return line + +''' + def parse_args(self, data): + args = [] + + pctxt = parser.PContext() + pctxt.set_content_list(data) + + while pctxt.has_more_lines(): + line = pctxt.get_line() + arg_indent = parser.get_indent(line) + argument = re.sub(r' *([^ ]+).*', r'\1', line) + if True or argument: + arg_desc = [] + trailing_desc = line.replace(argument, " " * len(self.unescape(argument)), 1)[arg_indent:] + if trailing_desc.strip(): + arg_desc.append(trailing_desc) + pctxt.next() + add_empty_lines = 0 + while pctxt.has_more_lines() and parser.get_indent(pctxt.get_line()) > arg_indent: + for i in range(0, add_empty_lines): + arg_desc.append("") + arg_desc.append(pctxt.get_line()[arg_indent:]) + pctxt.next() + add_empty_lines = pctxt.eat_empty_lines() + + parser.remove_indent(arg_desc) + + args.append({ + 'name': argument, + 'desc': arg_desc + }) + return args + + def unescape(self, s): + s = s.replace("<", "<") + s = s.replace(">", ">") + # this has to be last: + s = s.replace("&", "&") + return s +''' diff --git a/debian/dconv/parser/example.py b/debian/dconv/parser/example.py new file mode 100644 index 0000000..3958992 --- /dev/null +++ b/debian/dconv/parser/example.py @@ -0,0 +1,77 @@ +import re +import parser + +# Detect examples blocks +class Parser(parser.Parser): + def __init__(self, pctxt): + parser.Parser.__init__(self, pctxt) + template = pctxt.templates.get_template("parser/example/comment.tpl") + self.comment = template.render(pctxt=pctxt).strip() + + + def parse(self, line): + pctxt = self.pctxt + + result = re.search(r'^ *(Examples? *:)(.*)', line) + if result: + label = result.group(1) + + desc_indent = False + desc = result.group(2).strip() + + # Some examples have a description + if desc: + desc_indent = len(line) - len(desc) + + indent = parser.get_indent(line) + + if desc: + # And some description are on multiple lines + while pctxt.get_line(1) and parser.get_indent(pctxt.get_line(1)) == desc_indent: + desc += " " + pctxt.get_line(1).strip() + pctxt.next() + + pctxt.next() + add_empty_line = pctxt.eat_empty_lines() + + content = [] + + if parser.get_indent(pctxt.get_line()) > indent: + if desc: + desc = desc[0].upper() + desc[1:] + add_empty_line = 0 + while pctxt.has_more_lines() and ((not pctxt.get_line()) or (parser.get_indent(pctxt.get_line()) > indent)): + if pctxt.get_line(): + for j in range(0, add_empty_line): + content.append("") + + content.append(re.sub(r'(#.*)$', self.comment, pctxt.get_line())) + add_empty_line = 0 + else: + add_empty_line += 1 + pctxt.next() + elif parser.get_indent(pctxt.get_line()) == indent: + # Simple example that can't have empty lines + if add_empty_line and desc: + # This means that the example was on the same line as the 'Example' tag + # and was not a description + content.append(" " * indent + desc) + desc = False + else: + while pctxt.has_more_lines() and (parser.get_indent(pctxt.get_line()) >= indent): + content.append(pctxt.get_line()) + pctxt.next() + pctxt.eat_empty_lines() # Skip empty remaining lines + + pctxt.stop = True + + parser.remove_indent(content) + + template = pctxt.templates.get_template("parser/example.tpl") + return template.render( + pctxt=pctxt, + label=label, + desc=desc, + content=content + ) + return line diff --git a/debian/dconv/parser/keyword.py b/debian/dconv/parser/keyword.py new file mode 100644 index 0000000..f20944f --- /dev/null +++ b/debian/dconv/parser/keyword.py @@ -0,0 +1,142 @@ +import re +import parser +from urllib.parse import quote + +class Parser(parser.Parser): + def __init__(self, pctxt): + parser.Parser.__init__(self, pctxt) + self.keywordPattern = re.compile(r'^(%s%s)(%s)' % ( + '([a-z][a-z0-9\-\+_\.]*[a-z0-9\-\+_)])', # keyword + '( [a-z0-9\-_]+)*', # subkeywords + '(\([^ ]*\))?', # arg (ex: (<backend>), (<frontend>/<backend>), (<offset1>,<length>[,<offset2>]) ... + )) + + def parse(self, line): + pctxt = self.pctxt + keywords = pctxt.keywords + keywordsCount = pctxt.keywordsCount + chapters = pctxt.chapters + + res = "" + + if line != "" and not re.match(r'^ ', line): + parsed = self.keywordPattern.match(line) + if parsed != None: + keyword = parsed.group(1) + arg = parsed.group(4) + parameters = line[len(keyword) + len(arg):] + if (parameters != "" and not re.match("^ +((<|\[|\{|/).*|(: [a-z +]+))?(\(deprecated\))?$", parameters)): + # Dirty hack + # - parameters should only start with the characer "<", "[", "{", "/" + # - or a column (":") followed by a alpha keywords to identify fetching samples (optionally separated by the character "+") + # - or the string "(deprecated)" at the end + keyword = False + else: + splitKeyword = keyword.split(" ") + + parameters = arg + parameters + else: + keyword = False + + if keyword and (len(splitKeyword) <= 5): + toplevel = pctxt.details["toplevel"] + for j in range(0, len(splitKeyword)): + subKeyword = " ".join(splitKeyword[0:j + 1]) + if subKeyword != "no": + if not subKeyword in keywords: + keywords[subKeyword] = set() + keywords[subKeyword].add(pctxt.details["chapter"]) + res += '<a class="anchor" name="%s"></a>' % subKeyword + res += '<a class="anchor" name="%s-%s"></a>' % (toplevel, subKeyword) + res += '<a class="anchor" name="%s-%s"></a>' % (pctxt.details["chapter"], subKeyword) + res += '<a class="anchor" name="%s (%s)"></a>' % (subKeyword, chapters[toplevel]['title']) + res += '<a class="anchor" name="%s (%s)"></a>' % (subKeyword, chapters[pctxt.details["chapter"]]['title']) + + deprecated = parameters.find("(deprecated)") + if deprecated != -1: + prefix = "" + suffix = "" + parameters = parameters.replace("(deprecated)", '<span class="label label-warning">(deprecated)</span>') + else: + prefix = "" + suffix = "" + + nextline = pctxt.get_line(1) + + while nextline.startswith(" "): + # Found parameters on the next line + parameters += "\n" + nextline + pctxt.next() + if pctxt.has_more_lines(1): + nextline = pctxt.get_line(1) + else: + nextline = "" + + + parameters = self.colorize(parameters) + res += '<div class="keyword">%s<b><a class="anchor" name="%s"></a><a href="#%s">%s</a></b>%s%s</div>' % (prefix, keyword, quote("%s-%s" % (pctxt.details["chapter"], keyword)), keyword, parameters, suffix) + pctxt.next() + pctxt.stop = True + elif line.startswith("/*"): + # Skip comments in the documentation + while not pctxt.get_line().endswith("*/"): + pctxt.next() + pctxt.next() + else: + # This is probably not a keyword but a text, ignore it + res += line + else: + res += line + + return res + + # Used to colorize keywords parameters + # TODO : use CSS styling + def colorize(self, text): + colorized = "" + tags = [ + [ "[" , "]" , "#008" ], + [ "{" , "}" , "#800" ], + [ "<", ">", "#080" ], + ] + heap = [] + pos = 0 + while pos < len(text): + substring = text[pos:] + found = False + for tag in tags: + if substring.startswith(tag[0]): + # Opening tag + heap.append(tag) + colorized += '<span style="color: %s">%s' % (tag[2], substring[0:len(tag[0])]) + pos += len(tag[0]) + found = True + break + elif substring.startswith(tag[1]): + # Closing tag + + # pop opening tags until the corresponding one is found + openingTag = False + while heap and openingTag != tag: + openingTag = heap.pop() + if openingTag != tag: + colorized += '</span>' + # all intermediate tags are now closed, we can display the tag + colorized += substring[0:len(tag[1])] + # and the close it if it was previously opened + if openingTag == tag: + colorized += '</span>' + pos += len(tag[1]) + found = True + break + if not found: + colorized += substring[0] + pos += 1 + # close all unterminated tags + while heap: + tag = heap.pop() + colorized += '</span>' + + return colorized + + diff --git a/debian/dconv/parser/seealso.py b/debian/dconv/parser/seealso.py new file mode 100644 index 0000000..bbb53f9 --- /dev/null +++ b/debian/dconv/parser/seealso.py @@ -0,0 +1,32 @@ +import re +import parser + +class Parser(parser.Parser): + def parse(self, line): + pctxt = self.pctxt + + result = re.search(r'(See also *:)', line) + if result: + label = result.group(0) + + desc = re.sub(r'.*See also *:', '', line).strip() + + indent = parser.get_indent(line) + + # Some descriptions are on multiple lines + while pctxt.has_more_lines(1) and parser.get_indent(pctxt.get_line(1)) >= indent: + desc += " " + pctxt.get_line(1).strip() + pctxt.next() + + pctxt.eat_empty_lines() + pctxt.next() + pctxt.stop = True + + template = pctxt.templates.get_template("parser/seealso.tpl") + return template.render( + pctxt=pctxt, + label=label, + desc=desc, + ) + + return line diff --git a/debian/dconv/parser/table.py b/debian/dconv/parser/table.py new file mode 100644 index 0000000..e2575b1 --- /dev/null +++ b/debian/dconv/parser/table.py @@ -0,0 +1,244 @@ +import re +import sys +import parser + +class Parser(parser.Parser): + def __init__(self, pctxt): + parser.Parser.__init__(self, pctxt) + self.table1Pattern = re.compile(r'^ *(-+\+)+-+') + self.table2Pattern = re.compile(r'^ *\+(-+\+)+') + + def parse(self, line): + global document, keywords, keywordsCount, chapters, keyword_conflicts + + pctxt = self.pctxt + + if pctxt.context['headers']['subtitle'] != 'Configuration Manual': + # Quick exit + return line + elif pctxt.details['chapter'] == "4": + # BUG: the matrix in chapter 4. Proxies is not well displayed, we skip this chapter + return line + + if pctxt.has_more_lines(1): + nextline = pctxt.get_line(1) + else: + nextline = "" + + if self.table1Pattern.match(nextline): + # activate table rendering only for the Configuration Manual + lineSeparator = nextline + nbColumns = nextline.count("+") + 1 + extraColumns = 0 + print("Entering table mode (%d columns)" % nbColumns, file=sys.stderr) + table = [] + if line.find("|") != -1: + row = [] + while pctxt.has_more_lines(): + line = pctxt.get_line() + if pctxt.has_more_lines(1): + nextline = pctxt.get_line(1) + else: + nextline = "" + if line == lineSeparator: + # New row + table.append(row) + row = [] + if nextline.find("|") == -1: + break # End of table + else: + # Data + columns = line.split("|") + for j in range(0, len(columns)): + try: + if row[j]: + row[j] += "<br />" + row[j] += columns[j].strip() + except: + row.append(columns[j].strip()) + pctxt.next() + else: + row = [] + headers = nextline + while pctxt.has_more_lines(): + line = pctxt.get_line() + if pctxt.has_more_lines(1): + nextline = pctxt.get_line(1) + else: + nextline = "" + + if nextline == "": + if row: table.append(row) + break # End of table + + if (line != lineSeparator) and (line[0] != "-"): + start = 0 + + if row and not line.startswith(" "): + # Row is complete, parse a new one + table.append(row) + row = [] + + tmprow = [] + while start != -1: + end = headers.find("+", start) + if end == -1: + end = len(headers) + + realend = end + if realend == len(headers): + realend = len(line) + else: + while realend < len(line) and line[realend] != " ": + realend += 1 + end += 1 + + tmprow.append(line[start:realend]) + + start = end + 1 + if start >= len(headers): + start = -1 + for j in range(0, nbColumns): + try: + row[j] += tmprow[j].strip() + except: + row.append(tmprow[j].strip()) + + deprecated = row[0].endswith("(deprecated)") + if deprecated: + row[0] = row[0][: -len("(deprecated)")].rstrip() + + nooption = row[1].startswith("(*)") + if nooption: + row[1] = row[1][len("(*)"):].strip() + + if deprecated or nooption: + extraColumns = 1 + extra = "" + if deprecated: + extra += '<span class="label label-warning">(deprecated)</span>' + if nooption: + extra += '<span>(*)</span>' + row.append(extra) + + pctxt.next() + print("Leaving table mode", file=sys.stderr) + pctxt.next() # skip useless next line + pctxt.stop = True + + return self.renderTable(table, nbColumns, pctxt.details["toplevel"]) + # elif self.table2Pattern.match(line): + # return self.parse_table_format2() + elif line.find("May be used in sections") != -1: + nextline = pctxt.get_line(1) + rows = [] + headers = line.split(":") + rows.append(headers[1].split("|")) + rows.append(nextline.split("|")) + table = { + "rows": rows, + "title": headers[0] + } + pctxt.next(2) # skip this previous table + pctxt.stop = True + + return self.renderTable(table) + + return line + + + def parse_table_format2(self): + pctxt = self.pctxt + + linesep = pctxt.get_line() + rows = [] + + pctxt.next() + maxcols = 0 + while pctxt.get_line().strip().startswith("|"): + row = pctxt.get_line().strip()[1:-1].split("|") + rows.append(row) + maxcols = max(maxcols, len(row)) + pctxt.next() + if pctxt.get_line() == linesep: + # TODO : find a way to define a special style for next row + pctxt.next() + pctxt.stop = True + + return self.renderTable(rows, maxcols) + + # Render tables detected by the conversion parser + def renderTable(self, table, maxColumns = 0, toplevel = None): + pctxt = self.pctxt + template = pctxt.templates.get_template("parser/table.tpl") + + res = "" + + title = None + if isinstance(table, dict): + title = table["title"] + table = table["rows"] + + if not maxColumns: + maxColumns = len(table[0]) + + rows = [] + + mode = "th" + headerLine = "" + hasKeywords = False + i = 0 + for row in table: + line = "" + + if i == 0: + row_template = pctxt.templates.get_template("parser/table/header.tpl") + else: + row_template = pctxt.templates.get_template("parser/table/row.tpl") + + if i > 1 and (i - 1) % 20 == 0 and len(table) > 50: + # Repeat headers periodically for long tables + rows.append(headerLine) + + j = 0 + cols = [] + for column in row: + if j >= maxColumns: + break + + tplcol = {} + + data = column.strip() + keyword = column + if j == 0 and i == 0 and keyword == 'keyword': + hasKeywords = True + if j == 0 and i != 0 and hasKeywords: + if keyword.startswith("[no] "): + keyword = keyword[len("[no] "):] + tplcol['toplevel'] = toplevel + tplcol['keyword'] = keyword + tplcol['extra'] = [] + if j == 0 and len(row) > maxColumns: + for k in range(maxColumns, len(row)): + tplcol['extra'].append(row[k]) + tplcol['data'] = data + cols.append(tplcol) + j += 1 + mode = "td" + + line = row_template.render( + pctxt=pctxt, + columns=cols + ).strip() + if i == 0: + headerLine = line + + rows.append(line) + + i += 1 + + return template.render( + pctxt=pctxt, + title=title, + rows=rows, + ) diff --git a/debian/dconv/parser/underline.py b/debian/dconv/parser/underline.py new file mode 100644 index 0000000..3a2350c --- /dev/null +++ b/debian/dconv/parser/underline.py @@ -0,0 +1,16 @@ +import parser + +class Parser(parser.Parser): + # Detect underlines + def parse(self, line): + pctxt = self.pctxt + if pctxt.has_more_lines(1): + nextline = pctxt.get_line(1) + if (len(line) > 0) and (len(nextline) > 0) and (nextline[0] == '-') and ("-" * len(line) == nextline): + template = pctxt.templates.get_template("parser/underline.tpl") + line = template.render(pctxt=pctxt, data=line).strip() + pctxt.next(2) + pctxt.eat_empty_lines() + pctxt.stop = True + + return line diff --git a/debian/dconv/templates/parser/arguments.tpl b/debian/dconv/templates/parser/arguments.tpl new file mode 100644 index 0000000..b5f91e9 --- /dev/null +++ b/debian/dconv/templates/parser/arguments.tpl @@ -0,0 +1,9 @@ +<div class="separator"> +<span class="label label-info">${label}</span>\ +% if desc: + ${desc} +% endif +% if content: +<pre class="prettyprint arguments">${"\n".join(content)}</pre> +% endif +</div> diff --git a/debian/dconv/templates/parser/example.tpl b/debian/dconv/templates/parser/example.tpl new file mode 100644 index 0000000..184b6dd --- /dev/null +++ b/debian/dconv/templates/parser/example.tpl @@ -0,0 +1,12 @@ +<div class="separator"> +<span class="label label-success">${label}</span> +<pre class="prettyprint"> +% if desc: +<div class="example-desc">${desc}</div>\ +% endif +<code>\ +% for line in content: +${line} +% endfor +</code></pre> +</div>
\ No newline at end of file diff --git a/debian/dconv/templates/parser/example/comment.tpl b/debian/dconv/templates/parser/example/comment.tpl new file mode 100644 index 0000000..b51ec2d --- /dev/null +++ b/debian/dconv/templates/parser/example/comment.tpl @@ -0,0 +1 @@ +<span class="comment">\1</span>
\ No newline at end of file diff --git a/debian/dconv/templates/parser/seealso.tpl b/debian/dconv/templates/parser/seealso.tpl new file mode 100644 index 0000000..72cf5f9 --- /dev/null +++ b/debian/dconv/templates/parser/seealso.tpl @@ -0,0 +1 @@ +<div class="page-header"><b>${label}</b> ${desc}</div> diff --git a/debian/dconv/templates/parser/table.tpl b/debian/dconv/templates/parser/table.tpl new file mode 100644 index 0000000..0119176 --- /dev/null +++ b/debian/dconv/templates/parser/table.tpl @@ -0,0 +1,11 @@ +% if title: +<div><p>${title} :</p>\ +% endif +<table class="table table-bordered" border="0" cellspacing="0" cellpadding="0"> +% for row in rows: +${row} +% endfor +</table>\ +% if title: +</div> +% endif
\ No newline at end of file diff --git a/debian/dconv/templates/parser/table/header.tpl b/debian/dconv/templates/parser/table/header.tpl new file mode 100644 index 0000000..e84b47f --- /dev/null +++ b/debian/dconv/templates/parser/table/header.tpl @@ -0,0 +1,6 @@ +<thead><tr>\ +% for col in columns: +<% data = col['data'] %>\ +<th>${data}</th>\ +% endfor +</tr></thead> diff --git a/debian/dconv/templates/parser/table/row.tpl b/debian/dconv/templates/parser/table/row.tpl new file mode 100644 index 0000000..e4f2bef --- /dev/null +++ b/debian/dconv/templates/parser/table/row.tpl @@ -0,0 +1,36 @@ +<% from urllib.parse import quote %> +<% base = pctxt.context['base'] %> +<tr>\ +% for col in columns: +<% data = col['data'] %>\ +<% + if data in ['yes']: + style = "class=\"alert-success pagination-centered\"" + data = 'yes<br /><img src="%scss/check.png" alt="yes" title="yes" />' % base + elif data in ['no']: + style = "class=\"alert-error pagination-centered\"" + data = 'no<br /><img src="%scss/cross.png" alt="no" title="no" />' % base + elif data in ['X']: + style = "class=\"pagination-centered\"" + data = '<img src="%scss/check.png" alt="X" title="yes" />' % base + elif data in ['-']: + style = "class=\"pagination-centered\"" + data = ' ' + elif data in ['*']: + style = "class=\"pagination-centered\"" + else: + style = None +%>\ +<td ${style}>\ +% if "keyword" in col: +<a href="#${quote("%s-%s" % (col['toplevel'], col['keyword']))}">\ +% for extra in col['extra']: +<span class="pull-right">${extra}</span>\ +% endfor +${data}</a>\ +% else: +${data}\ +% endif +</td>\ +% endfor +</tr> diff --git a/debian/dconv/templates/parser/underline.tpl b/debian/dconv/templates/parser/underline.tpl new file mode 100644 index 0000000..4f35f7e --- /dev/null +++ b/debian/dconv/templates/parser/underline.tpl @@ -0,0 +1 @@ +<h5>${data}</h5> diff --git a/debian/dconv/templates/summary.html b/debian/dconv/templates/summary.html new file mode 100644 index 0000000..87c6414 --- /dev/null +++ b/debian/dconv/templates/summary.html @@ -0,0 +1,43 @@ +<a class="anchor" id="summary" name="summary"></a> +<div class="page-header"> + <h1 id="chapter-summary" data-target="summary">Summary</h1> +</div> +<div class="row"> + <div class="col-md-6"> + <% previousLevel = None %> + % for k in chapterIndexes: + <% chapter = chapters[k] %> + % if chapter['title']: + <% + if chapter['level'] == 1: + otag = "<b>" + etag = "</b>" + else: + otag = etag = "" + %> + % if chapter['chapter'] == '7': + ## Quick and dirty hack to split the summary in 2 columns + ## TODO : implement a generic way split the summary + </div><div class="col-md-6"> + <% previousLevel = None %> + % endif + % if otag and previousLevel: + <br /> + % endif + <div class="row"> + <div class="col-md-2 pagination-right noheight">${otag}<small>${chapter['chapter']}.</small>${etag}</div> + <div class="col-md-10 noheight"> + % for tab in range(1, chapter['level']): + <div class="tab"> + % endfor + <a href="#${chapter['chapter']}">${otag}${chapter['title']}${etag}</a> + % for tab in range(1, chapter['level']): + </div> + % endfor + </div> + </div> + <% previousLevel = chapter['level'] %> + % endif + % endfor + </div> +</div> diff --git a/debian/dconv/templates/template.html b/debian/dconv/templates/template.html new file mode 100644 index 0000000..c72b355 --- /dev/null +++ b/debian/dconv/templates/template.html @@ -0,0 +1,238 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8" /> + <title>${headers['title']} ${headers['version']} - ${headers['subtitle']}</title> + <link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet" /> + <link href="${base}css/page.css?${version}" rel="stylesheet" /> + </head> + <body> + <nav class="navbar navbar-default navbar-fixed-top" role="navigation"> + <div class="navbar-header"> + <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#menu"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <a class="navbar-brand" href="${base}index.html">${headers['title']} <small>${headers['subtitle']}</small></a> + </div> + <!-- /.navbar-header --> + + <!-- Collect the nav links, forms, and other content for toggling --> + <div class="collapse navbar-collapse" id="menu"> + <ul class="nav navbar-nav"> + <li><a href="http://www.haproxy.org/">HAProxy home page</a></li> + <li class="dropdown"> + <a href="#" class="dropdown-toggle" data-toggle="dropdown">Versions <b class="caret"></b></a> + <ul class="dropdown-menu"> + ## TODO : provide a structure to dynamically generate per version links + <li class="dropdown-header">HAProxy 1.4</li> + <li><a href="${base}configuration-1.4.html">Configuration Manual <small>(stable)</small></a></li> + <li><a href="${base}snapshot/configuration-1.4.html">Configuration Manual <small>(snapshot)</small></a></li> + <li><a href="http://git.1wt.eu/git/haproxy-1.4.git/">GIT Repository</a></li> + <li><a href="http://www.haproxy.org/git/?p=haproxy-1.4.git">Browse repository</a></li> + <li><a href="http://www.haproxy.org/download/1.4/">Browse directory</a></li> + <li class="divider"></li> + <li class="dropdown-header">HAProxy 1.5</li> + <li><a href="${base}configuration-1.5.html">Configuration Manual <small>(stable)</small></a></li> + <li><a href="${base}snapshot/configuration-1.5.html">Configuration Manual <small>(snapshot)</small></a></li> + <li><a href="http://git.1wt.eu/git/haproxy-1.5.git/">GIT Repository</a></li> + <li><a href="http://www.haproxy.org/git/?p=haproxy-1.5.git">Browse repository</a></li> + <li><a href="http://www.haproxy.org/download/1.5/">Browse directory</a></li> + <li class="divider"></li> + <li class="dropdown-header">HAProxy 1.6</li> + <li><a href="${base}configuration-1.6.html">Configuration Manual <small>(stable)</small></a></li> + <li><a href="${base}snapshot/configuration-1.6.html">Configuration Manual <small>(snapshot)</small></a></li> + <li><a href="${base}intro-1.6.html">Starter Guide <small>(stable)</small></a></li> + <li><a href="${base}snapshot/intro-1.6.html">Starter Guide <small>(snapshot)</small></a></li> + <li><a href="http://git.1wt.eu/git/haproxy.git/">GIT Repository</a></li> + <li><a href="http://www.haproxy.org/git/?p=haproxy.git">Browse repository</a></li> + <li><a href="http://www.haproxy.org/download/1.6/">Browse directory</a></li> + </ul> + </li> + </ul> + </div> + </nav> + <!-- /.navbar-static-side --> + + <div id="wrapper"> + + <div id="sidebar"> + <form onsubmit="search(this.keyword.value); return false" role="form"> + <div id="searchKeyword" class="form-group"> + <input type="text" class="form-control typeahead" id="keyword" name="keyword" placeholder="Search..." autocomplete="off"> + </div> + </form> + <p> + Keyboard navigation : <span id="keyboardNavStatus"></span> + </p> + <p> + When enabled, you can use <strong>left</strong> and <strong>right</strong> arrow keys to navigate between chapters.<br> + The feature is automatically disabled when the search field is focused. + </p> + <p class="text-right"> + <small>Converted with <a href="https://github.com/cbonte/haproxy-dconv">haproxy-dconv</a> v<b>${version}</b> on <b>${date}</b></small> + </p> + </div> + <!-- /.sidebar --> + + <div id="page-wrapper"> + <div class="row"> + <div class="col-lg-12"> + <div class="text-center"> + <h1>${headers['title']}</h1> + <h2>${headers['subtitle']}</h2> + <p><strong>${headers['version']}</strong></p> + <p> + <a href="http://www.haproxy.org/" title="HAProxy Home Page"><img src="${base}img/logo-med.png" /></a><br> + ${headers['author']}<br> + ${headers['date']} + </p> + </div> + + ${document} + <br> + <hr> + <div class="text-right"> + ${headers['title']} ${headers['version'].replace("version ", "")} – ${headers['subtitle']}<br> + <small>${headers['date']}, ${headers['author']}</small> + </div> + </div> + <!-- /.col-lg-12 --> + </div> + <!-- /.row --> + <div style="position: fixed; z-index: 1000; bottom: 0; left: 0; right: 0; padding: 10px"> + <ul class="pager" style="margin: 0"> + <li class="previous"><a id="previous" href="#"></a></li> + <li class="next"><a id="next" href="#"></a></li> + </ul> + </div> + </div> + <!-- /#page-wrapper --> + + </div> + <!-- /#wrapper --> + + <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> + <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/js/bootstrap.min.js"></script> + <script src="//cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.min.js"></script> + <script> + /* Keyword search */ + var searchFocus = false + var keywords = [ + "${'",\n\t\t\t\t"'.join(keywords)}" + ] + + function updateKeyboardNavStatus() { + var status = searchFocus ? '<span class="label label-disabled">Disabled</span>' : '<span class="label label-success">Enabled</span>' + $('#keyboardNavStatus').html(status) + } + + function search(keyword) { + if (keyword && !!~$.inArray(keyword, keywords)) { + window.location.hash = keyword + } + } + // constructs the suggestion engine + var kwbh = new Bloodhound({ + datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'), + queryTokenizer: Bloodhound.tokenizers.whitespace, + local: $.map(keywords, function(keyword) { return { value: keyword }; }) + }); + kwbh.initialize() + + $('#searchKeyword .typeahead').typeahead({ + hint: true, + highlight: true, + minLength: 1, + autoselect: true + }, + { + name: 'keywords', + displayKey: 'value', + limit: keywords.length, + source: kwbh.ttAdapter() + }).focus(function() { + searchFocus = true + updateKeyboardNavStatus() + }).blur(function() { + searchFocus = false + updateKeyboardNavStatus() + }).bind('typeahead:selected', function ($e, datum) { + search(datum.value) + }) + + /* EXPERIMENTAL - Previous/Next navigation */ + var headings = $(":header") + var previousTarget = false + var nextTarget = false + var $previous = $('#previous') + var $next = $('#next') + function refreshNavigation() { + var previous = false + var next = false + $.each(headings, function(item, value) { + var el = $(value) + + // TODO : avoid target recalculation on each refresh + var target = el.attr('data-target') + if (! target) return true + + var target_el = $('#' + target.replace(/\./, "\\.")) + if (! target_el.attr('id')) return true + + if (target_el.offset().top < $(window).scrollTop()) { + previous = el + } + if (target_el.offset().top - 1 > $(window).scrollTop()) { + next = el + } + if (next) return false + }) + + previousTarget = previous ? previous.attr('data-target') : 'top' + $previous.html( + previous && previousTarget ? + '<span class="glyphicon glyphicon-arrow-left"></span> ' + previous.text() : + '<span class="glyphicon glyphicon-arrow-up"></span> Top' + ).attr('href', '#' + previousTarget) + + nextTarget = next ? next.attr('data-target') : 'bottom' + $next.html( + next && nextTarget ? + next.text() + ' <span class="glyphicon glyphicon-arrow-right"></span>' : + 'Bottom <span class="glyphicon glyphicon-arrow-down"></span>' + ).attr('href', '#' + nextTarget) + } + + $(window).scroll(function () { + refreshNavigation() + }); + $(document).ready(function() { + refreshNavigation() + updateKeyboardNavStatus() + }); + + /* EXPERIMENTAL - Enable keyboard navigation */ + $(document).keydown(function(e){ + if (searchFocus) return + + switch(e.which) { + case 37: // left + window.location.hash = previousTarget ? previousTarget : 'top' + break + + case 39: // right + window.location.hash = nextTarget ? nextTarget : 'bottom' + break + + default: return // exit this handler for other keys + } + e.preventDefault() + }) + </script> + ${footer} + <a class="anchor" name="bottom"></a> + </body> +</html> diff --git a/debian/dconv/tools/generate-docs.sh b/debian/dconv/tools/generate-docs.sh new file mode 100755 index 0000000..36fdf1b --- /dev/null +++ b/debian/dconv/tools/generate-docs.sh @@ -0,0 +1,177 @@ +#!/bin/bash + +PROJECT_HOME=$(dirname $(readlink -f $0)) +cd $PROJECT_HOME || exit 1 + +WORK_DIR=$PROJECT_HOME/work + +function on_exit() +{ + echo "-- END $(date)" +} + +function init() +{ + trap on_exit EXIT + + echo + echo "-- START $(date)" + echo "PROJECT_HOME = $PROJECT_HOME" + + echo "Preparing work directories..." + mkdir -p $WORK_DIR || exit 1 + mkdir -p $WORK_DIR/haproxy || exit 1 + mkdir -p $WORK_DIR/haproxy-dconv || exit 1 + + UPDATED=0 + PUSH=0 + +} + +# Needed as "git -C" is only available since git 1.8.5 +function git-C() +{ + _gitpath=$1 + shift + echo "git --git-dir=$_gitpath/.git --work-tree=$_gitpath $@" >&2 + git --git-dir=$_gitpath/.git --work-tree=$_gitpath "$@" +} + +function fetch_haproxy_dconv() +{ + echo "Fetching latest haproxy-dconv public version..." + if [ ! -e $WORK_DIR/haproxy-dconv/master ]; + then + git clone -v git://github.com/cbonte/haproxy-dconv.git $WORK_DIR/haproxy-dconv/master || exit 1 + fi + GIT="git-C $WORK_DIR/haproxy-dconv/master" + + OLD_MD5="$($GIT log -1 | md5sum) $($GIT describe --tags)" + $GIT checkout master && $GIT pull -v + version=$($GIT describe --tags) + version=${version%-g*} + NEW_MD5="$($GIT log -1 | md5sum) $($GIT describe --tags)" + if [ "$OLD_MD5" != "$NEW_MD5" ]; + then + UPDATED=1 + fi + + echo "Fetching last haproxy-dconv public pages version..." + if [ ! -e $WORK_DIR/haproxy-dconv/gh-pages ]; + then + cp -a $WORK_DIR/haproxy-dconv/master $WORK_DIR/haproxy-dconv/gh-pages || exit 1 + fi + GIT="git-C $WORK_DIR/haproxy-dconv/gh-pages" + + $GIT checkout gh-pages && $GIT pull -v +} + +function fetch_haproxy() +{ + url=$1 + path=$2 + + echo "Fetching HAProxy 1.4 repository..." + if [ ! -e $path ]; + then + git clone -v $url $path || exit 1 + fi + GIT="git-C $path" + + $GIT checkout master && $GIT pull -v +} + +function _generate_file() +{ + infile=$1 + destfile=$2 + git_version=$3 + state=$4 + + $GIT checkout $git_version + + if [ -e $gitpath/doc/$infile ]; + then + + git_version_simple=${git_version%-g*} + doc_version=$(tail -n1 $destfile 2>/dev/null | grep " git:" | sed 's/.* git:\([^ ]*\).*/\1/') + if [ $UPDATED -eq 1 -o "$git_version" != "$doc_version" ]; + then + HTAG="VERSION-$(basename $gitpath | sed 's/[.]/\\&/g')" + if [ "$state" == "snapshot" ]; + then + base=".." + HTAG="$HTAG-SNAPSHOT" + else + base="." + fi + + + $WORK_DIR/haproxy-dconv/master/haproxy-dconv.py -i $gitpath/doc/$infile -o $destfile --base=$base && + echo "<!-- git:$git_version -->" >> $destfile && + sed -i "s/\(<\!-- $HTAG -->\)\(.*\)\(<\!-- \/$HTAG -->\)/\1${git_version_simple}\3/" $docroot/index.html + + else + echo "Already up to date." + fi + + if [ "$doc_version" != "" -a "$git_version" != "$doc_version" ]; + then + changelog=$($GIT log --oneline $doc_version..$git_version $gitpath/doc/$infile) + else + changelog="" + fi + + GITDOC="git-C $docroot" + if [ "$($GITDOC status -s $destfile)" != "" ]; + then + $GITDOC add $destfile && + $GITDOC commit -m "Updating HAProxy $state $infile ${git_version_simple} generated by haproxy-dconv $version" -m "$changelog" $destfile $docroot/index.html && + PUSH=1 + fi + fi +} + +function generate_docs() +{ + url=$1 + gitpath=$2 + docroot=$3 + infile=$4 + outfile=$5 + + fetch_haproxy $url $gitpath + + GIT="git-C $gitpath" + + $GIT checkout master + git_version=$($GIT describe --tags --match 'v*') + git_version_stable=${git_version%-*-g*} + + echo "Generating snapshot version $git_version..." + _generate_file $infile $docroot/snapshot/$outfile $git_version snapshot + + echo "Generating stable version $git_version..." + _generate_file $infile $docroot/$outfile $git_version_stable stable +} + +function push() +{ + docroot=$1 + GITDOC="git-C $docroot" + + if [ $PUSH -eq 1 ]; + then + $GITDOC push origin gh-pages + fi + +} + + +init +fetch_haproxy_dconv +generate_docs http://git.1wt.eu/git/haproxy-1.4.git/ $WORK_DIR/haproxy/1.4 $WORK_DIR/haproxy-dconv/gh-pages configuration.txt configuration-1.4.html +generate_docs http://git.1wt.eu/git/haproxy-1.5.git/ $WORK_DIR/haproxy/1.5 $WORK_DIR/haproxy-dconv/gh-pages configuration.txt configuration-1.5.html +generate_docs http://git.1wt.eu/git/haproxy.git/ $WORK_DIR/haproxy/1.6 $WORK_DIR/haproxy-dconv/gh-pages configuration.txt configuration-1.6.html +generate_docs http://git.1wt.eu/git/haproxy.git/ $WORK_DIR/haproxy/1.6 $WORK_DIR/haproxy-dconv/gh-pages intro.txt intro-1.6.html +push $WORK_DIR/haproxy-dconv/gh-pages diff --git a/debian/gbp.conf b/debian/gbp.conf new file mode 100644 index 0000000..2140c2f --- /dev/null +++ b/debian/gbp.conf @@ -0,0 +1,3 @@ +[DEFAULT] +pristine-tar = True +upstream-branch = upstream-2.6 diff --git a/debian/halog.1 b/debian/halog.1 new file mode 100644 index 0000000..f5dd19f --- /dev/null +++ b/debian/halog.1 @@ -0,0 +1,108 @@ +.TH HALOG "1" "July 2013" "halog" "User Commands" +.SH NAME +halog \- HAProxy log statistics reporter +.SH SYNOPSIS +.B halog +[\fI-h|--help\fR] +.br +.B halog +[\fIoptions\fR] <LOGFILE +.SH DESCRIPTION +.B halog +reads HAProxy log data from stdin and extracts and displays lines matching +user-specified criteria. +.SH OPTIONS +.SS Input filters \fR(several filters may be combined) +.TP +\fB\-H\fR +Only match lines containing HTTP logs (ignore TCP) +.TP +\fB\-E\fR +Only match lines without any error (no 5xx status) +.TP +\fB\-e\fR +Only match lines with errors (status 5xx or negative) +.TP +\fB\-rt\fR|\fB\-RT\fR <time> +Only match response times larger|smaller than <time> +.TP +\fB\-Q\fR|\fB\-QS\fR +Only match queued requests (any queue|server queue) +.TP +\fB\-tcn\fR|\fB\-TCN\fR <code> +Only match requests with/without termination code <code> +.TP +\fB\-hs\fR|\fB\-HS\fR <[min][:][max]> +Only match requests with HTTP status codes within/not within min..max. Any of +them may be omitted. Exact code is checked for if no ':' is specified. +.SS +Modifiers +.TP +\fB\-v\fR +Invert the input filtering condition +.TP +\fB\-q\fR +Don't report errors/warnings +.TP +\fB\-m\fR <lines> +Limit output to the first <lines> lines +.SS +Output filters \fR\- only one may be used at a time +.TP +\fB\-c\fR +Only report the number of lines that would have been printed +.TP +\fB\-pct\fR +Output connect and response times percentiles +.TP +\fB\-st\fR +Output number of requests per HTTP status code +.TP +\fB\-cc\fR +Output number of requests per cookie code (2 chars) +.TP +\fB\-tc\fR +Output number of requests per termination code (2 chars) +.TP +\fB\-srv\fR +Output statistics per server (time, requests, errors) +.TP +\fB\-u\fR* +Output statistics per URL (time, requests, errors) +.br +Additional characters indicate the output sorting key: +.RS +.TP +\fB\-u\fR +URL +.TP +\fB\-uc\fR +Request count +.TP +\fB\-ue\fR +Error count +.TP +\fB\-ua\fR +Average response time +.TP +\fB\-ut\fR +Average total time +.TP +\fB\-uao\fR, \fB\-uto\fR +Average times computed on valid ('OK') requests +.TP +\fB\-uba\fR +Average bytes returned +.TP +\fB\-ubt\fR +Total bytes returned +.RE +.SH "SEE ALSO" +.BR haproxy (1) +.SH AUTHOR +.PP +\fBhalog\fR was written by Willy Tarreau <w@1wt.eu> and is part of \fBhaproxy\fR(1). +.PP +This manual page was written by Apollon Oikonomopoulos <apoikos@gmail.com> for the Debian project (but may +be used by others). + diff --git a/debian/haproxy-doc.doc-base.haproxy b/debian/haproxy-doc.doc-base.haproxy new file mode 100644 index 0000000..9d9a967 --- /dev/null +++ b/debian/haproxy-doc.doc-base.haproxy @@ -0,0 +1,9 @@ +Document: haproxy-doc +Title: HAProxy Documentation +Author: Willy Tarreau +Abstract: This documentation covers the configuration of HAProxy. +Section: System/Administration + +Format: HTML +Index: /usr/share/doc/haproxy/html/configuration.html +Files: /usr/share/doc/haproxy/html/*.html diff --git a/debian/haproxy-doc.doc-base.haproxy-lua b/debian/haproxy-doc.doc-base.haproxy-lua new file mode 100644 index 0000000..8234d78 --- /dev/null +++ b/debian/haproxy-doc.doc-base.haproxy-lua @@ -0,0 +1,9 @@ +Document: haproxy-lua-api +Title: HAProxy Lua API Documentation +Author: Thierry FOURNIER +Abstract: This documentation covers HAProxy's Lua API +Section: System/Administration + +Format: HTML +Index: /usr/share/doc/haproxy/lua/index.html +Files: /usr/share/doc/haproxy/lua/*.html diff --git a/debian/haproxy-doc.docs b/debian/haproxy-doc.docs new file mode 100644 index 0000000..569c21a --- /dev/null +++ b/debian/haproxy-doc.docs @@ -0,0 +1 @@ +debian/dconv/NOTICE diff --git a/debian/haproxy-doc.install b/debian/haproxy-doc.install new file mode 100644 index 0000000..e0a347e --- /dev/null +++ b/debian/haproxy-doc.install @@ -0,0 +1,7 @@ +doc/configuration.html usr/share/doc/haproxy/html/ +doc/intro.html usr/share/doc/haproxy/html/ +doc/management.html usr/share/doc/haproxy/html/ +doc/lua-api/_build/html/* usr/share/doc/haproxy/lua/ +debian/dconv/css/* usr/share/doc/haproxy/html/css/ +debian/dconv/js/* usr/share/doc/haproxy/html/js/ +debian/dconv/img/* usr/share/doc/haproxy/html/img/ diff --git a/debian/haproxy-doc.links b/debian/haproxy-doc.links new file mode 100644 index 0000000..93738f6 --- /dev/null +++ b/debian/haproxy-doc.links @@ -0,0 +1,6 @@ +usr/share/javascript/bootstrap/css/bootstrap.min.css usr/share/doc/haproxy/html/css/bootstrap.min.css +usr/share/javascript/bootstrap/js/bootstrap.min.js usr/share/doc/haproxy/html/js/bootstrap.min.js +usr/share/javascript/bootstrap/fonts usr/share/doc/haproxy/html/fonts +usr/share/javascript/jquery/jquery.min.js usr/share/doc/haproxy/html/js/jquery.min.js +usr/share/doc/haproxy/html /usr/share/doc/haproxy-doc/html +usr/share/doc/haproxy/lua /usr/share/doc/haproxy-doc/lua diff --git a/debian/haproxy-doc.maintscript b/debian/haproxy-doc.maintscript new file mode 100644 index 0000000..2f54652 --- /dev/null +++ b/debian/haproxy-doc.maintscript @@ -0,0 +1,2 @@ +dir_to_symlink /usr/share/doc/haproxy-doc/html /usr/share/doc/haproxy/html 1.6.3-2~ +dir_to_symlink /usr/share/doc/haproxy-doc/lua /usr/share/doc/haproxy/lua 1.6.3-2~ diff --git a/debian/haproxy.README.Debian b/debian/haproxy.README.Debian new file mode 100644 index 0000000..6e3e3ab --- /dev/null +++ b/debian/haproxy.README.Debian @@ -0,0 +1,29 @@ +Syslog support +-------------- +Upstream recommends using syslog over UDP to log from HAProxy processes, as +this allows seamless logging from chroot'ed processes without access to +/dev/log. However, many syslog implementations do not enable UDP syslog by +default. + +The default HAProxy configuration in Debian uses /dev/log for logging and +ships an rsyslog snippet that creates /dev/log in HAProxy's chroot and logs all +HAProxy messages to /var/log/haproxy.log. To take advantage of this, you must +restart rsyslog after installing this package. For other syslog daemons you +will have to take manual measures to enable UDP logging or create /dev/log +under HAProxy's chroot: +a. For sysklogd, add SYSLOG="-a /var/lib/haproxy/dev/log" to + /etc/default/syslog. +b. For inetutils-syslogd, add SYSLOGD_OPTS="-a /var/lib/haproxy/dev/log" to + /etc/default/inetutils-syslogd. + +Prometheus exporter +------------------- +HAProxy is shipped with a builtin Prometheus exporter. To enable it, +you need to configure the Prometheus endpoint: + + frontend stats + bind *:8404 + http-request use-service prometheus-exporter if { path /metrics } + stats enable + stats uri /stats + stats refresh 10s diff --git a/debian/haproxy.cfg b/debian/haproxy.cfg new file mode 100644 index 0000000..1eb7f18 --- /dev/null +++ b/debian/haproxy.cfg @@ -0,0 +1,34 @@ +global + log /dev/log local0 + log /dev/log local1 notice + chroot /var/lib/haproxy + stats socket /run/haproxy/admin.sock mode 660 level admin + stats timeout 30s + user haproxy + group haproxy + daemon + + # Default SSL material locations + ca-base /etc/ssl/certs + crt-base /etc/ssl/private + + # See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate + ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 + ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 + ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets + +defaults + log global + mode http + option httplog + option dontlognull + timeout connect 5000 + timeout client 50000 + timeout server 50000 + errorfile 400 /etc/haproxy/errors/400.http + errorfile 403 /etc/haproxy/errors/403.http + errorfile 408 /etc/haproxy/errors/408.http + errorfile 500 /etc/haproxy/errors/500.http + errorfile 502 /etc/haproxy/errors/502.http + errorfile 503 /etc/haproxy/errors/503.http + errorfile 504 /etc/haproxy/errors/504.http diff --git a/debian/haproxy.default b/debian/haproxy.default new file mode 100644 index 0000000..e15c193 --- /dev/null +++ b/debian/haproxy.default @@ -0,0 +1,10 @@ +# Defaults file for HAProxy +# +# This is sourced by both, the initscript and the systemd unit file, so do not +# treat it as a shell script fragment. + +# Change the config file location if needed +#CONFIG="/etc/haproxy/haproxy.cfg" + +# Add extra flags here, see haproxy(1) for a few options +#EXTRAOPTS="-de -m 16" diff --git a/debian/haproxy.dirs b/debian/haproxy.dirs new file mode 100644 index 0000000..b2e3c52 --- /dev/null +++ b/debian/haproxy.dirs @@ -0,0 +1,4 @@ +etc/haproxy +etc/haproxy/errors +var/lib/haproxy +var/lib/haproxy/dev diff --git a/debian/haproxy.docs b/debian/haproxy.docs new file mode 100644 index 0000000..a392a17 --- /dev/null +++ b/debian/haproxy.docs @@ -0,0 +1,9 @@ +doc/architecture.txt +doc/configuration.txt +doc/intro.txt +doc/lua.txt +doc/management.txt +doc/network-namespaces.txt +doc/SPOE.txt +admin +README diff --git a/debian/haproxy.examples b/debian/haproxy.examples new file mode 100644 index 0000000..08088cb --- /dev/null +++ b/debian/haproxy.examples @@ -0,0 +1 @@ +examples/*.cfg diff --git a/debian/haproxy.init b/debian/haproxy.init new file mode 100644 index 0000000..6f4096b --- /dev/null +++ b/debian/haproxy.init @@ -0,0 +1,197 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: haproxy +# Required-Start: $local_fs $network $remote_fs $syslog $named +# Required-Stop: $local_fs $remote_fs $syslog $named +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: fast and reliable load balancing reverse proxy +# Description: This file should be used to start and stop haproxy. +### END INIT INFO + +# Author: Arnaud Cornet <acornet@debian.org> + +PATH=/sbin:/usr/sbin:/bin:/usr/bin +BASENAME=haproxy +PIDFILE=/var/run/${BASENAME}.pid +CONFIG=/etc/${BASENAME}/${BASENAME}.cfg +HAPROXY=/usr/sbin/haproxy +RUNDIR=/run/${BASENAME} +EXTRAOPTS= + +test -x $HAPROXY || exit 0 + +if [ -e /etc/default/${BASENAME} ]; then + . /etc/default/${BASENAME} +fi + +test -f "$CONFIG" || exit 0 + +[ -f /etc/default/rcS ] && . /etc/default/rcS +. /lib/lsb/init-functions + + +check_haproxy_config() +{ + $HAPROXY -c -f "$CONFIG" $EXTRAOPTS >/dev/null + if [ $? -eq 1 ]; then + log_end_msg 1 + exit 1 + fi +} + +haproxy_start() +{ + [ -d "$RUNDIR" ] || mkdir "$RUNDIR" + chown haproxy:haproxy "$RUNDIR" + chmod 2775 "$RUNDIR" + + check_haproxy_config + + start-stop-daemon --quiet --oknodo --start --pidfile "$PIDFILE" \ + --exec $HAPROXY -- -f "$CONFIG" -D -p "$PIDFILE" \ + $EXTRAOPTS || return 2 + return 0 +} + +haproxy_stop() +{ + if [ ! -f $PIDFILE ] ; then + # This is a success according to LSB + return 0 + fi + + ret=0 + tmppid="$(mktemp)" + + # HAProxy's pidfile may contain multiple PIDs, if nbproc > 1, so loop + # over each PID. Note that start-stop-daemon has a --pid option, but it + # was introduced in dpkg 1.17.6, post wheezy, so we use a temporary + # pidfile instead to ease backports. + for pid in $(cat $PIDFILE); do + echo "$pid" > "$tmppid" + start-stop-daemon --quiet --oknodo --stop \ + --retry 5 --pidfile "$tmppid" --exec $HAPROXY || ret=$? + done + + rm -f "$tmppid" + [ $ret -eq 0 ] && rm -f $PIDFILE + + return $ret +} + +haproxy_reload() +{ + check_haproxy_config + + $HAPROXY -f "$CONFIG" -p $PIDFILE -sf $(cat $PIDFILE) -D $EXTRAOPTS \ + || return 2 + return 0 +} + +haproxy_status() +{ + if [ ! -f $PIDFILE ] ; then + # program not running + return 3 + fi + + for pid in $(cat $PIDFILE) ; do + if ! ps --no-headers p "$pid" | grep haproxy > /dev/null ; then + # program running, bogus pidfile + return 1 + fi + done + + return 0 +} + + +case "$1" in +start) + log_daemon_msg "Starting haproxy" "${BASENAME}" + haproxy_start + ret=$? + case "$ret" in + 0) + log_end_msg 0 + ;; + 1) + log_end_msg 1 + echo "pid file '$PIDFILE' found, ${BASENAME} not started." + ;; + 2) + log_end_msg 1 + ;; + esac + exit $ret + ;; +stop) + log_daemon_msg "Stopping haproxy" "${BASENAME}" + haproxy_stop + ret=$? + case "$ret" in + 0|1) + log_end_msg 0 + ;; + 2) + log_end_msg 1 + ;; + esac + exit $ret + ;; +reload|force-reload) + log_daemon_msg "Reloading haproxy" "${BASENAME}" + haproxy_reload + ret=$? + case "$ret" in + 0|1) + log_end_msg 0 + ;; + 2) + log_end_msg 1 + ;; + esac + exit $ret + ;; +restart) + log_daemon_msg "Restarting haproxy" "${BASENAME}" + haproxy_stop + haproxy_start + ret=$? + case "$ret" in + 0) + log_end_msg 0 + ;; + 1) + log_end_msg 1 + ;; + 2) + log_end_msg 1 + ;; + esac + exit $ret + ;; +status) + haproxy_status + ret=$? + case "$ret" in + 0) + echo "${BASENAME} is running." + ;; + 1) + echo "${BASENAME} dead, but $PIDFILE exists." + ;; + *) + echo "${BASENAME} not running." + ;; + esac + exit $ret + ;; +*) + echo "Usage: /etc/init.d/${BASENAME} {start|stop|reload|restart|status}" + exit 2 + ;; +esac + +: diff --git a/debian/haproxy.install b/debian/haproxy.install new file mode 100644 index 0000000..0f13f73 --- /dev/null +++ b/debian/haproxy.install @@ -0,0 +1,4 @@ +debian/haproxy.cfg etc/haproxy +examples/errorfiles/*.http etc/haproxy/errors +admin/systemd/haproxy.service lib/systemd/system +admin/halog/halog usr/bin diff --git a/debian/haproxy.maintscript b/debian/haproxy.maintscript new file mode 100644 index 0000000..7a45edb --- /dev/null +++ b/debian/haproxy.maintscript @@ -0,0 +1 @@ +mv_conffile /etc/rsyslog.d/haproxy.conf /etc/rsyslog.d/49-haproxy.conf 1.5.3-2~ diff --git a/debian/haproxy.manpages b/debian/haproxy.manpages new file mode 100644 index 0000000..cee4732 --- /dev/null +++ b/debian/haproxy.manpages @@ -0,0 +1,3 @@ +doc/haproxy.1 +doc/lua-api/_build/man/haproxy-lua.1 +debian/halog.1 diff --git a/debian/haproxy.postinst b/debian/haproxy.postinst new file mode 100644 index 0000000..08feb12 --- /dev/null +++ b/debian/haproxy.postinst @@ -0,0 +1,22 @@ +#!/bin/sh + +set -e + +adduser --system --disabled-password --disabled-login --home /var/lib/haproxy \ + --no-create-home --quiet --force-badname --group haproxy + +#DEBHELPER# + +if [ -n "$2" ]; then + if dpkg --compare-versions "$2" lt "1.8.0-1~" && [ -d /run/systemd/system ]; then + # Do a full restart when upgrading to 1.8 series on systemd, as + # the systemd wrapper is no longer there. + invoke-rc.d haproxy restart || true + elif dpkg --compare-versions "$2" gt "1.5~dev24-2~"; then + # Reload already running instances. Since 1.5~dev24-2 we do not stop + # haproxy in prerm during upgrades. + invoke-rc.d haproxy reload || true + fi +fi + +exit 0 diff --git a/debian/haproxy.postrm b/debian/haproxy.postrm new file mode 100644 index 0000000..5e41016 --- /dev/null +++ b/debian/haproxy.postrm @@ -0,0 +1,16 @@ +#!/bin/sh + +set -e + +#DEBHELPER# + +case "$1" in + purge) + deluser --system haproxy || true + delgroup --system haproxy || true + ;; + *) + ;; +esac + +exit 0 diff --git a/debian/haproxy.tmpfile b/debian/haproxy.tmpfile new file mode 100644 index 0000000..9978887 --- /dev/null +++ b/debian/haproxy.tmpfile @@ -0,0 +1 @@ +d /run/haproxy 2775 haproxy haproxy - diff --git a/debian/haproxy.vim b/debian/haproxy.vim new file mode 100644 index 0000000..d58d0a5 --- /dev/null +++ b/debian/haproxy.vim @@ -0,0 +1,2 @@ +" detect HAProxy configuration +au BufRead,BufNewFile haproxy*.cfg set filetype=haproxy diff --git a/debian/logrotate.conf b/debian/logrotate.conf new file mode 100644 index 0000000..0086ee1 --- /dev/null +++ b/debian/logrotate.conf @@ -0,0 +1,11 @@ +/var/log/haproxy.log { + daily + rotate 7 + missingok + notifempty + compress + delaycompress + postrotate + [ ! -x /usr/lib/rsyslog/rsyslog-rotate ] || /usr/lib/rsyslog/rsyslog-rotate + endscript +} diff --git a/debian/patches/BUG-MAJOR-h3-reject-header-values-containing-invalid.patch b/debian/patches/BUG-MAJOR-h3-reject-header-values-containing-invalid.patch new file mode 100644 index 0000000..11ae6f8 --- /dev/null +++ b/debian/patches/BUG-MAJOR-h3-reject-header-values-containing-invalid.patch @@ -0,0 +1,100 @@ +From: Willy Tarreau <w@1wt.eu> +Date: Tue, 8 Aug 2023 17:18:27 +0200 +Subject: BUG/MAJOR: h3: reject header values containing invalid chars +Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=20a35c4d505475215122d37405ce173075338032 + +In practice it's exactly the same for h3 as 54f53ef7c ("BUG/MAJOR: h2: +reject header values containing invalid chars") was for h2: we must +make sure never to accept NUL/CR/LF in any header value because this +may be used to construct splitted headers on the backend. Hence we +apply the same solution. Here pseudo-headers, headers and trailers are +checked separately, which explains why we have 3 locations instead of +2 for h2 (+1 for response which we don't have here). + +This is marked major for consistency and due to the impact if abused, +but the reality is that at the time of writing, this problem is limited +by the scarcity of the tools which would permit to build such a request +in the first place. But this may change over time. + +This must be backported to 2.6. This depends on the following commit +that exposes the filtering function: + + REORG: http: move has_forbidden_char() from h2.c to http.h + +(cherry picked from commit d13a80abb7c1badaa42045c37cfff79f24f05726) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 0404bf14c900d6ac879ec432a198435e0741d835) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit f58b63af68f239464c29e698a34f08ff3eef862f) + [ad: no http/3 trailer support in 2.6] +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +--- + src/h3.c | 38 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/src/h3.c b/src/h3.c +index 9b4bc6f096d7..b42d41647e4e 100644 +--- a/src/h3.c ++++ b/src/h3.c +@@ -401,6 +401,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf, + struct ist scheme = IST_NULL, authority = IST_NULL; + int hdr_idx, ret; + int cookie = -1, last_cookie = -1, i; ++ const char *ctl; + + /* RFC 9114 4.1.2. Malformed Requests and Responses + * +@@ -464,6 +465,24 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf, + if (!istmatch(list[hdr_idx].n, ist(":"))) + break; + ++ /* RFC 9114 10.3 Intermediary-Encapsulation Attacks ++ * ++ * While most values that can be encoded will not alter field ++ * parsing, carriage return (ASCII 0x0d), line feed (ASCII 0x0a), ++ * and the null character (ASCII 0x00) might be exploited by an ++ * attacker if they are translated verbatim. Any request or ++ * response that contains a character not permitted in a field ++ * value MUST be treated as malformed ++ */ ++ ++ /* look for forbidden control characters in the pseudo-header value */ ++ ctl = ist_find_ctl(list[hdr_idx].v); ++ if (unlikely(ctl) && http_header_has_forbidden_char(list[hdr_idx].v, ctl)) { ++ TRACE_ERROR("control character present in pseudo-header value", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs); ++ len = -1; ++ goto out; ++ } ++ + /* pseudo-header. Malformed name with uppercase character or + * invalid token will be rejected in the else clause. + */ +@@ -561,6 +580,25 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf, + } + } + ++ ++ /* RFC 9114 10.3 Intermediary-Encapsulation Attacks ++ * ++ * While most values that can be encoded will not alter field ++ * parsing, carriage return (ASCII 0x0d), line feed (ASCII 0x0a), ++ * and the null character (ASCII 0x00) might be exploited by an ++ * attacker if they are translated verbatim. Any request or ++ * response that contains a character not permitted in a field ++ * value MUST be treated as malformed ++ */ ++ ++ /* look for forbidden control characters in the header value */ ++ ctl = ist_find_ctl(list[hdr_idx].v); ++ if (unlikely(ctl) && http_header_has_forbidden_char(list[hdr_idx].v, ctl)) { ++ TRACE_ERROR("control character present in header value", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs); ++ len = -1; ++ goto out; ++ } ++ + if (isteq(list[hdr_idx].n, ist("cookie"))) { + http_cookie_register(list, hdr_idx, &cookie, &last_cookie); + ++hdr_idx; +-- +2.43.0 + diff --git a/debian/patches/BUG-MAJOR-http-reject-any-empty-content-length-heade.patch b/debian/patches/BUG-MAJOR-http-reject-any-empty-content-length-heade.patch new file mode 100644 index 0000000..fb8bcb0 --- /dev/null +++ b/debian/patches/BUG-MAJOR-http-reject-any-empty-content-length-heade.patch @@ -0,0 +1,274 @@ +From: Willy Tarreau <w@1wt.eu> +Date: Wed, 9 Aug 2023 08:32:48 +0200 +Subject: BUG/MAJOR: http: reject any empty content-length header value +Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=d17c50010d591d1c070e1cb0567a06032d8869e9 +Bug-Debian: https://bugs.debian.org/1043502 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2023-40225 + +The content-length header parser has its dedicated function, in order +to take extreme care about invalid, unparsable, or conflicting values. +But there's a corner case in it, by which it stops comparing values +when reaching the end of the header. This has for a side effect that +an empty value or a value that ends with a comma does not deserve +further analysis, and it acts as if the header was absent. + +While this is not necessarily a problem for the value ending with a +comma as it will be cause a header folding and will disappear, it is a +problem for the first isolated empty header because this one will not +be recontructed when next ones are seen, and will be passed as-is to the +backend server. A vulnerable HTTP/1 server hosted behind haproxy that +would just use this first value as "0" and ignore the valid one would +then not be protected by haproxy and could be attacked this way, taking +the payload for an extra request. + +In field the risk depends on the server. Most commonly used servers +already have safe content-length parsers, but users relying on haproxy +to protect a known-vulnerable server might be at risk (and the risk of +a bug even in a reputable server should never be dismissed). + +A configuration-based work-around consists in adding the following rule +in the frontend, to explicitly reject requests featuring an empty +content-length header that would have not be folded into an existing +one: + + http-request deny if { hdr_len(content-length) 0 } + +The real fix consists in adjusting the parser so that it always expects a +value at the beginning of the header or after a comma. It will now reject +requests and responses having empty values anywhere in the C-L header. + +This needs to be backported to all supported versions. Note that the +modification was made to functions h1_parse_cont_len_header() and +http_parse_cont_len_header(). Prior to 2.8 the latter was in +h2_parse_cont_len_header(). One day the two should be refused but the +former is also used by Lua. + +The HTTP messaging reg-tests were completed to test these cases. + +Thanks to Ben Kallus of Dartmouth College and Narf Industries for +reporting this! (this is in GH #2237). + +(cherry picked from commit 6492f1f29d738457ea9f382aca54537f35f9d856) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit a32f99f6f991d123ea3e307bf8aa63220836d365) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 65921ee12d88e9fb1fa9f6cd8198fd64b3a3f37f) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +--- + reg-tests/http-messaging/h1_to_h1.vtc | 26 ++++++++++++ + reg-tests/http-messaging/h2_to_h1.vtc | 60 +++++++++++++++++++++++++++ + src/h1.c | 20 +++++++-- + src/http.c | 20 +++++++-- + 4 files changed, 120 insertions(+), 6 deletions(-) + +diff --git a/reg-tests/http-messaging/h1_to_h1.vtc b/reg-tests/http-messaging/h1_to_h1.vtc +index 0d6536698608..67aba1440949 100644 +--- a/reg-tests/http-messaging/h1_to_h1.vtc ++++ b/reg-tests/http-messaging/h1_to_h1.vtc +@@ -273,3 +273,29 @@ client c3h1 -connect ${h1_feh1_sock} { + # arrive here. + expect_close + } -run ++ ++client c4h1 -connect ${h1_feh1_sock} { ++ # this request is invalid and advertises an invalid C-L ending with an ++ # empty value, which results in a stream error. ++ txreq \ ++ -req "GET" \ ++ -url "/test31.html" \ ++ -hdr "content-length: 0," \ ++ -hdr "connection: close" ++ rxresp ++ expect resp.status == 400 ++ expect_close ++} -run ++ ++client c5h1 -connect ${h1_feh1_sock} { ++ # this request is invalid and advertises an empty C-L, which results ++ # in a stream error. ++ txreq \ ++ -req "GET" \ ++ -url "/test41.html" \ ++ -hdr "content-length:" \ ++ -hdr "connection: close" ++ rxresp ++ expect resp.status == 400 ++ expect_close ++} -run +diff --git a/reg-tests/http-messaging/h2_to_h1.vtc b/reg-tests/http-messaging/h2_to_h1.vtc +index 852ee4caf9dd..5c8c8214314b 100644 +--- a/reg-tests/http-messaging/h2_to_h1.vtc ++++ b/reg-tests/http-messaging/h2_to_h1.vtc +@@ -10,6 +10,8 @@ barrier b1 cond 2 -cyclic + barrier b2 cond 2 -cyclic + barrier b3 cond 2 -cyclic + barrier b4 cond 2 -cyclic ++barrier b5 cond 2 -cyclic ++barrier b6 cond 2 -cyclic + + server s1 { + rxreq +@@ -31,6 +33,12 @@ server s1 { + + barrier b4 sync + # the next request is never received ++ ++ barrier b5 sync ++ # the next request is never received ++ ++ barrier b6 sync ++ # the next request is never received + } -repeat 2 -start + + haproxy h1 -conf { +@@ -120,6 +128,32 @@ client c1h2 -connect ${h1_feh2_sock} { + txdata -data "this is sent and ignored" + rxrst + } -run ++ ++ # fifth request is invalid and advertises an invalid C-L ending with an ++ # empty value, which results in a stream error. ++ stream 9 { ++ barrier b5 sync ++ txreq \ ++ -req "GET" \ ++ -scheme "https" \ ++ -url "/test5.html" \ ++ -hdr "content-length" "0," \ ++ -nostrend ++ rxrst ++ } -run ++ ++ # sixth request is invalid and advertises an empty C-L, which results ++ # in a stream error. ++ stream 11 { ++ barrier b6 sync ++ txreq \ ++ -req "GET" \ ++ -scheme "https" \ ++ -url "/test6.html" \ ++ -hdr "content-length" "" \ ++ -nostrend ++ rxrst ++ } -run + } -run + + # HEAD requests : don't work well yet +@@ -262,4 +296,30 @@ client c3h2 -connect ${h1_feh2_sock} { + txdata -data "this is sent and ignored" + rxrst + } -run ++ ++ # fifth request is invalid and advertises invalid C-L ending with an ++ # empty value, which results in a stream error. ++ stream 9 { ++ barrier b5 sync ++ txreq \ ++ -req "POST" \ ++ -scheme "https" \ ++ -url "/test25.html" \ ++ -hdr "content-length" "0," \ ++ -nostrend ++ rxrst ++ } -run ++ ++ # sixth request is invalid and advertises an empty C-L, which results ++ # in a stream error. ++ stream 11 { ++ barrier b6 sync ++ txreq \ ++ -req "POST" \ ++ -scheme "https" \ ++ -url "/test26.html" \ ++ -hdr "content-length" "" \ ++ -nostrend ++ rxrst ++ } -run + } -run +diff --git a/src/h1.c b/src/h1.c +index 88a54c4a593d..126f23cc7376 100644 +--- a/src/h1.c ++++ b/src/h1.c +@@ -34,13 +34,20 @@ int h1_parse_cont_len_header(struct h1m *h1m, struct ist *value) + int not_first = !!(h1m->flags & H1_MF_CLEN); + struct ist word; + +- word.ptr = value->ptr - 1; // -1 for next loop's pre-increment ++ word.ptr = value->ptr; + e = value->ptr + value->len; + +- while (++word.ptr < e) { ++ while (1) { ++ if (word.ptr >= e) { ++ /* empty header or empty value */ ++ goto fail; ++ } ++ + /* skip leading delimiter and blanks */ +- if (unlikely(HTTP_IS_LWS(*word.ptr))) ++ if (unlikely(HTTP_IS_LWS(*word.ptr))) { ++ word.ptr++; + continue; ++ } + + /* digits only now */ + for (cl = 0, n = word.ptr; n < e; n++) { +@@ -79,6 +86,13 @@ int h1_parse_cont_len_header(struct h1m *h1m, struct ist *value) + h1m->flags |= H1_MF_CLEN; + h1m->curr_len = h1m->body_len = cl; + *value = word; ++ ++ /* Now either n==e and we're done, or n points to the comma, ++ * and we skip it and continue. ++ */ ++ if (n++ == e) ++ break; ++ + word.ptr = n; + } + /* here we've reached the end with a single value or a series of +diff --git a/src/http.c b/src/http.c +index edf4744553a2..a33c673c11da 100644 +--- a/src/http.c ++++ b/src/http.c +@@ -707,13 +707,20 @@ int http_parse_cont_len_header(struct ist *value, unsigned long long *body_len, + struct ist word; + int check_prev = not_first; + +- word.ptr = value->ptr - 1; // -1 for next loop's pre-increment ++ word.ptr = value->ptr; + e = value->ptr + value->len; + +- while (++word.ptr < e) { ++ while (1) { ++ if (word.ptr >= e) { ++ /* empty header or empty value */ ++ goto fail; ++ } ++ + /* skip leading delimiter and blanks */ +- if (unlikely(HTTP_IS_LWS(*word.ptr))) ++ if (unlikely(HTTP_IS_LWS(*word.ptr))) { ++ word.ptr++; + continue; ++ } + + /* digits only now */ + for (cl = 0, n = word.ptr; n < e; n++) { +@@ -751,6 +758,13 @@ int http_parse_cont_len_header(struct ist *value, unsigned long long *body_len, + /* OK, store this result as the one to be indexed */ + *body_len = cl; + *value = word; ++ ++ /* Now either n==e and we're done, or n points to the comma, ++ * and we skip it and continue. ++ */ ++ if (n++ == e) ++ break; ++ + word.ptr = n; + check_prev = 1; + } +-- +2.43.0 + diff --git a/debian/patches/BUG-MINOR-h1-do-not-accept-as-part-of-the-URI-compon.patch b/debian/patches/BUG-MINOR-h1-do-not-accept-as-part-of-the-URI-compon.patch new file mode 100644 index 0000000..02d1e74 --- /dev/null +++ b/debian/patches/BUG-MINOR-h1-do-not-accept-as-part-of-the-URI-compon.patch @@ -0,0 +1,118 @@ +From: Willy Tarreau <w@1wt.eu> +Date: Tue, 8 Aug 2023 16:17:22 +0200 +Subject: BUG/MINOR: h1: do not accept '#' as part of the URI component +Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=832b672eee54866c7a42a1d46078cc9ae0d544d9 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2023-45539 + +Seth Manesse and Paul Plasil reported that the "path" sample fetch +function incorrectly accepts '#' as part of the path component. This +can in some cases lead to misrouted requests for rules that would apply +on the suffix: + + use_backend static if { path_end .png .jpg .gif .css .js } + +Note that this behavior can be selectively configured using +"normalize-uri fragment-encode" and "normalize-uri fragment-strip". + +The problem is that while the RFC says that this '#' must never be +emitted, as often it doesn't suggest how servers should handle it. A +diminishing number of servers still do accept it and trim it silently, +while others are rejecting it, as indicated in the conversation below +with other implementers: + + https://lists.w3.org/Archives/Public/ietf-http-wg/2023JulSep/0070.html + +Looking at logs from publicly exposed servers, such requests appear at +a rate of roughly 1 per million and only come from attacks or poorly +written web crawlers incorrectly following links found on various pages. + +Thus it looks like the best solution to this problem is to simply reject +such ambiguous requests by default, and include this in the list of +controls that can be disabled using "option accept-invalid-http-request". + +We're already rejecting URIs containing any control char anyway, so we +should also reject '#'. + +In the H1 parser for the H1_MSG_RQURI state, there is an accelerated +parser for bytes 0x21..0x7e that has been tightened to 0x24..0x7e (it +should not impact perf since 0x21..0x23 are not supposed to appear in +a URI anyway). This way '#' falls through the fine-grained filter and +we can add the special case for it also conditionned by a check on the +proxy's option "accept-invalid-http-request", with no overhead for the +vast majority of valid URIs. Here this information is available through +h1m->err_pos that's set to -2 when the option is here (so we don't need +to change the API to expose the proxy). Example with a trivial GET +through netcat: + + [08/Aug/2023:16:16:52.651] frontend layer1 (#2): invalid request + backend <NONE> (#-1), server <NONE> (#-1), event #0, src 127.0.0.1:50812 + buffer starts at 0 (including 0 out), 16361 free, + len 23, wraps at 16336, error at position 7 + H1 connection flags 0x00000000, H1 stream flags 0x00000810 + H1 msg state MSG_RQURI(4), H1 msg flags 0x00001400 + H1 chunk len 0 bytes, H1 body len 0 bytes : + + 00000 GET /aa#bb HTTP/1.0\r\n + 00021 \r\n + +This should be progressively backported to all stable versions along with +the following patch: + + REGTESTS: http-rules: add accept-invalid-http-request for normalize-uri tests + +Similar fixes for h2 and h3 will come in followup patches. + +Thanks to Seth Manesse and Paul Plasil for reporting this problem with +detailed explanations. + +(cherry picked from commit 2eab6d354322932cfec2ed54de261e4347eca9a6) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 9bf75c8e22a8f2537f27c557854a8803087046d0) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 9facd01c9ac85fe9bcb331594b80fa08e7406552) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +--- + src/h1.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/src/h1.c b/src/h1.c +index 126f23cc7376..92ec96bfe19e 100644 +--- a/src/h1.c ++++ b/src/h1.c +@@ -565,13 +565,13 @@ int h1_headers_to_hdr_list(char *start, const char *stop, + case H1_MSG_RQURI: + http_msg_rquri: + #ifdef HA_UNALIGNED_LE +- /* speedup: skip bytes not between 0x21 and 0x7e inclusive */ ++ /* speedup: skip bytes not between 0x24 and 0x7e inclusive */ + while (ptr <= end - sizeof(int)) { +- int x = *(int *)ptr - 0x21212121; ++ int x = *(int *)ptr - 0x24242424; + if (x & 0x80808080) + break; + +- x -= 0x5e5e5e5e; ++ x -= 0x5b5b5b5b; + if (!(x & 0x80808080)) + break; + +@@ -583,8 +583,15 @@ int h1_headers_to_hdr_list(char *start, const char *stop, + goto http_msg_ood; + } + http_msg_rquri2: +- if (likely((unsigned char)(*ptr - 33) <= 93)) /* 33 to 126 included */ ++ if (likely((unsigned char)(*ptr - 33) <= 93)) { /* 33 to 126 included */ ++ if (*ptr == '#') { ++ if (h1m->err_pos < -1) /* PR_O2_REQBUG_OK not set */ ++ goto invalid_char; ++ if (h1m->err_pos == -1) /* PR_O2_REQBUG_OK set: just log */ ++ h1m->err_pos = ptr - start + skip; ++ } + EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rquri2, http_msg_ood, state, H1_MSG_RQURI); ++ } + + if (likely(HTTP_IS_SPHT(*ptr))) { + sl.rq.u.len = ptr - sl.rq.u.ptr; +-- +2.43.0 + diff --git a/debian/patches/BUG-MINOR-h2-reject-more-chars-from-the-path-pseudo-.patch b/debian/patches/BUG-MINOR-h2-reject-more-chars-from-the-path-pseudo-.patch new file mode 100644 index 0000000..c5b2b9d --- /dev/null +++ b/debian/patches/BUG-MINOR-h2-reject-more-chars-from-the-path-pseudo-.patch @@ -0,0 +1,68 @@ +From: Willy Tarreau <w@1wt.eu> +Date: Tue, 8 Aug 2023 15:40:49 +0200 +Subject: BUG/MINOR: h2: reject more chars from the :path pseudo header +Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=c8e07f2fd8b5462527f102f7145d6027c0d041da + +This is the h2 version of this previous fix: + + BUG/MINOR: h1: do not accept '#' as part of the URI component + +In addition to the current NUL/CR/LF, this will also reject all other +control chars, the space and '#' from the :path pseudo-header, to avoid +taking the '#' for a part of the path. It's still possible to fall back +to the previous behavior using "option accept-invalid-http-request". + +This patch modifies the request parser to change the ":path" pseudo header +validation function with a new one that rejects 0x00-0x1F (control chars), +space and '#'. This way such chars will be dropped early in the chain, and +the search for '#' doesn't incur a second pass over the header's value. + +This should be progressively backported to stable versions, along with the +following commits it relies on: + + REGTESTS: http-rules: add accept-invalid-http-request for normalize-uri tests + REORG: http: move has_forbidden_char() from h2.c to http.h + MINOR: ist: add new function ist_find_range() to find a character range + MINOR: http: add new function http_path_has_forbidden_char() + MINOR: h2: pass accept-invalid-http-request down the request parser + +(cherry picked from commit b3119d4fb4588087e2483a80b01d322683719e29) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 462a8600ce9e478573a957e046b446a7dcffd286) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 648e59e30723b8fd4e71aab02cb679f6ea7446e7) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +--- + src/h2.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/src/h2.c b/src/h2.c +index cf42b7a5610e..67a443661c3e 100644 +--- a/src/h2.c ++++ b/src/h2.c +@@ -337,11 +337,18 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms + } + + /* RFC7540#10.3: intermediaries forwarding to HTTP/1 must take care of +- * rejecting NUL, CR and LF characters. ++ * rejecting NUL, CR and LF characters. For :path we reject all CTL ++ * chars, spaces, and '#'. + */ +- ctl = ist_find_ctl(list[idx].v); +- if (unlikely(ctl) && http_header_has_forbidden_char(list[idx].v, ctl)) +- goto fail; ++ if (phdr == H2_PHDR_IDX_PATH && !relaxed) { ++ ctl = ist_find_range(list[idx].v, 0, '#'); ++ if (unlikely(ctl) && http_path_has_forbidden_char(list[idx].v, ctl)) ++ goto fail; ++ } else { ++ ctl = ist_find_ctl(list[idx].v); ++ if (unlikely(ctl) && http_header_has_forbidden_char(list[idx].v, ctl)) ++ goto fail; ++ } + + if (phdr > 0 && phdr < H2_PHDR_NUM_ENTRIES) { + /* insert a pseudo header by its index (in phdr) and value (in value) */ +-- +2.43.0 + diff --git a/debian/patches/BUG-MINOR-h3-reject-more-chars-from-the-path-pseudo-.patch b/debian/patches/BUG-MINOR-h3-reject-more-chars-from-the-path-pseudo-.patch new file mode 100644 index 0000000..cbc086c --- /dev/null +++ b/debian/patches/BUG-MINOR-h3-reject-more-chars-from-the-path-pseudo-.patch @@ -0,0 +1,71 @@ +From: Willy Tarreau <w@1wt.eu> +Date: Tue, 8 Aug 2023 17:54:26 +0200 +Subject: BUG/MINOR: h3: reject more chars from the :path pseudo header +Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=eacaa76e7b0e4182dfd17e1e7ca8c02c1cdab72c + +This is the h3 version of this previous fix: + + BUG/MINOR: h2: reject more chars from the :path pseudo header + +In addition to the current NUL/CR/LF, this will also reject all other +control chars, the space and '#' from the :path pseudo-header, to avoid +taking the '#' for a part of the path. It's still possible to fall back +to the previous behavior using "option accept-invalid-http-request". + +Here the :path header value is scanned a second time to look for +forbidden chars because we don't know upfront if we're dealing with a +path header field or another one. This is no big deal anyway for now. + +This should be progressively backported to 2.6, along with the +following commits it relies on (the same as for h2): + + REGTESTS: http-rules: add accept-invalid-http-request for normalize-uri tests + REORG: http: move has_forbidden_char() from h2.c to http.h + MINOR: ist: add new function ist_find_range() to find a character range + MINOR: http: add new function http_path_has_forbidden_char() + +(cherry picked from commit 2e97857a845540887a92029a566deb5b51f61d0b) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 96dfea858edab8f1f63fa6e4df43f505b81fdad9) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 97c15782afd9c70281ff0c72971485227494cc12) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +--- + src/h3.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/src/h3.c b/src/h3.c +index b42d41647e4e..e519fb4432e7 100644 +--- a/src/h3.c ++++ b/src/h3.c +@@ -402,6 +402,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf, + int hdr_idx, ret; + int cookie = -1, last_cookie = -1, i; + const char *ctl; ++ int relaxed = !!(h3c->qcc->proxy->options2 & PR_O2_REQBUG_OK); + + /* RFC 9114 4.1.2. Malformed Requests and Responses + * +@@ -500,6 +501,19 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf, + len = -1; + goto out; + } ++ ++ if (!relaxed) { ++ /* we need to reject any control chars or '#' from the path, ++ * unless option accept-invalid-http-request is set. ++ */ ++ ctl = ist_find_range(list[hdr_idx].v, 0, '#'); ++ if (unlikely(ctl) && http_path_has_forbidden_char(list[hdr_idx].v, ctl)) { ++ TRACE_ERROR("forbidden character in ':path' pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs); ++ len = -1; ++ goto out; ++ } ++ } ++ + path = list[hdr_idx].v; + } + else if (isteq(list[hdr_idx].n, ist(":scheme"))) { +-- +2.43.0 + diff --git a/debian/patches/DOC-clarify-the-handling-of-URL-fragments-in-request.patch b/debian/patches/DOC-clarify-the-handling-of-URL-fragments-in-request.patch new file mode 100644 index 0000000..8730e9a --- /dev/null +++ b/debian/patches/DOC-clarify-the-handling-of-URL-fragments-in-request.patch @@ -0,0 +1,76 @@ +From: Willy Tarreau <w@1wt.eu> +Date: Tue, 8 Aug 2023 19:35:25 +0200 +Subject: DOC: clarify the handling of URL fragments in requests +Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=c47814a58ec153a526e8e9e822cda6e66cef5cc2 + +We indicate in path/pathq/url that they may contain '#' if the frontend +is configured with "option accept-invalid-http-request", and that option +mentions the fragment as well. + +(cherry picked from commit 7ab4949ef107a7088777f954de800fe8cf727796) + [ad: backported as a companion to BUG/MINOR: h1: do not accept '#' as + part of the URI component] +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 965fb74eb180ab4f275ef907e018128e7eee0e69) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit e9903d6073ce9ff0ed8b304700e9d2b435ed8050) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +--- + doc/configuration.txt | 20 +++++++++++++++++--- + 1 file changed, 17 insertions(+), 3 deletions(-) + +diff --git a/doc/configuration.txt b/doc/configuration.txt +index 7219c489ef9a..c01abb2d0a66 100644 +--- a/doc/configuration.txt ++++ b/doc/configuration.txt +@@ -8609,6 +8609,8 @@ no option accept-invalid-http-request + option also relaxes the test on the HTTP version, it allows HTTP/0.9 requests + to pass through (no version specified), as well as different protocol names + (e.g. RTSP), and multiple digits for both the major and the minor version. ++ Finally, this option also allows incoming URLs to contain fragment references ++ ('#' after the path). + + This option should never be enabled by default as it hides application bugs + and open security breaches. It should only be deployed after a problem has +@@ -20991,7 +20993,11 @@ path : string + information from databases and keep them in caches. Note that with outgoing + caches, it would be wiser to use "url" instead. With ACLs, it's typically + used to match exact file names (e.g. "/login.php"), or directory parts using +- the derivative forms. See also the "url" and "base" fetch methods. ++ the derivative forms. See also the "url" and "base" fetch methods. Please ++ note that any fragment reference in the URI ('#' after the path) is strictly ++ forbidden by the HTTP standard and will be rejected. However, if the frontend ++ receiving the request has "option accept-invalid-http-request", then this ++ fragment part will be accepted and will also appear in the path. + + ACL derivatives : + path : exact string match +@@ -21009,7 +21015,11 @@ pathq : string + relative URI, excluding the scheme and the authority part, if any. Indeed, + while it is the common representation for an HTTP/1.1 request target, in + HTTP/2, an absolute URI is often used. This sample fetch will return the same +- result in both cases. ++ result in both cases. Please note that any fragment reference in the URI ('#' ++ after the path) is strictly forbidden by the HTTP standard and will be ++ rejected. However, if the frontend receiving the request has "option ++ accept-invalid-http-request", then this fragment part will be accepted and ++ will also appear in the path. + + query : string + This extracts the request's query string, which starts after the first +@@ -21242,7 +21252,11 @@ url : string + "path" is preferred over using "url", because clients may send a full URL as + is normally done with proxies. The only real use is to match "*" which does + not match in "path", and for which there is already a predefined ACL. See +- also "path" and "base". ++ also "path" and "base". Please note that any fragment reference in the URI ++ ('#' after the path) is strictly forbidden by the HTTP standard and will be ++ rejected. However, if the frontend receiving the request has "option ++ accept-invalid-http-request", then this fragment part will be accepted and ++ will also appear in the url. + + ACL derivatives : + url : exact string match +-- +2.43.0 + diff --git a/debian/patches/MINOR-h2-pass-accept-invalid-http-request-down-the-r.patch b/debian/patches/MINOR-h2-pass-accept-invalid-http-request-down-the-r.patch new file mode 100644 index 0000000..dac7216 --- /dev/null +++ b/debian/patches/MINOR-h2-pass-accept-invalid-http-request-down-the-r.patch @@ -0,0 +1,73 @@ +From: Willy Tarreau <w@1wt.eu> +Date: Tue, 8 Aug 2023 15:38:28 +0200 +Subject: MINOR: h2: pass accept-invalid-http-request down the request parser +Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=014945a1508f43e88ac4e89950fa9037e4fb0679 + +We're adding a new argument "relaxed" to h2_make_htx_request() so that +we can control its level of acceptance of certain invalid requests at +the proxy level with "option accept-invalid-http-request". The goal +will be to add deactivable checks that are still desirable to have by +default. For now no test is subject to it. + +(cherry picked from commit d93a00861d714313faa0395ff9e2acb14b0a2fca) + [ad: backported for following fix : BUG/MINOR: h2: reject more chars + from the :path pseudo header] +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit b6be1a4f858eb6602490c192235114c1a163fef9) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 26fa3a285df0748fc79e73e552161268b66fb527) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +--- + include/haproxy/h2.h | 2 +- + src/h2.c | 6 +++++- + src/mux_h2.c | 3 ++- + 3 files changed, 8 insertions(+), 3 deletions(-) + +diff --git a/include/haproxy/h2.h b/include/haproxy/h2.h +index 84e4c76fc260..4082b38a80f9 100644 +--- a/include/haproxy/h2.h ++++ b/include/haproxy/h2.h +@@ -207,7 +207,7 @@ extern struct h2_frame_definition h2_frame_definition[H2_FT_ENTRIES]; + /* various protocol processing functions */ + + int h2_parse_cont_len_header(unsigned int *msgf, struct ist *value, unsigned long long *body_len); +-int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len); ++int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len, int relaxed); + int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len, char *upgrade_protocol); + int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx); + +diff --git a/src/h2.c b/src/h2.c +index 76c936783461..cf42b7a5610e 100644 +--- a/src/h2.c ++++ b/src/h2.c +@@ -296,8 +296,12 @@ static struct htx_sl *h2_prepare_htx_reqline(uint32_t fields, struct ist *phdr, + * + * The Cookie header will be reassembled at the end, and for this, the <list> + * will be used to create a linked list, so its contents may be destroyed. ++ * ++ * When <relaxed> is non-nul, some non-dangerous checks will be ignored. This ++ * is in order to satisfy "option accept-invalid-http-request" for ++ * interoperability purposes. + */ +-int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len) ++int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len, int relaxed) + { + struct ist phdr_val[H2_PHDR_NUM_ENTRIES]; + uint32_t fields; /* bit mask of H2_PHDR_FND_* */ +diff --git a/src/mux_h2.c b/src/mux_h2.c +index 752f074cac87..9e5ee8a56c34 100644 +--- a/src/mux_h2.c ++++ b/src/mux_h2.c +@@ -5090,7 +5090,8 @@ static int h2c_decode_headers(struct h2c *h2c, struct buffer *rxbuf, uint32_t *f + if (h2c->flags & H2_CF_IS_BACK) + outlen = h2_make_htx_response(list, htx, &msgf, body_len, upgrade_protocol); + else +- outlen = h2_make_htx_request(list, htx, &msgf, body_len); ++ outlen = h2_make_htx_request(list, htx, &msgf, body_len, ++ !!(((const struct session *)h2c->conn->owner)->fe->options2 & PR_O2_REQBUG_OK)); + + if (outlen < 0 || htx_free_space(htx) < global.tune.maxrewrite) { + /* too large headers? this is a stream error only */ +-- +2.43.0 + diff --git a/debian/patches/MINOR-http-add-new-function-http_path_has_forbidden_.patch b/debian/patches/MINOR-http-add-new-function-http_path_has_forbidden_.patch new file mode 100644 index 0000000..46cdf99 --- /dev/null +++ b/debian/patches/MINOR-http-add-new-function-http_path_has_forbidden_.patch @@ -0,0 +1,56 @@ +From: Willy Tarreau <w@1wt.eu> +Date: Tue, 8 Aug 2023 15:24:54 +0200 +Subject: MINOR: http: add new function http_path_has_forbidden_char() +Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=c699bb17b7e334c9d56e829422e29e5a204615ec + +As its name implies, this function checks if a path component has any +forbidden headers starting at the designated location. The goal is to +seek from the result of a successful ist_find_range() for more precise +chars. Here we're focusing on 0x00-0x1F, 0x20 and 0x23 to make sure +we're not too strict at this point. + +(cherry picked from commit 30f58f4217d585efeac3d85cb1b695ba53b7760b) + [ad: backported for following fix : BUG/MINOR: h2: reject more chars + from the :path pseudo header] +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit b491940181a88bb6c69ab2afc24b93a50adfa67c) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit f7666e5e43ce63e804ebffdf224d92cfd3367282) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +--- + include/haproxy/http.h | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/include/haproxy/http.h b/include/haproxy/http.h +index 41eca98a1e87..534b6ec2b2f0 100644 +--- a/include/haproxy/http.h ++++ b/include/haproxy/http.h +@@ -190,6 +190,25 @@ static inline int http_header_has_forbidden_char(const struct ist ist, const cha + return 0; + } + ++/* Looks into <ist> for forbidden characters for :path values (0x00..0x1F, ++ * 0x20, 0x23), starting at pointer <start> which must be within <ist>. ++ * Returns non-zero if such a character is found, 0 otherwise. When run on ++ * unlikely header match, it's recommended to first check for the presence ++ * of control chars using ist_find_ctl(). ++ */ ++static inline int http_path_has_forbidden_char(const struct ist ist, const char *start) ++{ ++ do { ++ if ((uint8_t)*start <= 0x23) { ++ if ((uint8_t)*start < 0x20) ++ return 1; ++ if ((1U << ((uint8_t)*start & 0x1F)) & ((1<<3) | (1<<0))) ++ return 1; ++ } ++ start++; ++ } while (start < istend(ist)); ++ return 0; ++} + + #endif /* _HAPROXY_HTTP_H */ + +-- +2.43.0 + diff --git a/debian/patches/MINOR-ist-add-new-function-ist_find_range-to-find-a-.patch b/debian/patches/MINOR-ist-add-new-function-ist_find_range-to-find-a-.patch new file mode 100644 index 0000000..40c3a08 --- /dev/null +++ b/debian/patches/MINOR-ist-add-new-function-ist_find_range-to-find-a-.patch @@ -0,0 +1,84 @@ +From: Willy Tarreau <w@1wt.eu> +Date: Tue, 8 Aug 2023 15:23:19 +0200 +Subject: MINOR: ist: add new function ist_find_range() to find a character + range +Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=b375df60341c7f7a4904c2d8041a09c66115c754 + +This looks up the character range <min>..<max> in the input string and +returns a pointer to the first one found. It's essentially the equivalent +of ist_find_ctl() in that it searches by 32 or 64 bits at once, but deals +with a range. + +(cherry picked from commit 197668de975e495f0c0f0e4ff51b96203fa9842d) + [ad: backported for following fix : BUG/MINOR: h2: reject more chars + from the :path pseudo header] +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 451ac6628acc4b9eed3260501a49c60d4e4d4e55) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 3468f7f8e04c9c5ca5c985c7511e05e78fe1eded) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +--- + include/import/ist.h | 47 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 47 insertions(+) + +diff --git a/include/import/ist.h b/include/import/ist.h +index 978fb3c72247..38fe9363c2a1 100644 +--- a/include/import/ist.h ++++ b/include/import/ist.h +@@ -746,6 +746,53 @@ static inline const char *ist_find_ctl(const struct ist ist) + return NULL; + } + ++/* Returns a pointer to the first character found <ist> that belongs to the ++ * range [min:max] inclusive, or NULL if none is present. The function is ++ * optimized for strings having no such chars by processing up to sizeof(long) ++ * bytes at once on architectures supporting efficient unaligned accesses. ++ * Despite this it is not very fast (~0.43 byte/cycle) and should mostly be ++ * used on low match probability when it can save a call to a much slower ++ * function. Will not work for characters 0x80 and above. It's optimized for ++ * min and max to be known at build time. ++ */ ++static inline const char *ist_find_range(const struct ist ist, unsigned char min, unsigned char max) ++{ ++ const union { unsigned long v; } __attribute__((packed)) *u; ++ const char *curr = (void *)ist.ptr - sizeof(long); ++ const char *last = curr + ist.len; ++ unsigned long l1, l2; ++ ++ /* easier with an exclusive boundary */ ++ max++; ++ ++ do { ++ curr += sizeof(long); ++ if (curr > last) ++ break; ++ u = (void *)curr; ++ /* add 0x<min><min><min><min>..<min> then subtract ++ * 0x<max><max><max><max>..<max> to the value to generate a ++ * carry in the lower byte if the byte contains a lower value. ++ * If we generate a bit 7 that was not there, it means the byte ++ * was min..max. ++ */ ++ l2 = u->v; ++ l1 = ~l2 & ((~0UL / 255) * 0x80); /* 0x808080...80 */ ++ l2 += (~0UL / 255) * min; /* 0x<min><min>..<min> */ ++ l2 -= (~0UL / 255) * max; /* 0x<max><max>..<max> */ ++ } while ((l1 & l2) == 0); ++ ++ last += sizeof(long); ++ if (__builtin_expect(curr < last, 0)) { ++ do { ++ if ((unsigned char)(*curr - min) < (unsigned char)(max - min)) ++ return curr; ++ curr++; ++ } while (curr < last); ++ } ++ return NULL; ++} ++ + /* looks for first occurrence of character <chr> in string <ist> and returns + * the tail of the string starting with this character, or (ist.end,0) if not + * found. +-- +2.43.0 + diff --git a/debian/patches/REGTESTS-http-rules-add-accept-invalid-http-request-.patch b/debian/patches/REGTESTS-http-rules-add-accept-invalid-http-request-.patch new file mode 100644 index 0000000..60caf8f --- /dev/null +++ b/debian/patches/REGTESTS-http-rules-add-accept-invalid-http-request-.patch @@ -0,0 +1,44 @@ +From: Willy Tarreau <w@1wt.eu> +Date: Tue, 8 Aug 2023 19:52:45 +0200 +Subject: REGTESTS: http-rules: add accept-invalid-http-request for + normalize-uri tests +Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=65849396fd6f192d9f14e81702c6c3851e580345 + +We'll soon block the '#' by default so let's prepare the test to continue +to work. + +(cherry picked from commit 069d0e221e58a46119d7c049bb07fa4bcb8d0075) + [ad: backported for following fix : BUG/MINOR: h2: reject more chars + from the :path pseudo header] +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 1660481fab69856a39ac44cf88b76cdbcc0ea954) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 90d0300cea6cda18a4e20369f4dc0b4c4783d6c9) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +--- + reg-tests/http-rules/normalize_uri.vtc | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/reg-tests/http-rules/normalize_uri.vtc b/reg-tests/http-rules/normalize_uri.vtc +index 82c810718df1..34905eaf93ae 100644 +--- a/reg-tests/http-rules/normalize_uri.vtc ++++ b/reg-tests/http-rules/normalize_uri.vtc +@@ -127,6 +127,7 @@ haproxy h1 -conf { + + frontend fe_fragment_strip + bind "fd@${fe_fragment_strip}" ++ option accept-invalid-http-request + + http-request set-var(txn.before) url + http-request normalize-uri fragment-strip +@@ -139,6 +140,7 @@ haproxy h1 -conf { + + frontend fe_fragment_encode + bind "fd@${fe_fragment_encode}" ++ option accept-invalid-http-request + + http-request set-var(txn.before) url + http-request normalize-uri fragment-encode +-- +2.43.0 + diff --git a/debian/patches/REGTESTS-http-rules-verify-that-we-block-by-default-.patch b/debian/patches/REGTESTS-http-rules-verify-that-we-block-by-default-.patch new file mode 100644 index 0000000..6703482 --- /dev/null +++ b/debian/patches/REGTESTS-http-rules-verify-that-we-block-by-default-.patch @@ -0,0 +1,50 @@ +From: Willy Tarreau <w@1wt.eu> +Date: Tue, 8 Aug 2023 19:53:51 +0200 +Subject: REGTESTS: http-rules: verify that we block '#' by default for + normalize-uri +Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=b6b330eb117d520a890e5b3cd623eaa73479db1b + +Since we now block fragments by default, let's add an extra test there +to confirm that it's blocked even when stripping it. + +(cherry picked from commit 4d0175b54b2b4eeb01aa6e31282b0a5b0d7d8ace) + [ad: backported to test conformance of BUG/MINOR: h1: do not accept '#' + as part of the URI component] +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit b3f26043df74c661155566a0abd56103e8116078) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 41d161ccbbfa846b4b17ed0166ff08f6bf0c3ea1) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +--- + reg-tests/http-rules/normalize_uri.vtc | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/reg-tests/http-rules/normalize_uri.vtc b/reg-tests/http-rules/normalize_uri.vtc +index 34905eaf93ae..ad7b44acfe55 100644 +--- a/reg-tests/http-rules/normalize_uri.vtc ++++ b/reg-tests/http-rules/normalize_uri.vtc +@@ -151,6 +151,11 @@ haproxy h1 -conf { + + default_backend be + ++ frontend fe_fragment_block ++ bind "fd@${fe_fragment_block}" ++ http-request normalize-uri fragment-strip ++ default_backend be ++ + backend be + server s1 ${s1_addr}:${s1_port} + +@@ -536,3 +541,9 @@ client c10 -connect ${h1_fe_fragment_encode_sock} { + expect resp.http.before == "*" + expect resp.http.after == "*" + } -run ++ ++client c11 -connect ${h1_fe_fragment_block_sock} { ++ txreq -url "/#foo" ++ rxresp ++ expect resp.status == 400 ++} -run +-- +2.43.0 + diff --git a/debian/patches/REORG-http-move-has_forbidden_char-from-h2.c-to-http.patch b/debian/patches/REORG-http-move-has_forbidden_char-from-h2.c-to-http.patch new file mode 100644 index 0000000..5bf1eef --- /dev/null +++ b/debian/patches/REORG-http-move-has_forbidden_char-from-h2.c-to-http.patch @@ -0,0 +1,109 @@ +From: Willy Tarreau <w@1wt.eu> +Date: Tue, 8 Aug 2023 17:00:50 +0200 +Subject: REORG: http: move has_forbidden_char() from h2.c to http.h +Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=4a776fd01560a8dfa7a57b30b4d5249c8da7b12c + +This function is not H2 specific but rather generic to HTTP. We'll +need it in H3 soon, so let's move it to HTTP and rename it to +http_header_has_forbidden_char(). + +(cherry picked from commit d4069f3cee0f6e94afaec518b6373dd368073f52) + [ad: backported for next patch BUG/MAJOR: h3: reject header values + containing invalid chars] +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 21c4ffd025115058994a3e2765c17fc3cee52f90) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +(cherry picked from commit 9c0bc4f201cf58c10706416cb4807c0f4794f8ac) +Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com> +--- + include/haproxy/http.h | 18 ++++++++++++++++++ + src/h2.c | 23 +++-------------------- + 2 files changed, 21 insertions(+), 20 deletions(-) + +diff --git a/include/haproxy/http.h b/include/haproxy/http.h +index f597ee4cd1dc..41eca98a1e87 100644 +--- a/include/haproxy/http.h ++++ b/include/haproxy/http.h +@@ -173,6 +173,24 @@ static inline struct http_uri_parser http_uri_parser_init(const struct ist uri) + return parser; + } + ++/* Looks into <ist> for forbidden characters for header values (0x00, 0x0A, ++ * 0x0D), starting at pointer <start> which must be within <ist>. Returns ++ * non-zero if such a character is found, 0 otherwise. When run on unlikely ++ * header match, it's recommended to first check for the presence of control ++ * chars using ist_find_ctl(). ++ */ ++static inline int http_header_has_forbidden_char(const struct ist ist, const char *start) ++{ ++ do { ++ if ((uint8_t)*start <= 0x0d && ++ (1U << (uint8_t)*start) & ((1<<13) | (1<<10) | (1<<0))) ++ return 1; ++ start++; ++ } while (start < istend(ist)); ++ return 0; ++} ++ ++ + #endif /* _HAPROXY_HTTP_H */ + + /* +diff --git a/src/h2.c b/src/h2.c +index f794262ee7af..76c936783461 100644 +--- a/src/h2.c ++++ b/src/h2.c +@@ -49,23 +49,6 @@ struct h2_frame_definition h2_frame_definition[H2_FT_ENTRIES] = { + [H2_FT_CONTINUATION ] = { .dir = 3, .min_id = 1, .max_id = H2_MAX_STREAM_ID, .min_len = 0, .max_len = H2_MAX_FRAME_LEN, }, + }; + +-/* Looks into <ist> for forbidden characters for header values (0x00, 0x0A, +- * 0x0D), starting at pointer <start> which must be within <ist>. Returns +- * non-zero if such a character is found, 0 otherwise. When run on unlikely +- * header match, it's recommended to first check for the presence of control +- * chars using ist_find_ctl(). +- */ +-static int has_forbidden_char(const struct ist ist, const char *start) +-{ +- do { +- if ((uint8_t)*start <= 0x0d && +- (1U << (uint8_t)*start) & ((1<<13) | (1<<10) | (1<<0))) +- return 1; +- start++; +- } while (start < istend(ist)); +- return 0; +-} +- + /* Prepare the request line into <htx> from pseudo headers stored in <phdr[]>. + * <fields> indicates what was found so far. This should be called once at the + * detection of the first general header field or at the end of the request if +@@ -353,7 +336,7 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms + * rejecting NUL, CR and LF characters. + */ + ctl = ist_find_ctl(list[idx].v); +- if (unlikely(ctl) && has_forbidden_char(list[idx].v, ctl)) ++ if (unlikely(ctl) && http_header_has_forbidden_char(list[idx].v, ctl)) + goto fail; + + if (phdr > 0 && phdr < H2_PHDR_NUM_ENTRIES) { +@@ -638,7 +621,7 @@ int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *m + * rejecting NUL, CR and LF characters. + */ + ctl = ist_find_ctl(list[idx].v); +- if (unlikely(ctl) && has_forbidden_char(list[idx].v, ctl)) ++ if (unlikely(ctl) && http_header_has_forbidden_char(list[idx].v, ctl)) + goto fail; + + if (phdr > 0 && phdr < H2_PHDR_NUM_ENTRIES) { +@@ -797,7 +780,7 @@ int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx) + * rejecting NUL, CR and LF characters. + */ + ctl = ist_find_ctl(list[idx].v); +- if (unlikely(ctl) && has_forbidden_char(list[idx].v, ctl)) ++ if (unlikely(ctl) && http_header_has_forbidden_char(list[idx].v, ctl)) + goto fail; + + if (!htx_add_trailer(htx, list[idx].n, list[idx].v)) +-- +2.43.0 + diff --git a/debian/patches/debianize-dconv.patch b/debian/patches/debianize-dconv.patch new file mode 100644 index 0000000..34710ce --- /dev/null +++ b/debian/patches/debianize-dconv.patch @@ -0,0 +1,170 @@ +From: Apollon Oikonomopoulos <apoikos@debian.org> +Date: Wed, 29 Apr 2015 13:51:49 +0300 +Subject: [PATCH] dconv: debianize + + - Use Debian bootstrap and jquery packages + - Add Debian-related resources to the template + - Use the package's version instead of HAProxy's git version + - Strip the conversion date from the output to ensure reproducible + build. + - 2020-01-17: make get_haproxy_debian_version() return a string, for py3 + compatibility + +diff --git a/debian/dconv/haproxy-dconv.py b/debian/dconv/haproxy-dconv.py +index fe2b96dce325..702eefac6a3b 100755 +--- a/debian/dconv/haproxy-dconv.py ++++ b/debian/dconv/haproxy-dconv.py +@@ -44,12 +44,11 @@ VERSION = "" + HAPROXY_GIT_VERSION = False + + def main(): +- global VERSION, HAPROXY_GIT_VERSION ++ global HAPROXY_GIT_VERSION + + usage="Usage: %prog --infile <infile> --outfile <outfile>" + + optparser = OptionParser(description='Generate HTML Document from HAProxy configuation.txt', +- version=VERSION, + usage=usage) + optparser.add_option('--infile', '-i', help='Input file mostly the configuration.txt') + optparser.add_option('--outfile','-o', help='Output file') +@@ -65,11 +64,7 @@ def main(): + + os.chdir(os.path.dirname(__file__)) + +- VERSION = get_git_version() +- if not VERSION: +- sys.exit(1) +- +- HAPROXY_GIT_VERSION = get_haproxy_git_version(os.path.dirname(option.infile)) ++ HAPROXY_GIT_VERSION = get_haproxy_debian_version(os.path.dirname(option.infile)) + + convert(option.infile, option.outfile, option.base) + +@@ -114,6 +109,15 @@ def get_haproxy_git_version(path): + version = re.sub(r'-g.*', '', version) + return version + ++def get_haproxy_debian_version(path): ++ try: ++ version = subprocess.check_output(["dpkg-parsechangelog", "-Sversion"], ++ cwd=os.path.join(path, "..")) ++ except subprocess.CalledProcessError: ++ return False ++ ++ return version.decode("utf-8").strip() ++ + def getTitleDetails(string): + array = string.split(".") + +@@ -506,7 +510,6 @@ def convert(infile, outfile, base=''): + keywords = keywords, + keywordsCount = keywordsCount, + keyword_conflicts = keyword_conflicts, +- version = VERSION, + date = datetime.datetime.now().strftime("%Y/%m/%d"), + ) + except TopLevelLookupException: +@@ -524,7 +527,6 @@ def convert(infile, outfile, base=''): + keywords = keywords, + keywordsCount = keywordsCount, + keyword_conflicts = keyword_conflicts, +- version = VERSION, + date = datetime.datetime.now().strftime("%Y/%m/%d"), + footer = footer + ) +diff --git a/debian/dconv/templates/template.html b/debian/dconv/templates/template.html +index c72b3558c2dd..9aefa16dd82d 100644 +--- a/debian/dconv/templates/template.html ++++ b/debian/dconv/templates/template.html +@@ -3,8 +3,8 @@ + <head> + <meta charset="utf-8" /> + <title>${headers['title']} ${headers['version']} - ${headers['subtitle']}</title> +- <link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet" /> +- <link href="${base}css/page.css?${version}" rel="stylesheet" /> ++ <link href="${base}css/bootstrap.min.css" rel="stylesheet" /> ++ <link href="${base}css/page.css" rel="stylesheet" /> + </head> + <body> + <nav class="navbar navbar-default navbar-fixed-top" role="navigation"> +@@ -15,7 +15,7 @@ + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> +- <a class="navbar-brand" href="${base}index.html">${headers['title']} <small>${headers['subtitle']}</small></a> ++ <a class="navbar-brand" href="${base}configuration.html">${headers['title']}</a> + </div> + <!-- /.navbar-header --> + +@@ -24,31 +24,16 @@ + <ul class="nav navbar-nav"> + <li><a href="http://www.haproxy.org/">HAProxy home page</a></li> + <li class="dropdown"> +- <a href="#" class="dropdown-toggle" data-toggle="dropdown">Versions <b class="caret"></b></a> ++ <a href="#" class="dropdown-toggle" data-toggle="dropdown">Debian resources <b class="caret"></b></a> + <ul class="dropdown-menu"> + ## TODO : provide a structure to dynamically generate per version links +- <li class="dropdown-header">HAProxy 1.4</li> +- <li><a href="${base}configuration-1.4.html">Configuration Manual <small>(stable)</small></a></li> +- <li><a href="${base}snapshot/configuration-1.4.html">Configuration Manual <small>(snapshot)</small></a></li> +- <li><a href="http://git.1wt.eu/git/haproxy-1.4.git/">GIT Repository</a></li> +- <li><a href="http://www.haproxy.org/git/?p=haproxy-1.4.git">Browse repository</a></li> +- <li><a href="http://www.haproxy.org/download/1.4/">Browse directory</a></li> +- <li class="divider"></li> +- <li class="dropdown-header">HAProxy 1.5</li> +- <li><a href="${base}configuration-1.5.html">Configuration Manual <small>(stable)</small></a></li> +- <li><a href="${base}snapshot/configuration-1.5.html">Configuration Manual <small>(snapshot)</small></a></li> +- <li><a href="http://git.1wt.eu/git/haproxy-1.5.git/">GIT Repository</a></li> +- <li><a href="http://www.haproxy.org/git/?p=haproxy-1.5.git">Browse repository</a></li> +- <li><a href="http://www.haproxy.org/download/1.5/">Browse directory</a></li> +- <li class="divider"></li> +- <li class="dropdown-header">HAProxy 1.6</li> +- <li><a href="${base}configuration-1.6.html">Configuration Manual <small>(stable)</small></a></li> +- <li><a href="${base}snapshot/configuration-1.6.html">Configuration Manual <small>(snapshot)</small></a></li> +- <li><a href="${base}intro-1.6.html">Starter Guide <small>(stable)</small></a></li> +- <li><a href="${base}snapshot/intro-1.6.html">Starter Guide <small>(snapshot)</small></a></li> +- <li><a href="http://git.1wt.eu/git/haproxy.git/">GIT Repository</a></li> +- <li><a href="http://www.haproxy.org/git/?p=haproxy.git">Browse repository</a></li> +- <li><a href="http://www.haproxy.org/download/1.6/">Browse directory</a></li> ++ <li><a href="https://bugs.debian.org/src:haproxy">Bug Tracking System</a></li> ++ <li><a href="https://packages.debian.org/haproxy">Package page</a></li> ++ <li><a href="http://tracker.debian.org/pkg/haproxy">Package Tracking System</a></li> ++ <li class="divider"></li> ++ <li><a href="${base}intro.html">Starter Guide</a></li> ++ <li><a href="${base}configuration.html">Configuration Manual</a></li> ++ <li><a href="http://anonscm.debian.org/gitweb/?p=pkg-haproxy/haproxy.git">Package Git Repository</a></li> + </ul> + </li> + </ul> +@@ -72,7 +57,7 @@ + The feature is automatically disabled when the search field is focused. + </p> + <p class="text-right"> +- <small>Converted with <a href="https://github.com/cbonte/haproxy-dconv">haproxy-dconv</a> v<b>${version}</b> on <b>${date}</b></small> ++ <small>Converted with <a href="https://github.com/cbonte/haproxy-dconv">haproxy-dconv</a></small> + </p> + </div> + <!-- /.sidebar --> +@@ -83,7 +68,7 @@ + <div class="text-center"> + <h1>${headers['title']}</h1> + <h2>${headers['subtitle']}</h2> +- <p><strong>${headers['version']}</strong></p> ++ <p><strong>${headers['version']} (Debian)</strong></p> + <p> + <a href="http://www.haproxy.org/" title="HAProxy Home Page"><img src="${base}img/logo-med.png" /></a><br> + ${headers['author']}<br> +@@ -114,9 +99,9 @@ + </div> + <!-- /#wrapper --> + +- <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> +- <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/js/bootstrap.min.js"></script> +- <script src="//cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.min.js"></script> ++ <script src="${base}js/jquery.min.js"></script> ++ <script src="${base}js/bootstrap.min.js"></script> ++ <script src="${base}js/typeahead.bundle.js"></script> + <script> + /* Keyword search */ + var searchFocus = false diff --git a/debian/patches/haproxy.service-add-documentation.patch b/debian/patches/haproxy.service-add-documentation.patch new file mode 100644 index 0000000..a60b0d1 --- /dev/null +++ b/debian/patches/haproxy.service-add-documentation.patch @@ -0,0 +1,23 @@ +From: Debian HAProxy Maintainers + <pkg-haproxy-maintainers@lists.alioth.debian.org> +Date: Sun, 25 Mar 2018 11:31:50 +0200 +Subject: Add documentation field to the systemd unit + +Forwarded: no +Last-Update: 2014-01-03 +--- + admin/systemd/haproxy.service.in | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/admin/systemd/haproxy.service.in b/admin/systemd/haproxy.service.in +index 243acf2..ac88c37 100644 +--- a/admin/systemd/haproxy.service.in ++++ b/admin/systemd/haproxy.service.in +@@ -1,5 +1,7 @@ + [Unit] + Description=HAProxy Load Balancer ++Documentation=man:haproxy(1) ++Documentation=file:/usr/share/doc/haproxy/configuration.txt.gz + After=network-online.target rsyslog.service + Wants=network-online.target + diff --git a/debian/patches/haproxy.service-make-systemd-bind-dev-log-inside-chroot.patch b/debian/patches/haproxy.service-make-systemd-bind-dev-log-inside-chroot.patch new file mode 100644 index 0000000..666f916 --- /dev/null +++ b/debian/patches/haproxy.service-make-systemd-bind-dev-log-inside-chroot.patch @@ -0,0 +1,21 @@ +From: Vincent Bernat <bernat@debian.org> +Date: Thu, 25 Nov 2021 21:35:48 +0100 +Subject: haproxy.service: make systemd bind /dev/log inside chroot + +This enables logging to work without rsyslog being present. +--- + admin/systemd/haproxy.service.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/admin/systemd/haproxy.service.in b/admin/systemd/haproxy.service.in +index 0288568..20824df 100644 +--- a/admin/systemd/haproxy.service.in ++++ b/admin/systemd/haproxy.service.in +@@ -8,6 +8,7 @@ Wants=network-online.target + [Service] + EnvironmentFile=-/etc/default/haproxy + EnvironmentFile=-/etc/sysconfig/haproxy ++BindReadOnlyPaths=/dev/log:/var/lib/haproxy/dev/log + Environment="CONFIG=/etc/haproxy/haproxy.cfg" "PIDFILE=/run/haproxy.pid" "EXTRAOPTS=-S /run/haproxy-master.sock" + ExecStart=@SBINDIR@/haproxy -Ws -f $CONFIG -p $PIDFILE $EXTRAOPTS + ExecReload=@SBINDIR@/haproxy -Ws -f $CONFIG -c -q $EXTRAOPTS diff --git a/debian/patches/haproxy.service-start-after-syslog.patch b/debian/patches/haproxy.service-start-after-syslog.patch new file mode 100644 index 0000000..14577bd --- /dev/null +++ b/debian/patches/haproxy.service-start-after-syslog.patch @@ -0,0 +1,27 @@ +From: Apollon Oikonomopoulos <apoikos@debian.org> +Date: Sun, 25 Mar 2018 11:31:50 +0200 +Subject: Start after rsyslog.service + +As HAProxy is running chrooted by default, we rely on an additional syslog +socket created by rsyslog inside the chroot for logging. As this socket cannot +trigger syslog activation, we explicitly order HAProxy after rsyslog.service. +Note that we are not using syslog.service here, since the additional socket is +rsyslog-specific. +Forwarded: no +Last-Update: 2017-12-01 +--- + admin/systemd/haproxy.service.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/admin/systemd/haproxy.service.in b/admin/systemd/haproxy.service.in +index 74e66e3..243acf2 100644 +--- a/admin/systemd/haproxy.service.in ++++ b/admin/systemd/haproxy.service.in +@@ -1,6 +1,6 @@ + [Unit] + Description=HAProxy Load Balancer +-After=network-online.target ++After=network-online.target rsyslog.service + Wants=network-online.target + + [Service] diff --git a/debian/patches/reproducible.patch b/debian/patches/reproducible.patch new file mode 100644 index 0000000..bbc95b8 --- /dev/null +++ b/debian/patches/reproducible.patch @@ -0,0 +1,13 @@ +diff --git a/Makefile b/Makefile +index 566bdb26a3e7..8603dea25c21 100644 +--- a/Makefile ++++ b/Makefile +@@ -975,7 +975,7 @@ src/haproxy.o: src/haproxy.c $(DEP) + -DBUILD_ARCH='"$(strip $(ARCH))"' \ + -DBUILD_CPU='"$(strip $(CPU))"' \ + -DBUILD_CC='"$(strip $(CC))"' \ +- -DBUILD_CFLAGS='"$(strip $(VERBOSE_CFLAGS))"' \ ++ -DBUILD_CFLAGS='"$(filter-out -ffile-prefix-map=%,$(strip $(VERBOSE_CFLAGS)))"' \ + -DBUILD_OPTIONS='"$(strip $(BUILD_OPTIONS))"' \ + -DBUILD_DEBUG='"$(strip $(DEBUG))"' \ + -DBUILD_FEATURES='"$(strip $(BUILD_FEATURES))"' \ diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..7136a90 --- /dev/null +++ b/debian/patches/series @@ -0,0 +1,19 @@ +haproxy.service-start-after-syslog.patch +haproxy.service-add-documentation.patch +haproxy.service-make-systemd-bind-dev-log-inside-chroot.patch +reproducible.patch +REORG-http-move-has_forbidden_char-from-h2.c-to-http.patch +BUG-MAJOR-h3-reject-header-values-containing-invalid.patch +BUG-MAJOR-http-reject-any-empty-content-length-heade.patch +MINOR-ist-add-new-function-ist_find_range-to-find-a-.patch +MINOR-http-add-new-function-http_path_has_forbidden_.patch +MINOR-h2-pass-accept-invalid-http-request-down-the-r.patch +REGTESTS-http-rules-add-accept-invalid-http-request-.patch +BUG-MINOR-h1-do-not-accept-as-part-of-the-URI-compon.patch +BUG-MINOR-h2-reject-more-chars-from-the-path-pseudo-.patch +BUG-MINOR-h3-reject-more-chars-from-the-path-pseudo-.patch +REGTESTS-http-rules-verify-that-we-block-by-default-.patch +DOC-clarify-the-handling-of-URL-fragments-in-request.patch + +# applied during the build process: +# debianize-dconv.patch diff --git a/debian/rsyslog.conf b/debian/rsyslog.conf new file mode 100644 index 0000000..36a1261 --- /dev/null +++ b/debian/rsyslog.conf @@ -0,0 +1,9 @@ +# Create an additional socket in haproxy's chroot in order to allow logging via +# /dev/log to chroot'ed HAProxy processes +$AddUnixListenSocket /var/lib/haproxy/dev/log + +# Send HAProxy messages to a dedicated logfile +:programname, startswith, "haproxy" { + /var/log/haproxy.log + stop +} diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..cc7ff8e --- /dev/null +++ b/debian/rules @@ -0,0 +1,90 @@ +#!/usr/bin/make -f + +include /usr/share/dpkg/pkg-info.mk +include /usr/share/dpkg/architecture.mk +include /usr/share/dpkg/buildflags.mk + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all +export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed + +MAKEARGS=V=1 \ + DESTDIR=debian/haproxy \ + PREFIX=/usr \ + IGNOREGIT=true \ + MANDIR=/usr/share/man \ + DOCDIR=/usr/share/doc/haproxy \ + USE_PCRE2=1 \ + USE_PCRE2_JIT=1 \ + USE_OPENSSL=1 \ + USE_SLZ=1 \ + USE_LUA=1 \ + USE_PROMEX=1 \ + USE_OT=1 \ + LUA_INC=/usr/include/lua5.3 \ + EXTRA=admin/halog/halog + +ifeq ($(DEB_HOST_ARCH_OS),linux) + MAKEARGS+= TARGET=linux-glibc USE_SYSTEMD=1 +else ifeq ($(DEB_HOST_ARCH_OS),kfreebsd) + MAKEARGS+= TARGET=freebsd +else + MAKEARGS+= TARGET=generic +endif + +ifneq ($(filter armel mips mipsel m68k powerpc powerpcspe sh4 riscv64,$(DEB_HOST_ARCH)),) + MAKEARGS+= ADDLIB="-latomic" +endif + +MAKEARGS += DEBUG_CFLAGS="$(CFLAGS) $(CPPFLAGS)" +MAKEARGS += LDFLAGS="$(LDFLAGS)" +MAKEARGS += VERSION="$(DEB_VERSION_UPSTREAM)" +MAKEARGS += SUBVERS="-$(lastword $(subst -, ,$(DEB_VERSION)))" +MAKEARGS += VERDATE="$(shell TZ=UTC date -d "@$(SOURCE_DATE_EPOCH)" "+%Y/%m/%d")" + +%: + dh $@ --with sphinxdoc + +override_dh_auto_configure: + +override_dh_auto_build-arch: + make $(MAKEARGS) + make -C admin/systemd $(MAKEARGS) + $(MAKE) -C doc/lua-api man + +override_dh_auto_build-indep: + # Build the HTML documentation, after patching dconv + patch -p1 < $(CURDIR)/debian/patches/debianize-dconv.patch + for doc in intro configuration management; do \ + python3 -B $(CURDIR)/debian/dconv/haproxy-dconv.py \ + -i $(CURDIR)/doc/$${doc}.txt \ + -o $(CURDIR)/doc/$${doc}.html ;\ + done + patch -p1 -R < $(CURDIR)/debian/patches/debianize-dconv.patch + $(MAKE) -C doc/lua-api html + +override_dh_auto_clean: + make -C admin/systemd clean + $(MAKE) -C doc/lua-api clean + dh_auto_clean + +override_dh_auto_install-arch: + make $(MAKEARGS) install + install -m 0644 -D debian/rsyslog.conf debian/haproxy/etc/rsyslog.d/49-haproxy.conf + install -m 0644 -D debian/logrotate.conf debian/haproxy/etc/logrotate.d/haproxy + +override_dh_auto_install-indep: + +override_dh_installdocs: + dh_installdocs -Xsystemd/ -Xhalog/ + +override_dh_installexamples: + dh_installexamples -X build.cfg + +override_dh_installinit: + dh_installinit --no-restart-after-upgrade --no-stop-on-upgrade + +override_dh_installsystemd: + dh_installsystemd --no-restart-after-upgrade --no-stop-on-upgrade + +override_dh_strip: + dh_strip --dbgsym-migration="haproxy-dbg" diff --git a/debian/salsa-ci.yml b/debian/salsa-ci.yml new file mode 100644 index 0000000..33c3a64 --- /dev/null +++ b/debian/salsa-ci.yml @@ -0,0 +1,4 @@ +--- +include: + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/debian/source/include-binaries b/debian/source/include-binaries new file mode 100644 index 0000000..a46fd83 --- /dev/null +++ b/debian/source/include-binaries @@ -0,0 +1,3 @@ +debian/dconv/css/check.png +debian/dconv/css/cross.png +debian/dconv/img/logo-med.png diff --git a/debian/tests/cli b/debian/tests/cli new file mode 100644 index 0000000..941b4af --- /dev/null +++ b/debian/tests/cli @@ -0,0 +1,7 @@ +#!/bin/sh + +set -e + +echo "show stat" | socat STDIO UNIX-CONNECT:/run/haproxy/admin.sock | grep "^#" + +echo "show info" | socat STDIO UNIX-CONNECT:/run/haproxy/admin.sock | grep "^Version:" diff --git a/debian/tests/control b/debian/tests/control new file mode 100644 index 0000000..ccc2b53 --- /dev/null +++ b/debian/tests/control @@ -0,0 +1,15 @@ +Tests: cli +Depends: haproxy, socat +Restrictions: needs-root + +Tests: proxy-localhost +Depends: haproxy, wget, apache2 +Restrictions: needs-root, allow-stderr, isolation-container + +Tests: proxy-ssl-termination +Depends: haproxy, wget, apache2, gnutls-bin, ssl-cert +Restrictions: needs-root, allow-stderr, isolation-container + +Tests: proxy-ssl-pass-through +Depends: haproxy, wget, apache2, gnutls-bin, ssl-cert +Restrictions: needs-root, allow-stderr, isolation-container diff --git a/debian/tests/proxy-localhost b/debian/tests/proxy-localhost new file mode 100644 index 0000000..0736985 --- /dev/null +++ b/debian/tests/proxy-localhost @@ -0,0 +1,44 @@ +#!/bin/sh + +set -eux + +WDIR=$(dirname "$0") +. "${WDIR}/utils" + +cat > /etc/haproxy/haproxy.cfg <<EOF +global + chroot /var/lib/haproxy + user haproxy + group haproxy + daemon + maxconn 4096 + +defaults + log global + option dontlognull + option redispatch + retries 3 + timeout client 50s + timeout connect 10s + timeout http-request 5s + timeout server 50s + maxconn 4096 + +frontend test-front + bind *:8080 + mode http + default_backend test-back + +backend test-back + mode http + stick store-request src + stick-table type ip size 256k expire 30m + server test-1 localhost:80 +EOF + +service haproxy restart +sleep 2 # Apache 2 could be still starting... See #976997. + +check_index_file "http://localhost:8080" + +exit 0 diff --git a/debian/tests/proxy-ssl-pass-through b/debian/tests/proxy-ssl-pass-through new file mode 100644 index 0000000..aa0bd2c --- /dev/null +++ b/debian/tests/proxy-ssl-pass-through @@ -0,0 +1,59 @@ +#!/bin/sh + +set -eux + +WDIR=$(dirname "$0") +. "${WDIR}/utils" + +CERT_DIR=/etc/ssl/localhost +APACHE2_CONFIG=/etc/apache2/sites-available/default-ssl.conf + +create_ca +create_selfsigned_cert ${CERT_DIR} + +# Use the self-signed certificate in apache2 config +sed -i "s#/etc/ssl/certs/ssl-cert-snakeoil.pem#${CERT_DIR}/localhost_cert.pem#" ${APACHE2_CONFIG} +sed -i "s#/etc/ssl/private/ssl-cert-snakeoil.key#${CERT_DIR}/localhost_key.pem#" ${APACHE2_CONFIG} + +cat > /etc/haproxy/haproxy.cfg <<EOF +global + chroot /var/lib/haproxy + user haproxy + group haproxy + daemon + maxconn 4096 + +defaults + log global + option dontlognull + option redispatch + retries 3 + timeout client 50s + timeout connect 10s + timeout http-request 5s + timeout server 50s + maxconn 4096 + +frontend test-front + bind *:4433 + mode tcp + option tcplog + default_backend test-back + +backend test-back + mode tcp + stick store-request src + stick-table type ip size 256k expire 30m + option ssl-hello-chk + server test-1 localhost:443 check +EOF + +systemctl restart haproxy +a2enmod ssl +a2ensite default-ssl +systemctl restart apache2 +sleep 5 # Apache 2 could be still starting... See #976997. It needs some extra seconds because of SSL + +check_index_file "https://localhost:4433" + +exit 0 diff --git a/debian/tests/proxy-ssl-termination b/debian/tests/proxy-ssl-termination new file mode 100644 index 0000000..6cc1bcc --- /dev/null +++ b/debian/tests/proxy-ssl-termination @@ -0,0 +1,48 @@ +#!/bin/sh + +set -eux + +WDIR=$(dirname "$0") +. "${WDIR}/utils" + +CERT_DIR=/etc/ssl/localhost +create_ca +create_selfsigned_cert ${CERT_DIR} + +cat > /etc/haproxy/haproxy.cfg <<EOF +global + chroot /var/lib/haproxy + user haproxy + group haproxy + daemon + maxconn 4096 + ssl-default-bind-options ssl-min-ver SSLv3 + +defaults + log global + option dontlognull + option redispatch + retries 3 + timeout client 50s + timeout connect 10s + timeout http-request 5s + timeout server 50s + maxconn 4096 + +frontend test-front + bind *:443 ssl crt ${CERT_DIR}/localhost.pem + default_backend test-back + +backend test-back + mode http + stick store-request src + stick-table type ip size 256k expire 30m + server test-1 localhost:80 check +EOF + +systemctl restart haproxy +sleep 2 # Apache 2 could be still starting... See #976997. + +check_index_file "https://localhost" + +exit 0 diff --git a/debian/tests/utils b/debian/tests/utils new file mode 100644 index 0000000..df11b55 --- /dev/null +++ b/debian/tests/utils @@ -0,0 +1,58 @@ + +create_ca() { + certtool --generate-privkey --bits 4096 --outfile /etc/ssl/private/mycakey.pem + + cat <<EOF > /etc/ssl/ca.info +cn = Example Company +ca +cert_signing_key +expiration_days = 3650 +EOF + + certtool --generate-self-signed \ + --load-privkey /etc/ssl/private/mycakey.pem \ + --template /etc/ssl/ca.info \ + --outfile /usr/local/share/ca-certificates/mycacert.crt + + update-ca-certificates +} + +create_selfsigned_cert() { + dir="$1" + mkdir -p "${dir}" + + certtool --generate-privkey --bits 2048 --outfile "${dir}/localhost_key.pem" + + cat <<EOF > "${dir}/localhost.info" +organization = Example Company +cn = localhost +tls_www_server +encryption_key +signing_key +expiration_days = 365 +EOF + + certtool --generate-certificate \ + --load-privkey "${dir}/localhost_key.pem" \ + --load-ca-certificate /etc/ssl/certs/mycacert.pem \ + --load-ca-privkey /etc/ssl/private/mycakey.pem \ + --template "${dir}/localhost.info" \ + --outfile "${dir}/localhost_cert.pem" + + cat "${dir}/localhost_cert.pem" "${dir}/localhost_key.pem" | tee "${dir}/localhost.pem" + chgrp haproxy "${dir}/localhost_key.pem" "${dir}/localhost.pem" + chmod 0640 "${dir}/localhost_key.pem" "${dir}/localhost.pem" +} + +check_index_file() { + haproxy_url="$1" + # index.html is shipped with apache2 + # Download it via haproxy and compare + if wget -t1 "${haproxy_url}" -O- | cmp /var/www/html/index.html -; then + echo "OK: index.html downloaded via haproxy matches the source file." + else + echo "FAIL: downloaded index.html via haproxy is different from the" + echo " file delivered by apache." + exit 1 + fi +} diff --git a/debian/vim-haproxy.install b/debian/vim-haproxy.install new file mode 100644 index 0000000..b51ecb1 --- /dev/null +++ b/debian/vim-haproxy.install @@ -0,0 +1,3 @@ +debian/vim-haproxy.yaml /usr/share/vim/registry +debian/haproxy.vim /usr/share/vim/addons/ftdetect +admin/syntax-highlight/haproxy.vim /usr/share/vim/addons/syntax diff --git a/debian/vim-haproxy.yaml b/debian/vim-haproxy.yaml new file mode 100644 index 0000000..f87e84f --- /dev/null +++ b/debian/vim-haproxy.yaml @@ -0,0 +1,5 @@ +addon: haproxy +description: "Syntax highlighting for HAProxy" +files: + - syntax/haproxy.vim + - ftdetect/haproxy.vim diff --git a/debian/watch b/debian/watch new file mode 100644 index 0000000..429616d --- /dev/null +++ b/debian/watch @@ -0,0 +1,2 @@ +version=3 +opts="uversionmangle=s/-(dev\d+)/~$1/" https://www.haproxy.org/download/2.6/src/ haproxy-(2\.6(?:\.|-dev)\d+)\.(?:tgz|tbz2|tar\.(?:gz|bz2|xz)) |