summaryrefslogtreecommitdiffstats
path: root/testenv
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--testenv/Makefile.am130
-rw-r--r--testenv/Makefile.in2236
-rw-r--r--testenv/README306
-rwxr-xr-xtestenv/Test--convert-links--content-on-error.py77
-rwxr-xr-xtestenv/Test--https-crl.py51
-rwxr-xr-xtestenv/Test--https.py56
-rwxr-xr-xtestenv/Test--rejected-log.py100
-rwxr-xr-xtestenv/Test--spider-r.py104
-rwxr-xr-xtestenv/Test-416.py53
-rwxr-xr-xtestenv/Test-504.py70
-rwxr-xr-xtestenv/Test-Content-disposition-2.py52
-rwxr-xr-xtestenv/Test-Content-disposition.py54
-rwxr-xr-xtestenv/Test-Head.py42
-rwxr-xr-xtestenv/Test-O.py43
-rwxr-xr-xtestenv/Test-Post.py46
-rwxr-xr-xtestenv/Test-auth-basic-fail.py49
-rwxr-xr-xtestenv/Test-auth-basic-netrc-pass-given.py68
-rwxr-xr-xtestenv/Test-auth-basic-netrc-user-given.py68
-rwxr-xr-xtestenv/Test-auth-basic-netrc.py66
-rwxr-xr-xtestenv/Test-auth-basic-no-netrc-fail.py59
-rwxr-xr-xtestenv/Test-auth-basic.py57
-rwxr-xr-xtestenv/Test-auth-both.py85
-rwxr-xr-xtestenv/Test-auth-digest.py64
-rwxr-xr-xtestenv/Test-auth-no-challenge-url.py52
-rwxr-xr-xtestenv/Test-auth-no-challenge.py52
-rwxr-xr-xtestenv/Test-auth-retcode.py48
-rwxr-xr-xtestenv/Test-auth-with-content-disposition.py52
-rwxr-xr-xtestenv/Test-c-full.py51
-rwxr-xr-xtestenv/Test-condget.py138
-rwxr-xr-xtestenv/Test-cookie-401.py57
-rwxr-xr-xtestenv/Test-cookie-domain-mismatch.py56
-rwxr-xr-xtestenv/Test-cookie-expires.py79
-rwxr-xr-xtestenv/Test-cookie.py55
-rwxr-xr-xtestenv/Test-hsts.py80
-rwxr-xr-xtestenv/Test-metalink-http-baddigest.py93
-rwxr-xr-xtestenv/Test-metalink-http-quoted.py126
-rwxr-xr-xtestenv/Test-metalink-http-xml-trust-name.py272
-rwxr-xr-xtestenv/Test-metalink-http-xml-trust.py272
-rwxr-xr-xtestenv/Test-metalink-http-xml-type-content.py221
-rwxr-xr-xtestenv/Test-metalink-http-xml-type-trust-content.py221
-rwxr-xr-xtestenv/Test-metalink-http-xml-type-trust.py221
-rwxr-xr-xtestenv/Test-metalink-http-xml-type.py221
-rwxr-xr-xtestenv/Test-metalink-http-xml.py272
-rwxr-xr-xtestenv/Test-metalink-http.py126
-rwxr-xr-xtestenv/Test-metalink-xml-abspath-trust.py101
-rwxr-xr-xtestenv/Test-metalink-xml-abspath.py100
-rwxr-xr-xtestenv/Test-metalink-xml-absprefix-trust.py102
-rwxr-xr-xtestenv/Test-metalink-xml-absprefix.py101
-rw-r--r--testenv/Test-metalink-xml-continue.py107
-rwxr-xr-xtestenv/Test-metalink-xml-emptyprefix-trust.py102
-rwxr-xr-xtestenv/Test-metalink-xml-homepath-trust.py102
-rwxr-xr-xtestenv/Test-metalink-xml-homepath.py101
-rwxr-xr-xtestenv/Test-metalink-xml-homeprefix-trust.py102
-rwxr-xr-xtestenv/Test-metalink-xml-homeprefix.py101
-rwxr-xr-xtestenv/Test-metalink-xml-nohash.py100
-rwxr-xr-xtestenv/Test-metalink-xml-nourls.py100
-rwxr-xr-xtestenv/Test-metalink-xml-prefix-trust.py102
-rwxr-xr-xtestenv/Test-metalink-xml-prefix.py101
-rwxr-xr-xtestenv/Test-metalink-xml-relpath-trust.py101
-rwxr-xr-xtestenv/Test-metalink-xml-relpath.py100
-rwxr-xr-xtestenv/Test-metalink-xml-relprefix-trust.py102
-rwxr-xr-xtestenv/Test-metalink-xml-relprefix.py101
-rwxr-xr-xtestenv/Test-metalink-xml-size.py100
-rwxr-xr-xtestenv/Test-metalink-xml-trust.py101
-rwxr-xr-xtestenv/Test-metalink-xml-urlbreak.py236
-rw-r--r--testenv/Test-metalink-xml.py100
-rwxr-xr-xtestenv/Test-missing-scheme-retval.py42
-rwxr-xr-xtestenv/Test-no_proxy-env.py161
-rwxr-xr-xtestenv/Test-pinnedpubkey-der-https.py57
-rwxr-xr-xtestenv/Test-pinnedpubkey-der-no-check-https.py56
-rwxr-xr-xtestenv/Test-pinnedpubkey-hash-https.py60
-rwxr-xr-xtestenv/Test-pinnedpubkey-hash-no-check-fail-https.py51
-rwxr-xr-xtestenv/Test-pinnedpubkey-pem-fail-https.py53
-rwxr-xr-xtestenv/Test-pinnedpubkey-pem-https.py57
-rwxr-xr-xtestenv/Test-recursive-basic.py59
-rwxr-xr-xtestenv/Test-recursive-include.py56
-rw-r--r--testenv/Test-recursive-redirect.py64
-rwxr-xr-xtestenv/Test-redirect-crash.py72
-rwxr-xr-xtestenv/Test-redirect.py57
-rwxr-xr-xtestenv/Test-reserved-chars.py57
-rw-r--r--testenv/certs/README87
-rw-r--r--testenv/certs/ca-cert.pem19
-rw-r--r--testenv/certs/ca-key.pem144
-rw-r--r--testenv/certs/ca-template.cfg246
-rwxr-xr-xtestenv/certs/make_ca.sh23
-rw-r--r--testenv/certs/server-cert.pem21
-rw-r--r--testenv/certs/server-crl.pem12
-rw-r--r--testenv/certs/server-key.pem144
-rw-r--r--testenv/certs/server-pubkey-sha256.base641
-rw-r--r--testenv/certs/server-pubkey.derbin0 -> 294 bytes
-rw-r--r--testenv/certs/server-pubkey.pem9
-rw-r--r--testenv/certs/server-template.cfg245
-rw-r--r--testenv/conf/__init__.py48
-rw-r--r--testenv/conf/authentication.py23
-rw-r--r--testenv/conf/domains.py9
-rw-r--r--testenv/conf/environment_variables.py14
-rw-r--r--testenv/conf/expect_header.py12
-rw-r--r--testenv/conf/expected_files.py58
-rw-r--r--testenv/conf/expected_ret_code.py27
-rw-r--r--testenv/conf/files_crawled.py27
-rw-r--r--testenv/conf/hook_sample.py22
-rw-r--r--testenv/conf/local_files.py26
-rw-r--r--testenv/conf/reject_header.py13
-rw-r--r--testenv/conf/response.py11
-rw-r--r--testenv/conf/rule_sample.py10
-rw-r--r--testenv/conf/send_header.py12
-rw-r--r--testenv/conf/server_files.py26
-rw-r--r--testenv/conf/urls.py14
-rw-r--r--testenv/conf/wget_commands.py15
-rw-r--r--testenv/exc/__init__.py0
-rw-r--r--testenv/exc/server_error.py19
-rw-r--r--testenv/exc/test_failed.py7
-rw-r--r--testenv/misc/__init__.py0
-rw-r--r--testenv/misc/colour_terminal.py46
-rw-r--r--testenv/misc/metalinkv3_xml.py305
-rw-r--r--testenv/misc/wget_file.py16
-rw-r--r--testenv/server/__init__.py0
-rw-r--r--testenv/server/ftp/__init__.py0
-rw-r--r--testenv/server/ftp/ftp_server.py162
-rw-r--r--testenv/server/http/__init__.py0
-rw-r--r--testenv/server/http/http_server.py492
-rw-r--r--testenv/test/__init__.py0
-rw-r--r--testenv/test/base_test.py279
-rw-r--r--testenv/test/http_test.py61
-rw-r--r--testenv/valgrind-suppressions-ssl49
125 files changed, 12720 insertions, 0 deletions
diff --git a/testenv/Makefile.am b/testenv/Makefile.am
new file mode 100644
index 0000000..7996af2
--- /dev/null
+++ b/testenv/Makefile.am
@@ -0,0 +1,130 @@
+# Makefile for `wget' utility
+# Copyright (C) 2013, 2015, 2018-2022 Free Software Foundation, Inc.
+
+# 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 3 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 Wget. If not, see <http://www.gnu.org/licenses/>.
+
+# Additional permission under GNU GPL version 3 section 7
+
+# If you modify this program, or any covered work, by linking or
+# combining it with the OpenSSL project's OpenSSL library (or a
+# modified version of that library), containing parts covered by the
+# terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
+# grants you additional permission to convey the resulting work.
+# Corresponding Source for a non-source form of such a combination
+# shall include the source code for the parts of OpenSSL used as well
+# as that of the covered work.
+
+DEFAULT_TESTS = \
+ Test-504.py \
+ Test-416.py \
+ Test-auth-basic-fail.py \
+ Test-auth-basic.py \
+ Test-auth-basic-netrc.py \
+ Test-auth-basic-netrc-user-given.py \
+ Test-auth-basic-netrc-pass-given.py \
+ Test-auth-basic-no-netrc-fail.py \
+ Test-auth-both.py \
+ Test-auth-digest.py \
+ Test-auth-no-challenge.py \
+ Test-auth-no-challenge-url.py \
+ Test-auth-retcode.py \
+ Test-auth-with-content-disposition.py \
+ Test-c-full.py \
+ Test-condget.py \
+ Test-Content-disposition-2.py \
+ Test-Content-disposition.py \
+ Test--convert-links--content-on-error.py \
+ Test-cookie-401.py \
+ Test-cookie-domain-mismatch.py \
+ Test-cookie-expires.py \
+ Test-cookie.py \
+ Test-Head.py \
+ Test-hsts.py \
+ Test--https.py \
+ Test--https-crl.py \
+ Test-missing-scheme-retval.py \
+ Test-O.py \
+ Test-pinnedpubkey-der-https.py \
+ Test-pinnedpubkey-der-no-check-https.py \
+ Test-pinnedpubkey-hash-https.py \
+ Test-pinnedpubkey-hash-no-check-fail-https.py \
+ Test-pinnedpubkey-pem-fail-https.py \
+ Test-pinnedpubkey-pem-https.py \
+ Test-Post.py \
+ Test-recursive-basic.py \
+ Test-recursive-include.py \
+ Test-recursive-redirect.py \
+ Test-redirect.py \
+ Test-redirect-crash.py \
+ Test--rejected-log.py \
+ Test-reserved-chars.py \
+ Test--spider-r.py \
+ Test-no_proxy-env.py
+
+METALINK_TESTS = \
+ Test-metalink-http.py \
+ Test-metalink-http-quoted.py \
+ Test-metalink-http-baddigest.py \
+ Test-metalink-http-xml.py \
+ Test-metalink-http-xml-trust.py \
+ Test-metalink-http-xml-trust-name.py \
+ Test-metalink-http-xml-type.py \
+ Test-metalink-http-xml-type-trust.py \
+ Test-metalink-http-xml-type-content.py \
+ Test-metalink-http-xml-type-trust-content.py \
+ Test-metalink-xml.py \
+ Test-metalink-xml-continue.py \
+ Test-metalink-xml-relpath.py \
+ Test-metalink-xml-abspath.py \
+ Test-metalink-xml-homepath.py \
+ Test-metalink-xml-trust.py \
+ Test-metalink-xml-relpath-trust.py \
+ Test-metalink-xml-abspath-trust.py \
+ Test-metalink-xml-homepath-trust.py \
+ Test-metalink-xml-prefix.py \
+ Test-metalink-xml-relprefix.py \
+ Test-metalink-xml-absprefix.py \
+ Test-metalink-xml-homeprefix.py \
+ Test-metalink-xml-prefix-trust.py \
+ Test-metalink-xml-relprefix-trust.py \
+ Test-metalink-xml-absprefix-trust.py \
+ Test-metalink-xml-homeprefix-trust.py \
+ Test-metalink-xml-emptyprefix-trust.py \
+ Test-metalink-xml-size.py \
+ Test-metalink-xml-nohash.py \
+ Test-metalink-xml-nourls.py \
+ Test-metalink-xml-urlbreak.py
+
+AUTOMAKE_OPTIONS = parallel-tests
+AM_TESTS_ENVIRONMENT = export WGETRC=/dev/null; MAKE_CHECK=True; export MAKE_CHECK;\
+ export PYTHONPATH=$$PYTHONPATH$(PATH_SEPARATOR)$(srcdir); export VALGRIND_TESTS="@VALGRIND_TESTS@";
+
+if WITH_SSL
+ AM_TESTS_ENVIRONMENT += export SSL_TESTS=1;
+endif
+
+if HAVE_PYTHON3
+TESTS = $(DEFAULT_TESTS)
+if WITH_METALINK
+ TESTS += $(METALINK_TESTS)
+endif
+endif
+
+EXTRA_DIST = certs conf exc misc server test README \
+ valgrind-suppressions-ssl \
+ $(DEFAULT_TESTS) $(METALINK_TESTS)
+
+TEST_EXTENSIONS = .py
+PY_LOG_COMPILER = python3
+AM_PY_LOG_FLAGS = -O
diff --git a/testenv/Makefile.in b/testenv/Makefile.in
new file mode 100644
index 0000000..b4d7ba5
--- /dev/null
+++ b/testenv/Makefile.in
@@ -0,0 +1,2236 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile for `wget' utility
+# Copyright (C) 2013, 2015, 2018-2022 Free Software Foundation, Inc.
+
+# 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 3 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 Wget. If not, see <http://www.gnu.org/licenses/>.
+
+# Additional permission under GNU GPL version 3 section 7
+
+# If you modify this program, or any covered work, by linking or
+# combining it with the OpenSSL project's OpenSSL library (or a
+# modified version of that library), containing parts covered by the
+# terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
+# grants you additional permission to convey the resulting work.
+# Corresponding Source for a non-source form of such a combination
+# shall include the source code for the parts of OpenSSL used as well
+# as that of the covered work.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@WITH_SSL_TRUE@am__append_1 = export SSL_TESTS=1;
+@HAVE_PYTHON3_TRUE@@WITH_METALINK_TRUE@am__append_2 = $(METALINK_TESTS)
+subdir = testenv
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/00gnulib.m4 \
+ $(top_srcdir)/m4/__inline.m4 \
+ $(top_srcdir)/m4/absolute-header.m4 $(top_srcdir)/m4/access.m4 \
+ $(top_srcdir)/m4/af_alg.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/arpa_inet_h.m4 \
+ $(top_srcdir)/m4/asm-underscore.m4 $(top_srcdir)/m4/base32.m4 \
+ $(top_srcdir)/m4/btowc.m4 $(top_srcdir)/m4/builtin-expect.m4 \
+ $(top_srcdir)/m4/byteswap.m4 $(top_srcdir)/m4/calloc.m4 \
+ $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/close.m4 $(top_srcdir)/m4/closedir.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/ctype_h.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/dirent_h.m4 \
+ $(top_srcdir)/m4/dirfd.m4 \
+ $(top_srcdir)/m4/double-slash-root.m4 $(top_srcdir)/m4/dup.m4 \
+ $(top_srcdir)/m4/dup2.m4 $(top_srcdir)/m4/eaccess.m4 \
+ $(top_srcdir)/m4/eealloc.m4 $(top_srcdir)/m4/environ.m4 \
+ $(top_srcdir)/m4/errno_h.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/exponentd.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/extern-inline.m4 \
+ $(top_srcdir)/m4/fatal-signal.m4 $(top_srcdir)/m4/fchdir.m4 \
+ $(top_srcdir)/m4/fcntl-o.m4 $(top_srcdir)/m4/fcntl.m4 \
+ $(top_srcdir)/m4/fcntl_h.m4 $(top_srcdir)/m4/fdopendir.m4 \
+ $(top_srcdir)/m4/fflush.m4 $(top_srcdir)/m4/filenamecat.m4 \
+ $(top_srcdir)/m4/findprog-in.m4 $(top_srcdir)/m4/flexmember.m4 \
+ $(top_srcdir)/m4/float_h.m4 $(top_srcdir)/m4/flock.m4 \
+ $(top_srcdir)/m4/fnmatch.m4 $(top_srcdir)/m4/fnmatch_h.m4 \
+ $(top_srcdir)/m4/fopen.m4 $(top_srcdir)/m4/fpurge.m4 \
+ $(top_srcdir)/m4/freading.m4 $(top_srcdir)/m4/free.m4 \
+ $(top_srcdir)/m4/fseek.m4 $(top_srcdir)/m4/fseeko.m4 \
+ $(top_srcdir)/m4/fstat.m4 $(top_srcdir)/m4/fstatat.m4 \
+ $(top_srcdir)/m4/ftell.m4 $(top_srcdir)/m4/ftello.m4 \
+ $(top_srcdir)/m4/futimens.m4 $(top_srcdir)/m4/getaddrinfo.m4 \
+ $(top_srcdir)/m4/getcwd-abort-bug.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdelim.m4 $(top_srcdir)/m4/getdtablesize.m4 \
+ $(top_srcdir)/m4/getgroups.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getopt.m4 $(top_srcdir)/m4/getpagesize.m4 \
+ $(top_srcdir)/m4/getpass.m4 $(top_srcdir)/m4/getprogname.m4 \
+ $(top_srcdir)/m4/getrandom.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gettime.m4 $(top_srcdir)/m4/gettimeofday.m4 \
+ $(top_srcdir)/m4/gl-openssl.m4 \
+ $(top_srcdir)/m4/gnulib-common.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 \
+ $(top_srcdir)/m4/group-member.m4 \
+ $(top_srcdir)/m4/host-cpu-c-abi.m4 $(top_srcdir)/m4/hostent.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/iconv_h.m4 \
+ $(top_srcdir)/m4/include_next.m4 $(top_srcdir)/m4/inet_ntop.m4 \
+ $(top_srcdir)/m4/inline.m4 $(top_srcdir)/m4/intlmacosx.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/ioctl.m4 \
+ $(top_srcdir)/m4/isblank.m4 $(top_srcdir)/m4/iswblank.m4 \
+ $(top_srcdir)/m4/iswdigit.m4 $(top_srcdir)/m4/iswxdigit.m4 \
+ $(top_srcdir)/m4/langinfo_h.m4 $(top_srcdir)/m4/largefile.m4 \
+ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+ $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libunistring-base.m4 \
+ $(top_srcdir)/m4/libunistring-optional.m4 \
+ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/limits-h.m4 \
+ $(top_srcdir)/m4/link.m4 $(top_srcdir)/m4/localcharset.m4 \
+ $(top_srcdir)/m4/locale-fr.m4 $(top_srcdir)/m4/locale-ja.m4 \
+ $(top_srcdir)/m4/locale-zh.m4 $(top_srcdir)/m4/locale_h.m4 \
+ $(top_srcdir)/m4/localeconv.m4 $(top_srcdir)/m4/lock.m4 \
+ $(top_srcdir)/m4/lseek.m4 $(top_srcdir)/m4/lstat.m4 \
+ $(top_srcdir)/m4/malloc.m4 $(top_srcdir)/m4/malloca.m4 \
+ $(top_srcdir)/m4/mbchar.m4 $(top_srcdir)/m4/mbiter.m4 \
+ $(top_srcdir)/m4/mbrtowc.m4 $(top_srcdir)/m4/mbsinit.m4 \
+ $(top_srcdir)/m4/mbsrtowcs.m4 $(top_srcdir)/m4/mbstate_t.m4 \
+ $(top_srcdir)/m4/mbtowc.m4 $(top_srcdir)/m4/md4.m4 \
+ $(top_srcdir)/m4/md5.m4 $(top_srcdir)/m4/memchr.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/minmax.m4 $(top_srcdir)/m4/mkdir.m4 \
+ $(top_srcdir)/m4/mkostemp.m4 $(top_srcdir)/m4/mkstemp.m4 \
+ $(top_srcdir)/m4/mktime.m4 $(top_srcdir)/m4/mmap-anon.m4 \
+ $(top_srcdir)/m4/mode_t.m4 $(top_srcdir)/m4/msvc-inval.m4 \
+ $(top_srcdir)/m4/msvc-nothrow.m4 $(top_srcdir)/m4/multiarch.m4 \
+ $(top_srcdir)/m4/nanosleep.m4 $(top_srcdir)/m4/netdb_h.m4 \
+ $(top_srcdir)/m4/netinet_in_h.m4 \
+ $(top_srcdir)/m4/nl_langinfo.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/nocrash.m4 $(top_srcdir)/m4/off_t.m4 \
+ $(top_srcdir)/m4/open-cloexec.m4 \
+ $(top_srcdir)/m4/open-slash.m4 $(top_srcdir)/m4/open.m4 \
+ $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/opendir.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/pipe.m4 \
+ $(top_srcdir)/m4/pipe2.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/posix_spawn.m4 \
+ $(top_srcdir)/m4/posix_spawn_faction_addchdir.m4 \
+ $(top_srcdir)/m4/printf.m4 $(top_srcdir)/m4/pselect.m4 \
+ $(top_srcdir)/m4/pthread_rwlock_rdlock.m4 \
+ $(top_srcdir)/m4/pthread_sigmask.m4 $(top_srcdir)/m4/quote.m4 \
+ $(top_srcdir)/m4/quotearg.m4 $(top_srcdir)/m4/raise.m4 \
+ $(top_srcdir)/m4/rawmemchr.m4 $(top_srcdir)/m4/readdir.m4 \
+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/realloc.m4 \
+ $(top_srcdir)/m4/reallocarray.m4 $(top_srcdir)/m4/regex.m4 \
+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/rewinddir.m4 \
+ $(top_srcdir)/m4/rmdir.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/sched_h.m4 $(top_srcdir)/m4/secure_getenv.m4 \
+ $(top_srcdir)/m4/select.m4 $(top_srcdir)/m4/servent.m4 \
+ $(top_srcdir)/m4/setlocale_null.m4 \
+ $(top_srcdir)/m4/sh-filename.m4 $(top_srcdir)/m4/sha1.m4 \
+ $(top_srcdir)/m4/sha256.m4 $(top_srcdir)/m4/sha512.m4 \
+ $(top_srcdir)/m4/sig_atomic_t.m4 $(top_srcdir)/m4/sigaction.m4 \
+ $(top_srcdir)/m4/signal_h.m4 \
+ $(top_srcdir)/m4/signalblocking.m4 $(top_srcdir)/m4/sigpipe.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/snprintf.m4 \
+ $(top_srcdir)/m4/socketlib.m4 $(top_srcdir)/m4/sockets.m4 \
+ $(top_srcdir)/m4/socklen.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/spawn-pipe.m4 $(top_srcdir)/m4/spawn_h.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-time.m4 \
+ $(top_srcdir)/m4/stat.m4 $(top_srcdir)/m4/stdalign.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stddef_h.m4 \
+ $(top_srcdir)/m4/stdint.m4 $(top_srcdir)/m4/stdint_h.m4 \
+ $(top_srcdir)/m4/stdio_h.m4 $(top_srcdir)/m4/stdlib_h.m4 \
+ $(top_srcdir)/m4/stpcpy.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strchrnul.m4 $(top_srcdir)/m4/strdup.m4 \
+ $(top_srcdir)/m4/strerror.m4 $(top_srcdir)/m4/strerror_r.m4 \
+ $(top_srcdir)/m4/string_h.m4 $(top_srcdir)/m4/strings_h.m4 \
+ $(top_srcdir)/m4/strndup.m4 $(top_srcdir)/m4/strnlen.m4 \
+ $(top_srcdir)/m4/strpbrk.m4 $(top_srcdir)/m4/strptime.m4 \
+ $(top_srcdir)/m4/strtok_r.m4 $(top_srcdir)/m4/strtol.m4 \
+ $(top_srcdir)/m4/strtoll.m4 $(top_srcdir)/m4/symlink.m4 \
+ $(top_srcdir)/m4/sys_file_h.m4 $(top_srcdir)/m4/sys_ioctl_h.m4 \
+ $(top_srcdir)/m4/sys_random_h.m4 \
+ $(top_srcdir)/m4/sys_select_h.m4 \
+ $(top_srcdir)/m4/sys_socket_h.m4 \
+ $(top_srcdir)/m4/sys_stat_h.m4 $(top_srcdir)/m4/sys_time_h.m4 \
+ $(top_srcdir)/m4/sys_types_h.m4 $(top_srcdir)/m4/sys_uio_h.m4 \
+ $(top_srcdir)/m4/sys_wait_h.m4 $(top_srcdir)/m4/tempname.m4 \
+ $(top_srcdir)/m4/threadlib.m4 $(top_srcdir)/m4/time_h.m4 \
+ $(top_srcdir)/m4/time_r.m4 $(top_srcdir)/m4/timegm.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/tmpdir.m4 $(top_srcdir)/m4/ungetc.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 $(top_srcdir)/m4/unistd_h.m4 \
+ $(top_srcdir)/m4/unlink.m4 $(top_srcdir)/m4/unlocked-io.m4 \
+ $(top_srcdir)/m4/utime.m4 $(top_srcdir)/m4/utime_h.m4 \
+ $(top_srcdir)/m4/utimens.m4 $(top_srcdir)/m4/utimes.m4 \
+ $(top_srcdir)/m4/vasnprintf.m4 $(top_srcdir)/m4/vasprintf.m4 \
+ $(top_srcdir)/m4/visibility.m4 $(top_srcdir)/m4/vsnprintf.m4 \
+ $(top_srcdir)/m4/wait-process.m4 $(top_srcdir)/m4/waitpid.m4 \
+ $(top_srcdir)/m4/warn-on-use.m4 $(top_srcdir)/m4/warnings.m4 \
+ $(top_srcdir)/m4/wchar_h.m4 $(top_srcdir)/m4/wchar_t.m4 \
+ $(top_srcdir)/m4/wcrtomb.m4 $(top_srcdir)/m4/wctype_h.m4 \
+ $(top_srcdir)/m4/wcwidth.m4 $(top_srcdir)/m4/wget.m4 \
+ $(top_srcdir)/m4/wget_manywarnings.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/wmemchr.m4 \
+ $(top_srcdir)/m4/wmempcpy.m4 $(top_srcdir)/m4/write.m4 \
+ $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/m4/xsize.m4 \
+ $(top_srcdir)/m4/xstrndup.m4 $(top_srcdir)/m4/year2038.m4 \
+ $(top_srcdir)/m4/zzgnulib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/src/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.py.log=.log)
+PY_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver
+PY_LOG_COMPILE = $(PY_LOG_COMPILER) $(AM_PY_LOG_FLAGS) $(PY_LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/build-aux/test-driver README
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@
+AR = @AR@
+ARFLAGS = @ARFLAGS@
+ASM_SYMBOL_PREFIX = @ASM_SYMBOL_PREFIX@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@
+BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@
+BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@
+BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@
+BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@
+BYTESWAP_H = @BYTESWAP_H@
+CARES_CFLAGS = @CARES_CFLAGS@
+CARES_LIBS = @CARES_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
+CODE_COVERAGE_CPPFLAGS = @CODE_COVERAGE_CPPFLAGS@
+CODE_COVERAGE_CXXFLAGS = @CODE_COVERAGE_CXXFLAGS@
+CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
+CODE_COVERAGE_LIBS = @CODE_COVERAGE_LIBS@
+COMMENT_IF_NO_POD2MAN = @COMMENT_IF_NO_POD2MAN@
+CONFIG_INCLUDE = @CONFIG_INCLUDE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EMULTIHOP_HIDDEN = @EMULTIHOP_HIDDEN@
+EMULTIHOP_VALUE = @EMULTIHOP_VALUE@
+ENOLINK_HIDDEN = @ENOLINK_HIDDEN@
+ENOLINK_VALUE = @ENOLINK_VALUE@
+EOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@
+EOVERFLOW_VALUE = @EOVERFLOW_VALUE@
+ERRNO_H = @ERRNO_H@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FLOAT_H = @FLOAT_H@
+FNMATCH_H = @FNMATCH_H@
+FUZZ_LIBS = @FUZZ_LIBS@
+GCOV = @GCOV@
+GENHTML = @GENHTML@
+GETADDRINFO_LIB = @GETADDRINFO_LIB@
+GETOPT_CDEFS_H = @GETOPT_CDEFS_H@
+GETOPT_H = @GETOPT_H@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GL_CFLAG_ALLOW_WARNINGS = @GL_CFLAG_ALLOW_WARNINGS@
+GL_CFLAG_GNULIB_WARNINGS = @GL_CFLAG_GNULIB_WARNINGS@
+GL_GNULIB_ACCEPT = @GL_GNULIB_ACCEPT@
+GL_GNULIB_ACCEPT4 = @GL_GNULIB_ACCEPT4@
+GL_GNULIB_ACCESS = @GL_GNULIB_ACCESS@
+GL_GNULIB_ALIGNED_ALLOC = @GL_GNULIB_ALIGNED_ALLOC@
+GL_GNULIB_ALPHASORT = @GL_GNULIB_ALPHASORT@
+GL_GNULIB_ATOLL = @GL_GNULIB_ATOLL@
+GL_GNULIB_BIND = @GL_GNULIB_BIND@
+GL_GNULIB_BTOWC = @GL_GNULIB_BTOWC@
+GL_GNULIB_CALLOC_GNU = @GL_GNULIB_CALLOC_GNU@
+GL_GNULIB_CALLOC_POSIX = @GL_GNULIB_CALLOC_POSIX@
+GL_GNULIB_CANONICALIZE_FILE_NAME = @GL_GNULIB_CANONICALIZE_FILE_NAME@
+GL_GNULIB_CHDIR = @GL_GNULIB_CHDIR@
+GL_GNULIB_CHOWN = @GL_GNULIB_CHOWN@
+GL_GNULIB_CLOSE = @GL_GNULIB_CLOSE@
+GL_GNULIB_CLOSEDIR = @GL_GNULIB_CLOSEDIR@
+GL_GNULIB_CONNECT = @GL_GNULIB_CONNECT@
+GL_GNULIB_COPY_FILE_RANGE = @GL_GNULIB_COPY_FILE_RANGE@
+GL_GNULIB_CREAT = @GL_GNULIB_CREAT@
+GL_GNULIB_CTIME = @GL_GNULIB_CTIME@
+GL_GNULIB_DIRFD = @GL_GNULIB_DIRFD@
+GL_GNULIB_DPRINTF = @GL_GNULIB_DPRINTF@
+GL_GNULIB_DUP = @GL_GNULIB_DUP@
+GL_GNULIB_DUP2 = @GL_GNULIB_DUP2@
+GL_GNULIB_DUP3 = @GL_GNULIB_DUP3@
+GL_GNULIB_DUPLOCALE = @GL_GNULIB_DUPLOCALE@
+GL_GNULIB_ENVIRON = @GL_GNULIB_ENVIRON@
+GL_GNULIB_EUIDACCESS = @GL_GNULIB_EUIDACCESS@
+GL_GNULIB_EXECL = @GL_GNULIB_EXECL@
+GL_GNULIB_EXECLE = @GL_GNULIB_EXECLE@
+GL_GNULIB_EXECLP = @GL_GNULIB_EXECLP@
+GL_GNULIB_EXECV = @GL_GNULIB_EXECV@
+GL_GNULIB_EXECVE = @GL_GNULIB_EXECVE@
+GL_GNULIB_EXECVP = @GL_GNULIB_EXECVP@
+GL_GNULIB_EXECVPE = @GL_GNULIB_EXECVPE@
+GL_GNULIB_EXPLICIT_BZERO = @GL_GNULIB_EXPLICIT_BZERO@
+GL_GNULIB_FACCESSAT = @GL_GNULIB_FACCESSAT@
+GL_GNULIB_FCHDIR = @GL_GNULIB_FCHDIR@
+GL_GNULIB_FCHMODAT = @GL_GNULIB_FCHMODAT@
+GL_GNULIB_FCHOWNAT = @GL_GNULIB_FCHOWNAT@
+GL_GNULIB_FCLOSE = @GL_GNULIB_FCLOSE@
+GL_GNULIB_FCNTL = @GL_GNULIB_FCNTL@
+GL_GNULIB_FDATASYNC = @GL_GNULIB_FDATASYNC@
+GL_GNULIB_FDOPEN = @GL_GNULIB_FDOPEN@
+GL_GNULIB_FDOPENDIR = @GL_GNULIB_FDOPENDIR@
+GL_GNULIB_FFLUSH = @GL_GNULIB_FFLUSH@
+GL_GNULIB_FFS = @GL_GNULIB_FFS@
+GL_GNULIB_FFSL = @GL_GNULIB_FFSL@
+GL_GNULIB_FFSLL = @GL_GNULIB_FFSLL@
+GL_GNULIB_FGETC = @GL_GNULIB_FGETC@
+GL_GNULIB_FGETS = @GL_GNULIB_FGETS@
+GL_GNULIB_FLOCK = @GL_GNULIB_FLOCK@
+GL_GNULIB_FNMATCH = @GL_GNULIB_FNMATCH@
+GL_GNULIB_FOPEN = @GL_GNULIB_FOPEN@
+GL_GNULIB_FOPEN_GNU = @GL_GNULIB_FOPEN_GNU@
+GL_GNULIB_FPRINTF = @GL_GNULIB_FPRINTF@
+GL_GNULIB_FPRINTF_POSIX = @GL_GNULIB_FPRINTF_POSIX@
+GL_GNULIB_FPURGE = @GL_GNULIB_FPURGE@
+GL_GNULIB_FPUTC = @GL_GNULIB_FPUTC@
+GL_GNULIB_FPUTS = @GL_GNULIB_FPUTS@
+GL_GNULIB_FREAD = @GL_GNULIB_FREAD@
+GL_GNULIB_FREE_POSIX = @GL_GNULIB_FREE_POSIX@
+GL_GNULIB_FREOPEN = @GL_GNULIB_FREOPEN@
+GL_GNULIB_FSCANF = @GL_GNULIB_FSCANF@
+GL_GNULIB_FSEEK = @GL_GNULIB_FSEEK@
+GL_GNULIB_FSEEKO = @GL_GNULIB_FSEEKO@
+GL_GNULIB_FSTAT = @GL_GNULIB_FSTAT@
+GL_GNULIB_FSTATAT = @GL_GNULIB_FSTATAT@
+GL_GNULIB_FSYNC = @GL_GNULIB_FSYNC@
+GL_GNULIB_FTELL = @GL_GNULIB_FTELL@
+GL_GNULIB_FTELLO = @GL_GNULIB_FTELLO@
+GL_GNULIB_FTRUNCATE = @GL_GNULIB_FTRUNCATE@
+GL_GNULIB_FUTIMENS = @GL_GNULIB_FUTIMENS@
+GL_GNULIB_FWRITE = @GL_GNULIB_FWRITE@
+GL_GNULIB_GETADDRINFO = @GL_GNULIB_GETADDRINFO@
+GL_GNULIB_GETC = @GL_GNULIB_GETC@
+GL_GNULIB_GETCHAR = @GL_GNULIB_GETCHAR@
+GL_GNULIB_GETCWD = @GL_GNULIB_GETCWD@
+GL_GNULIB_GETDELIM = @GL_GNULIB_GETDELIM@
+GL_GNULIB_GETDOMAINNAME = @GL_GNULIB_GETDOMAINNAME@
+GL_GNULIB_GETDTABLESIZE = @GL_GNULIB_GETDTABLESIZE@
+GL_GNULIB_GETENTROPY = @GL_GNULIB_GETENTROPY@
+GL_GNULIB_GETGROUPS = @GL_GNULIB_GETGROUPS@
+GL_GNULIB_GETHOSTNAME = @GL_GNULIB_GETHOSTNAME@
+GL_GNULIB_GETLINE = @GL_GNULIB_GETLINE@
+GL_GNULIB_GETLOADAVG = @GL_GNULIB_GETLOADAVG@
+GL_GNULIB_GETLOGIN = @GL_GNULIB_GETLOGIN@
+GL_GNULIB_GETLOGIN_R = @GL_GNULIB_GETLOGIN_R@
+GL_GNULIB_GETOPT_POSIX = @GL_GNULIB_GETOPT_POSIX@
+GL_GNULIB_GETPAGESIZE = @GL_GNULIB_GETPAGESIZE@
+GL_GNULIB_GETPASS = @GL_GNULIB_GETPASS@
+GL_GNULIB_GETPASS_GNU = @GL_GNULIB_GETPASS_GNU@
+GL_GNULIB_GETPEERNAME = @GL_GNULIB_GETPEERNAME@
+GL_GNULIB_GETRANDOM = @GL_GNULIB_GETRANDOM@
+GL_GNULIB_GETSOCKNAME = @GL_GNULIB_GETSOCKNAME@
+GL_GNULIB_GETSOCKOPT = @GL_GNULIB_GETSOCKOPT@
+GL_GNULIB_GETSUBOPT = @GL_GNULIB_GETSUBOPT@
+GL_GNULIB_GETTIMEOFDAY = @GL_GNULIB_GETTIMEOFDAY@
+GL_GNULIB_GETUMASK = @GL_GNULIB_GETUMASK@
+GL_GNULIB_GETUSERSHELL = @GL_GNULIB_GETUSERSHELL@
+GL_GNULIB_GRANTPT = @GL_GNULIB_GRANTPT@
+GL_GNULIB_GROUP_MEMBER = @GL_GNULIB_GROUP_MEMBER@
+GL_GNULIB_ICONV = @GL_GNULIB_ICONV@
+GL_GNULIB_IMAXABS = @GL_GNULIB_IMAXABS@
+GL_GNULIB_IMAXDIV = @GL_GNULIB_IMAXDIV@
+GL_GNULIB_INET_NTOP = @GL_GNULIB_INET_NTOP@
+GL_GNULIB_INET_PTON = @GL_GNULIB_INET_PTON@
+GL_GNULIB_IOCTL = @GL_GNULIB_IOCTL@
+GL_GNULIB_ISATTY = @GL_GNULIB_ISATTY@
+GL_GNULIB_ISBLANK = @GL_GNULIB_ISBLANK@
+GL_GNULIB_ISWBLANK = @GL_GNULIB_ISWBLANK@
+GL_GNULIB_ISWCTYPE = @GL_GNULIB_ISWCTYPE@
+GL_GNULIB_ISWDIGIT = @GL_GNULIB_ISWDIGIT@
+GL_GNULIB_ISWXDIGIT = @GL_GNULIB_ISWXDIGIT@
+GL_GNULIB_LCHMOD = @GL_GNULIB_LCHMOD@
+GL_GNULIB_LCHOWN = @GL_GNULIB_LCHOWN@
+GL_GNULIB_LINK = @GL_GNULIB_LINK@
+GL_GNULIB_LINKAT = @GL_GNULIB_LINKAT@
+GL_GNULIB_LISTEN = @GL_GNULIB_LISTEN@
+GL_GNULIB_LOCALECONV = @GL_GNULIB_LOCALECONV@
+GL_GNULIB_LOCALENAME = @GL_GNULIB_LOCALENAME@
+GL_GNULIB_LOCALTIME = @GL_GNULIB_LOCALTIME@
+GL_GNULIB_LSEEK = @GL_GNULIB_LSEEK@
+GL_GNULIB_LSTAT = @GL_GNULIB_LSTAT@
+GL_GNULIB_MALLOC_GNU = @GL_GNULIB_MALLOC_GNU@
+GL_GNULIB_MALLOC_POSIX = @GL_GNULIB_MALLOC_POSIX@
+GL_GNULIB_MBRLEN = @GL_GNULIB_MBRLEN@
+GL_GNULIB_MBRTOWC = @GL_GNULIB_MBRTOWC@
+GL_GNULIB_MBSCASECMP = @GL_GNULIB_MBSCASECMP@
+GL_GNULIB_MBSCASESTR = @GL_GNULIB_MBSCASESTR@
+GL_GNULIB_MBSCHR = @GL_GNULIB_MBSCHR@
+GL_GNULIB_MBSCSPN = @GL_GNULIB_MBSCSPN@
+GL_GNULIB_MBSINIT = @GL_GNULIB_MBSINIT@
+GL_GNULIB_MBSLEN = @GL_GNULIB_MBSLEN@
+GL_GNULIB_MBSNCASECMP = @GL_GNULIB_MBSNCASECMP@
+GL_GNULIB_MBSNLEN = @GL_GNULIB_MBSNLEN@
+GL_GNULIB_MBSNRTOWCS = @GL_GNULIB_MBSNRTOWCS@
+GL_GNULIB_MBSPBRK = @GL_GNULIB_MBSPBRK@
+GL_GNULIB_MBSPCASECMP = @GL_GNULIB_MBSPCASECMP@
+GL_GNULIB_MBSRCHR = @GL_GNULIB_MBSRCHR@
+GL_GNULIB_MBSRTOWCS = @GL_GNULIB_MBSRTOWCS@
+GL_GNULIB_MBSSEP = @GL_GNULIB_MBSSEP@
+GL_GNULIB_MBSSPN = @GL_GNULIB_MBSSPN@
+GL_GNULIB_MBSSTR = @GL_GNULIB_MBSSTR@
+GL_GNULIB_MBSTOK_R = @GL_GNULIB_MBSTOK_R@
+GL_GNULIB_MBTOWC = @GL_GNULIB_MBTOWC@
+GL_GNULIB_MDA_ACCESS = @GL_GNULIB_MDA_ACCESS@
+GL_GNULIB_MDA_CHDIR = @GL_GNULIB_MDA_CHDIR@
+GL_GNULIB_MDA_CHMOD = @GL_GNULIB_MDA_CHMOD@
+GL_GNULIB_MDA_CLOSE = @GL_GNULIB_MDA_CLOSE@
+GL_GNULIB_MDA_CREAT = @GL_GNULIB_MDA_CREAT@
+GL_GNULIB_MDA_DUP = @GL_GNULIB_MDA_DUP@
+GL_GNULIB_MDA_DUP2 = @GL_GNULIB_MDA_DUP2@
+GL_GNULIB_MDA_ECVT = @GL_GNULIB_MDA_ECVT@
+GL_GNULIB_MDA_EXECL = @GL_GNULIB_MDA_EXECL@
+GL_GNULIB_MDA_EXECLE = @GL_GNULIB_MDA_EXECLE@
+GL_GNULIB_MDA_EXECLP = @GL_GNULIB_MDA_EXECLP@
+GL_GNULIB_MDA_EXECV = @GL_GNULIB_MDA_EXECV@
+GL_GNULIB_MDA_EXECVE = @GL_GNULIB_MDA_EXECVE@
+GL_GNULIB_MDA_EXECVP = @GL_GNULIB_MDA_EXECVP@
+GL_GNULIB_MDA_EXECVPE = @GL_GNULIB_MDA_EXECVPE@
+GL_GNULIB_MDA_FCLOSEALL = @GL_GNULIB_MDA_FCLOSEALL@
+GL_GNULIB_MDA_FCVT = @GL_GNULIB_MDA_FCVT@
+GL_GNULIB_MDA_FDOPEN = @GL_GNULIB_MDA_FDOPEN@
+GL_GNULIB_MDA_FILENO = @GL_GNULIB_MDA_FILENO@
+GL_GNULIB_MDA_GCVT = @GL_GNULIB_MDA_GCVT@
+GL_GNULIB_MDA_GETCWD = @GL_GNULIB_MDA_GETCWD@
+GL_GNULIB_MDA_GETPID = @GL_GNULIB_MDA_GETPID@
+GL_GNULIB_MDA_GETW = @GL_GNULIB_MDA_GETW@
+GL_GNULIB_MDA_ISATTY = @GL_GNULIB_MDA_ISATTY@
+GL_GNULIB_MDA_LSEEK = @GL_GNULIB_MDA_LSEEK@
+GL_GNULIB_MDA_MEMCCPY = @GL_GNULIB_MDA_MEMCCPY@
+GL_GNULIB_MDA_MKDIR = @GL_GNULIB_MDA_MKDIR@
+GL_GNULIB_MDA_MKTEMP = @GL_GNULIB_MDA_MKTEMP@
+GL_GNULIB_MDA_OPEN = @GL_GNULIB_MDA_OPEN@
+GL_GNULIB_MDA_PUTENV = @GL_GNULIB_MDA_PUTENV@
+GL_GNULIB_MDA_PUTW = @GL_GNULIB_MDA_PUTW@
+GL_GNULIB_MDA_READ = @GL_GNULIB_MDA_READ@
+GL_GNULIB_MDA_RMDIR = @GL_GNULIB_MDA_RMDIR@
+GL_GNULIB_MDA_STRDUP = @GL_GNULIB_MDA_STRDUP@
+GL_GNULIB_MDA_SWAB = @GL_GNULIB_MDA_SWAB@
+GL_GNULIB_MDA_TEMPNAM = @GL_GNULIB_MDA_TEMPNAM@
+GL_GNULIB_MDA_TZSET = @GL_GNULIB_MDA_TZSET@
+GL_GNULIB_MDA_UMASK = @GL_GNULIB_MDA_UMASK@
+GL_GNULIB_MDA_UNLINK = @GL_GNULIB_MDA_UNLINK@
+GL_GNULIB_MDA_UTIME = @GL_GNULIB_MDA_UTIME@
+GL_GNULIB_MDA_WCSDUP = @GL_GNULIB_MDA_WCSDUP@
+GL_GNULIB_MDA_WRITE = @GL_GNULIB_MDA_WRITE@
+GL_GNULIB_MEMCHR = @GL_GNULIB_MEMCHR@
+GL_GNULIB_MEMMEM = @GL_GNULIB_MEMMEM@
+GL_GNULIB_MEMPCPY = @GL_GNULIB_MEMPCPY@
+GL_GNULIB_MEMRCHR = @GL_GNULIB_MEMRCHR@
+GL_GNULIB_MKDIR = @GL_GNULIB_MKDIR@
+GL_GNULIB_MKDIRAT = @GL_GNULIB_MKDIRAT@
+GL_GNULIB_MKDTEMP = @GL_GNULIB_MKDTEMP@
+GL_GNULIB_MKFIFO = @GL_GNULIB_MKFIFO@
+GL_GNULIB_MKFIFOAT = @GL_GNULIB_MKFIFOAT@
+GL_GNULIB_MKNOD = @GL_GNULIB_MKNOD@
+GL_GNULIB_MKNODAT = @GL_GNULIB_MKNODAT@
+GL_GNULIB_MKOSTEMP = @GL_GNULIB_MKOSTEMP@
+GL_GNULIB_MKOSTEMPS = @GL_GNULIB_MKOSTEMPS@
+GL_GNULIB_MKSTEMP = @GL_GNULIB_MKSTEMP@
+GL_GNULIB_MKSTEMPS = @GL_GNULIB_MKSTEMPS@
+GL_GNULIB_MKTIME = @GL_GNULIB_MKTIME@
+GL_GNULIB_NANOSLEEP = @GL_GNULIB_NANOSLEEP@
+GL_GNULIB_NL_LANGINFO = @GL_GNULIB_NL_LANGINFO@
+GL_GNULIB_NONBLOCKING = @GL_GNULIB_NONBLOCKING@
+GL_GNULIB_OBSTACK_PRINTF = @GL_GNULIB_OBSTACK_PRINTF@
+GL_GNULIB_OBSTACK_PRINTF_POSIX = @GL_GNULIB_OBSTACK_PRINTF_POSIX@
+GL_GNULIB_OPEN = @GL_GNULIB_OPEN@
+GL_GNULIB_OPENAT = @GL_GNULIB_OPENAT@
+GL_GNULIB_OPENDIR = @GL_GNULIB_OPENDIR@
+GL_GNULIB_OVERRIDES_STRUCT_STAT = @GL_GNULIB_OVERRIDES_STRUCT_STAT@
+GL_GNULIB_PCLOSE = @GL_GNULIB_PCLOSE@
+GL_GNULIB_PERROR = @GL_GNULIB_PERROR@
+GL_GNULIB_PIPE = @GL_GNULIB_PIPE@
+GL_GNULIB_PIPE2 = @GL_GNULIB_PIPE2@
+GL_GNULIB_POPEN = @GL_GNULIB_POPEN@
+GL_GNULIB_POSIX_MEMALIGN = @GL_GNULIB_POSIX_MEMALIGN@
+GL_GNULIB_POSIX_OPENPT = @GL_GNULIB_POSIX_OPENPT@
+GL_GNULIB_POSIX_SPAWN = @GL_GNULIB_POSIX_SPAWN@
+GL_GNULIB_POSIX_SPAWNATTR_DESTROY = @GL_GNULIB_POSIX_SPAWNATTR_DESTROY@
+GL_GNULIB_POSIX_SPAWNATTR_GETFLAGS = @GL_GNULIB_POSIX_SPAWNATTR_GETFLAGS@
+GL_GNULIB_POSIX_SPAWNATTR_GETPGROUP = @GL_GNULIB_POSIX_SPAWNATTR_GETPGROUP@
+GL_GNULIB_POSIX_SPAWNATTR_GETSCHEDPARAM = @GL_GNULIB_POSIX_SPAWNATTR_GETSCHEDPARAM@
+GL_GNULIB_POSIX_SPAWNATTR_GETSCHEDPOLICY = @GL_GNULIB_POSIX_SPAWNATTR_GETSCHEDPOLICY@
+GL_GNULIB_POSIX_SPAWNATTR_GETSIGDEFAULT = @GL_GNULIB_POSIX_SPAWNATTR_GETSIGDEFAULT@
+GL_GNULIB_POSIX_SPAWNATTR_GETSIGMASK = @GL_GNULIB_POSIX_SPAWNATTR_GETSIGMASK@
+GL_GNULIB_POSIX_SPAWNATTR_INIT = @GL_GNULIB_POSIX_SPAWNATTR_INIT@
+GL_GNULIB_POSIX_SPAWNATTR_SETFLAGS = @GL_GNULIB_POSIX_SPAWNATTR_SETFLAGS@
+GL_GNULIB_POSIX_SPAWNATTR_SETPGROUP = @GL_GNULIB_POSIX_SPAWNATTR_SETPGROUP@
+GL_GNULIB_POSIX_SPAWNATTR_SETSCHEDPARAM = @GL_GNULIB_POSIX_SPAWNATTR_SETSCHEDPARAM@
+GL_GNULIB_POSIX_SPAWNATTR_SETSCHEDPOLICY = @GL_GNULIB_POSIX_SPAWNATTR_SETSCHEDPOLICY@
+GL_GNULIB_POSIX_SPAWNATTR_SETSIGDEFAULT = @GL_GNULIB_POSIX_SPAWNATTR_SETSIGDEFAULT@
+GL_GNULIB_POSIX_SPAWNATTR_SETSIGMASK = @GL_GNULIB_POSIX_SPAWNATTR_SETSIGMASK@
+GL_GNULIB_POSIX_SPAWNP = @GL_GNULIB_POSIX_SPAWNP@
+GL_GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR = @GL_GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR@
+GL_GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE = @GL_GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE@
+GL_GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2 = @GL_GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2@
+GL_GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR = @GL_GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR@
+GL_GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN = @GL_GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN@
+GL_GNULIB_POSIX_SPAWN_FILE_ACTIONS_DESTROY = @GL_GNULIB_POSIX_SPAWN_FILE_ACTIONS_DESTROY@
+GL_GNULIB_POSIX_SPAWN_FILE_ACTIONS_INIT = @GL_GNULIB_POSIX_SPAWN_FILE_ACTIONS_INIT@
+GL_GNULIB_PREAD = @GL_GNULIB_PREAD@
+GL_GNULIB_PRINTF = @GL_GNULIB_PRINTF@
+GL_GNULIB_PRINTF_POSIX = @GL_GNULIB_PRINTF_POSIX@
+GL_GNULIB_PSELECT = @GL_GNULIB_PSELECT@
+GL_GNULIB_PTHREAD_SIGMASK = @GL_GNULIB_PTHREAD_SIGMASK@
+GL_GNULIB_PTSNAME = @GL_GNULIB_PTSNAME@
+GL_GNULIB_PTSNAME_R = @GL_GNULIB_PTSNAME_R@
+GL_GNULIB_PUTC = @GL_GNULIB_PUTC@
+GL_GNULIB_PUTCHAR = @GL_GNULIB_PUTCHAR@
+GL_GNULIB_PUTENV = @GL_GNULIB_PUTENV@
+GL_GNULIB_PUTS = @GL_GNULIB_PUTS@
+GL_GNULIB_PWRITE = @GL_GNULIB_PWRITE@
+GL_GNULIB_QSORT_R = @GL_GNULIB_QSORT_R@
+GL_GNULIB_RAISE = @GL_GNULIB_RAISE@
+GL_GNULIB_RANDOM = @GL_GNULIB_RANDOM@
+GL_GNULIB_RANDOM_R = @GL_GNULIB_RANDOM_R@
+GL_GNULIB_RAWMEMCHR = @GL_GNULIB_RAWMEMCHR@
+GL_GNULIB_READ = @GL_GNULIB_READ@
+GL_GNULIB_READDIR = @GL_GNULIB_READDIR@
+GL_GNULIB_READLINK = @GL_GNULIB_READLINK@
+GL_GNULIB_READLINKAT = @GL_GNULIB_READLINKAT@
+GL_GNULIB_REALLOCARRAY = @GL_GNULIB_REALLOCARRAY@
+GL_GNULIB_REALLOC_GNU = @GL_GNULIB_REALLOC_GNU@
+GL_GNULIB_REALLOC_POSIX = @GL_GNULIB_REALLOC_POSIX@
+GL_GNULIB_REALPATH = @GL_GNULIB_REALPATH@
+GL_GNULIB_RECV = @GL_GNULIB_RECV@
+GL_GNULIB_RECVFROM = @GL_GNULIB_RECVFROM@
+GL_GNULIB_REMOVE = @GL_GNULIB_REMOVE@
+GL_GNULIB_RENAME = @GL_GNULIB_RENAME@
+GL_GNULIB_RENAMEAT = @GL_GNULIB_RENAMEAT@
+GL_GNULIB_REWINDDIR = @GL_GNULIB_REWINDDIR@
+GL_GNULIB_RMDIR = @GL_GNULIB_RMDIR@
+GL_GNULIB_RPMATCH = @GL_GNULIB_RPMATCH@
+GL_GNULIB_SCANDIR = @GL_GNULIB_SCANDIR@
+GL_GNULIB_SCANF = @GL_GNULIB_SCANF@
+GL_GNULIB_SCHED_YIELD = @GL_GNULIB_SCHED_YIELD@
+GL_GNULIB_SECURE_GETENV = @GL_GNULIB_SECURE_GETENV@
+GL_GNULIB_SELECT = @GL_GNULIB_SELECT@
+GL_GNULIB_SEND = @GL_GNULIB_SEND@
+GL_GNULIB_SENDTO = @GL_GNULIB_SENDTO@
+GL_GNULIB_SETENV = @GL_GNULIB_SETENV@
+GL_GNULIB_SETHOSTNAME = @GL_GNULIB_SETHOSTNAME@
+GL_GNULIB_SETLOCALE = @GL_GNULIB_SETLOCALE@
+GL_GNULIB_SETLOCALE_NULL = @GL_GNULIB_SETLOCALE_NULL@
+GL_GNULIB_SETSOCKOPT = @GL_GNULIB_SETSOCKOPT@
+GL_GNULIB_SHUTDOWN = @GL_GNULIB_SHUTDOWN@
+GL_GNULIB_SIGABBREV_NP = @GL_GNULIB_SIGABBREV_NP@
+GL_GNULIB_SIGACTION = @GL_GNULIB_SIGACTION@
+GL_GNULIB_SIGDESCR_NP = @GL_GNULIB_SIGDESCR_NP@
+GL_GNULIB_SIGNAL_H_SIGPIPE = @GL_GNULIB_SIGNAL_H_SIGPIPE@
+GL_GNULIB_SIGPROCMASK = @GL_GNULIB_SIGPROCMASK@
+GL_GNULIB_SLEEP = @GL_GNULIB_SLEEP@
+GL_GNULIB_SNPRINTF = @GL_GNULIB_SNPRINTF@
+GL_GNULIB_SOCKET = @GL_GNULIB_SOCKET@
+GL_GNULIB_SPRINTF_POSIX = @GL_GNULIB_SPRINTF_POSIX@
+GL_GNULIB_STAT = @GL_GNULIB_STAT@
+GL_GNULIB_STDIO_H_NONBLOCKING = @GL_GNULIB_STDIO_H_NONBLOCKING@
+GL_GNULIB_STDIO_H_SIGPIPE = @GL_GNULIB_STDIO_H_SIGPIPE@
+GL_GNULIB_STPCPY = @GL_GNULIB_STPCPY@
+GL_GNULIB_STPNCPY = @GL_GNULIB_STPNCPY@
+GL_GNULIB_STRCASESTR = @GL_GNULIB_STRCASESTR@
+GL_GNULIB_STRCHRNUL = @GL_GNULIB_STRCHRNUL@
+GL_GNULIB_STRDUP = @GL_GNULIB_STRDUP@
+GL_GNULIB_STRERROR = @GL_GNULIB_STRERROR@
+GL_GNULIB_STRERRORNAME_NP = @GL_GNULIB_STRERRORNAME_NP@
+GL_GNULIB_STRERROR_R = @GL_GNULIB_STRERROR_R@
+GL_GNULIB_STRFTIME = @GL_GNULIB_STRFTIME@
+GL_GNULIB_STRNCAT = @GL_GNULIB_STRNCAT@
+GL_GNULIB_STRNDUP = @GL_GNULIB_STRNDUP@
+GL_GNULIB_STRNLEN = @GL_GNULIB_STRNLEN@
+GL_GNULIB_STRPBRK = @GL_GNULIB_STRPBRK@
+GL_GNULIB_STRPTIME = @GL_GNULIB_STRPTIME@
+GL_GNULIB_STRSEP = @GL_GNULIB_STRSEP@
+GL_GNULIB_STRSIGNAL = @GL_GNULIB_STRSIGNAL@
+GL_GNULIB_STRSTR = @GL_GNULIB_STRSTR@
+GL_GNULIB_STRTOD = @GL_GNULIB_STRTOD@
+GL_GNULIB_STRTOIMAX = @GL_GNULIB_STRTOIMAX@
+GL_GNULIB_STRTOK_R = @GL_GNULIB_STRTOK_R@
+GL_GNULIB_STRTOL = @GL_GNULIB_STRTOL@
+GL_GNULIB_STRTOLD = @GL_GNULIB_STRTOLD@
+GL_GNULIB_STRTOLL = @GL_GNULIB_STRTOLL@
+GL_GNULIB_STRTOUL = @GL_GNULIB_STRTOUL@
+GL_GNULIB_STRTOULL = @GL_GNULIB_STRTOULL@
+GL_GNULIB_STRTOUMAX = @GL_GNULIB_STRTOUMAX@
+GL_GNULIB_STRVERSCMP = @GL_GNULIB_STRVERSCMP@
+GL_GNULIB_SYMLINK = @GL_GNULIB_SYMLINK@
+GL_GNULIB_SYMLINKAT = @GL_GNULIB_SYMLINKAT@
+GL_GNULIB_SYSTEM_POSIX = @GL_GNULIB_SYSTEM_POSIX@
+GL_GNULIB_TIMEGM = @GL_GNULIB_TIMEGM@
+GL_GNULIB_TIMESPEC_GET = @GL_GNULIB_TIMESPEC_GET@
+GL_GNULIB_TIMESPEC_GETRES = @GL_GNULIB_TIMESPEC_GETRES@
+GL_GNULIB_TIME_R = @GL_GNULIB_TIME_R@
+GL_GNULIB_TIME_RZ = @GL_GNULIB_TIME_RZ@
+GL_GNULIB_TMPFILE = @GL_GNULIB_TMPFILE@
+GL_GNULIB_TOWCTRANS = @GL_GNULIB_TOWCTRANS@
+GL_GNULIB_TRUNCATE = @GL_GNULIB_TRUNCATE@
+GL_GNULIB_TTYNAME_R = @GL_GNULIB_TTYNAME_R@
+GL_GNULIB_TZSET = @GL_GNULIB_TZSET@
+GL_GNULIB_UNISTD_H_GETOPT = @GL_GNULIB_UNISTD_H_GETOPT@
+GL_GNULIB_UNISTD_H_NONBLOCKING = @GL_GNULIB_UNISTD_H_NONBLOCKING@
+GL_GNULIB_UNISTD_H_SIGPIPE = @GL_GNULIB_UNISTD_H_SIGPIPE@
+GL_GNULIB_UNLINK = @GL_GNULIB_UNLINK@
+GL_GNULIB_UNLINKAT = @GL_GNULIB_UNLINKAT@
+GL_GNULIB_UNLOCKPT = @GL_GNULIB_UNLOCKPT@
+GL_GNULIB_UNSETENV = @GL_GNULIB_UNSETENV@
+GL_GNULIB_USLEEP = @GL_GNULIB_USLEEP@
+GL_GNULIB_UTIME = @GL_GNULIB_UTIME@
+GL_GNULIB_UTIMENSAT = @GL_GNULIB_UTIMENSAT@
+GL_GNULIB_VASPRINTF = @GL_GNULIB_VASPRINTF@
+GL_GNULIB_VDPRINTF = @GL_GNULIB_VDPRINTF@
+GL_GNULIB_VFPRINTF = @GL_GNULIB_VFPRINTF@
+GL_GNULIB_VFPRINTF_POSIX = @GL_GNULIB_VFPRINTF_POSIX@
+GL_GNULIB_VFSCANF = @GL_GNULIB_VFSCANF@
+GL_GNULIB_VPRINTF = @GL_GNULIB_VPRINTF@
+GL_GNULIB_VPRINTF_POSIX = @GL_GNULIB_VPRINTF_POSIX@
+GL_GNULIB_VSCANF = @GL_GNULIB_VSCANF@
+GL_GNULIB_VSNPRINTF = @GL_GNULIB_VSNPRINTF@
+GL_GNULIB_VSPRINTF_POSIX = @GL_GNULIB_VSPRINTF_POSIX@
+GL_GNULIB_WAITPID = @GL_GNULIB_WAITPID@
+GL_GNULIB_WCPCPY = @GL_GNULIB_WCPCPY@
+GL_GNULIB_WCPNCPY = @GL_GNULIB_WCPNCPY@
+GL_GNULIB_WCRTOMB = @GL_GNULIB_WCRTOMB@
+GL_GNULIB_WCSCASECMP = @GL_GNULIB_WCSCASECMP@
+GL_GNULIB_WCSCAT = @GL_GNULIB_WCSCAT@
+GL_GNULIB_WCSCHR = @GL_GNULIB_WCSCHR@
+GL_GNULIB_WCSCMP = @GL_GNULIB_WCSCMP@
+GL_GNULIB_WCSCOLL = @GL_GNULIB_WCSCOLL@
+GL_GNULIB_WCSCPY = @GL_GNULIB_WCSCPY@
+GL_GNULIB_WCSCSPN = @GL_GNULIB_WCSCSPN@
+GL_GNULIB_WCSDUP = @GL_GNULIB_WCSDUP@
+GL_GNULIB_WCSFTIME = @GL_GNULIB_WCSFTIME@
+GL_GNULIB_WCSLEN = @GL_GNULIB_WCSLEN@
+GL_GNULIB_WCSNCASECMP = @GL_GNULIB_WCSNCASECMP@
+GL_GNULIB_WCSNCAT = @GL_GNULIB_WCSNCAT@
+GL_GNULIB_WCSNCMP = @GL_GNULIB_WCSNCMP@
+GL_GNULIB_WCSNCPY = @GL_GNULIB_WCSNCPY@
+GL_GNULIB_WCSNLEN = @GL_GNULIB_WCSNLEN@
+GL_GNULIB_WCSNRTOMBS = @GL_GNULIB_WCSNRTOMBS@
+GL_GNULIB_WCSPBRK = @GL_GNULIB_WCSPBRK@
+GL_GNULIB_WCSRCHR = @GL_GNULIB_WCSRCHR@
+GL_GNULIB_WCSRTOMBS = @GL_GNULIB_WCSRTOMBS@
+GL_GNULIB_WCSSPN = @GL_GNULIB_WCSSPN@
+GL_GNULIB_WCSSTR = @GL_GNULIB_WCSSTR@
+GL_GNULIB_WCSTOK = @GL_GNULIB_WCSTOK@
+GL_GNULIB_WCSWIDTH = @GL_GNULIB_WCSWIDTH@
+GL_GNULIB_WCSXFRM = @GL_GNULIB_WCSXFRM@
+GL_GNULIB_WCTOB = @GL_GNULIB_WCTOB@
+GL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@
+GL_GNULIB_WCTRANS = @GL_GNULIB_WCTRANS@
+GL_GNULIB_WCTYPE = @GL_GNULIB_WCTYPE@
+GL_GNULIB_WCWIDTH = @GL_GNULIB_WCWIDTH@
+GL_GNULIB_WMEMCHR = @GL_GNULIB_WMEMCHR@
+GL_GNULIB_WMEMCMP = @GL_GNULIB_WMEMCMP@
+GL_GNULIB_WMEMCPY = @GL_GNULIB_WMEMCPY@
+GL_GNULIB_WMEMMOVE = @GL_GNULIB_WMEMMOVE@
+GL_GNULIB_WMEMPCPY = @GL_GNULIB_WMEMPCPY@
+GL_GNULIB_WMEMSET = @GL_GNULIB_WMEMSET@
+GL_GNULIB_WRITE = @GL_GNULIB_WRITE@
+GL_GNULIB__EXIT = @GL_GNULIB__EXIT@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNULIBHEADERS_OVERRIDE_WINT_T = @GNULIBHEADERS_OVERRIDE_WINT_T@
+GNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@
+GNULIB_WARN_CFLAGS = @GNULIB_WARN_CFLAGS@
+GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
+GNUTLS_LIBS = @GNUTLS_LIBS@
+GPGME_CFLAGS = @GPGME_CFLAGS@
+GPGME_CONFIG = @GPGME_CONFIG@
+GPGME_LIBS = @GPGME_LIBS@
+GREP = @GREP@
+HAVE_ACCEPT4 = @HAVE_ACCEPT4@
+HAVE_ALIGNED_ALLOC = @HAVE_ALIGNED_ALLOC@
+HAVE_ALLOCA_H = @HAVE_ALLOCA_H@
+HAVE_ALPHASORT = @HAVE_ALPHASORT@
+HAVE_ARPA_INET_H = @HAVE_ARPA_INET_H@
+HAVE_ATOLL = @HAVE_ATOLL@
+HAVE_BTOWC = @HAVE_BTOWC@
+HAVE_C99_STDINT_H = @HAVE_C99_STDINT_H@
+HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@
+HAVE_CHOWN = @HAVE_CHOWN@
+HAVE_CLOSEDIR = @HAVE_CLOSEDIR@
+HAVE_COPY_FILE_RANGE = @HAVE_COPY_FILE_RANGE@
+HAVE_CRTDEFS_H = @HAVE_CRTDEFS_H@
+HAVE_DECL_DIRFD = @HAVE_DECL_DIRFD@
+HAVE_DECL_ECVT = @HAVE_DECL_ECVT@
+HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@
+HAVE_DECL_EXECVPE = @HAVE_DECL_EXECVPE@
+HAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@
+HAVE_DECL_FCLOSEALL = @HAVE_DECL_FCLOSEALL@
+HAVE_DECL_FCVT = @HAVE_DECL_FCVT@
+HAVE_DECL_FDATASYNC = @HAVE_DECL_FDATASYNC@
+HAVE_DECL_FDOPENDIR = @HAVE_DECL_FDOPENDIR@
+HAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@
+HAVE_DECL_FREEADDRINFO = @HAVE_DECL_FREEADDRINFO@
+HAVE_DECL_FSEEKO = @HAVE_DECL_FSEEKO@
+HAVE_DECL_FTELLO = @HAVE_DECL_FTELLO@
+HAVE_DECL_GAI_STRERROR = @HAVE_DECL_GAI_STRERROR@
+HAVE_DECL_GCVT = @HAVE_DECL_GCVT@
+HAVE_DECL_GETADDRINFO = @HAVE_DECL_GETADDRINFO@
+HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@
+HAVE_DECL_GETDOMAINNAME = @HAVE_DECL_GETDOMAINNAME@
+HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@
+HAVE_DECL_GETLOADAVG = @HAVE_DECL_GETLOADAVG@
+HAVE_DECL_GETLOGIN = @HAVE_DECL_GETLOGIN@
+HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@
+HAVE_DECL_GETNAMEINFO = @HAVE_DECL_GETNAMEINFO@
+HAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@
+HAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@
+HAVE_DECL_IMAXABS = @HAVE_DECL_IMAXABS@
+HAVE_DECL_IMAXDIV = @HAVE_DECL_IMAXDIV@
+HAVE_DECL_INET_NTOP = @HAVE_DECL_INET_NTOP@
+HAVE_DECL_INET_PTON = @HAVE_DECL_INET_PTON@
+HAVE_DECL_INITSTATE = @HAVE_DECL_INITSTATE@
+HAVE_DECL_LOCALTIME_R = @HAVE_DECL_LOCALTIME_R@
+HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@
+HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@
+HAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@
+HAVE_DECL_SETENV = @HAVE_DECL_SETENV@
+HAVE_DECL_SETHOSTNAME = @HAVE_DECL_SETHOSTNAME@
+HAVE_DECL_SETSTATE = @HAVE_DECL_SETSTATE@
+HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@
+HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@
+HAVE_DECL_STRERROR_R = @HAVE_DECL_STRERROR_R@
+HAVE_DECL_STRNCASECMP = @HAVE_DECL_STRNCASECMP@
+HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@
+HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@
+HAVE_DECL_STRSIGNAL = @HAVE_DECL_STRSIGNAL@
+HAVE_DECL_STRTOIMAX = @HAVE_DECL_STRTOIMAX@
+HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@
+HAVE_DECL_STRTOUMAX = @HAVE_DECL_STRTOUMAX@
+HAVE_DECL_TRUNCATE = @HAVE_DECL_TRUNCATE@
+HAVE_DECL_TTYNAME_R = @HAVE_DECL_TTYNAME_R@
+HAVE_DECL_UNSETENV = @HAVE_DECL_UNSETENV@
+HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@
+HAVE_DECL_WCSDUP = @HAVE_DECL_WCSDUP@
+HAVE_DECL_WCTOB = @HAVE_DECL_WCTOB@
+HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@
+HAVE_DIRENT_H = @HAVE_DIRENT_H@
+HAVE_DPRINTF = @HAVE_DPRINTF@
+HAVE_DUP3 = @HAVE_DUP3@
+HAVE_DUPLOCALE = @HAVE_DUPLOCALE@
+HAVE_EUIDACCESS = @HAVE_EUIDACCESS@
+HAVE_EXECVPE = @HAVE_EXECVPE@
+HAVE_EXPLICIT_BZERO = @HAVE_EXPLICIT_BZERO@
+HAVE_FACCESSAT = @HAVE_FACCESSAT@
+HAVE_FCHDIR = @HAVE_FCHDIR@
+HAVE_FCHMODAT = @HAVE_FCHMODAT@
+HAVE_FCHOWNAT = @HAVE_FCHOWNAT@
+HAVE_FCNTL = @HAVE_FCNTL@
+HAVE_FDATASYNC = @HAVE_FDATASYNC@
+HAVE_FDOPENDIR = @HAVE_FDOPENDIR@
+HAVE_FEATURES_H = @HAVE_FEATURES_H@
+HAVE_FFS = @HAVE_FFS@
+HAVE_FFSL = @HAVE_FFSL@
+HAVE_FFSLL = @HAVE_FFSLL@
+HAVE_FLOCK = @HAVE_FLOCK@
+HAVE_FNMATCH = @HAVE_FNMATCH@
+HAVE_FNMATCH_H = @HAVE_FNMATCH_H@
+HAVE_FREELOCALE = @HAVE_FREELOCALE@
+HAVE_FSEEKO = @HAVE_FSEEKO@
+HAVE_FSTATAT = @HAVE_FSTATAT@
+HAVE_FSYNC = @HAVE_FSYNC@
+HAVE_FTELLO = @HAVE_FTELLO@
+HAVE_FTRUNCATE = @HAVE_FTRUNCATE@
+HAVE_FUTIMENS = @HAVE_FUTIMENS@
+HAVE_GETDTABLESIZE = @HAVE_GETDTABLESIZE@
+HAVE_GETENTROPY = @HAVE_GETENTROPY@
+HAVE_GETGROUPS = @HAVE_GETGROUPS@
+HAVE_GETHOSTNAME = @HAVE_GETHOSTNAME@
+HAVE_GETLOGIN = @HAVE_GETLOGIN@
+HAVE_GETOPT_H = @HAVE_GETOPT_H@
+HAVE_GETPAGESIZE = @HAVE_GETPAGESIZE@
+HAVE_GETPASS = @HAVE_GETPASS@
+HAVE_GETRANDOM = @HAVE_GETRANDOM@
+HAVE_GETSUBOPT = @HAVE_GETSUBOPT@
+HAVE_GETTIMEOFDAY = @HAVE_GETTIMEOFDAY@
+HAVE_GETUMASK = @HAVE_GETUMASK@
+HAVE_GRANTPT = @HAVE_GRANTPT@
+HAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@
+HAVE_IMAXDIV_T = @HAVE_IMAXDIV_T@
+HAVE_INITSTATE = @HAVE_INITSTATE@
+HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
+HAVE_ISBLANK = @HAVE_ISBLANK@
+HAVE_ISWBLANK = @HAVE_ISWBLANK@
+HAVE_ISWCNTRL = @HAVE_ISWCNTRL@
+HAVE_LANGINFO_ALTMON = @HAVE_LANGINFO_ALTMON@
+HAVE_LANGINFO_CODESET = @HAVE_LANGINFO_CODESET@
+HAVE_LANGINFO_ERA = @HAVE_LANGINFO_ERA@
+HAVE_LANGINFO_H = @HAVE_LANGINFO_H@
+HAVE_LANGINFO_T_FMT_AMPM = @HAVE_LANGINFO_T_FMT_AMPM@
+HAVE_LANGINFO_YESEXPR = @HAVE_LANGINFO_YESEXPR@
+HAVE_LCHMOD = @HAVE_LCHMOD@
+HAVE_LCHOWN = @HAVE_LCHOWN@
+HAVE_LIBGNUTLS = @HAVE_LIBGNUTLS@
+HAVE_LIBSSL = @HAVE_LIBSSL@
+HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@
+HAVE_LINK = @HAVE_LINK@
+HAVE_LINKAT = @HAVE_LINKAT@
+HAVE_LSTAT = @HAVE_LSTAT@
+HAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@
+HAVE_MBRLEN = @HAVE_MBRLEN@
+HAVE_MBRTOWC = @HAVE_MBRTOWC@
+HAVE_MBSINIT = @HAVE_MBSINIT@
+HAVE_MBSLEN = @HAVE_MBSLEN@
+HAVE_MBSNRTOWCS = @HAVE_MBSNRTOWCS@
+HAVE_MBSRTOWCS = @HAVE_MBSRTOWCS@
+HAVE_MBTOWC = @HAVE_MBTOWC@
+HAVE_MEMPCPY = @HAVE_MEMPCPY@
+HAVE_MKDIRAT = @HAVE_MKDIRAT@
+HAVE_MKDTEMP = @HAVE_MKDTEMP@
+HAVE_MKFIFO = @HAVE_MKFIFO@
+HAVE_MKFIFOAT = @HAVE_MKFIFOAT@
+HAVE_MKNOD = @HAVE_MKNOD@
+HAVE_MKNODAT = @HAVE_MKNODAT@
+HAVE_MKOSTEMP = @HAVE_MKOSTEMP@
+HAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@
+HAVE_MKSTEMP = @HAVE_MKSTEMP@
+HAVE_MKSTEMPS = @HAVE_MKSTEMPS@
+HAVE_MSVC_INVALID_PARAMETER_HANDLER = @HAVE_MSVC_INVALID_PARAMETER_HANDLER@
+HAVE_NANOSLEEP = @HAVE_NANOSLEEP@
+HAVE_NETDB_H = @HAVE_NETDB_H@
+HAVE_NETINET_IN_H = @HAVE_NETINET_IN_H@
+HAVE_NEWLOCALE = @HAVE_NEWLOCALE@
+HAVE_NL_LANGINFO = @HAVE_NL_LANGINFO@
+HAVE_OPENAT = @HAVE_OPENAT@
+HAVE_OPENDIR = @HAVE_OPENDIR@
+HAVE_OS_H = @HAVE_OS_H@
+HAVE_PCLOSE = @HAVE_PCLOSE@
+HAVE_PIPE = @HAVE_PIPE@
+HAVE_PIPE2 = @HAVE_PIPE2@
+HAVE_POPEN = @HAVE_POPEN@
+HAVE_POSIX_MEMALIGN = @HAVE_POSIX_MEMALIGN@
+HAVE_POSIX_OPENPT = @HAVE_POSIX_OPENPT@
+HAVE_POSIX_SIGNALBLOCKING = @HAVE_POSIX_SIGNALBLOCKING@
+HAVE_POSIX_SPAWN = @HAVE_POSIX_SPAWN@
+HAVE_POSIX_SPAWNATTR_T = @HAVE_POSIX_SPAWNATTR_T@
+HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR = @HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR@
+HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR = @HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR@
+HAVE_POSIX_SPAWN_FILE_ACTIONS_T = @HAVE_POSIX_SPAWN_FILE_ACTIONS_T@
+HAVE_PREAD = @HAVE_PREAD@
+HAVE_PSELECT = @HAVE_PSELECT@
+HAVE_PTHREAD_SIGMASK = @HAVE_PTHREAD_SIGMASK@
+HAVE_PTSNAME = @HAVE_PTSNAME@
+HAVE_PTSNAME_R = @HAVE_PTSNAME_R@
+HAVE_PWRITE = @HAVE_PWRITE@
+HAVE_QSORT_R = @HAVE_QSORT_R@
+HAVE_RAISE = @HAVE_RAISE@
+HAVE_RANDOM = @HAVE_RANDOM@
+HAVE_RANDOM_H = @HAVE_RANDOM_H@
+HAVE_RANDOM_R = @HAVE_RANDOM_R@
+HAVE_RAWMEMCHR = @HAVE_RAWMEMCHR@
+HAVE_READDIR = @HAVE_READDIR@
+HAVE_READLINK = @HAVE_READLINK@
+HAVE_READLINKAT = @HAVE_READLINKAT@
+HAVE_REALLOCARRAY = @HAVE_REALLOCARRAY@
+HAVE_REALPATH = @HAVE_REALPATH@
+HAVE_RENAMEAT = @HAVE_RENAMEAT@
+HAVE_REWINDDIR = @HAVE_REWINDDIR@
+HAVE_RPMATCH = @HAVE_RPMATCH@
+HAVE_SA_FAMILY_T = @HAVE_SA_FAMILY_T@
+HAVE_SCANDIR = @HAVE_SCANDIR@
+HAVE_SCHED_H = @HAVE_SCHED_H@
+HAVE_SCHED_YIELD = @HAVE_SCHED_YIELD@
+HAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@
+HAVE_SETENV = @HAVE_SETENV@
+HAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@
+HAVE_SETSTATE = @HAVE_SETSTATE@
+HAVE_SIGABBREV_NP = @HAVE_SIGABBREV_NP@
+HAVE_SIGACTION = @HAVE_SIGACTION@
+HAVE_SIGDESCR_NP = @HAVE_SIGDESCR_NP@
+HAVE_SIGHANDLER_T = @HAVE_SIGHANDLER_T@
+HAVE_SIGINFO_T = @HAVE_SIGINFO_T@
+HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@
+HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@
+HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@
+HAVE_SIGSET_T = @HAVE_SIGSET_T@
+HAVE_SLEEP = @HAVE_SLEEP@
+HAVE_SPAWN_H = @HAVE_SPAWN_H@
+HAVE_STDINT_H = @HAVE_STDINT_H@
+HAVE_STPCPY = @HAVE_STPCPY@
+HAVE_STPNCPY = @HAVE_STPNCPY@
+HAVE_STRCASECMP = @HAVE_STRCASECMP@
+HAVE_STRCASESTR = @HAVE_STRCASESTR@
+HAVE_STRCHRNUL = @HAVE_STRCHRNUL@
+HAVE_STRERRORNAME_NP = @HAVE_STRERRORNAME_NP@
+HAVE_STRINGS_H = @HAVE_STRINGS_H@
+HAVE_STRPBRK = @HAVE_STRPBRK@
+HAVE_STRPTIME = @HAVE_STRPTIME@
+HAVE_STRSEP = @HAVE_STRSEP@
+HAVE_STRTOD = @HAVE_STRTOD@
+HAVE_STRTOL = @HAVE_STRTOL@
+HAVE_STRTOLD = @HAVE_STRTOLD@
+HAVE_STRTOLL = @HAVE_STRTOLL@
+HAVE_STRTOUL = @HAVE_STRTOUL@
+HAVE_STRTOULL = @HAVE_STRTOULL@
+HAVE_STRUCT_ADDRINFO = @HAVE_STRUCT_ADDRINFO@
+HAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@
+HAVE_STRUCT_SCHED_PARAM = @HAVE_STRUCT_SCHED_PARAM@
+HAVE_STRUCT_SIGACTION_SA_SIGACTION = @HAVE_STRUCT_SIGACTION_SA_SIGACTION@
+HAVE_STRUCT_SOCKADDR_STORAGE = @HAVE_STRUCT_SOCKADDR_STORAGE@
+HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY = @HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY@
+HAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@
+HAVE_STRVERSCMP = @HAVE_STRVERSCMP@
+HAVE_SYMLINK = @HAVE_SYMLINK@
+HAVE_SYMLINKAT = @HAVE_SYMLINKAT@
+HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@
+HAVE_SYS_CDEFS_H = @HAVE_SYS_CDEFS_H@
+HAVE_SYS_FILE_H = @HAVE_SYS_FILE_H@
+HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@
+HAVE_SYS_IOCTL_H = @HAVE_SYS_IOCTL_H@
+HAVE_SYS_LOADAVG_H = @HAVE_SYS_LOADAVG_H@
+HAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@
+HAVE_SYS_RANDOM_H = @HAVE_SYS_RANDOM_H@
+HAVE_SYS_SELECT_H = @HAVE_SYS_SELECT_H@
+HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@
+HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@
+HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@
+HAVE_SYS_UIO_H = @HAVE_SYS_UIO_H@
+HAVE_TIMEGM = @HAVE_TIMEGM@
+HAVE_TIMESPEC_GET = @HAVE_TIMESPEC_GET@
+HAVE_TIMESPEC_GETRES = @HAVE_TIMESPEC_GETRES@
+HAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@
+HAVE_TYPE_VOLATILE_SIG_ATOMIC_T = @HAVE_TYPE_VOLATILE_SIG_ATOMIC_T@
+HAVE_UNISTD_H = @HAVE_UNISTD_H@
+HAVE_UNLINKAT = @HAVE_UNLINKAT@
+HAVE_UNLOCKPT = @HAVE_UNLOCKPT@
+HAVE_USLEEP = @HAVE_USLEEP@
+HAVE_UTIME = @HAVE_UTIME@
+HAVE_UTIMENSAT = @HAVE_UTIMENSAT@
+HAVE_UTIME_H = @HAVE_UTIME_H@
+HAVE_VALGRIND = @HAVE_VALGRIND@
+HAVE_VASPRINTF = @HAVE_VASPRINTF@
+HAVE_VDPRINTF = @HAVE_VDPRINTF@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+HAVE_WCHAR_H = @HAVE_WCHAR_H@
+HAVE_WCHAR_T = @HAVE_WCHAR_T@
+HAVE_WCPCPY = @HAVE_WCPCPY@
+HAVE_WCPNCPY = @HAVE_WCPNCPY@
+HAVE_WCRTOMB = @HAVE_WCRTOMB@
+HAVE_WCSCASECMP = @HAVE_WCSCASECMP@
+HAVE_WCSCAT = @HAVE_WCSCAT@
+HAVE_WCSCHR = @HAVE_WCSCHR@
+HAVE_WCSCMP = @HAVE_WCSCMP@
+HAVE_WCSCOLL = @HAVE_WCSCOLL@
+HAVE_WCSCPY = @HAVE_WCSCPY@
+HAVE_WCSCSPN = @HAVE_WCSCSPN@
+HAVE_WCSDUP = @HAVE_WCSDUP@
+HAVE_WCSFTIME = @HAVE_WCSFTIME@
+HAVE_WCSLEN = @HAVE_WCSLEN@
+HAVE_WCSNCASECMP = @HAVE_WCSNCASECMP@
+HAVE_WCSNCAT = @HAVE_WCSNCAT@
+HAVE_WCSNCMP = @HAVE_WCSNCMP@
+HAVE_WCSNCPY = @HAVE_WCSNCPY@
+HAVE_WCSNLEN = @HAVE_WCSNLEN@
+HAVE_WCSNRTOMBS = @HAVE_WCSNRTOMBS@
+HAVE_WCSPBRK = @HAVE_WCSPBRK@
+HAVE_WCSRCHR = @HAVE_WCSRCHR@
+HAVE_WCSRTOMBS = @HAVE_WCSRTOMBS@
+HAVE_WCSSPN = @HAVE_WCSSPN@
+HAVE_WCSSTR = @HAVE_WCSSTR@
+HAVE_WCSTOK = @HAVE_WCSTOK@
+HAVE_WCSWIDTH = @HAVE_WCSWIDTH@
+HAVE_WCSXFRM = @HAVE_WCSXFRM@
+HAVE_WCTRANS_T = @HAVE_WCTRANS_T@
+HAVE_WCTYPE_H = @HAVE_WCTYPE_H@
+HAVE_WCTYPE_T = @HAVE_WCTYPE_T@
+HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@
+HAVE_WINT_T = @HAVE_WINT_T@
+HAVE_WMEMCHR = @HAVE_WMEMCHR@
+HAVE_WMEMCMP = @HAVE_WMEMCMP@
+HAVE_WMEMCPY = @HAVE_WMEMCPY@
+HAVE_WMEMMOVE = @HAVE_WMEMMOVE@
+HAVE_WMEMPCPY = @HAVE_WMEMPCPY@
+HAVE_WMEMSET = @HAVE_WMEMSET@
+HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@
+HAVE_XLOCALE_H = @HAVE_XLOCALE_H@
+HAVE__BOOL = @HAVE__BOOL@
+HAVE__EXIT = @HAVE__EXIT@
+HOSTENT_LIB = @HOSTENT_LIB@
+ICONV_CONST = @ICONV_CONST@
+ICONV_H = @ICONV_H@
+INCLUDE_NEXT = @INCLUDE_NEXT@
+INCLUDE_NEXT_AS_FIRST_DIRECTIVE = @INCLUDE_NEXT_AS_FIRST_DIRECTIVE@
+INET_NTOP_LIB = @INET_NTOP_LIB@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INT32_MAX_LT_INTMAX_MAX = @INT32_MAX_LT_INTMAX_MAX@
+INT64_MAX_EQ_LONG_MAX = @INT64_MAX_EQ_LONG_MAX@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LCOV = @LCOV@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBGNUTLS = @LIBGNUTLS@
+LIBGNUTLS_PREFIX = @LIBGNUTLS_PREFIX@
+LIBGNU_LIBDEPS = @LIBGNU_LIBDEPS@
+LIBGNU_LTLIBDEPS = @LIBGNU_LTLIBDEPS@
+LIBICONV = @LIBICONV@
+LIBIDN2_CFLAGS = @LIBIDN2_CFLAGS@
+LIBIDN2_LIBS = @LIBIDN2_LIBS@
+LIBINTL = @LIBINTL@
+LIBMULTITHREAD = @LIBMULTITHREAD@
+LIBOBJS = @LIBOBJS@
+LIBPMULTITHREAD = @LIBPMULTITHREAD@
+LIBPSL_CFLAGS = @LIBPSL_CFLAGS@
+LIBPSL_LIBS = @LIBPSL_LIBS@
+LIBPTHREAD = @LIBPTHREAD@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBSSL_PREFIX = @LIBSSL_PREFIX@
+LIBSTDTHREAD = @LIBSTDTHREAD@
+LIBTHREAD = @LIBTHREAD@
+LIBUNISTRING = @LIBUNISTRING@
+LIBUNISTRING_PREFIX = @LIBUNISTRING_PREFIX@
+LIBUNISTRING_UNICASE_H = @LIBUNISTRING_UNICASE_H@
+LIBUNISTRING_UNICTYPE_H = @LIBUNISTRING_UNICTYPE_H@
+LIBUNISTRING_UNINORM_H = @LIBUNISTRING_UNINORM_H@
+LIBUNISTRING_UNISTR_H = @LIBUNISTRING_UNISTR_H@
+LIBUNISTRING_UNITYPES_H = @LIBUNISTRING_UNITYPES_H@
+LIBUNISTRING_UNIWIDTH_H = @LIBUNISTRING_UNIWIDTH_H@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_CRYPTO = @LIB_CRYPTO@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIB_GETRANDOM = @LIB_GETRANDOM@
+LIB_HARD_LOCALE = @LIB_HARD_LOCALE@
+LIB_MBRTOWC = @LIB_MBRTOWC@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LIB_NL_LANGINFO = @LIB_NL_LANGINFO@
+LIB_POSIX_SPAWN = @LIB_POSIX_SPAWN@
+LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@
+LIB_SCHED_YIELD = @LIB_SCHED_YIELD@
+LIB_SELECT = @LIB_SELECT@
+LIB_SETLOCALE_NULL = @LIB_SETLOCALE_NULL@
+LIMITS_H = @LIMITS_H@
+LOCALCHARSET_TESTS_ENVIRONMENT = @LOCALCHARSET_TESTS_ENVIRONMENT@
+LOCALENAME_ENHANCE_LOCALE_FUNCS = @LOCALENAME_ENHANCE_LOCALE_FUNCS@
+LOCALE_FR = @LOCALE_FR@
+LOCALE_FR_UTF8 = @LOCALE_FR_UTF8@
+LOCALE_JA = @LOCALE_JA@
+LOCALE_ZH_CN = @LOCALE_ZH_CN@
+LTLIBGNUTLS = @LTLIBGNUTLS@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBSSL = @LTLIBSSL@
+LTLIBTHREAD = @LTLIBTHREAD@
+LTLIBUNISTRING = @LTLIBUNISTRING@
+MAKEINFO = @MAKEINFO@
+METALINK_CFLAGS = @METALINK_CFLAGS@
+METALINK_LIBS = @METALINK_LIBS@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
+NETINET_IN_H = @NETINET_IN_H@
+NETTLE_CFLAGS = @NETTLE_CFLAGS@
+NETTLE_LIBS = @NETTLE_LIBS@
+NEXT_ARPA_INET_H = @NEXT_ARPA_INET_H@
+NEXT_AS_FIRST_DIRECTIVE_ARPA_INET_H = @NEXT_AS_FIRST_DIRECTIVE_ARPA_INET_H@
+NEXT_AS_FIRST_DIRECTIVE_CTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_CTYPE_H@
+NEXT_AS_FIRST_DIRECTIVE_DIRENT_H = @NEXT_AS_FIRST_DIRECTIVE_DIRENT_H@
+NEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@
+NEXT_AS_FIRST_DIRECTIVE_FCNTL_H = @NEXT_AS_FIRST_DIRECTIVE_FCNTL_H@
+NEXT_AS_FIRST_DIRECTIVE_FLOAT_H = @NEXT_AS_FIRST_DIRECTIVE_FLOAT_H@
+NEXT_AS_FIRST_DIRECTIVE_FNMATCH_H = @NEXT_AS_FIRST_DIRECTIVE_FNMATCH_H@
+NEXT_AS_FIRST_DIRECTIVE_GETOPT_H = @NEXT_AS_FIRST_DIRECTIVE_GETOPT_H@
+NEXT_AS_FIRST_DIRECTIVE_ICONV_H = @NEXT_AS_FIRST_DIRECTIVE_ICONV_H@
+NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H = @NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H@
+NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H = @NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H@
+NEXT_AS_FIRST_DIRECTIVE_LIMITS_H = @NEXT_AS_FIRST_DIRECTIVE_LIMITS_H@
+NEXT_AS_FIRST_DIRECTIVE_LOCALE_H = @NEXT_AS_FIRST_DIRECTIVE_LOCALE_H@
+NEXT_AS_FIRST_DIRECTIVE_NETDB_H = @NEXT_AS_FIRST_DIRECTIVE_NETDB_H@
+NEXT_AS_FIRST_DIRECTIVE_NETINET_IN_H = @NEXT_AS_FIRST_DIRECTIVE_NETINET_IN_H@
+NEXT_AS_FIRST_DIRECTIVE_SCHED_H = @NEXT_AS_FIRST_DIRECTIVE_SCHED_H@
+NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H = @NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H@
+NEXT_AS_FIRST_DIRECTIVE_SPAWN_H = @NEXT_AS_FIRST_DIRECTIVE_SPAWN_H@
+NEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@
+NEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@
+NEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@
+NEXT_AS_FIRST_DIRECTIVE_STDLIB_H = @NEXT_AS_FIRST_DIRECTIVE_STDLIB_H@
+NEXT_AS_FIRST_DIRECTIVE_STRINGS_H = @NEXT_AS_FIRST_DIRECTIVE_STRINGS_H@
+NEXT_AS_FIRST_DIRECTIVE_STRING_H = @NEXT_AS_FIRST_DIRECTIVE_STRING_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_FILE_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_FILE_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_IOCTL_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_IOCTL_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_RANDOM_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_RANDOM_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_SELECT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SELECT_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_WAIT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_WAIT_H@
+NEXT_AS_FIRST_DIRECTIVE_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_TIME_H@
+NEXT_AS_FIRST_DIRECTIVE_UNISTD_H = @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@
+NEXT_AS_FIRST_DIRECTIVE_UTIME_H = @NEXT_AS_FIRST_DIRECTIVE_UTIME_H@
+NEXT_AS_FIRST_DIRECTIVE_WCHAR_H = @NEXT_AS_FIRST_DIRECTIVE_WCHAR_H@
+NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H@
+NEXT_CTYPE_H = @NEXT_CTYPE_H@
+NEXT_DIRENT_H = @NEXT_DIRENT_H@
+NEXT_ERRNO_H = @NEXT_ERRNO_H@
+NEXT_FCNTL_H = @NEXT_FCNTL_H@
+NEXT_FLOAT_H = @NEXT_FLOAT_H@
+NEXT_FNMATCH_H = @NEXT_FNMATCH_H@
+NEXT_GETOPT_H = @NEXT_GETOPT_H@
+NEXT_ICONV_H = @NEXT_ICONV_H@
+NEXT_INTTYPES_H = @NEXT_INTTYPES_H@
+NEXT_LANGINFO_H = @NEXT_LANGINFO_H@
+NEXT_LIMITS_H = @NEXT_LIMITS_H@
+NEXT_LOCALE_H = @NEXT_LOCALE_H@
+NEXT_NETDB_H = @NEXT_NETDB_H@
+NEXT_NETINET_IN_H = @NEXT_NETINET_IN_H@
+NEXT_SCHED_H = @NEXT_SCHED_H@
+NEXT_SIGNAL_H = @NEXT_SIGNAL_H@
+NEXT_SPAWN_H = @NEXT_SPAWN_H@
+NEXT_STDDEF_H = @NEXT_STDDEF_H@
+NEXT_STDINT_H = @NEXT_STDINT_H@
+NEXT_STDIO_H = @NEXT_STDIO_H@
+NEXT_STDLIB_H = @NEXT_STDLIB_H@
+NEXT_STRINGS_H = @NEXT_STRINGS_H@
+NEXT_STRING_H = @NEXT_STRING_H@
+NEXT_SYS_FILE_H = @NEXT_SYS_FILE_H@
+NEXT_SYS_IOCTL_H = @NEXT_SYS_IOCTL_H@
+NEXT_SYS_RANDOM_H = @NEXT_SYS_RANDOM_H@
+NEXT_SYS_SELECT_H = @NEXT_SYS_SELECT_H@
+NEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@
+NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@
+NEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@
+NEXT_SYS_TYPES_H = @NEXT_SYS_TYPES_H@
+NEXT_SYS_UIO_H = @NEXT_SYS_UIO_H@
+NEXT_SYS_WAIT_H = @NEXT_SYS_WAIT_H@
+NEXT_TIME_H = @NEXT_TIME_H@
+NEXT_UNISTD_H = @NEXT_UNISTD_H@
+NEXT_UTIME_H = @NEXT_UTIME_H@
+NEXT_WCHAR_H = @NEXT_WCHAR_H@
+NEXT_WCTYPE_H = @NEXT_WCTYPE_H@
+OBJEXT = @OBJEXT@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PCRE2_CFLAGS = @PCRE2_CFLAGS@
+PCRE2_LIBS = @PCRE2_LIBS@
+PCRE_CFLAGS = @PCRE_CFLAGS@
+PCRE_LIBS = @PCRE_LIBS@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POD2MAN = @POD2MAN@
+POSUB = @POSUB@
+PRAGMA_COLUMNS = @PRAGMA_COLUMNS@
+PRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@
+PRIPTR_PREFIX = @PRIPTR_PREFIX@
+PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@
+PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+REPLACE_ACCESS = @REPLACE_ACCESS@
+REPLACE_ALIGNED_ALLOC = @REPLACE_ALIGNED_ALLOC@
+REPLACE_BTOWC = @REPLACE_BTOWC@
+REPLACE_CALLOC_FOR_CALLOC_GNU = @REPLACE_CALLOC_FOR_CALLOC_GNU@
+REPLACE_CALLOC_FOR_CALLOC_POSIX = @REPLACE_CALLOC_FOR_CALLOC_POSIX@
+REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@
+REPLACE_CHOWN = @REPLACE_CHOWN@
+REPLACE_CLOSE = @REPLACE_CLOSE@
+REPLACE_CLOSEDIR = @REPLACE_CLOSEDIR@
+REPLACE_COPY_FILE_RANGE = @REPLACE_COPY_FILE_RANGE@
+REPLACE_CREAT = @REPLACE_CREAT@
+REPLACE_CTIME = @REPLACE_CTIME@
+REPLACE_DIRFD = @REPLACE_DIRFD@
+REPLACE_DPRINTF = @REPLACE_DPRINTF@
+REPLACE_DUP = @REPLACE_DUP@
+REPLACE_DUP2 = @REPLACE_DUP2@
+REPLACE_DUPLOCALE = @REPLACE_DUPLOCALE@
+REPLACE_EXECL = @REPLACE_EXECL@
+REPLACE_EXECLE = @REPLACE_EXECLE@
+REPLACE_EXECLP = @REPLACE_EXECLP@
+REPLACE_EXECV = @REPLACE_EXECV@
+REPLACE_EXECVE = @REPLACE_EXECVE@
+REPLACE_EXECVP = @REPLACE_EXECVP@
+REPLACE_EXECVPE = @REPLACE_EXECVPE@
+REPLACE_FACCESSAT = @REPLACE_FACCESSAT@
+REPLACE_FCHMODAT = @REPLACE_FCHMODAT@
+REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@
+REPLACE_FCLOSE = @REPLACE_FCLOSE@
+REPLACE_FCNTL = @REPLACE_FCNTL@
+REPLACE_FDOPEN = @REPLACE_FDOPEN@
+REPLACE_FDOPENDIR = @REPLACE_FDOPENDIR@
+REPLACE_FFLUSH = @REPLACE_FFLUSH@
+REPLACE_FFSLL = @REPLACE_FFSLL@
+REPLACE_FNMATCH = @REPLACE_FNMATCH@
+REPLACE_FOPEN = @REPLACE_FOPEN@
+REPLACE_FOPEN_FOR_FOPEN_GNU = @REPLACE_FOPEN_FOR_FOPEN_GNU@
+REPLACE_FPRINTF = @REPLACE_FPRINTF@
+REPLACE_FPURGE = @REPLACE_FPURGE@
+REPLACE_FREE = @REPLACE_FREE@
+REPLACE_FREELOCALE = @REPLACE_FREELOCALE@
+REPLACE_FREOPEN = @REPLACE_FREOPEN@
+REPLACE_FSEEK = @REPLACE_FSEEK@
+REPLACE_FSEEKO = @REPLACE_FSEEKO@
+REPLACE_FSTAT = @REPLACE_FSTAT@
+REPLACE_FSTATAT = @REPLACE_FSTATAT@
+REPLACE_FTELL = @REPLACE_FTELL@
+REPLACE_FTELLO = @REPLACE_FTELLO@
+REPLACE_FTRUNCATE = @REPLACE_FTRUNCATE@
+REPLACE_FUTIMENS = @REPLACE_FUTIMENS@
+REPLACE_GAI_STRERROR = @REPLACE_GAI_STRERROR@
+REPLACE_GETADDRINFO = @REPLACE_GETADDRINFO@
+REPLACE_GETCWD = @REPLACE_GETCWD@
+REPLACE_GETDELIM = @REPLACE_GETDELIM@
+REPLACE_GETDOMAINNAME = @REPLACE_GETDOMAINNAME@
+REPLACE_GETDTABLESIZE = @REPLACE_GETDTABLESIZE@
+REPLACE_GETGROUPS = @REPLACE_GETGROUPS@
+REPLACE_GETLINE = @REPLACE_GETLINE@
+REPLACE_GETLOGIN_R = @REPLACE_GETLOGIN_R@
+REPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@
+REPLACE_GETPASS = @REPLACE_GETPASS@
+REPLACE_GETPASS_FOR_GETPASS_GNU = @REPLACE_GETPASS_FOR_GETPASS_GNU@
+REPLACE_GETRANDOM = @REPLACE_GETRANDOM@
+REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@
+REPLACE_GMTIME = @REPLACE_GMTIME@
+REPLACE_ICONV = @REPLACE_ICONV@
+REPLACE_ICONV_OPEN = @REPLACE_ICONV_OPEN@
+REPLACE_ICONV_UTF = @REPLACE_ICONV_UTF@
+REPLACE_INET_NTOP = @REPLACE_INET_NTOP@
+REPLACE_INET_PTON = @REPLACE_INET_PTON@
+REPLACE_INITSTATE = @REPLACE_INITSTATE@
+REPLACE_IOCTL = @REPLACE_IOCTL@
+REPLACE_ISATTY = @REPLACE_ISATTY@
+REPLACE_ISWBLANK = @REPLACE_ISWBLANK@
+REPLACE_ISWCNTRL = @REPLACE_ISWCNTRL@
+REPLACE_ISWDIGIT = @REPLACE_ISWDIGIT@
+REPLACE_ISWXDIGIT = @REPLACE_ISWXDIGIT@
+REPLACE_ITOLD = @REPLACE_ITOLD@
+REPLACE_LCHOWN = @REPLACE_LCHOWN@
+REPLACE_LINK = @REPLACE_LINK@
+REPLACE_LINKAT = @REPLACE_LINKAT@
+REPLACE_LOCALECONV = @REPLACE_LOCALECONV@
+REPLACE_LOCALTIME = @REPLACE_LOCALTIME@
+REPLACE_LOCALTIME_R = @REPLACE_LOCALTIME_R@
+REPLACE_LSEEK = @REPLACE_LSEEK@
+REPLACE_LSTAT = @REPLACE_LSTAT@
+REPLACE_MALLOC_FOR_MALLOC_GNU = @REPLACE_MALLOC_FOR_MALLOC_GNU@
+REPLACE_MALLOC_FOR_MALLOC_POSIX = @REPLACE_MALLOC_FOR_MALLOC_POSIX@
+REPLACE_MBRLEN = @REPLACE_MBRLEN@
+REPLACE_MBRTOWC = @REPLACE_MBRTOWC@
+REPLACE_MBSINIT = @REPLACE_MBSINIT@
+REPLACE_MBSNRTOWCS = @REPLACE_MBSNRTOWCS@
+REPLACE_MBSRTOWCS = @REPLACE_MBSRTOWCS@
+REPLACE_MBSTATE_T = @REPLACE_MBSTATE_T@
+REPLACE_MBTOWC = @REPLACE_MBTOWC@
+REPLACE_MEMCHR = @REPLACE_MEMCHR@
+REPLACE_MEMMEM = @REPLACE_MEMMEM@
+REPLACE_MKDIR = @REPLACE_MKDIR@
+REPLACE_MKFIFO = @REPLACE_MKFIFO@
+REPLACE_MKFIFOAT = @REPLACE_MKFIFOAT@
+REPLACE_MKNOD = @REPLACE_MKNOD@
+REPLACE_MKNODAT = @REPLACE_MKNODAT@
+REPLACE_MKSTEMP = @REPLACE_MKSTEMP@
+REPLACE_MKTIME = @REPLACE_MKTIME@
+REPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@
+REPLACE_NEWLOCALE = @REPLACE_NEWLOCALE@
+REPLACE_NL_LANGINFO = @REPLACE_NL_LANGINFO@
+REPLACE_NULL = @REPLACE_NULL@
+REPLACE_OBSTACK_PRINTF = @REPLACE_OBSTACK_PRINTF@
+REPLACE_OPEN = @REPLACE_OPEN@
+REPLACE_OPENAT = @REPLACE_OPENAT@
+REPLACE_OPENDIR = @REPLACE_OPENDIR@
+REPLACE_PERROR = @REPLACE_PERROR@
+REPLACE_POPEN = @REPLACE_POPEN@
+REPLACE_POSIX_MEMALIGN = @REPLACE_POSIX_MEMALIGN@
+REPLACE_POSIX_SPAWN = @REPLACE_POSIX_SPAWN@
+REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR = @REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR@
+REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE = @REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE@
+REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2 = @REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2@
+REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR = @REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR@
+REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN = @REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN@
+REPLACE_PREAD = @REPLACE_PREAD@
+REPLACE_PRINTF = @REPLACE_PRINTF@
+REPLACE_PSELECT = @REPLACE_PSELECT@
+REPLACE_PTHREAD_SIGMASK = @REPLACE_PTHREAD_SIGMASK@
+REPLACE_PTSNAME = @REPLACE_PTSNAME@
+REPLACE_PTSNAME_R = @REPLACE_PTSNAME_R@
+REPLACE_PUTENV = @REPLACE_PUTENV@
+REPLACE_PWRITE = @REPLACE_PWRITE@
+REPLACE_QSORT_R = @REPLACE_QSORT_R@
+REPLACE_RAISE = @REPLACE_RAISE@
+REPLACE_RANDOM = @REPLACE_RANDOM@
+REPLACE_RANDOM_R = @REPLACE_RANDOM_R@
+REPLACE_READ = @REPLACE_READ@
+REPLACE_READLINK = @REPLACE_READLINK@
+REPLACE_READLINKAT = @REPLACE_READLINKAT@
+REPLACE_REALLOCARRAY = @REPLACE_REALLOCARRAY@
+REPLACE_REALLOC_FOR_REALLOC_GNU = @REPLACE_REALLOC_FOR_REALLOC_GNU@
+REPLACE_REALLOC_FOR_REALLOC_POSIX = @REPLACE_REALLOC_FOR_REALLOC_POSIX@
+REPLACE_REALPATH = @REPLACE_REALPATH@
+REPLACE_REMOVE = @REPLACE_REMOVE@
+REPLACE_RENAME = @REPLACE_RENAME@
+REPLACE_RENAMEAT = @REPLACE_RENAMEAT@
+REPLACE_RMDIR = @REPLACE_RMDIR@
+REPLACE_SCHED_YIELD = @REPLACE_SCHED_YIELD@
+REPLACE_SELECT = @REPLACE_SELECT@
+REPLACE_SETENV = @REPLACE_SETENV@
+REPLACE_SETLOCALE = @REPLACE_SETLOCALE@
+REPLACE_SETSTATE = @REPLACE_SETSTATE@
+REPLACE_SLEEP = @REPLACE_SLEEP@
+REPLACE_SNPRINTF = @REPLACE_SNPRINTF@
+REPLACE_SPRINTF = @REPLACE_SPRINTF@
+REPLACE_STAT = @REPLACE_STAT@
+REPLACE_STDIO_READ_FUNCS = @REPLACE_STDIO_READ_FUNCS@
+REPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@
+REPLACE_STPNCPY = @REPLACE_STPNCPY@
+REPLACE_STRCASESTR = @REPLACE_STRCASESTR@
+REPLACE_STRCHRNUL = @REPLACE_STRCHRNUL@
+REPLACE_STRDUP = @REPLACE_STRDUP@
+REPLACE_STRERROR = @REPLACE_STRERROR@
+REPLACE_STRERRORNAME_NP = @REPLACE_STRERRORNAME_NP@
+REPLACE_STRERROR_R = @REPLACE_STRERROR_R@
+REPLACE_STRFTIME = @REPLACE_STRFTIME@
+REPLACE_STRNCAT = @REPLACE_STRNCAT@
+REPLACE_STRNDUP = @REPLACE_STRNDUP@
+REPLACE_STRNLEN = @REPLACE_STRNLEN@
+REPLACE_STRSIGNAL = @REPLACE_STRSIGNAL@
+REPLACE_STRSTR = @REPLACE_STRSTR@
+REPLACE_STRTOD = @REPLACE_STRTOD@
+REPLACE_STRTOIMAX = @REPLACE_STRTOIMAX@
+REPLACE_STRTOK_R = @REPLACE_STRTOK_R@
+REPLACE_STRTOL = @REPLACE_STRTOL@
+REPLACE_STRTOLD = @REPLACE_STRTOLD@
+REPLACE_STRTOLL = @REPLACE_STRTOLL@
+REPLACE_STRTOUL = @REPLACE_STRTOUL@
+REPLACE_STRTOULL = @REPLACE_STRTOULL@
+REPLACE_STRTOUMAX = @REPLACE_STRTOUMAX@
+REPLACE_STRUCT_LCONV = @REPLACE_STRUCT_LCONV@
+REPLACE_STRUCT_TIMEVAL = @REPLACE_STRUCT_TIMEVAL@
+REPLACE_SYMLINK = @REPLACE_SYMLINK@
+REPLACE_SYMLINKAT = @REPLACE_SYMLINKAT@
+REPLACE_TIMEGM = @REPLACE_TIMEGM@
+REPLACE_TMPFILE = @REPLACE_TMPFILE@
+REPLACE_TOWLOWER = @REPLACE_TOWLOWER@
+REPLACE_TRUNCATE = @REPLACE_TRUNCATE@
+REPLACE_TTYNAME_R = @REPLACE_TTYNAME_R@
+REPLACE_TZSET = @REPLACE_TZSET@
+REPLACE_UNLINK = @REPLACE_UNLINK@
+REPLACE_UNLINKAT = @REPLACE_UNLINKAT@
+REPLACE_UNSETENV = @REPLACE_UNSETENV@
+REPLACE_USLEEP = @REPLACE_USLEEP@
+REPLACE_UTIME = @REPLACE_UTIME@
+REPLACE_UTIMENSAT = @REPLACE_UTIMENSAT@
+REPLACE_VASPRINTF = @REPLACE_VASPRINTF@
+REPLACE_VDPRINTF = @REPLACE_VDPRINTF@
+REPLACE_VFPRINTF = @REPLACE_VFPRINTF@
+REPLACE_VPRINTF = @REPLACE_VPRINTF@
+REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@
+REPLACE_VSPRINTF = @REPLACE_VSPRINTF@
+REPLACE_WCRTOMB = @REPLACE_WCRTOMB@
+REPLACE_WCSFTIME = @REPLACE_WCSFTIME@
+REPLACE_WCSNRTOMBS = @REPLACE_WCSNRTOMBS@
+REPLACE_WCSRTOMBS = @REPLACE_WCSRTOMBS@
+REPLACE_WCSTOK = @REPLACE_WCSTOK@
+REPLACE_WCSWIDTH = @REPLACE_WCSWIDTH@
+REPLACE_WCTOB = @REPLACE_WCTOB@
+REPLACE_WCTOMB = @REPLACE_WCTOMB@
+REPLACE_WCWIDTH = @REPLACE_WCWIDTH@
+REPLACE_WRITE = @REPLACE_WRITE@
+SED = @SED@
+SERVENT_LIB = @SERVENT_LIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@
+SIZE_T_SUFFIX = @SIZE_T_SUFFIX@
+STDALIGN_H = @STDALIGN_H@
+STDBOOL_H = @STDBOOL_H@
+STDDEF_H = @STDDEF_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+SYS_IOCTL_H_HAVE_WINSOCK2_H = @SYS_IOCTL_H_HAVE_WINSOCK2_H@
+SYS_IOCTL_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @SYS_IOCTL_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@
+SYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@
+TIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@
+TIME_H_DEFINES_TIME_UTC = @TIME_H_DEFINES_TIME_UTC@
+UINT32_MAX_LT_UINTMAX_MAX = @UINT32_MAX_LT_UINTMAX_MAX@
+UINT64_MAX_EQ_ULONG_MAX = @UINT64_MAX_EQ_ULONG_MAX@
+UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@
+UNISTD_H_DEFINES_STRUCT_TIMESPEC = @UNISTD_H_DEFINES_STRUCT_TIMESPEC@
+UNISTD_H_HAVE_SYS_RANDOM_H = @UNISTD_H_HAVE_SYS_RANDOM_H@
+UNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@
+UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@
+USE_NLS = @USE_NLS@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VALGRIND_TESTS = @VALGRIND_TESTS@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@
+WINDOWS_64_BIT_OFF_T = @WINDOWS_64_BIT_OFF_T@
+WINDOWS_64_BIT_ST_SIZE = @WINDOWS_64_BIT_ST_SIZE@
+WINDOWS_STAT_INODES = @WINDOWS_STAT_INODES@
+WINDOWS_STAT_TIMESPEC = @WINDOWS_STAT_TIMESPEC@
+WINT_T_SUFFIX = @WINT_T_SUFFIX@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gl_LIBOBJDEPS = @gl_LIBOBJDEPS@
+gl_LIBOBJS = @gl_LIBOBJS@
+gl_LTLIBOBJS = @gl_LTLIBOBJS@
+gltests_LIBOBJDEPS = @gltests_LIBOBJDEPS@
+gltests_LIBOBJS = @gltests_LIBOBJS@
+gltests_LTLIBOBJS = @gltests_LTLIBOBJS@
+gltests_WITNESS = @gltests_WITNESS@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+ifGNUmake = @ifGNUmake@
+ifnGNUmake = @ifnGNUmake@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+DEFAULT_TESTS = \
+ Test-504.py \
+ Test-416.py \
+ Test-auth-basic-fail.py \
+ Test-auth-basic.py \
+ Test-auth-basic-netrc.py \
+ Test-auth-basic-netrc-user-given.py \
+ Test-auth-basic-netrc-pass-given.py \
+ Test-auth-basic-no-netrc-fail.py \
+ Test-auth-both.py \
+ Test-auth-digest.py \
+ Test-auth-no-challenge.py \
+ Test-auth-no-challenge-url.py \
+ Test-auth-retcode.py \
+ Test-auth-with-content-disposition.py \
+ Test-c-full.py \
+ Test-condget.py \
+ Test-Content-disposition-2.py \
+ Test-Content-disposition.py \
+ Test--convert-links--content-on-error.py \
+ Test-cookie-401.py \
+ Test-cookie-domain-mismatch.py \
+ Test-cookie-expires.py \
+ Test-cookie.py \
+ Test-Head.py \
+ Test-hsts.py \
+ Test--https.py \
+ Test--https-crl.py \
+ Test-missing-scheme-retval.py \
+ Test-O.py \
+ Test-pinnedpubkey-der-https.py \
+ Test-pinnedpubkey-der-no-check-https.py \
+ Test-pinnedpubkey-hash-https.py \
+ Test-pinnedpubkey-hash-no-check-fail-https.py \
+ Test-pinnedpubkey-pem-fail-https.py \
+ Test-pinnedpubkey-pem-https.py \
+ Test-Post.py \
+ Test-recursive-basic.py \
+ Test-recursive-include.py \
+ Test-recursive-redirect.py \
+ Test-redirect.py \
+ Test-redirect-crash.py \
+ Test--rejected-log.py \
+ Test-reserved-chars.py \
+ Test--spider-r.py \
+ Test-no_proxy-env.py
+
+METALINK_TESTS = \
+ Test-metalink-http.py \
+ Test-metalink-http-quoted.py \
+ Test-metalink-http-baddigest.py \
+ Test-metalink-http-xml.py \
+ Test-metalink-http-xml-trust.py \
+ Test-metalink-http-xml-trust-name.py \
+ Test-metalink-http-xml-type.py \
+ Test-metalink-http-xml-type-trust.py \
+ Test-metalink-http-xml-type-content.py \
+ Test-metalink-http-xml-type-trust-content.py \
+ Test-metalink-xml.py \
+ Test-metalink-xml-continue.py \
+ Test-metalink-xml-relpath.py \
+ Test-metalink-xml-abspath.py \
+ Test-metalink-xml-homepath.py \
+ Test-metalink-xml-trust.py \
+ Test-metalink-xml-relpath-trust.py \
+ Test-metalink-xml-abspath-trust.py \
+ Test-metalink-xml-homepath-trust.py \
+ Test-metalink-xml-prefix.py \
+ Test-metalink-xml-relprefix.py \
+ Test-metalink-xml-absprefix.py \
+ Test-metalink-xml-homeprefix.py \
+ Test-metalink-xml-prefix-trust.py \
+ Test-metalink-xml-relprefix-trust.py \
+ Test-metalink-xml-absprefix-trust.py \
+ Test-metalink-xml-homeprefix-trust.py \
+ Test-metalink-xml-emptyprefix-trust.py \
+ Test-metalink-xml-size.py \
+ Test-metalink-xml-nohash.py \
+ Test-metalink-xml-nourls.py \
+ Test-metalink-xml-urlbreak.py
+
+AUTOMAKE_OPTIONS = parallel-tests
+AM_TESTS_ENVIRONMENT = export WGETRC=/dev/null; MAKE_CHECK=True; \
+ export MAKE_CHECK; export \
+ PYTHONPATH=$$PYTHONPATH$(PATH_SEPARATOR)$(srcdir); export \
+ VALGRIND_TESTS="@VALGRIND_TESTS@"; $(am__append_1)
+@HAVE_PYTHON3_TRUE@TESTS = $(DEFAULT_TESTS) $(am__append_2)
+EXTRA_DIST = certs conf exc misc server test README \
+ valgrind-suppressions-ssl \
+ $(DEFAULT_TESTS) $(METALINK_TESTS)
+
+TEST_EXTENSIONS = .py
+PY_LOG_COMPILER = python3
+AM_PY_LOG_FLAGS = -O
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .log .py .py$(EXEEXT) .trs
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu testenv/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu testenv/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS:
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+.py.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(PY_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_PY_LOG_DRIVER_FLAGS) $(PY_LOG_DRIVER_FLAGS) -- $(PY_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.py$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(PY_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_PY_LOG_DRIVER_FLAGS) $(PY_LOG_DRIVER_FLAGS) -- $(PY_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: all all-am check check-TESTS check-am clean clean-generic \
+ cscopelist-am ctags-am distclean distclean-generic distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+ pdf-am ps ps-am recheck tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/testenv/README b/testenv/README
new file mode 100644
index 0000000..d4fabdd
--- /dev/null
+++ b/testenv/README
@@ -0,0 +1,306 @@
+This document describes the working of the GNU Wget Test Suite.
+
+Install Instructions:
+================================================================================
+
+This Test Suite exploits the Parallel Test Harness available in GNU Autotools.
+Since it uses features from a relatively recent version of Autotools, the minimum
+required version as been bumped up to 1.11.
+Run the './configure' command to generate the Makefile and then run 'make check'
+to execute the Test Suite. Use the '-j n' option with 'make check' to execute
+n tests simultaneously.
+
+Structure:
+================================================================================
+
+ * server: This package contains custom programmatically configurable servers
+ (both HTTP and FTP) for testing Wget. The HTTP server runs an instance of
+ Python's http.server module. The FTP server is to be implemented.
+
+ * test: This package contains the test case classes for HTTP and FTP. The
+ test case classes includes methods for initializing and cleaning up of the
+ test environment.
+
+ * Test-Proto.py: This is a prototype Test Case file. The file defines all
+ the acceptable elements and their uses. Typically, one must copy this file
+ and edit it for writing Test Cases.
+
+ * exc: This package contains custom exception classes used in this test
+ suite.
+
+ * conf: This package contains the configuration classes for servers to be
+ configured with.
+
+ * misc: This package contains several helper modules used in this test
+ suite.
+ - colour_terminal.py: A custom module for printing coloured output to
+ the terminal. Currently it only supports 4 colours in a *nix
+ environment.
+ - wget_file.py: Module which contains WgetFile, which is a file data
+ container object.
+
+Working:
+================================================================================
+
+The Test Files are valid Python scripts and the default mask for them is 755.
+A singular Test must be invoked in the following manner, with the current
+directory being the testenv directory:
+$ ./python3 <Name of Test File> OR
+$ ./<Name of Test File>
+The script will then initialize the various elements and pass them to an object
+of the respective Test Class. A directory with the name <Test name>-test will be
+created and the PWD will be changed to this directory. The server is then
+spawned with the required configuration elements. A blocking call to Wget is
+made with the command line arguments specified in the Test Case along with the
+list of URLs that it must download. The server is killed once Wget returns and
+the following checks are used to determine the pass/fail status of the test:
+ * Return Code: The Exit code of Wget is matched against the expected Exit
+ Code as mentioned in the Test Case File.
+ * Downloaded Files: Check whether the expected downloaded files exist on
+ disk.
+ * File Content: Test whether the file contents were correctly downloaded by
+ Wget and not corrupted mid-way.
+ * Excess Files: Check to see whether any unexpected files were downloaded
+ by Wget.
+
+Exit Codes:
+===============================================================================
+
+Following is a list of Exit Status Codes for the tests:
+* 0 Test Successful
+* 66 Errors/Warnings Reported by Thread Sanitizer (If built with -fsanitize)
+* 77 Test Skipped
+* 99 Hard Error
+* 100 Test Failed
+
+Tests are skipped when they are either not supported by the platform, or Wget
+is not compiled with support for that feature. This feature has not yet been
+implemented.
+
+Hard Errors occur when there are problems with the Environment code. Hard
+Error reporting is currently not enabled and all errors are reported as
+failures.
+
+All exceptions should ideally be handled gracefully. If you see any unhandled
+exceptions, please file a bug report at <bug-wget@gnu.org>
+
+Environment Variables:
+================================================================================
+
+* SERVER_WAIT: Set this environment variable with a value for the number of
+ seconds the test should sleep between invoking the server and calling the Wget
+ executable. This is used when one would like to test a different version of
+ the executable or for running the test through external utilities like gdb and
+ valgrind.
+* NO_CLEANUP: Do not remove the temporary files created by the test.
+ This will prevent the ${testname}-test directory from being deleted
+* VALGRIND_TESTS: If this variable is set and contains the valgrind command line,
+ the test suite will execute all the tests via this command.
+ If it is set to "1", valgrind memcheck is enabled with hard coded options.
+ This variable is set by ./configure --enable-valgrind-tests.
+* SSL_TESTS: This must be set to run any https tests.
+* WGET_PATH: Set this environment variable to a path to wget binary on which you
+ want to run tests. This is useful for OS distributions, which want to reuse
+ upstream tests for testing wget build that they distribute. If the variable is
+ not set, the "../src/wget" binary is used by tests.
+
+
+File Structure:
+================================================================================
+
+The test case files are Python scripts. It is believed that Python is a simple
+yet elegant language and should be easy for everyone to comprehend. This test
+suite is written with the objective of making it easy to write new tests. The
+structure has been kept as intuitive as possible and should not require much
+effort to get accustomed to.
+
+All Test Files MUST begin with the following Three Lines:
+#!/usr/bin/python3
+from sys import exit
+from WgetTest import {HTTPTest|FTPTest}
+from misc.wget_file import WgetFile
+
+It is recommended that a small description of the Test Case is provided next.
+This would be very helpful to future contributors.
+
+Each File in the Test must be represented as a WgetFile object. The WgetFile
+Class has the following prototype:
+WgetFile (str name, str contents, str timestamp, dict rules)
+None except name is a mandatory parameter, one may pass only those parameters
+that are required by the File object.
+
+The timestamp string should be in a format: "YYYY-MM-DD HH:MM:SS" in UTC zone.
+The rules object is a dictionary element, with the key as the Rule Name and
+value as the Rule Data. In most cases, the Rule Data is another dictionary.
+
+Various variables used consistently across all tests are:
+ * WGET_OPTIONS: The command line string passed to Wget upon invocation. This
+ string may contain URLs, like in the case where in-URL authentication is
+ used. Variable names passed like {{var_name}} will be replaced by the
+ contents of the variable self.var_name before being passed to Wget
+ * WGET_URLS: This is a list of filenames which will be appended as the URLs
+ to Wget during invocation. This is a list of lists, where WGET_URLS[0]
+ represents the list of Filenames called from Server[0], WGET_URLS[1] is a
+ list of files downloaded from Server[2], etc. They must be relative URLs,
+ i.e., not start with "/".
+ * Files: This variable defines the files that exist in the Server's
+ filesystem. The Files variable is a list of lists of WgetFile objects.
+ This means that File[0] is a list of WgetFile objects that lie on Server[0],
+ File[1] a list of files on Server[1] and so on.
+ * Existing_Files: This is a list of files that already exist in the
+ directory from which Wget is invoked.
+ * ExpectedReturnCode: The Exit Code expected to be returned by Wget after
+ the test.
+ * ExpectedDownloadedFiles: A list of files that are expected in the local
+ directory after Wget has finished executing. This does not include the files
+ already existing before Wget was launched and must be mentioned again.
+ * Request_List: An unordered list of Requests that each server must receive.
+ This too is a list of lists and follows the same convention as others above.
+
+Both, the HTTPTest and FTPTest modules have the same prototype:
+{
+ pre_hook,
+ test_options,
+ post_hook,
+ protocols
+}
+the three hooks should be Python dict objects and protocols should be a list of
+protocols, like [HTTP, HTTPS].
+
+Valid File Rules:
+================================================================================
+
+This section lists the currently supported File Rules and their structure.
+
+ * Authentication: Used when a File must require Authorization for access.
+ The value for this key is the following dictionary:
+ |-->Type : Basic|Digest|Both|Both_inline
+ |-->User : <Username>
+ --->Pass : <Password>
+
+ * ExpectHeader : The following Headers MUST exist in every Request for the
+ File. The value for this key is a dictionary object where each header is
+ represented as:
+ |-->Header Name : <Header Data>
+
+ * RejectHeader : This list of Headers must NEVER occur in a request. It
+ uses the same value format as ExpectHeader.
+
+ * SendHeader : This list of Headers will be sent in EVERY response to a
+ request for the respective file. It follows the same value format as
+ ExpectHeader. Additionally you can specify a list of strings as <Header Data>
+ if you want the header repeated with multiple values.
+
+ * Response : The HTTP Response Code to send to a request for this File.
+ The value is an Integer that represents a valid HTTP Response Code.
+
+Pre Test Hooks:
+================================================================================
+
+The Pre-Test Hooks are executed just after starting the server and just before
+spawning an instance of the server. These are usually used for setting up the
+Test Environment and Server Rules. The currently supported Pre-Test Hooks are:
+
+ * ServerFiles : A list of WgetFile objects that must exist on the Server
+ * LocalFiles : A list of WgetFile objects that exist locally on disk
+ before Wget is executed.
+
+Since pre_test is a dictionary, one may not assume that the hooks will be
+executed in the same order as they are defined.
+
+Test Options:
+================================================================================
+
+The test_options dictionary defines the commands to be used when the Test is
+executed. The currently supported options are:
+
+ * Urls : A list of the filenames that Wget must attempt to
+ download. The complete URL will be created and passed to Wget
+ automatically. (alias URLs)
+ * WgetCommands : A string consisting of the various commandline switches
+ sent to Wget upon invocation. Any data placed between {{ }} in this string
+ will be replaced with the contents of self.<data> before being passed to
+ Wget. This is particularly useful for getting the hostname and port for a
+ file. While all Download URL's are passed to Urls, a notable exception is
+ when in-url authentication is used. In such a case, the URL is specified in
+ the WgetCommands string.
+ * EnvironmentVariables: A dictionary with key-value items, which will be
+ defined as environment variables during the execution of wget command in
+ test.
+
+Post-Test Hooks:
+================================================================================
+
+These hooks are executed as soon as the call to Wget returns. The post-test
+hooks are usually used to run checks on the data, files downloaded, return code,
+etc. The following hooks are currently supported:
+
+ * ExpectedRetcode : This is an integer value of the ReturnCode with which
+ Wget is expected to exit. (alias ExpectedRetCode)
+ * ExpectedFiles : This is a list of WgetFile objects of the files that
+ must exist locally on disk in the Test directory.
+ * FilesCrawled : This requires a list of the Requests that the server is
+ expected to receive. The order is un-important since it will vary on the
+ parallel-wget branch. This hook is used in tests for Recursive mode to
+ ensure that the website is traversed correctly.
+
+Writing New Tests:
+================================================================================
+
+See Test-Proto.py for an example of how to write Test Case files. The
+recommended method for writing new Test Case files is to copy Test-Proto.py and
+modify it to ones needs.
+
+In case you require any functionality that is not currently defined in List of
+Rules defined above, you should implement a new class in the conf package. The
+file name doesn't matter (though it's better to give it an appropriate name).
+The new rule or hook class should be like this:
+============================================
+from conf import rule
+
+
+@rule()
+class MyNewRule:
+ def __init__(self, rule_arg):
+ self.rule_arg = rule_arg
+ # your rule initialization code goes here
+============================================
+from conf import hook
+
+
+@hook()
+class MyNewHook:
+ def __init__(self, hook_arg):
+ self.hook_arg = hook_arg
+ # your hook initialization code goes here
+
+ def __call__(self, test_obj):
+ # your hook code goes here
+============================================
+
+Once a new Test File is created, it must be added to the TESTS variable in
+Makefile.am. This way the Test will be executed on running a 'make check'.
+If a Test is expected to fail on the current master branch, then the Test should
+also be added to the XFAIL_TESTS variable. This will allow expected failures to
+pass through. If a test mentioned in the XFAIL_TESTS variable passes, it gets
+red-flagged as a XPASS. Currently, tests expected to fail under valgrind are not
+explicitly marked as XFAIL. Tests failing under valgrind must always be
+considered a blocking error.
+
+Work Remaining:
+================================================================================
+
+Some amount of work still remains to be done.
+ * Errors in server-side checks need to be handled more explicitly
+ * Support parallel-wget branch
+ * Support to spawn multiple servers is already in place. Need to handle
+ multiple requests to a server simultaneously. Use THreading MixIn.
+ * SSL Tests. Use xyne's HTTPS server implementation
+ * Complete support for FTP Tests
+ * IRI Support. This shouldn't require much effort
+
+Requirements:
+================================================================================
+
+1. Python >= 3.0
+2. Automake >= 1.11
diff --git a/testenv/Test--convert-links--content-on-error.py b/testenv/Test--convert-links--content-on-error.py
new file mode 100755
index 0000000..37fcc47
--- /dev/null
+++ b/testenv/Test--convert-links--content-on-error.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures that Wget link conversion works also on HTTP error pages.
+"""
+############# File Definitions ###############################################
+a_x_FileContent = """
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title></title>
+</head>
+<body>
+ <a href="/b/y.html"></a>
+</body>
+</html>
+"""
+a_x_LocalFileContent = """
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title></title>
+</head>
+<body>
+ <a href="../b/y.html"></a>
+</body>
+</html>
+"""
+
+error_FileContent = '404 page content'
+error_FileRules = {
+ 'Response': 404 ,
+ 'SendHeader': {
+ 'Content-Length': len(error_FileContent),
+ 'Content-Type': 'text/plain',
+ }
+}
+
+a_x_File = WgetFile ("a/x.html", a_x_FileContent)
+robots_File = WgetFile ("robots.txt", '')
+error_File = WgetFile ("b/y.html", error_FileContent, rules=error_FileRules)
+
+B_File = WgetFile ("a/x.html", a_x_LocalFileContent)
+
+WGET_OPTIONS = "--no-host-directories -r -l2 --convert-links --content-on-error"
+WGET_URLS = [["a/x.html"]]
+
+Files = [[a_x_File, robots_File, error_File]]
+
+ExpectedReturnCode = 8
+ExpectedDownloadedFiles = [B_File, robots_File, error_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test--https-crl.py b/testenv/Test--https-crl.py
new file mode 100755
index 0000000..6c7002e
--- /dev/null
+++ b/testenv/Test--https-crl.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from test.base_test import HTTPS, SKIP_TEST
+from misc.wget_file import WgetFile
+import os
+
+"""
+ This test ensures that Wget can download files from HTTPS Servers
+"""
+if os.getenv('SSL_TESTS') is None:
+ exit (SKIP_TEST)
+
+############# File Definitions ###############################################
+File1 = "Would you like some Tea?"
+File2 = "With lemon or cream?"
+
+A_File = WgetFile ("File1", File1)
+B_File = WgetFile ("File2", File2)
+
+CAFILE = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs', 'ca-cert.pem'))
+CRLFILE = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs', 'server-crl.pem'))
+WGET_OPTIONS = "--crl-file " + CRLFILE + " --ca-certificate=" + CAFILE
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+
+Servers = [HTTPS]
+
+ExpectedReturnCode = 5
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+ protocols=Servers
+).begin ()
+
+exit (err)
diff --git a/testenv/Test--https.py b/testenv/Test--https.py
new file mode 100755
index 0000000..d9431a3
--- /dev/null
+++ b/testenv/Test--https.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from test.base_test import HTTPS, SKIP_TEST
+from misc.wget_file import WgetFile
+import os
+
+"""
+ This test ensures that Wget can download files from HTTPS Servers
+"""
+if os.getenv('SSL_TESTS') is None:
+ exit (SKIP_TEST)
+
+############# File Definitions ###############################################
+File1 = "Would you like some Tea?"
+File2 = "With lemon or cream?"
+File3 = "Sure you're joking Mr. Feynman"
+
+A_File = WgetFile ("File1", File1)
+B_File = WgetFile ("File2", File2)
+C_File = WgetFile ("File3", File3)
+
+CAFILE = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs', 'ca-cert.pem'))
+WGET_OPTIONS = "--ca-certificate=" + CAFILE
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+Existing_Files = [C_File]
+
+Servers = [HTTPS]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File, B_File, C_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+ protocols=Servers
+).begin ()
+
+exit (err)
diff --git a/testenv/Test--rejected-log.py b/testenv/Test--rejected-log.py
new file mode 100755
index 0000000..fb4f9f4
--- /dev/null
+++ b/testenv/Test--rejected-log.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test executed Wget in recursive mode with a rejected log outputted.
+"""
+############# File Definitions ###############################################
+mainpage = """
+<html>
+<head>
+ <title>Main Page</title>
+</head>
+<body>
+ <p>
+ Recurse to a <a href="http://localhost:{{port}}/secondpage.html">second page</a>.
+ </p>
+</body>
+</html>
+"""
+
+secondpage = """
+<html>
+<head>
+ <title>Second Page</title>
+</head>
+<body>
+ <p>
+ Recurse to a <a href="http://localhost:{{port}}/thirdpage.html">third page</a>.
+ Try the blacklisted <a href="http://localhost:{{port}}/index.html">main page</a>.
+ </p>
+</body>
+</html>
+"""
+
+thirdpage = """
+<html>
+<head>
+ <title>Third Page</title>
+</head>
+<body>
+ <p>
+ Try a hidden <a href="http://localhost:{{port}}/dummy.txt">dummy file</a>.
+ Try to leave to <a href="http://no.such.domain/">another domain</a>.
+ </p>
+</body>
+</html>
+"""
+
+robots = """
+User-agent: *
+Disallow: /dummy.txt
+"""
+
+log = """\
+REASON\tU_URL\tU_SCHEME\tU_HOST\tU_PORT\tU_PATH\tU_PARAMS\tU_QUERY\tU_FRAGMENT\tP_URL\tP_SCHEME\tP_HOST\tP_PORT\tP_PATH\tP_PARAMS\tP_QUERY\tP_FRAGMENT
+BLACKLIST\thttp%3A//localhost%3A{{port}}/index.html\tSCHEME_HTTP\tlocalhost\t{{port}}\tindex.html\t\t\t\thttp%3A//localhost%3A{{port}}/secondpage.html\tSCHEME_HTTP\tlocalhost\t{{port}}\tsecondpage.html\t\t\t
+ROBOTS\thttp%3A//localhost%3A{{port}}/dummy.txt\tSCHEME_HTTP\tlocalhost\t{{port}}\tdummy.txt\t\t\t\thttp%3A//localhost%3A{{port}}/thirdpage.html\tSCHEME_HTTP\tlocalhost\t{{port}}\tthirdpage.html\t\t\t
+SPANNEDHOST\thttp%3A//no.such.domain/\tSCHEME_HTTP\tno.such.domain\t80\t\t\t\t\thttp%3A//localhost%3A{{port}}/thirdpage.html\tSCHEME_HTTP\tlocalhost\t{{port}}\tthirdpage.html\t\t\t
+"""
+
+dummyfile = "Don't care."
+
+
+index_html = WgetFile ("index.html", mainpage)
+secondpage_html = WgetFile ("secondpage.html", secondpage)
+thirdpage_html = WgetFile ("thirdpage.html", thirdpage)
+robots_txt = WgetFile ("robots.txt", robots)
+dummy_txt = WgetFile ("dummy.txt", dummyfile)
+log_csv = WgetFile ("log.csv", log)
+
+WGET_OPTIONS = "-nd -r --rejected-log log.csv"
+WGET_URLS = [["index.html"]]
+
+Files = [[index_html, secondpage_html, thirdpage_html, robots_txt, dummy_txt]]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [index_html, secondpage_html, thirdpage_html, robots_txt, log_csv]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test--spider-r.py b/testenv/Test--spider-r.py
new file mode 100755
index 0000000..8d8c6f7
--- /dev/null
+++ b/testenv/Test--spider-r.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test executed Wget in Spider mode with recursive retrieval.
+"""
+############# File Definitions ###############################################
+mainpage = """
+<html>
+<head>
+ <title>Main Page</title>
+</head>
+<body>
+ <p>
+ Some text and a link to a <a href="http://localhost:{{port}}/secondpage.html">second page</a>.
+ Also, a <a href="http://localhost:{{port}}/nonexistent">broken link</a>.
+ </p>
+</body>
+</html>
+"""
+
+
+secondpage = """
+<html>
+<head>
+ <title>Second Page</title>
+</head>
+<body>
+ <p>
+ Some text and a link to a <a href="http://localhost:{{port}}/thirdpage.html">third page</a>.
+ Also, a <a href="http://localhost:{{port}}/nonexistent">broken link</a>.
+ </p>
+</body>
+</html>
+"""
+
+thirdpage = """
+<html>
+<head>
+ <title>Third Page</title>
+</head>
+<body>
+ <p>
+ Some text and a link to a <a href="http://localhost:{{port}}/dummy.txt">text file</a>.
+ Also, another <a href="http://localhost:{{port}}/againnonexistent">broken link</a>.
+ </p>
+</body>
+</html>
+"""
+
+dummyfile = "Don't care."
+
+
+index_html = WgetFile ("index.html", mainpage)
+secondpage_html = WgetFile ("secondpage.html", secondpage)
+thirdpage_html = WgetFile ("thirdpage.html", thirdpage)
+dummy_txt = WgetFile ("dummy.txt", dummyfile)
+
+Request_List = [
+ [
+ "HEAD /",
+ "GET /",
+ "GET /robots.txt",
+ "HEAD /secondpage.html",
+ "GET /secondpage.html",
+ "HEAD /nonexistent",
+ "HEAD /thirdpage.html",
+ "GET /thirdpage.html",
+ "HEAD /dummy.txt",
+ "HEAD /againnonexistent"
+ ]
+]
+
+WGET_OPTIONS = "--spider -r"
+WGET_URLS = [[""]]
+
+Files = [[index_html, secondpage_html, thirdpage_html, dummy_txt]]
+
+ExpectedReturnCode = 8
+ExpectedDownloadedFiles = []
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode,
+ "FilesCrawled" : Request_List
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-416.py b/testenv/Test-416.py
new file mode 100755
index 0000000..76b9421
--- /dev/null
+++ b/testenv/Test-416.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ Ensure that Wget behaves well when the server responds with a HTTP 416
+ status code. This test checks both cases:
+ 1. Server sends no body
+ 2. Server sends a body
+"""
+############# File Definitions ###############################################
+File1 = "abababababababababababababababababababababababababababababababababab"
+File2 = "ababababababababababababababababababab"
+
+A_File = WgetFile ("File1", File1)
+B_File = WgetFile ("File1", File1)
+
+C_File = WgetFile ("File2", File2)
+D_File = WgetFile ("File2", File1)
+
+E_File = WgetFile ("File3", File1)
+
+WGET_OPTIONS = "-c"
+WGET_URLS = [["File1", "File2", "File3"]]
+
+Files = [[A_File, C_File, E_File]]
+Existing_Files = [B_File, D_File]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [B_File, D_File, E_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-504.py b/testenv/Test-504.py
new file mode 100755
index 0000000..036f85d
--- /dev/null
+++ b/testenv/Test-504.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures that Wget handles a 504 Gateway Timeout response
+ correctly.
+ Since, we do not have a direct mechanism for conditionally sending responses
+ via the HTTP Server, I've used a workaround.
+ The server will always respond to a request for File1 with a 504 Gateway
+ Timeout. Using the --tries=2 option, we ensure that Wget attempts the file
+ only twice and then move on to the next file. Finally, check the exact
+ requests that the Server received and compare them, in order, to the
+ expected sequence of requests.
+
+ In this case, we expect Wget to attempt File1 twice and File2 once. If Wget
+ considered 504 as a general Server Error, it would be a fatal failure and
+ Wget would request File1 only once.
+"""
+############# File Definitions ###############################################
+File1 = """All happy families are alike;
+Each unhappy family is unhappy in its own way"""
+File2 = "Anyone for chocochip cookies?"
+
+File1_rules = {
+ "Response" : 504
+}
+
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+B_File = WgetFile ("File2", File2)
+
+Request_List = [
+ [
+ "GET /File1",
+ "GET /File1",
+ "GET /File2",
+ ]
+]
+
+
+WGET_OPTIONS = "--tries=2"
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+
+ExpectedReturnCode = 4
+ExpectedDownloadedFiles = [B_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode,
+ "FilesCrawled" : Request_List
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-Content-disposition-2.py b/testenv/Test-Content-disposition-2.py
new file mode 100755
index 0000000..debd833
--- /dev/null
+++ b/testenv/Test-Content-disposition-2.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures that Wget parses the Content-Disposition header
+ correctly and creates the appropriate file when the said filename exists.
+"""
+############# File Definitions ###############################################
+File1 = "Teapot"
+File2 = "The Teapot Protocol"
+
+# use upper case 'I' to provoke Wget failure with turkish locale
+File2_rules = {
+ "SendHeader" : {
+ "Content-DIsposition" : "Attachment; FILENAME=HTTP.Teapot"
+ }
+}
+A_File = WgetFile ("HTTP.Teapot", File1)
+B_File = WgetFile ("File2", File2, rules=File2_rules)
+
+WGET_OPTIONS = "--content-disposition"
+WGET_URLS = [["File2"]]
+
+Files = [[B_File]]
+Existing_Files = [A_File]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [WgetFile ("HTTP.Teapot.1", File2), A_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-Content-disposition.py b/testenv/Test-Content-disposition.py
new file mode 100755
index 0000000..3ee7be8
--- /dev/null
+++ b/testenv/Test-Content-disposition.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures that Wget parses the Content-Disposition header
+ correctly and creates a local file accordingly.
+"""
+############# File Definitions ###############################################
+File1 = """All that is gold does not glitter,
+ Not all those who wander are lost;
+ The old that is strong does not wither,
+ Deep roots are not reached by the frost.
+ From the ashes a fire shall be woken,
+ A light from the shadows shall spring;
+ Renewed shall be blade that was broken,
+ The crownless again shall be king."""
+
+File1_rules = {
+ "SendHeader" : {
+ "Content-Disposition" : "Attachment; filename=JRR.Tolkien"
+ }
+}
+A_File = WgetFile ("LOTR", File1, rules=File1_rules)
+
+WGET_OPTIONS = "--content-disposition"
+WGET_URLS = [["LOTR"]]
+
+Files = [[A_File]]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [WgetFile ("JRR.Tolkien", File1)]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-Head.py b/testenv/Test-Head.py
new file mode 100755
index 0000000..b653b2d
--- /dev/null
+++ b/testenv/Test-Head.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures that Wget correctly handles responses to HEAD requests
+ and does not actually download any data
+"""
+############# File Definitions ###############################################
+File1 = "You shall not pass!"
+
+A_File = WgetFile ("File1", File1)
+
+WGET_OPTIONS = "--method=HEAD"
+WGET_URLS = [["File1"]]
+
+Files = [[A_File]]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = []
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-O.py b/testenv/Test-O.py
new file mode 100755
index 0000000..f93e118
--- /dev/null
+++ b/testenv/Test-O.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures that Wget correctly handles the -O command for output
+ filenames.
+"""
+############# File Definitions ###############################################
+File1 = "Test Contents."
+
+A_File = WgetFile ("File1", File1)
+
+WGET_OPTIONS = "-O NewFile.txt"
+WGET_URLS = [["File1"]]
+
+Files = [[A_File]]
+ExistingFiles = [A_File]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [WgetFile ("NewFile.txt", File1)]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-Post.py b/testenv/Test-Post.py
new file mode 100755
index 0000000..b2fa7d7
--- /dev/null
+++ b/testenv/Test-Post.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ Simple test for HTTP POST Requests usiong the --method command
+"""
+############# File Definitions ###############################################
+File1 = """A reader lives a thousand lives before he dies, said Jojen.
+The man who never reads lives only one"""
+
+File1_response = """A reader lives a thousand lives before he dies, said Jojen.
+The man who never reads lives only one
+TestMessage"""
+
+A_File = WgetFile ("File1", File1)
+
+WGET_OPTIONS = "--method=post --body-data=TestMessage"
+WGET_URLS = [["File1"]]
+
+Files = [[A_File]]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [WgetFile ("File1", File1_response)]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-auth-basic-fail.py b/testenv/Test-auth-basic-fail.py
new file mode 100755
index 0000000..7b4a223
--- /dev/null
+++ b/testenv/Test-auth-basic-fail.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures that Wget returns the correct exit code when Basic
+ authentication fails due to a username/password error.
+"""
+############# File Definitions ###############################################
+File1 = "I am an invisible man."
+
+File1_rules = {
+ "Authentication" : {
+ "Type" : "Basic",
+ "User" : "Sauron",
+ "Pass" : "TheEye"
+ }
+}
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+
+WGET_OPTIONS = "--user=Sauron --password=Eye"
+WGET_URLS = [["File1"]]
+
+Files = [[A_File]]
+
+ExpectedReturnCode = 6
+ExpectedDownloadedFiles = []
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-auth-basic-netrc-pass-given.py b/testenv/Test-auth-basic-netrc-pass-given.py
new file mode 100755
index 0000000..b8bff59
--- /dev/null
+++ b/testenv/Test-auth-basic-netrc-pass-given.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures Wget uses credentials from .netrc for Basic Authorization Negotiation.
+ In this case we test that .netrc credentials are used in case only
+ password is given on the command line.
+ Also, we ensure that Wget saves the host after a successful auth and
+ doesn't wait for a challenge the second time.
+"""
+############# File Definitions ###############################################
+File1 = "I am an invisible man."
+File2 = "I too am an invisible man."
+
+User = "Sauron"
+Password = "TheEye"
+
+File1_rules = {
+ "Authentication" : {
+ "Type" : "Basic",
+ "User" : User,
+ "Pass" : Password
+ }
+}
+File2_rules = {
+ "ExpectHeader" : {
+ "Authorization" : "Basic U2F1cm9uOlRoZUV5ZQ=="
+ }
+}
+
+Netrc = "machine localhost\n\tlogin {0}".format(User)
+
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+B_File = WgetFile ("File2", File2, rules=File2_rules)
+Netrc_File = WgetFile (".netrc", Netrc)
+
+WGET_OPTIONS = "--password={0}".format(Password)
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+LocalFiles = [Netrc_File]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File, B_File, Netrc_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : LocalFiles
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-auth-basic-netrc-user-given.py b/testenv/Test-auth-basic-netrc-user-given.py
new file mode 100755
index 0000000..e5d1449
--- /dev/null
+++ b/testenv/Test-auth-basic-netrc-user-given.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures Wget uses credentials from .netrc for Basic Authorization Negotiation.
+ In this case we test that .netrc credentials are used in case only
+ user login is given on the command line.
+ Also, we ensure that Wget saves the host after a successful auth and
+ doesn't wait for a challenge the second time.
+"""
+############# File Definitions ###############################################
+File1 = "I am an invisible man."
+File2 = "I too am an invisible man."
+
+User = "Sauron"
+Password = "TheEye"
+
+File1_rules = {
+ "Authentication" : {
+ "Type" : "Basic",
+ "User" : User,
+ "Pass" : Password
+ }
+}
+File2_rules = {
+ "ExpectHeader" : {
+ "Authorization" : "Basic U2F1cm9uOlRoZUV5ZQ=="
+ }
+}
+
+Netrc = "machine localhost\n\tlogin {0}\n\tpassword {1}".format(User, Password)
+
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+B_File = WgetFile ("File2", File2, rules=File2_rules)
+Netrc_File = WgetFile (".netrc", Netrc)
+
+WGET_OPTIONS = "--user={0}".format(User)
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+LocalFiles = [Netrc_File]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File, B_File, Netrc_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : LocalFiles
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-auth-basic-netrc.py b/testenv/Test-auth-basic-netrc.py
new file mode 100755
index 0000000..f670603
--- /dev/null
+++ b/testenv/Test-auth-basic-netrc.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures Wget uses credentials from .netrc for Basic Authorization Negotiation.
+ In this case we test that .netrc credentials are used in case no user
+ login and no password is given on the command line.
+ Also, we ensure that Wget saves the host after a successful auth and
+ doesn't wait for a challenge the second time.
+"""
+############# File Definitions ###############################################
+File1 = "I am an invisible man."
+File2 = "I too am an invisible man."
+
+User = "Sauron"
+Password = "TheEye"
+
+File1_rules = {
+ "Authentication" : {
+ "Type" : "Basic",
+ "User" : User,
+ "Pass" : Password
+ }
+}
+File2_rules = {
+ "ExpectHeader" : {
+ "Authorization" : "Basic U2F1cm9uOlRoZUV5ZQ=="
+ }
+}
+
+Netrc = "machine localhost\n\tlogin {0}\n\tpassword {1}".format(User, Password)
+
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+B_File = WgetFile ("File2", File2, rules=File2_rules)
+Netrc_File = WgetFile (".netrc", Netrc)
+
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+LocalFiles = [Netrc_File]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File, B_File, Netrc_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : LocalFiles
+}
+test_options = {
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-auth-basic-no-netrc-fail.py b/testenv/Test-auth-basic-no-netrc-fail.py
new file mode 100755
index 0000000..1c3a405
--- /dev/null
+++ b/testenv/Test-auth-basic-no-netrc-fail.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures that Wget will not use credentials from .netrc
+ when --no-netrc option is specified and Basic authentication is required
+ and fails.
+"""
+############# File Definitions ###############################################
+File1 = "I am an invisible man."
+
+User = "Sauron"
+Password = "TheEye"
+
+File1_rules = {
+ "Authentication" : {
+ "Type" : "Basic",
+ "User" : User,
+ "Pass" : Password
+ }
+}
+
+Netrc = "machine 127.0.0.1\n\tlogin {0}\n\tpassword {1}".format(User, Password)
+
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+Netrc_File = WgetFile (".netrc", Netrc)
+
+WGET_OPTIONS = "--no-netrc"
+WGET_URLS = [["File1"]]
+
+Files = [[A_File]]
+LocalFiles = [Netrc_File]
+
+ExpectedReturnCode = 6
+ExpectedDownloadedFiles = [Netrc_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : LocalFiles
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-auth-basic.py b/testenv/Test-auth-basic.py
new file mode 100755
index 0000000..4f60c30
--- /dev/null
+++ b/testenv/Test-auth-basic.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures Wget's Basic Authorization Negotiation.
+ Also, we ensure that Wget saves the host after a successful auth and
+ doesn't wait for a challenge the second time.
+"""
+############# File Definitions ###############################################
+File1 = "I am an invisible man."
+File2 = "I too am an invisible man."
+
+File1_rules = {
+ "Authentication" : {
+ "Type" : "Basic",
+ "User" : "Sauron",
+ "Pass" : "TheEye"
+ }
+}
+File2_rules = {
+ "ExpectHeader" : {
+ "Authorization" : "Basic U2F1cm9uOlRoZUV5ZQ=="
+ }
+}
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+B_File = WgetFile ("File2", File2, rules=File2_rules)
+
+WGET_OPTIONS = "--user=Sauron --password=TheEye"
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File, B_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-auth-both.py b/testenv/Test-auth-both.py
new file mode 100755
index 0000000..6e5d712
--- /dev/null
+++ b/testenv/Test-auth-both.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures Wget's Basic Authorization Negotiation.
+ Also, we ensure that Wget saves the host after a successful auth and
+ doesn't wait for a challenge the second time.
+"""
+############# File Definitions ###############################################
+File1 = "Would you like some Tea?"
+File2 = "With lemon or cream?"
+File3 = "Sure you're joking Mr. Feynman"
+
+File1_rules = {
+ "Authentication" : {
+ "Type" : "Both",
+ "User" : "Sauron",
+ "Pass" : "TheEye",
+ "Parm" : {
+ "qop" : "auth"
+ }
+ },
+ "RejectHeader" : {
+ "Authorization" : "Basic U2F1cm9uOlRoZUV5ZQ=="
+ }
+}
+File2_rules = {
+ "Authentication" : {
+ "Type" : "Both_inline",
+ "User" : "Sauron",
+ "Pass" : "TheEye",
+ "Parm" : {
+ "qop" : "auth"
+ }
+ },
+ "RejectHeader" : {
+ "Authorization" : "Basic U2F1cm9uOlRoZUV5ZQ=="
+ }
+}
+File3_rules = {
+ "Authentication" : {
+ "Type" : "Digest",
+ "User" : "Sauron",
+ "Pass" : "TheEye",
+ "Parm" : {
+ "qop" : "auth"
+ }
+
+ }
+}
+
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+B_File = WgetFile ("File2", File2, rules=File2_rules)
+C_File = WgetFile ("File3", File3, rules=File3_rules)
+
+WGET_OPTIONS = "--user=Sauron --password=TheEye"
+WGET_URLS = [["File1", "File2", "File3"]]
+
+Files = [[A_File, B_File, C_File]]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File, B_File, C_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-auth-digest.py b/testenv/Test-auth-digest.py
new file mode 100755
index 0000000..a5e624f
--- /dev/null
+++ b/testenv/Test-auth-digest.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures Wget's Digest Authorization Negotiation.
+"""
+############# File Definitions ###############################################
+File1 = "Need a cookie?"
+File2 = "Want cookies with milk!"
+
+File1_rules = {
+ "Authentication" : {
+ "Type" : "Digest",
+ "User" : "Pacman",
+ "Pass" : "Omnomnom",
+ "Parm" : {
+ "qop" : "auth"
+ }
+ }
+}
+
+File2_rules = {
+ "Authentication" : {
+ "Type" : "Digest",
+ "User" : "Pacman",
+ "Pass" : "Omnomnom",
+ "Parm" : {
+ "qop" : None
+ }
+ }
+}
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+B_File = WgetFile ("File2", File2, rules=File2_rules)
+
+WGET_OPTIONS = "--user=Pacman --password=Omnomnom"
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File, B_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-auth-no-challenge-url.py b/testenv/Test-auth-no-challenge-url.py
new file mode 100755
index 0000000..6025232
--- /dev/null
+++ b/testenv/Test-auth-no-challenge-url.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures Wget's Basic Authorization Negotiation, when credentials
+ are provided in-URL
+"""
+############# File Definitions ###############################################
+File1 = "Need a cookie?"
+
+File1_rules = {
+ "Authentication" : {
+ "Type" : "Basic",
+ "User" : "Pacman",
+ "Pass" : "Omnomnom"
+ },
+ "ExpectHeader" : {
+ "Authorization" : "Basic UGFjbWFuOk9tbm9tbm9t"
+ }
+}
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+
+WGET_OPTIONS = "--auth-no-challenge http://Pacman:Omnomnom@localhost:{{port}}/File1"
+WGET_URLS = [[]]
+
+Files = [[A_File]]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-auth-no-challenge.py b/testenv/Test-auth-no-challenge.py
new file mode 100755
index 0000000..2022ac8
--- /dev/null
+++ b/testenv/Test-auth-no-challenge.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures Wget's Basic Authorization Negotiation, when the
+ --auth-no-challenge command is used.
+"""
+############# File Definitions ###############################################
+File1 = "Need a cookie?"
+
+File1_rules = {
+ "Authentication" : {
+ "Type" : "Basic",
+ "User" : "Pacman",
+ "Pass" : "Omnomnom"
+ },
+ "ExpectHeader" : {
+ "Authorization" : "Basic UGFjbWFuOk9tbm9tbm9t"
+ }
+}
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+
+WGET_OPTIONS = "--auth-no-challenge --user=Pacman --password=Omnomnom"
+WGET_URLS = [["File1"]]
+
+Files = [[A_File]]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-auth-retcode.py b/testenv/Test-auth-retcode.py
new file mode 100755
index 0000000..6414b5b
--- /dev/null
+++ b/testenv/Test-auth-retcode.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures that Wget returns the correct return code when sent
+ a 403 Forbidden by the Server.
+"""
+
+
+############# File Definitions ###############################################
+File1 = "Apples and Oranges? Really?"
+
+File1_rules = {
+ "Response" : 403
+}
+
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+
+WGET_OPTIONS = ""
+WGET_URLS = [["File1"]]
+
+Files = [[A_File]]
+
+ExpectedReturnCode = 8
+ExpectedDownloadedFiles = []
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-auth-with-content-disposition.py b/testenv/Test-auth-with-content-disposition.py
new file mode 100755
index 0000000..074b093
--- /dev/null
+++ b/testenv/Test-auth-with-content-disposition.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures that Wget handles Content-Disposition correctly when
+ coupled with Authentication
+"""
+############# File Definitions ###############################################
+File1 = "Need a cookie?"
+
+File1_rules = {
+ "Authentication" : {
+ "Type" : "Basic",
+ "User" : "Pacman",
+ "Pass" : "Omnomnom"
+ },
+ "SendHeader" : {
+ "Content-Disposition" : "Attachment; filename=Arch"
+ }
+}
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+
+WGET_OPTIONS = "--user=Pacman --password=Omnomnom --content-disposition"
+WGET_URLS = [["File1"]]
+
+Files = [[A_File]]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [WgetFile ("Arch", File1)]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-c-full.py b/testenv/Test-c-full.py
new file mode 100755
index 0000000..ada3c04
--- /dev/null
+++ b/testenv/Test-c-full.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ Test Wget's response when the file requested already exists on disk with
+ a filesize greater than or equal to the requested file.
+"""
+############# File Definitions ###############################################
+File1 = "abababababababababababababababababababababababababababababababababab"
+File2 = "ababababababababababababababababababab"
+
+A_File = WgetFile ("File1", File1)
+B_File = WgetFile ("File1", File1)
+
+C_File = WgetFile ("File2", File1)
+D_File = WgetFile ("File2", File2)
+
+E_File = WgetFile ("File3", File1)
+
+WGET_OPTIONS = "-c"
+WGET_URLS = [["File1", "File2", "File3"]]
+
+Files = [[A_File, C_File, E_File]]
+Existing_Files = [B_File, D_File]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File, C_File, E_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-condget.py b/testenv/Test-condget.py
new file mode 100755
index 0000000..a192f92
--- /dev/null
+++ b/testenv/Test-condget.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ Simple test for HTTP Conditional-GET Requests using the -N command
+"""
+############# File Definitions ###############################################
+# Keep same length !
+Cont1 = """THIS IS 1 FILE"""
+Cont2 = """THIS IS 2 FILE"""
+Cont3 = """THIS IS 3 FILE"""
+Cont4 = """THIS IS 4 FILE"""
+
+# Local Wget files
+
+# These have same timestamp as remote files
+UpToDate_Local_File1 = WgetFile ("UpToDateFile1", Cont1, timestamp="1995-01-01 00:00:00")
+UpToDate_Local_File2 = WgetFile ("UpToDateFile2", Cont1, timestamp="1995-01-01 00:00:00")
+UpToDate_Local_File3 = WgetFile ("UpToDateFile3", Cont1, timestamp="1995-01-01 00:00:00")
+
+# This is newer than remote (expected same behaviour as for above files)
+Newer_Local_File = WgetFile ("NewerFile", Cont1, timestamp="1995-02-02 02:02:02")
+
+# This is older than remote - should be clobbered
+Outdated_Local_File = WgetFile ("UpdatedFile", Cont2, timestamp="1990-01-01 00:00:00")
+
+UpToDate_Rules1 = {
+ "SendHeader" : {
+ # RFC1123 format
+ "Last-Modified" : "Sun, 01 Jan 1995 00:00:00 GMT",
+ },
+ "Response": 304,
+ "ExpectHeader" : {
+ "If-Modified-Since" : "Sun, 01 Jan 1995 00:00:00 GMT"
+ },
+}
+
+UpToDate_Rules2 = {
+ "SendHeader" : {
+ # RFC850 format
+ "Last-Modified" : "Sunday, 01-Jan-95 00:00:00 GMT",
+ },
+ "Response": 304,
+ "ExpectHeader" : {
+ "If-Modified-Since" : "Sun, 01 Jan 1995 00:00:00 GMT"
+ },
+}
+
+UpToDate_Rules3 = {
+ "SendHeader" : {
+ # Asctime format
+ "Last-Modified" : "Sun Jan 01 00:00:00 1995",
+ },
+ "Response": 304,
+ "ExpectHeader" : {
+ "If-Modified-Since" : "Sun, 01 Jan 1995 00:00:00 GMT"
+ },
+}
+
+Newer_Rules = {
+ "SendHeader" : {
+ # Asctime format
+ "Last-Modified" : "Sun Jan 01 00:00:00 1995",
+ },
+ "Response": 304,
+ "ExpectHeader" : {
+ "If-Modified-Since" : "Thu, 02 Feb 1995 02:02:02 GMT"
+ },
+}
+
+Outdated_Rules = {
+ "SendHeader" : {
+ # RFC850 format
+ "Last-Modified" : "Thursday, 01-Jan-15 00:00:00 GMT",
+ },
+ "ExpectHeader" : {
+ "If-Modified-Since" : "Mon, 01 Jan 1990 00:00:00 GMT",
+ },
+}
+
+UpToDate_Server_File1 = WgetFile ("UpToDateFile1", Cont3, rules=UpToDate_Rules1)
+UpToDate_Server_File2 = WgetFile ("UpToDateFile2", Cont3, rules=UpToDate_Rules2)
+UpToDate_Server_File3 = WgetFile ("UpToDateFile3", Cont3, rules=UpToDate_Rules3)
+Newer_Server_File = WgetFile ("NewerFile", Cont3, rules=Newer_Rules)
+Updated_Server_File = WgetFile ("UpdatedFile", Cont4, rules=Outdated_Rules)
+
+WGET_OPTIONS = "-N"
+WGET_URLS = [["UpToDateFile1", "UpToDateFile2", "UpToDateFile3", "NewerFile",
+ "UpdatedFile", ]]
+
+Files = [[UpToDate_Server_File1, UpToDate_Server_File2, UpToDate_Server_File3,
+ Newer_Server_File, Updated_Server_File, ]]
+
+Existing_Files = [UpToDate_Local_File1, UpToDate_Local_File2,
+ UpToDate_Local_File3, Newer_Local_File, Outdated_Local_File]
+
+ExpectedReturnCode = 0
+
+# The up-to-date file should not be downloaded
+ExpectedDownloadedFiles = [UpToDate_Local_File1, UpToDate_Local_File2,
+ UpToDate_Local_File3, Newer_Local_File,
+ Updated_Server_File]
+
+# Kind of hack to ensure proper request types
+Request_List = [
+ [
+ "GET /UpToDateFile1",
+ "GET /UpToDateFile2",
+ "GET /UpToDateFile3",
+ "GET /NewerFile",
+ "GET /UpdatedFile",
+ ]
+]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode,
+ "FilesCrawled" : Request_List,
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-cookie-401.py b/testenv/Test-cookie-401.py
new file mode 100755
index 0000000..b6ad5b8
--- /dev/null
+++ b/testenv/Test-cookie-401.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures that Wget stores the cookie even in the event of a
+ 401 Unauthorized Response
+"""
+############# File Definitions ###############################################
+File1 = """All happy families are alike;
+Each unhappy family is unhappy in its own way"""
+File2 = "Anyone for chocochip cookies?"
+
+File1_rules = {
+ "SendHeader" : {
+ "Set-Cookie" : "sess-id=0213; path=/"
+ },
+ "Response" : 401
+}
+File2_rules = {
+ "ExpectHeader" : {
+ "Cookie" : "sess-id=0213"
+ },
+}
+
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+B_File = WgetFile ("File2", File2, rules=File2_rules)
+
+WGET_OPTIONS = ""
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+
+ExpectedReturnCode = 6
+ExpectedDownloadedFiles = [B_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-cookie-domain-mismatch.py b/testenv/Test-cookie-domain-mismatch.py
new file mode 100755
index 0000000..06a9b69
--- /dev/null
+++ b/testenv/Test-cookie-domain-mismatch.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures that Wget identifies bad servers trying to set cookies
+ for a different domain and rejects them.
+"""
+############# File Definitions ###############################################
+File1 = "Would you care for a cup of coffee?"
+File2 = "Anyone for chocochip cookies?"
+
+File1_rules = {
+ "SendHeader" : {
+ # use upper case 'I' to provoke Wget failure with turkish locale
+ "Set-Cookie" : "sess-id=0213; path=/; DoMAIn=.example.com"
+ }
+}
+File2_rules = {
+ "RejectHeader" : {
+ "Cookie" : "sess-id=0213"
+ }
+}
+
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+B_File = WgetFile ("File2", File2, rules=File2_rules)
+
+WGET_OPTIONS = ""
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File, B_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-cookie-expires.py b/testenv/Test-cookie-expires.py
new file mode 100755
index 0000000..16fb980
--- /dev/null
+++ b/testenv/Test-cookie-expires.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures that Wget handles Cookie expiry dates correctly.
+ Simultaneuously, we also check if multiple cookies to the same domain
+ are handled correctly
+"""
+############# File Definitions ###############################################
+File1 = "Hello World!"
+File2 = "'Ello! This is Amazing!"
+File3 = "So what are we looking at?"
+File4 = "This was downloaded"
+
+File1_rules = {
+ "SendHeader" : {
+ "Set-Cookie" : "sess-id=0213; path=/"
+ }
+}
+File2_rules = {
+ "ExpectHeader" : {
+ "Cookie" : "sess-id=0213"
+ },
+ "SendHeader" : {
+ "Set-Cookie" : "new-sess=N"
+ }
+}
+File3_rules = {
+ "SendHeader" : {
+ # use upper case 'I' to provoke Wget failure with turkish locale
+ "Set-Cookie" : "sess-id=0213; path=/; ExPIRes=Sun, 06 Nov 2001 12:32:43 GMT"
+ },
+ "ExpectHeader" : {
+ "Cookie" : "new-sess=N; sess-id=0213"
+ }
+}
+File4_rules = {
+ "RejectHeader" : {
+ "Cookie" : "sess-id=0213"
+ },
+ "ExpectHeader" : {
+ "Cookie" : "new-sess=N"
+ }
+}
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+B_File = WgetFile ("File2", File2, rules=File2_rules)
+C_File = WgetFile ("File3", File3, rules=File3_rules)
+D_File = WgetFile ("File4", File4, rules=File4_rules)
+
+WGET_OPTIONS = ""
+WGET_URLS = [["File1", "File2", "File3", "File4"]]
+
+Files = [[A_File, B_File, C_File, D_File]]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File, B_File, C_File, D_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-cookie.py b/testenv/Test-cookie.py
new file mode 100755
index 0000000..ba6c055
--- /dev/null
+++ b/testenv/Test-cookie.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures that Wget's cookie jar support works correctly.
+"""
+############# File Definitions ###############################################
+File1 = """All happy families are alike;
+Each unhappy family is unhappy in its own way"""
+File2 = "Anyone for chocochip cookies?"
+
+File1_rules = {
+ "SendHeader" : {
+ "Set-Cookie" : "sess-id=0213; path=/"
+ }
+}
+File2_rules = {
+ "ExpectHeader" : {
+ "Cookie" : "sess-id=0213"
+ }
+}
+
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+B_File = WgetFile ("File2", File2, rules=File2_rules)
+
+WGET_OPTIONS = ""
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File, B_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-hsts.py b/testenv/Test-hsts.py
new file mode 100755
index 0000000..19bd4c4
--- /dev/null
+++ b/testenv/Test-hsts.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from test.base_test import HTTPS, SKIP_TEST
+from misc.wget_file import WgetFile
+import time
+import os
+
+"""
+This test makes sure Wget can parse a given HSTS database and apply the indicated HSTS policy.
+"""
+
+print (os.getenv('SSL_TESTS'))
+if os.getenv('SSL_TESTS') is None:
+ exit (SKIP_TEST)
+
+def hsts_database_path():
+ hsts_file = ".wget-hsts-testenv"
+ return os.path.abspath(hsts_file)
+
+def create_hsts_database(path, host, port):
+ # we want the current time as an integer,
+ # not as a floating point
+ curtime = int(time.time())
+ max_age = "123456"
+
+ f = open(path, "w")
+
+ f.write("# dummy comment\n")
+ f.write(host + "\t" + str(port) + "\t0\t" + str(curtime) + "\t" + max_age + "\n")
+ f.close()
+
+File_Name = "hw"
+File_Content = "Hello, world!"
+File = WgetFile(File_Name, File_Content)
+
+Hsts_File_Path = hsts_database_path()
+
+CAFILE = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs', 'ca-cert.pem'))
+
+WGET_OPTIONS = "--hsts-file=" + Hsts_File_Path + " --ca-certificate=" + CAFILE
+WGET_URLS = [[File_Name]]
+
+Files = [[File]]
+Servers = [HTTPS]
+Requests = ["http"]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [File]
+
+pre_test = {
+ "ServerFiles" : Files,
+ "Domains" : ["localhost"]
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetCode" : ExpectedReturnCode,
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+
+test = HTTPTest(
+ pre_hook = pre_test,
+ post_hook = post_test,
+ test_params = test_options,
+ protocols = Servers,
+ req_protocols = Requests
+)
+
+# start the web server and create the temporary HSTS database
+test.setup()
+create_hsts_database(Hsts_File_Path, 'localhost', test.port)
+
+err = test.begin()
+
+# remove the temporary HSTS database
+os.unlink(hsts_database_path())
+exit(err)
diff --git a/testenv/Test-metalink-http-baddigest.py b/testenv/Test-metalink-http-baddigest.py
new file mode 100755
index 0000000..2496da7
--- /dev/null
+++ b/testenv/Test-metalink-http-baddigest.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+import hashlib
+from base64 import b64encode
+
+"""
+ This is to test Metalink/HTTP with a malformed base64 Digest header.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+bad = "Ouch!"
+bad_sha256 = b64encode (hashlib.sha256 (bad.encode ('UTF-8')).digest ()).decode ('ascii')
+
+LinkHeaders = ["<http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file>; rel=duplicate; pri=1"]
+DigestHeader = "SHA-256=bad_base64,SHA-256={{BAD_HASH}}"
+
+# This will be filled as soon as we know server hostname and port
+MetaHTTPRules = {'SendHeader' : {}}
+
+MetaHTTP = WgetFile ("main.metalink", rules=MetaHTTPRules)
+
+wrong_file = WgetFile ("wrong_file", bad)
+wrong_file_down = WgetFile ("main.metalink", bad)
+
+WGET_OPTIONS = "--metalink-over-http"
+WGET_URLS = [["main.metalink"]]
+
+RequestList = [[
+ "HEAD /main.metalink",
+ "GET /wrong_file"
+]]
+
+Files = [[
+ MetaHTTP,
+ wrong_file
+]]
+Existing_Files = []
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [wrong_file_down]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode,
+ "FilesCrawled" : RequestList
+}
+
+http_test = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+)
+
+http_test.server_setup()
+### Get and use dynamic server sockname
+srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
+
+DigestHeader = DigestHeader.replace('{{BAD_HASH}}', bad_sha256)
+
+# Helper function for hostname, port and digest substitution
+def SubstituteServerInfo (text, host, port):
+ text = text.replace('{{SRV_HOST}}', host)
+ text = text.replace('{{SRV_PORT}}', str (port))
+ return text
+
+MetaHTTPRules["SendHeader"] = {
+ 'Link': [ SubstituteServerInfo (LinkHeader, srv_host, srv_port)
+ for LinkHeader in LinkHeaders ],
+ 'Digest': DigestHeader
+}
+
+err = http_test.begin ()
+
+exit (err)
diff --git a/testenv/Test-metalink-http-quoted.py b/testenv/Test-metalink-http-quoted.py
new file mode 100755
index 0000000..af2c445
--- /dev/null
+++ b/testenv/Test-metalink-http-quoted.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+import hashlib
+from base64 import b64encode
+
+"""
+ This is to test Metalink/HTTP quoted values support in Wget.
+"""
+
+# Helper function for hostname, port and digest substitution
+def SubstituteServerInfo (text, host, port, digest):
+ text = text.replace('{{FILE1_HASH}}', digest)
+ text = text.replace('{{SRV_HOST}}', host)
+ text = text.replace('{{SRV_PORT}}', str (port))
+ return text
+
+############# File Definitions ###############################################
+File1 = "Would you like some Tea?"
+File1_corrupted = "Would you like some Coffee?"
+File1_lowPref = "Do not take this"
+File1_sha256 = b64encode (hashlib.sha256 (File1.encode ('UTF-8')).digest ()).decode ('ascii')
+Signature = '''-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.0.7 (GNU/Linux)
+
+This is no valid signature. But it should be downloaded.
+The attempt to verify should fail but should not prevent
+a successful metalink resource retrieval (the sig failure
+should not be fatal).
+-----END PGP SIGNATURE-----
+'''
+File2 = "No meta data for this file."
+
+LinkHeaders = [
+ # This file has low priority and should not be picked.
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_lowPref>; rel=\"duplicate\"; pri=\"9\"; geo=\"pl\"",
+ # This file should be picked second, after hash failure.
+ "<http://0.0.0.0/File1_try2_badconnection>; rel =\"duplicate\";pref; pri=\"7\"",
+ # This signature download will fail.
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/Sig2.asc>; rel=\"describedby\"; type=\"application/pgp-signature\"",
+ # Two good signatures
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/Sig.asc>; rel=\"describedby\"; type=\"application/pgp-signature\"",
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/Sig.asc>; rel=\"describedby\"; type=\"application/pgp-signature\"",
+ # Bad URL scheme
+ "<invalid_url>; rel=\"duplicate\"; pri=\"4\"",
+ # rel missing
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/File1>; pri=\"1\"; pref",
+ # invalid rel
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/File1>; rel=\"strange\"; pri=\"4\"",
+ # This file should be picked first, because it has the lowest pri among preferred.
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_try1_corrupted>; rel=\"duplicate\"; geo=\"su\"; pri=\"4\"; pref",
+ # This file should NOT be picked third due to preferred location set to 'uk'
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_badgeo>; rel =\"duplicate\";pri=\"5\"",
+ # This file should be picked as third try, and it should succeed
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_try3_ok>; rel=\'duplicate\'; pri=\"5\";geo=\"uk\""
+ ]
+DigestHeader = "SHA-256=\'{{FILE1_HASH}}\'"
+
+# This will be filled as soon as we know server hostname and port
+MetaFileRules = {'SendHeader' : {}}
+
+FileOkServer = WgetFile ("File1_try3_ok", File1)
+FileBadPref = WgetFile ("File1_lowPref", File1_lowPref)
+FileBadHash = WgetFile ("File1_try1_corrupted", File1_corrupted)
+MetaFile = WgetFile ("test.meta", rules=MetaFileRules)
+# In case of Metalink over HTTP, the local file name is
+# derived from the URL suffix.
+FileOkLocal = WgetFile ("test.meta", File1)
+SigFile = WgetFile ("Sig.asc", Signature)
+FileNoMeta = WgetFile ("File2", File2)
+
+WGET_OPTIONS = "--metalink-over-http --preferred-location=uk"
+WGET_URLS = [["test.meta", "File2"]]
+
+Files = [[FileOkServer, FileBadPref, FileBadHash, MetaFile, SigFile, FileNoMeta]]
+Existing_Files = []
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [FileNoMeta, FileOkLocal]
+
+RequestList = [
+ [
+ "HEAD /test.meta",
+ "GET /Sig2.asc",
+ "GET /Sig.asc",
+ "GET /File1_try1_corrupted",
+ "GET /File1_try3_ok",
+ "HEAD /File2",
+ "GET /File2",
+ ]
+]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode,
+ "FilesCrawled" : RequestList,
+}
+
+http_test = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+)
+
+http_test.server_setup()
+srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
+
+MetaFileRules["SendHeader"] = {
+ 'Link': [ SubstituteServerInfo (LinkHeader, srv_host, srv_port, File1_sha256)
+ for LinkHeader in LinkHeaders ],
+ 'Digest': SubstituteServerInfo (DigestHeader, srv_host, srv_port, File1_sha256),
+}
+
+err = http_test.begin ()
+
+exit (err)
diff --git a/testenv/Test-metalink-http-xml-trust-name.py b/testenv/Test-metalink-http-xml-trust-name.py
new file mode 100755
index 0000000..7dae50e
--- /dev/null
+++ b/testenv/Test-metalink-http-xml-trust-name.py
@@ -0,0 +1,272 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+import hashlib
+from base64 import b64encode
+
+"""
+ This is to test Metalink/HTTP with Metalink/XML Link headers.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+bad = "Ouch!"
+bad_sha256 = hashlib.sha256 (bad.encode ('UTF-8')).hexdigest ()
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+File1_sha256 = hashlib.sha256 (File1.encode ('UTF-8')).hexdigest ()
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+File2_sha256 = hashlib.sha256 (File2.encode ('UTF-8')).hexdigest ()
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+File3_sha256 = hashlib.sha256 (File3.encode ('UTF-8')).hexdigest ()
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+File4_sha256 = hashlib.sha256 (File4.encode ('UTF-8')).hexdigest ()
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+File5_sha256 = hashlib.sha256 (File5.encode ('UTF-8')).hexdigest ()
+
+MetaXml1 = \
+"""<?xml version="1.0" encoding="utf-8"?>
+<metalink version="3.0" xmlns="http://www.metalinker.org/">
+ <publisher>
+ <name>GNU Wget</name>
+ </publisher>
+ <license>
+ <name>GNU GPL</name>
+ <url>http://www.gnu.org/licenses/gpl.html</url>
+ </license>
+ <identity>Wget Test Files</identity>
+ <version>1.2.3</version>
+ <description>Wget Test Files description</description>
+ <files>
+ <file name="dir/File1">
+ <verification>
+ <hash type="sha256">{{FILE1_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File1_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File1</url>
+ </resources>
+ </file>
+ <file name="dir/File2">
+ <verification>
+ <hash type="sha256">{{FILE2_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File2_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File2</url>
+ </resources>
+ </file>
+ <file name="/dir/File3"> <!-- rejected by libmetalink -->
+ <verification>
+ <hash type="sha256">{{FILE3_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File3_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File3</url>
+ </resources>
+ </file>
+ <file name="dir/File4">
+ <verification>
+ <hash type="sha256">{{FILE4_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File4_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File4</url>
+ </resources>
+ </file>
+ <file name="dir/File5">
+ <verification>
+ <hash type="sha256">{{FILE5_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File5_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File5</url>
+ </resources>
+ </file>
+ </files>
+</metalink>
+"""
+
+MetaXml2 = \
+"""<?xml version="1.0" encoding="utf-8"?>
+<metalink version="3.0" xmlns="http://www.metalinker.org/">
+ <publisher>
+ <name>GNU Wget</name>
+ </publisher>
+ <license>
+ <name>GNU GPL</name>
+ <url>http://www.gnu.org/licenses/gpl.html</url>
+ </license>
+ <identity>Wget Test Files</identity>
+ <version>1.2.3</version>
+ <description>Wget Test Files description</description>
+ <files>
+ <file name="bad">
+ <verification>
+ <hash type="sha256">{{BAD_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/bad</url>
+ </resources>
+ </file>
+ </files>
+</metalink>
+"""
+
+LinkHeaders = [
+ # This file has the lowest priority, and should go last
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/test1.metalink>; rel=describedby; pri=2; type=\"application/metalink4+xml\"; name=\"newname.metalink\"",
+ # This file has the highest priority, and should go first
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/test2.metalink>; rel=describedby; pri=1; type=\"application/metalink4+xml\""
+]
+
+# This will be filled as soon as we know server hostname and port
+MetaHTTPRules = {'SendHeader' : {}}
+
+MetaHTTP = WgetFile ("main.metalink", rules=MetaHTTPRules)
+
+wrong_file = WgetFile ("wrong_file", bad)
+
+File1_orig = WgetFile ("File1", File1)
+File1_down = WgetFile ("dir/File1", File1)
+File1_nono = WgetFile ("File1_lowPref", File1_lowPref)
+
+File2_orig = WgetFile ("File2", File2)
+File2_down = WgetFile ("dir/File2", File2)
+File2_nono = WgetFile ("File2_lowPref", File2_lowPref)
+
+# rejected by libmetalink
+File3_orig = WgetFile ("File3", File3)
+File3_nono = WgetFile ("File3_lowPref", File3_lowPref)
+
+File4_orig = WgetFile ("File4", File4)
+File4_down = WgetFile ("dir/File4", File4)
+File4_nono = WgetFile ("File4_lowPref", File4_lowPref)
+
+File5_orig = WgetFile ("File5", File5)
+File5_down = WgetFile ("dir/File5", File5)
+File5_nono = WgetFile ("File5_lowPref", File5_lowPref)
+
+MetaFile1 = WgetFile ("test1.metalink", MetaXml1)
+MetaFile1_down = WgetFile ("newname.metalink", MetaXml1)
+
+MetaFile2 = WgetFile ("test2.metalink", MetaXml2)
+
+WGET_OPTIONS = "--trust-server-names --metalink-over-http --metalink-index=2"
+WGET_URLS = [["main.metalink"]]
+
+RequestList = [[
+ "HEAD /main.metalink",
+ "GET /404",
+ "GET /wrong_file",
+ "GET /test1.metalink",
+ "GET /File1",
+ "GET /File2",
+ "GET /File4",
+ "GET /File5"
+]]
+
+Files = [[
+ MetaHTTP,
+ wrong_file,
+ MetaFile1, MetaFile2,
+ File1_orig, File1_nono,
+ File2_orig, File2_nono,
+ File3_orig, File3_nono,
+ File4_orig, File4_nono,
+ File5_orig, File5_nono
+]]
+Existing_Files = []
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [
+ MetaFile1_down,
+ File1_down,
+ File2_down,
+ File4_down,
+ File5_down
+]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode,
+ "FilesCrawled" : RequestList
+}
+
+http_test = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+)
+
+http_test.server_setup()
+### Get and use dynamic server sockname
+srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
+
+MetaXml1 = MetaXml1.replace('{{FILE1_HASH}}', File1_sha256)
+MetaXml1 = MetaXml1.replace('{{FILE2_HASH}}', File2_sha256)
+MetaXml1 = MetaXml1.replace('{{FILE3_HASH}}', File3_sha256)
+MetaXml1 = MetaXml1.replace('{{FILE4_HASH}}', File4_sha256)
+MetaXml1 = MetaXml1.replace('{{FILE5_HASH}}', File5_sha256)
+MetaXml1 = MetaXml1.replace('{{SRV_HOST}}', srv_host)
+MetaXml1 = MetaXml1.replace('{{SRV_PORT}}', str (srv_port))
+MetaFile1.content = MetaXml1
+MetaFile1_down.content = MetaXml1
+
+MetaXml2 = MetaXml2.replace('{{BAD_HASH}}', bad_sha256)
+MetaXml2 = MetaXml2.replace('{{SRV_HOST}}', srv_host)
+MetaXml2 = MetaXml2.replace('{{SRV_PORT}}', str (srv_port))
+MetaFile2.content = MetaXml2
+
+# Helper function for hostname, port and digest substitution
+def SubstituteServerInfo (text, host, port):
+ text = text.replace('{{SRV_HOST}}', host)
+ text = text.replace('{{SRV_PORT}}', str (port))
+ return text
+
+MetaHTTPRules["SendHeader"] = {
+ 'Link': [ SubstituteServerInfo (LinkHeader, srv_host, srv_port)
+ for LinkHeader in LinkHeaders ]
+}
+
+err = http_test.begin ()
+
+exit (err)
diff --git a/testenv/Test-metalink-http-xml-trust.py b/testenv/Test-metalink-http-xml-trust.py
new file mode 100755
index 0000000..1df6ce4
--- /dev/null
+++ b/testenv/Test-metalink-http-xml-trust.py
@@ -0,0 +1,272 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+import hashlib
+from base64 import b64encode
+
+"""
+ This is to test Metalink/HTTP with Metalink/XML Link headers.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+bad = "Ouch!"
+bad_sha256 = hashlib.sha256 (bad.encode ('UTF-8')).hexdigest ()
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+File1_sha256 = hashlib.sha256 (File1.encode ('UTF-8')).hexdigest ()
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+File2_sha256 = hashlib.sha256 (File2.encode ('UTF-8')).hexdigest ()
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+File3_sha256 = hashlib.sha256 (File3.encode ('UTF-8')).hexdigest ()
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+File4_sha256 = hashlib.sha256 (File4.encode ('UTF-8')).hexdigest ()
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+File5_sha256 = hashlib.sha256 (File5.encode ('UTF-8')).hexdigest ()
+
+MetaXml1 = \
+"""<?xml version="1.0" encoding="utf-8"?>
+<metalink version="3.0" xmlns="http://www.metalinker.org/">
+ <publisher>
+ <name>GNU Wget</name>
+ </publisher>
+ <license>
+ <name>GNU GPL</name>
+ <url>http://www.gnu.org/licenses/gpl.html</url>
+ </license>
+ <identity>Wget Test Files</identity>
+ <version>1.2.3</version>
+ <description>Wget Test Files description</description>
+ <files>
+ <file name="dir/File1">
+ <verification>
+ <hash type="sha256">{{FILE1_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File1_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File1</url>
+ </resources>
+ </file>
+ <file name="dir/File2">
+ <verification>
+ <hash type="sha256">{{FILE2_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File2_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File2</url>
+ </resources>
+ </file>
+ <file name="/dir/File3"> <!-- rejected by libmetalink -->
+ <verification>
+ <hash type="sha256">{{FILE3_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File3_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File3</url>
+ </resources>
+ </file>
+ <file name="dir/File4">
+ <verification>
+ <hash type="sha256">{{FILE4_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File4_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File4</url>
+ </resources>
+ </file>
+ <file name="dir/File5">
+ <verification>
+ <hash type="sha256">{{FILE5_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File5_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File5</url>
+ </resources>
+ </file>
+ </files>
+</metalink>
+"""
+
+MetaXml2 = \
+"""<?xml version="1.0" encoding="utf-8"?>
+<metalink version="3.0" xmlns="http://www.metalinker.org/">
+ <publisher>
+ <name>GNU Wget</name>
+ </publisher>
+ <license>
+ <name>GNU GPL</name>
+ <url>http://www.gnu.org/licenses/gpl.html</url>
+ </license>
+ <identity>Wget Test Files</identity>
+ <version>1.2.3</version>
+ <description>Wget Test Files description</description>
+ <files>
+ <file name="bad">
+ <verification>
+ <hash type="sha256">{{BAD_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/bad</url>
+ </resources>
+ </file>
+ </files>
+</metalink>
+"""
+
+LinkHeaders = [
+ # This file has the lowest priority, and should go last
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/test1.metalink>; rel=describedby; pri=2; type=\"application/metalink4+xml\"",
+ # This file has the highest priority, and should go first
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/test2.metalink>; rel=describedby; pri=1; type=\"application/metalink4+xml\""
+]
+
+# This will be filled as soon as we know server hostname and port
+MetaHTTPRules = {'SendHeader' : {}}
+
+MetaHTTP = WgetFile ("main.metalink", rules=MetaHTTPRules)
+
+wrong_file = WgetFile ("wrong_file", bad)
+
+File1_orig = WgetFile ("File1", File1)
+File1_down = WgetFile ("dir/File1", File1)
+File1_nono = WgetFile ("File1_lowPref", File1_lowPref)
+
+File2_orig = WgetFile ("File2", File2)
+File2_down = WgetFile ("dir/File2", File2)
+File2_nono = WgetFile ("File2_lowPref", File2_lowPref)
+
+# rejected by libmetalink
+File3_orig = WgetFile ("File3", File3)
+File3_nono = WgetFile ("File3_lowPref", File3_lowPref)
+
+File4_orig = WgetFile ("File4", File4)
+File4_down = WgetFile ("dir/File4", File4)
+File4_nono = WgetFile ("File4_lowPref", File4_lowPref)
+
+File5_orig = WgetFile ("File5", File5)
+File5_down = WgetFile ("dir/File5", File5)
+File5_nono = WgetFile ("File5_lowPref", File5_lowPref)
+
+MetaFile1 = WgetFile ("test1.metalink", MetaXml1)
+MetaFile1_down = WgetFile ("test1.metalink", MetaXml1)
+
+MetaFile2 = WgetFile ("test2.metalink", MetaXml2)
+
+WGET_OPTIONS = "--trust-server-names --metalink-over-http --metalink-index=2"
+WGET_URLS = [["main.metalink"]]
+
+RequestList = [[
+ "HEAD /main.metalink",
+ "GET /404",
+ "GET /wrong_file",
+ "GET /test1.metalink",
+ "GET /File1",
+ "GET /File2",
+ "GET /File4",
+ "GET /File5"
+]]
+
+Files = [[
+ MetaHTTP,
+ wrong_file,
+ MetaFile1, MetaFile2,
+ File1_orig, File1_nono,
+ File2_orig, File2_nono,
+ File3_orig, File3_nono,
+ File4_orig, File4_nono,
+ File5_orig, File5_nono
+]]
+Existing_Files = []
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [
+ MetaFile1_down,
+ File1_down,
+ File2_down,
+ File4_down,
+ File5_down
+]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode,
+ "FilesCrawled" : RequestList
+}
+
+http_test = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+)
+
+http_test.server_setup()
+### Get and use dynamic server sockname
+srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
+
+MetaXml1 = MetaXml1.replace('{{FILE1_HASH}}', File1_sha256)
+MetaXml1 = MetaXml1.replace('{{FILE2_HASH}}', File2_sha256)
+MetaXml1 = MetaXml1.replace('{{FILE3_HASH}}', File3_sha256)
+MetaXml1 = MetaXml1.replace('{{FILE4_HASH}}', File4_sha256)
+MetaXml1 = MetaXml1.replace('{{FILE5_HASH}}', File5_sha256)
+MetaXml1 = MetaXml1.replace('{{SRV_HOST}}', srv_host)
+MetaXml1 = MetaXml1.replace('{{SRV_PORT}}', str (srv_port))
+MetaFile1.content = MetaXml1
+MetaFile1_down.content = MetaXml1
+
+MetaXml2 = MetaXml2.replace('{{BAD_HASH}}', bad_sha256)
+MetaXml2 = MetaXml2.replace('{{SRV_HOST}}', srv_host)
+MetaXml2 = MetaXml2.replace('{{SRV_PORT}}', str (srv_port))
+MetaFile2.content = MetaXml2
+
+# Helper function for hostname, port and digest substitution
+def SubstituteServerInfo (text, host, port):
+ text = text.replace('{{SRV_HOST}}', host)
+ text = text.replace('{{SRV_PORT}}', str (port))
+ return text
+
+MetaHTTPRules["SendHeader"] = {
+ 'Link': [ SubstituteServerInfo (LinkHeader, srv_host, srv_port)
+ for LinkHeader in LinkHeaders ]
+}
+
+err = http_test.begin ()
+
+exit (err)
diff --git a/testenv/Test-metalink-http-xml-type-content.py b/testenv/Test-metalink-http-xml-type-content.py
new file mode 100755
index 0000000..b1ace27
--- /dev/null
+++ b/testenv/Test-metalink-http-xml-type-content.py
@@ -0,0 +1,221 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+import hashlib
+from base64 import b64encode
+
+"""
+ This is to test Metalink/HTTP with Content-Type Metalink/XML.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+bad = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+File1_sha256 = hashlib.sha256 (File1.encode ('UTF-8')).hexdigest ()
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+File2_sha256 = hashlib.sha256 (File2.encode ('UTF-8')).hexdigest ()
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+File3_sha256 = hashlib.sha256 (File3.encode ('UTF-8')).hexdigest ()
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+File4_sha256 = hashlib.sha256 (File4.encode ('UTF-8')).hexdigest ()
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+File5_sha256 = hashlib.sha256 (File5.encode ('UTF-8')).hexdigest ()
+
+MetaXml = \
+"""<?xml version="1.0" encoding="utf-8"?>
+<metalink version="3.0" xmlns="http://www.metalinker.org/">
+ <publisher>
+ <name>GNU Wget</name>
+ </publisher>
+ <license>
+ <name>GNU GPL</name>
+ <url>http://www.gnu.org/licenses/gpl.html</url>
+ </license>
+ <identity>Wget Test Files</identity>
+ <version>1.2.3</version>
+ <description>Wget Test Files description</description>
+ <files>
+ <file name="dir/File1">
+ <verification>
+ <hash type="sha256">{{FILE1_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File1_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File1</url>
+ </resources>
+ </file>
+ <file name="dir/File2">
+ <verification>
+ <hash type="sha256">{{FILE2_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File2_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File2</url>
+ </resources>
+ </file>
+ <file name="/dir/File3"> <!-- rejected by libmetalink -->
+ <verification>
+ <hash type="sha256">{{FILE3_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File3_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File3</url>
+ </resources>
+ </file>
+ <file name="dir/File4">
+ <verification>
+ <hash type="sha256">{{FILE4_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File4_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File4</url>
+ </resources>
+ </file>
+ <file name="dir/File5">
+ <verification>
+ <hash type="sha256">{{FILE5_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File5_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File5</url>
+ </resources>
+ </file>
+ </files>
+</metalink>
+"""
+
+# This will be filled as soon as we know server hostname and port
+MetaHTTPRules = {'SendHeader' : {}}
+
+MetaHTTP = WgetFile ("main.metalink", rules=MetaHTTPRules)
+MetaHTTP_down = WgetFile ("main.metalink.meta#1", MetaXml)
+
+wrong_file = WgetFile ("wrong_file", bad)
+
+File1_orig = WgetFile ("File1", File1)
+File1_down = WgetFile ("main.metalink.meta#1.#1", File1)
+File1_nono = WgetFile ("File1_lowPref", File1_lowPref)
+
+File2_orig = WgetFile ("File2", File2)
+File2_down = WgetFile ("main.metalink.meta#1.#2", File2)
+File2_nono = WgetFile ("File2_lowPref", File2_lowPref)
+
+# rejected by libmetalink
+File3_orig = WgetFile ("File3", File3)
+File3_nono = WgetFile ("File3_lowPref", File3_lowPref)
+
+File4_orig = WgetFile ("File4", File4)
+File4_down = WgetFile ("main.metalink.meta#1.#3", File4)
+File4_nono = WgetFile ("File4_lowPref", File4_lowPref)
+
+File5_orig = WgetFile ("File5", File5)
+File5_down = WgetFile ("main.metalink.meta#1.#4", File5)
+File5_nono = WgetFile ("File5_lowPref", File5_lowPref)
+
+WGET_OPTIONS = "--metalink-over-http --content-disposition --metalink-index=0"
+WGET_URLS = [["main.metalink"]]
+
+RequestList = [[
+ "HEAD /main.metalink",
+ "GET /main.metalink",
+ "GET /404",
+ "GET /wrong_file",
+ "GET /File1",
+ "GET /File2",
+ "GET /File4",
+ "GET /File5"
+]]
+
+Files = [[
+ MetaHTTP,
+ wrong_file,
+ File1_orig, File1_nono,
+ File2_orig, File2_nono,
+ File3_orig, File3_nono,
+ File4_orig, File4_nono,
+ File5_orig, File5_nono
+]]
+Existing_Files = []
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [
+ MetaHTTP_down,
+ File1_down,
+ File2_down,
+ File4_down,
+ File5_down
+]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode,
+ "FilesCrawled" : RequestList
+}
+
+http_test = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+)
+
+http_test.server_setup()
+### Get and use dynamic server sockname
+srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
+
+MetaXml = MetaXml.replace('{{FILE1_HASH}}', File1_sha256)
+MetaXml = MetaXml.replace('{{FILE2_HASH}}', File2_sha256)
+MetaXml = MetaXml.replace('{{FILE3_HASH}}', File3_sha256)
+MetaXml = MetaXml.replace('{{FILE4_HASH}}', File4_sha256)
+MetaXml = MetaXml.replace('{{FILE5_HASH}}', File5_sha256)
+MetaXml = MetaXml.replace('{{SRV_HOST}}', srv_host)
+MetaXml = MetaXml.replace('{{SRV_PORT}}', str (srv_port))
+MetaHTTP_down.content = MetaXml
+
+MetaHTTP.content = MetaXml
+
+MetaHTTPRules["SendHeader"] = {
+ 'Content-Type': 'application/metalink4+xml',
+ 'Content-Disposition': 'filename="newname.metalink"'
+}
+
+err = http_test.begin ()
+
+exit (err)
diff --git a/testenv/Test-metalink-http-xml-type-trust-content.py b/testenv/Test-metalink-http-xml-type-trust-content.py
new file mode 100755
index 0000000..7ee4197
--- /dev/null
+++ b/testenv/Test-metalink-http-xml-type-trust-content.py
@@ -0,0 +1,221 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+import hashlib
+from base64 import b64encode
+
+"""
+ This is to test Metalink/HTTP with Content-Type Metalink/XML.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+bad = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+File1_sha256 = hashlib.sha256 (File1.encode ('UTF-8')).hexdigest ()
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+File2_sha256 = hashlib.sha256 (File2.encode ('UTF-8')).hexdigest ()
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+File3_sha256 = hashlib.sha256 (File3.encode ('UTF-8')).hexdigest ()
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+File4_sha256 = hashlib.sha256 (File4.encode ('UTF-8')).hexdigest ()
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+File5_sha256 = hashlib.sha256 (File5.encode ('UTF-8')).hexdigest ()
+
+MetaXml = \
+"""<?xml version="1.0" encoding="utf-8"?>
+<metalink version="3.0" xmlns="http://www.metalinker.org/">
+ <publisher>
+ <name>GNU Wget</name>
+ </publisher>
+ <license>
+ <name>GNU GPL</name>
+ <url>http://www.gnu.org/licenses/gpl.html</url>
+ </license>
+ <identity>Wget Test Files</identity>
+ <version>1.2.3</version>
+ <description>Wget Test Files description</description>
+ <files>
+ <file name="dir/File1">
+ <verification>
+ <hash type="sha256">{{FILE1_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File1_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File1</url>
+ </resources>
+ </file>
+ <file name="dir/File2">
+ <verification>
+ <hash type="sha256">{{FILE2_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File2_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File2</url>
+ </resources>
+ </file>
+ <file name="/dir/File3"> <!-- rejected by libmetalink -->
+ <verification>
+ <hash type="sha256">{{FILE3_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File3_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File3</url>
+ </resources>
+ </file>
+ <file name="dir/File4">
+ <verification>
+ <hash type="sha256">{{FILE4_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File4_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File4</url>
+ </resources>
+ </file>
+ <file name="dir/File5">
+ <verification>
+ <hash type="sha256">{{FILE5_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File5_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File5</url>
+ </resources>
+ </file>
+ </files>
+</metalink>
+"""
+
+# This will be filled as soon as we know server hostname and port
+MetaHTTPRules = {'SendHeader' : {}}
+
+MetaHTTP = WgetFile ("main.metalink", rules=MetaHTTPRules)
+MetaHTTP_down = WgetFile ("newname.metalink", MetaXml)
+
+wrong_file = WgetFile ("wrong_file", bad)
+
+File1_orig = WgetFile ("File1", File1)
+File1_down = WgetFile ("dir/File1", File1)
+File1_nono = WgetFile ("File1_lowPref", File1_lowPref)
+
+File2_orig = WgetFile ("File2", File2)
+File2_down = WgetFile ("dir/File2", File2)
+File2_nono = WgetFile ("File2_lowPref", File2_lowPref)
+
+# rejected by libmetalink
+File3_orig = WgetFile ("File3", File3)
+File3_nono = WgetFile ("File3_lowPref", File3_lowPref)
+
+File4_orig = WgetFile ("File4", File4)
+File4_down = WgetFile ("dir/File4", File4)
+File4_nono = WgetFile ("File4_lowPref", File4_lowPref)
+
+File5_orig = WgetFile ("File5", File5)
+File5_down = WgetFile ("dir/File5", File5)
+File5_nono = WgetFile ("File5_lowPref", File5_lowPref)
+
+WGET_OPTIONS = "--trust-server-names --metalink-over-http --content-disposition --metalink-index=0"
+WGET_URLS = [["main.metalink"]]
+
+RequestList = [[
+ "HEAD /main.metalink",
+ "GET /main.metalink",
+ "GET /404",
+ "GET /wrong_file",
+ "GET /File1",
+ "GET /File2",
+ "GET /File4",
+ "GET /File5"
+]]
+
+Files = [[
+ MetaHTTP,
+ wrong_file,
+ File1_orig, File1_nono,
+ File2_orig, File2_nono,
+ File3_orig, File3_nono,
+ File4_orig, File4_nono,
+ File5_orig, File5_nono
+]]
+Existing_Files = []
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [
+ MetaHTTP_down,
+ File1_down,
+ File2_down,
+ File4_down,
+ File5_down
+]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode,
+ "FilesCrawled" : RequestList
+}
+
+http_test = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+)
+
+http_test.server_setup()
+### Get and use dynamic server sockname
+srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
+
+MetaXml = MetaXml.replace('{{FILE1_HASH}}', File1_sha256)
+MetaXml = MetaXml.replace('{{FILE2_HASH}}', File2_sha256)
+MetaXml = MetaXml.replace('{{FILE3_HASH}}', File3_sha256)
+MetaXml = MetaXml.replace('{{FILE4_HASH}}', File4_sha256)
+MetaXml = MetaXml.replace('{{FILE5_HASH}}', File5_sha256)
+MetaXml = MetaXml.replace('{{SRV_HOST}}', srv_host)
+MetaXml = MetaXml.replace('{{SRV_PORT}}', str (srv_port))
+MetaHTTP_down.content = MetaXml
+
+MetaHTTP.content = MetaXml
+
+MetaHTTPRules["SendHeader"] = {
+ 'Content-Type': 'application/metalink4+xml',
+ 'Content-Disposition': 'filename="newname.metalink"'
+}
+
+err = http_test.begin ()
+
+exit (err)
diff --git a/testenv/Test-metalink-http-xml-type-trust.py b/testenv/Test-metalink-http-xml-type-trust.py
new file mode 100755
index 0000000..0cf2074
--- /dev/null
+++ b/testenv/Test-metalink-http-xml-type-trust.py
@@ -0,0 +1,221 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+import hashlib
+from base64 import b64encode
+
+"""
+ This is to test Metalink/HTTP with Content-Type Metalink/XML.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+bad = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+File1_sha256 = hashlib.sha256 (File1.encode ('UTF-8')).hexdigest ()
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+File2_sha256 = hashlib.sha256 (File2.encode ('UTF-8')).hexdigest ()
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+File3_sha256 = hashlib.sha256 (File3.encode ('UTF-8')).hexdigest ()
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+File4_sha256 = hashlib.sha256 (File4.encode ('UTF-8')).hexdigest ()
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+File5_sha256 = hashlib.sha256 (File5.encode ('UTF-8')).hexdigest ()
+
+MetaXml = \
+"""<?xml version="1.0" encoding="utf-8"?>
+<metalink version="3.0" xmlns="http://www.metalinker.org/">
+ <publisher>
+ <name>GNU Wget</name>
+ </publisher>
+ <license>
+ <name>GNU GPL</name>
+ <url>http://www.gnu.org/licenses/gpl.html</url>
+ </license>
+ <identity>Wget Test Files</identity>
+ <version>1.2.3</version>
+ <description>Wget Test Files description</description>
+ <files>
+ <file name="dir/File1">
+ <verification>
+ <hash type="sha256">{{FILE1_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File1_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File1</url>
+ </resources>
+ </file>
+ <file name="dir/File2">
+ <verification>
+ <hash type="sha256">{{FILE2_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File2_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File2</url>
+ </resources>
+ </file>
+ <file name="/dir/File3"> <!-- rejected by libmetalink -->
+ <verification>
+ <hash type="sha256">{{FILE3_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File3_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File3</url>
+ </resources>
+ </file>
+ <file name="dir/File4">
+ <verification>
+ <hash type="sha256">{{FILE4_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File4_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File4</url>
+ </resources>
+ </file>
+ <file name="dir/File5">
+ <verification>
+ <hash type="sha256">{{FILE5_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File5_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File5</url>
+ </resources>
+ </file>
+ </files>
+</metalink>
+"""
+
+# This will be filled as soon as we know server hostname and port
+MetaHTTPRules = {'SendHeader' : {}}
+
+MetaHTTP = WgetFile ("main.metalink", rules=MetaHTTPRules)
+MetaHTTP_down = WgetFile ("main.metalink", MetaXml)
+
+wrong_file = WgetFile ("wrong_file", bad)
+
+File1_orig = WgetFile ("File1", File1)
+File1_down = WgetFile ("dir/File1", File1)
+File1_nono = WgetFile ("File1_lowPref", File1_lowPref)
+
+File2_orig = WgetFile ("File2", File2)
+File2_down = WgetFile ("dir/File2", File2)
+File2_nono = WgetFile ("File2_lowPref", File2_lowPref)
+
+# rejected by libmetalink
+File3_orig = WgetFile ("File3", File3)
+File3_nono = WgetFile ("File3_lowPref", File3_lowPref)
+
+File4_orig = WgetFile ("File4", File4)
+File4_down = WgetFile ("dir/File4", File4)
+File4_nono = WgetFile ("File4_lowPref", File4_lowPref)
+
+File5_orig = WgetFile ("File5", File5)
+File5_down = WgetFile ("dir/File5", File5)
+File5_nono = WgetFile ("File5_lowPref", File5_lowPref)
+
+WGET_OPTIONS = "--trust-server-names --metalink-over-http --metalink-index=0"
+WGET_URLS = [["main.metalink"]]
+
+RequestList = [[
+ "HEAD /main.metalink",
+ "GET /main.metalink",
+ "GET /404",
+ "GET /wrong_file",
+ "GET /File1",
+ "GET /File2",
+ "GET /File4",
+ "GET /File5"
+]]
+
+Files = [[
+ MetaHTTP,
+ wrong_file,
+ File1_orig, File1_nono,
+ File2_orig, File2_nono,
+ File3_orig, File3_nono,
+ File4_orig, File4_nono,
+ File5_orig, File5_nono
+]]
+Existing_Files = []
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [
+ MetaHTTP_down,
+ File1_down,
+ File2_down,
+ File4_down,
+ File5_down
+]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode,
+ "FilesCrawled" : RequestList
+}
+
+http_test = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+)
+
+http_test.server_setup()
+### Get and use dynamic server sockname
+srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
+
+MetaXml = MetaXml.replace('{{FILE1_HASH}}', File1_sha256)
+MetaXml = MetaXml.replace('{{FILE2_HASH}}', File2_sha256)
+MetaXml = MetaXml.replace('{{FILE3_HASH}}', File3_sha256)
+MetaXml = MetaXml.replace('{{FILE4_HASH}}', File4_sha256)
+MetaXml = MetaXml.replace('{{FILE5_HASH}}', File5_sha256)
+MetaXml = MetaXml.replace('{{SRV_HOST}}', srv_host)
+MetaXml = MetaXml.replace('{{SRV_PORT}}', str (srv_port))
+MetaHTTP_down.content = MetaXml
+
+MetaHTTP.content = MetaXml
+
+MetaHTTPRules["SendHeader"] = {
+ 'Content-Type': 'application/metalink4+xml',
+ 'Content-Disposition': 'filename="newname.metalink"'
+}
+
+err = http_test.begin ()
+
+exit (err)
diff --git a/testenv/Test-metalink-http-xml-type.py b/testenv/Test-metalink-http-xml-type.py
new file mode 100755
index 0000000..19a65f1
--- /dev/null
+++ b/testenv/Test-metalink-http-xml-type.py
@@ -0,0 +1,221 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+import hashlib
+from base64 import b64encode
+
+"""
+ This is to test Metalink/HTTP with Content-Type Metalink/XML.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+bad = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+File1_sha256 = hashlib.sha256 (File1.encode ('UTF-8')).hexdigest ()
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+File2_sha256 = hashlib.sha256 (File2.encode ('UTF-8')).hexdigest ()
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+File3_sha256 = hashlib.sha256 (File3.encode ('UTF-8')).hexdigest ()
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+File4_sha256 = hashlib.sha256 (File4.encode ('UTF-8')).hexdigest ()
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+File5_sha256 = hashlib.sha256 (File5.encode ('UTF-8')).hexdigest ()
+
+MetaXml = \
+"""<?xml version="1.0" encoding="utf-8"?>
+<metalink version="3.0" xmlns="http://www.metalinker.org/">
+ <publisher>
+ <name>GNU Wget</name>
+ </publisher>
+ <license>
+ <name>GNU GPL</name>
+ <url>http://www.gnu.org/licenses/gpl.html</url>
+ </license>
+ <identity>Wget Test Files</identity>
+ <version>1.2.3</version>
+ <description>Wget Test Files description</description>
+ <files>
+ <file name="dir/File1">
+ <verification>
+ <hash type="sha256">{{FILE1_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File1_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File1</url>
+ </resources>
+ </file>
+ <file name="dir/File2">
+ <verification>
+ <hash type="sha256">{{FILE2_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File2_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File2</url>
+ </resources>
+ </file>
+ <file name="/dir/File3"> <!-- rejected by libmetalink -->
+ <verification>
+ <hash type="sha256">{{FILE3_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File3_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File3</url>
+ </resources>
+ </file>
+ <file name="dir/File4">
+ <verification>
+ <hash type="sha256">{{FILE4_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File4_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File4</url>
+ </resources>
+ </file>
+ <file name="dir/File5">
+ <verification>
+ <hash type="sha256">{{FILE5_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File5_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File5</url>
+ </resources>
+ </file>
+ </files>
+</metalink>
+"""
+
+# This will be filled as soon as we know server hostname and port
+MetaHTTPRules = {'SendHeader' : {}}
+
+MetaHTTP = WgetFile ("main.metalink", rules=MetaHTTPRules)
+MetaHTTP_down = WgetFile ("main.metalink.meta#1", MetaXml)
+
+wrong_file = WgetFile ("wrong_file", bad)
+
+File1_orig = WgetFile ("File1", File1)
+File1_down = WgetFile ("main.metalink.meta#1.#1", File1)
+File1_nono = WgetFile ("File1_lowPref", File1_lowPref)
+
+File2_orig = WgetFile ("File2", File2)
+File2_down = WgetFile ("main.metalink.meta#1.#2", File2)
+File2_nono = WgetFile ("File2_lowPref", File2_lowPref)
+
+# rejected by libmetalink
+File3_orig = WgetFile ("File3", File3)
+File3_nono = WgetFile ("File3_lowPref", File3_lowPref)
+
+File4_orig = WgetFile ("File4", File4)
+File4_down = WgetFile ("main.metalink.meta#1.#3", File4)
+File4_nono = WgetFile ("File4_lowPref", File4_lowPref)
+
+File5_orig = WgetFile ("File5", File5)
+File5_down = WgetFile ("main.metalink.meta#1.#4", File5)
+File5_nono = WgetFile ("File5_lowPref", File5_lowPref)
+
+WGET_OPTIONS = "--metalink-over-http --metalink-index=0"
+WGET_URLS = [["main.metalink"]]
+
+RequestList = [[
+ "HEAD /main.metalink",
+ "GET /main.metalink",
+ "GET /404",
+ "GET /wrong_file",
+ "GET /File1",
+ "GET /File2",
+ "GET /File4",
+ "GET /File5"
+]]
+
+Files = [[
+ MetaHTTP,
+ wrong_file,
+ File1_orig, File1_nono,
+ File2_orig, File2_nono,
+ File3_orig, File3_nono,
+ File4_orig, File4_nono,
+ File5_orig, File5_nono
+]]
+Existing_Files = []
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [
+ MetaHTTP_down,
+ File1_down,
+ File2_down,
+ File4_down,
+ File5_down
+]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode,
+ "FilesCrawled" : RequestList
+}
+
+http_test = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+)
+
+http_test.server_setup()
+### Get and use dynamic server sockname
+srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
+
+MetaXml = MetaXml.replace('{{FILE1_HASH}}', File1_sha256)
+MetaXml = MetaXml.replace('{{FILE2_HASH}}', File2_sha256)
+MetaXml = MetaXml.replace('{{FILE3_HASH}}', File3_sha256)
+MetaXml = MetaXml.replace('{{FILE4_HASH}}', File4_sha256)
+MetaXml = MetaXml.replace('{{FILE5_HASH}}', File5_sha256)
+MetaXml = MetaXml.replace('{{SRV_HOST}}', srv_host)
+MetaXml = MetaXml.replace('{{SRV_PORT}}', str (srv_port))
+MetaHTTP_down.content = MetaXml
+
+MetaHTTP.content = MetaXml
+
+MetaHTTPRules["SendHeader"] = {
+ 'Content-Type': 'application/metalink4+xml',
+ 'Content-Disposition': 'filename="newname.metalink"'
+}
+
+err = http_test.begin ()
+
+exit (err)
diff --git a/testenv/Test-metalink-http-xml.py b/testenv/Test-metalink-http-xml.py
new file mode 100755
index 0000000..9cc49e9
--- /dev/null
+++ b/testenv/Test-metalink-http-xml.py
@@ -0,0 +1,272 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+import hashlib
+from base64 import b64encode
+
+"""
+ This is to test Metalink/HTTP with Metalink/XML Link headers.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+bad = "Ouch!"
+bad_sha256 = hashlib.sha256 (bad.encode ('UTF-8')).hexdigest ()
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+File1_sha256 = hashlib.sha256 (File1.encode ('UTF-8')).hexdigest ()
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+File2_sha256 = hashlib.sha256 (File2.encode ('UTF-8')).hexdigest ()
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+File3_sha256 = hashlib.sha256 (File3.encode ('UTF-8')).hexdigest ()
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+File4_sha256 = hashlib.sha256 (File4.encode ('UTF-8')).hexdigest ()
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+File5_sha256 = hashlib.sha256 (File5.encode ('UTF-8')).hexdigest ()
+
+MetaXml1 = \
+"""<?xml version="1.0" encoding="utf-8"?>
+<metalink version="3.0" xmlns="http://www.metalinker.org/">
+ <publisher>
+ <name>GNU Wget</name>
+ </publisher>
+ <license>
+ <name>GNU GPL</name>
+ <url>http://www.gnu.org/licenses/gpl.html</url>
+ </license>
+ <identity>Wget Test Files</identity>
+ <version>1.2.3</version>
+ <description>Wget Test Files description</description>
+ <files>
+ <file name="dir/File1">
+ <verification>
+ <hash type="sha256">{{FILE1_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File1_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File1</url>
+ </resources>
+ </file>
+ <file name="dir/File2">
+ <verification>
+ <hash type="sha256">{{FILE2_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File2_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File2</url>
+ </resources>
+ </file>
+ <file name="/dir/File3"> <!-- rejected by libmetalink -->
+ <verification>
+ <hash type="sha256">{{FILE3_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File3_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File3</url>
+ </resources>
+ </file>
+ <file name="dir/File4">
+ <verification>
+ <hash type="sha256">{{FILE4_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File4_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File4</url>
+ </resources>
+ </file>
+ <file name="dir/File5">
+ <verification>
+ <hash type="sha256">{{FILE5_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File5_lowPref</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File5</url>
+ </resources>
+ </file>
+ </files>
+</metalink>
+"""
+
+MetaXml2 = \
+"""<?xml version="1.0" encoding="utf-8"?>
+<metalink version="3.0" xmlns="http://www.metalinker.org/">
+ <publisher>
+ <name>GNU Wget</name>
+ </publisher>
+ <license>
+ <name>GNU GPL</name>
+ <url>http://www.gnu.org/licenses/gpl.html</url>
+ </license>
+ <identity>Wget Test Files</identity>
+ <version>1.2.3</version>
+ <description>Wget Test Files description</description>
+ <files>
+ <file name="bad">
+ <verification>
+ <hash type="sha256">{{BAD_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
+ <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
+ <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/bad</url>
+ </resources>
+ </file>
+ </files>
+</metalink>
+"""
+
+LinkHeaders = [
+ # This file has the lowest priority, and should go last
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/test1.metalink>; rel=describedby; pri=2; type=\"application/metalink4+xml\"",
+ # This file has the highest priority, and should go first
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/test2.metalink>; rel=describedby; pri=1; type=\"application/metalink4+xml\""
+]
+
+# This will be filled as soon as we know server hostname and port
+MetaHTTPRules = {'SendHeader' : {}}
+
+MetaHTTP = WgetFile ("main.metalink", rules=MetaHTTPRules)
+
+wrong_file = WgetFile ("wrong_file", bad)
+
+File1_orig = WgetFile ("File1", File1)
+File1_down = WgetFile ("main.metalink.meta#2.#1", File1)
+File1_nono = WgetFile ("File1_lowPref", File1_lowPref)
+
+File2_orig = WgetFile ("File2", File2)
+File2_down = WgetFile ("main.metalink.meta#2.#2", File2)
+File2_nono = WgetFile ("File2_lowPref", File2_lowPref)
+
+# rejected by libmetalink
+File3_orig = WgetFile ("File3", File3)
+File3_nono = WgetFile ("File3_lowPref", File3_lowPref)
+
+File4_orig = WgetFile ("File4", File4)
+File4_down = WgetFile ("main.metalink.meta#2.#3", File4)
+File4_nono = WgetFile ("File4_lowPref", File4_lowPref)
+
+File5_orig = WgetFile ("File5", File5)
+File5_down = WgetFile ("main.metalink.meta#2.#4", File5)
+File5_nono = WgetFile ("File5_lowPref", File5_lowPref)
+
+MetaFile1 = WgetFile ("test1.metalink", MetaXml1)
+MetaFile1_down = WgetFile ("main.metalink.meta#2", MetaXml1)
+
+MetaFile2 = WgetFile ("test2.metalink", MetaXml2)
+
+WGET_OPTIONS = "--metalink-over-http --metalink-index=2"
+WGET_URLS = [["main.metalink"]]
+
+RequestList = [[
+ "HEAD /main.metalink",
+ "GET /404",
+ "GET /wrong_file",
+ "GET /test1.metalink",
+ "GET /File1",
+ "GET /File2",
+ "GET /File4",
+ "GET /File5"
+]]
+
+Files = [[
+ MetaHTTP,
+ wrong_file,
+ MetaFile1, MetaFile2,
+ File1_orig, File1_nono,
+ File2_orig, File2_nono,
+ File3_orig, File3_nono,
+ File4_orig, File4_nono,
+ File5_orig, File5_nono
+]]
+Existing_Files = []
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [
+ MetaFile1_down,
+ File1_down,
+ File2_down,
+ File4_down,
+ File5_down
+]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode,
+ "FilesCrawled" : RequestList
+}
+
+http_test = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+)
+
+http_test.server_setup()
+### Get and use dynamic server sockname
+srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
+
+MetaXml1 = MetaXml1.replace('{{FILE1_HASH}}', File1_sha256)
+MetaXml1 = MetaXml1.replace('{{FILE2_HASH}}', File2_sha256)
+MetaXml1 = MetaXml1.replace('{{FILE3_HASH}}', File3_sha256)
+MetaXml1 = MetaXml1.replace('{{FILE4_HASH}}', File4_sha256)
+MetaXml1 = MetaXml1.replace('{{FILE5_HASH}}', File5_sha256)
+MetaXml1 = MetaXml1.replace('{{SRV_HOST}}', srv_host)
+MetaXml1 = MetaXml1.replace('{{SRV_PORT}}', str (srv_port))
+MetaFile1.content = MetaXml1
+MetaFile1_down.content = MetaXml1
+
+MetaXml2 = MetaXml2.replace('{{BAD_HASH}}', bad_sha256)
+MetaXml2 = MetaXml2.replace('{{SRV_HOST}}', srv_host)
+MetaXml2 = MetaXml2.replace('{{SRV_PORT}}', str (srv_port))
+MetaFile2.content = MetaXml2
+
+# Helper function for hostname, port and digest substitution
+def SubstituteServerInfo (text, host, port):
+ text = text.replace('{{SRV_HOST}}', host)
+ text = text.replace('{{SRV_PORT}}', str (port))
+ return text
+
+MetaHTTPRules["SendHeader"] = {
+ 'Link': [ SubstituteServerInfo (LinkHeader, srv_host, srv_port)
+ for LinkHeader in LinkHeaders ]
+}
+
+err = http_test.begin ()
+
+exit (err)
diff --git a/testenv/Test-metalink-http.py b/testenv/Test-metalink-http.py
new file mode 100755
index 0000000..b119da6
--- /dev/null
+++ b/testenv/Test-metalink-http.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+import hashlib
+from base64 import b64encode
+
+"""
+ This is to test Metalink as HTTP file support in Wget.
+"""
+
+# Helper function for hostname, port and digest substitution
+def SubstituteServerInfo (text, host, port, digest):
+ text = text.replace('{{FILE1_HASH}}', digest)
+ text = text.replace('{{SRV_HOST}}', host)
+ text = text.replace('{{SRV_PORT}}', str (port))
+ return text
+
+############# File Definitions ###############################################
+File1 = "Would you like some Tea?"
+File1_corrupted = "Would you like some Coffee?"
+File1_lowPref = "Do not take this"
+File1_sha256 = b64encode (hashlib.sha256 (File1.encode ('UTF-8')).digest ()).decode ('ascii')
+Signature = '''-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.0.7 (GNU/Linux)
+
+This is no valid signature. But it should be downloaded.
+The attempt to verify should fail but should not prevent
+a successful metalink resource retrieval (the sig failure
+should not be fatal).
+-----END PGP SIGNATURE-----
+'''
+File2 = "No meta data for this file."
+
+LinkHeaders = [
+ # This file has low priority and should not be picked.
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_lowPref>; rel=duplicate; pri=9; geo=pl",
+ # This file should be picked second, after hash failure.
+ "<http://this.is.no.good.example/File1_try2_badconnection>; rel =duplicate;pref; pri=7",
+ # This signature download will fail.
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/Sig2.asc>; rel=describedby; type=application/pgp-signature",
+ # Two good signatures
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/Sig.asc>; rel=describedby; type=application/pgp-signature",
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/Sig.asc>; rel=describedby; type=application/pgp-signature",
+ # Bad URL scheme
+ "<invalid_url>; rel=duplicate; pri=4",
+ # rel missing
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/File1>; pri=1; pref",
+ # invalid rel
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/File1>; rel=strange; pri=4",
+ # This file should be picked first, because it has the lowest pri among preferred.
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_try1_corrupted>; rel=duplicate; geo=su; pri=4; pref",
+ # This file should NOT be picked third due to preferred location set to 'uk'
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_badgeo>; rel =duplicate;pri=5",
+ # This file should be picked as third try, and it should succeed
+ "<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_try3_ok>; rel=duplicate; pri=5;geo=uk"
+ ]
+DigestHeader = "SHA-256={{FILE1_HASH}}"
+
+# This will be filled as soon as we know server hostname and port
+MetaFileRules = {'SendHeader' : {}}
+
+FileOkServer = WgetFile ("File1_try3_ok", File1)
+FileBadPref = WgetFile ("File1_lowPref", File1_lowPref)
+FileBadHash = WgetFile ("File1_try1_corrupted", File1_corrupted)
+MetaFile = WgetFile ("test.meta", rules=MetaFileRules)
+# In case of Metalink over HTTP, the local file name is
+# derived from the URL suffix.
+FileOkLocal = WgetFile ("test.meta", File1)
+SigFile = WgetFile ("Sig.asc", Signature)
+FileNoMeta = WgetFile ("File2", File2)
+
+WGET_OPTIONS = "--metalink-over-http --preferred-location=uk"
+WGET_URLS = [["test.meta", "File2"]]
+
+Files = [[FileOkServer, FileBadPref, FileBadHash, MetaFile, SigFile, FileNoMeta]]
+Existing_Files = []
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [FileNoMeta, FileOkLocal]
+
+RequestList = [
+ [
+ "HEAD /test.meta",
+ "GET /Sig2.asc",
+ "GET /Sig.asc",
+ "GET /File1_try1_corrupted",
+ "GET /File1_try3_ok",
+ "HEAD /File2",
+ "GET /File2",
+ ]
+]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode,
+ "FilesCrawled" : RequestList,
+}
+
+http_test = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+)
+
+http_test.server_setup()
+srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
+
+MetaFileRules["SendHeader"] = {
+ 'Link': [ SubstituteServerInfo (LinkHeader, srv_host, srv_port, File1_sha256)
+ for LinkHeader in LinkHeaders ],
+ 'Digest': SubstituteServerInfo (DigestHeader, srv_host, srv_port, File1_sha256),
+}
+
+err = http_test.begin ()
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-abspath-trust.py b/testenv/Test-metalink-xml-abspath-trust.py
new file mode 100755
index 0000000..5091cd0
--- /dev/null
+++ b/testenv/Test-metalink-xml-abspath-trust.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test if Metalink/XML forbids absolute paths.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["/File1", None, File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["File2", "File2", File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["/File3", None, File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["/File4", None, File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["File5", "File5", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--trust-server-names " + \
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-abspath.py b/testenv/Test-metalink-xml-abspath.py
new file mode 100755
index 0000000..e84fcf0
--- /dev/null
+++ b/testenv/Test-metalink-xml-abspath.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test if Metalink/XML forbids absolute paths.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["/File1", None, File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["File2", XmlName + ".#1", File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["/File3", None, File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["/File4", None, File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["File5", XmlName + ".#2", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-absprefix-trust.py b/testenv/Test-metalink-xml-absprefix-trust.py
new file mode 100755
index 0000000..4cf065d
--- /dev/null
+++ b/testenv/Test-metalink-xml-absprefix-trust.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test Metalink/XML absolute directory prefix support in Wget.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["subdir/File1", "File1", File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["/subdir/File2", None, File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["~/subdir/File3", None, File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["../subdir/File4", None, File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["subdir/File5", "File5", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--trust-server-names " + \
+ "--directory-prefix /dir " + \
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-absprefix.py b/testenv/Test-metalink-xml-absprefix.py
new file mode 100755
index 0000000..d19d178
--- /dev/null
+++ b/testenv/Test-metalink-xml-absprefix.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test Metalink/XML absolute directory prefix support in Wget.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["subdir/File1", XmlName + ".#1", File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["/subdir/File2", None, File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["~/subdir/File3", None, File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["../subdir/File4", None, File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["subdir/File5", XmlName + ".#2", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--directory-prefix /dir " + \
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-continue.py b/testenv/Test-metalink-xml-continue.py
new file mode 100644
index 0000000..782dbd5
--- /dev/null
+++ b/testenv/Test-metalink-xml-continue.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test Metalink/XML --continue support in Wget.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type (http, ftp, etc.)
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.add_LocalFiles (
+ [XmlName + ".#1", File1[0:14]], # File1 to continue from partial file
+ [XmlName + ".#2", File2], # File2 to keep, different from server
+ [XmlName + ".#3", File3], # File3 to keep, already fully retrieved
+ [XmlName + ".#4", File4], # File4 to keep, different from server
+)
+
+Meta.add_ExpectedFiles (
+ [XmlName + ".#2", File2], # File2 to keep, different from server
+ [XmlName + ".#3", File3], # File3 to keep, already fully retrieved
+ [XmlName + ".#4", File4], # File4 to keep, different from server
+)
+
+Meta.print_meta ()
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["File1", XmlName + ".#1", File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["File2", XmlName + ".#2", wrong_file, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["File3", XmlName + ".#3", File3, None, True,
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["File4", XmlName + ".#4", File4_lowPref, None, True,
+ ["wrong_file", wrong_file, "http", None, 35]],
+ ["File5", XmlName + ".#5", File5, None, True,
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--continue " + \
+ "--input-metalink " + XmlName, 1
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-emptyprefix-trust.py b/testenv/Test-metalink-xml-emptyprefix-trust.py
new file mode 100755
index 0000000..9b4272d
--- /dev/null
+++ b/testenv/Test-metalink-xml-emptyprefix-trust.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test Metalink/XML with an empty directory prefix.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["subdir/File1", "subdir/File1", File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["/subdir/File2", None, File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["~/subdir/File3", None, File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["../subdir/File4", None, File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["subdir/File5", "subdir/File5", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--trust-server-names " + \
+ "--directory-prefix '' " + \
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-homepath-trust.py b/testenv/Test-metalink-xml-homepath-trust.py
new file mode 100755
index 0000000..3831e80
--- /dev/null
+++ b/testenv/Test-metalink-xml-homepath-trust.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test if Metalink/XML forbids the home path and names
+ beginning with the ~ (tilde) character.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["~File1", None, File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["~/File2", None, File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["dir/~File3", None, File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["dir/File4~", "dir/File4~", File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["dir/~/File5", "dir/~/File5", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--trust-server-names " + \
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-homepath.py b/testenv/Test-metalink-xml-homepath.py
new file mode 100755
index 0000000..f38f2db
--- /dev/null
+++ b/testenv/Test-metalink-xml-homepath.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test if Metalink/XML forbids the home path and names
+ beginning with the ~ (tilde) character.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["~File1", None, File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["~/File2", None, File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["dir/~File3", None, File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["dir/File4~", XmlName + ".#1", File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["dir/~/File5", XmlName + ".#2", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-homeprefix-trust.py b/testenv/Test-metalink-xml-homeprefix-trust.py
new file mode 100755
index 0000000..23c7191
--- /dev/null
+++ b/testenv/Test-metalink-xml-homeprefix-trust.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test Metalink/XML home directory prefix support in Wget.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["subdir/File1", "File1", File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["/subdir/File2", None, File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["~/subdir/File3", None, File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["../subdir/File4", None, File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["subdir/File5", "File5", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--trust-server-names " + \
+ "--directory-prefix ~/dir " + \
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-homeprefix.py b/testenv/Test-metalink-xml-homeprefix.py
new file mode 100755
index 0000000..03b17a8
--- /dev/null
+++ b/testenv/Test-metalink-xml-homeprefix.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test Metalink/XML home directory prefix support in Wget.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["subdir/File1", XmlName + ".#1", File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["/subdir/File2", None, File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["~/subdir/File3", None, File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["../subdir/File4", None, File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["subdir/File5", XmlName + ".#2", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--directory-prefix ~/dir " + \
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-nohash.py b/testenv/Test-metalink-xml-nohash.py
new file mode 100755
index 0000000..4c82cb0
--- /dev/null
+++ b/testenv/Test-metalink-xml-nohash.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test if Metalink/XML with no hashes generates a SIGSEGV.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type (http, ftp, etc.)
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["File1", None, File1, None, False,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["File2", XmlName + ".#2", File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["File3", None, File3, None, None,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["File4", XmlName + ".#4", File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["File5", None, File5, None, "",
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--input-metalink " + XmlName, 1
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-nourls.py b/testenv/Test-metalink-xml-nourls.py
new file mode 100755
index 0000000..9f3d93e
--- /dev/null
+++ b/testenv/Test-metalink-xml-nourls.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test Metalink/XML with unknown url types.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type (http, ftp, etc.)
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["File1", XmlName + ".#1", File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["File2", None, File2, None, True,
+ ["wrong_file", wrong_file, "unknown", None, 35],
+ ["404", None, "unknown", None, 40],
+ ["File2_lowPref", File2_lowPref, "unknown", None, 25],
+ ["File2", File2, "unknown", None, 30]],
+ ["File3", XmlName + ".#3", File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["File4", XmlName + ".#4", File4, None, True,
+ ["wrong_file", wrong_file, "unknown", None, 35],
+ ["404", None, "unknown", None, 40],
+ ["File4_lowPref", File4_lowPref, "unknown", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["File5", XmlName + ".#5", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--input-metalink " + XmlName, 1
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-prefix-trust.py b/testenv/Test-metalink-xml-prefix-trust.py
new file mode 100755
index 0000000..1fef7f9
--- /dev/null
+++ b/testenv/Test-metalink-xml-prefix-trust.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test Metalink/XML directory prefix support in Wget.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["subdir/File1", "dir/" + "subdir/File1", File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["/subdir/File2", None, File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["~/subdir/File3", None, File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["../subdir/File4", None, File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["subdir/File5", "dir/" + "subdir/File5", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--trust-server-names " + \
+ "--directory-prefix dir " + \
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-prefix.py b/testenv/Test-metalink-xml-prefix.py
new file mode 100755
index 0000000..4275a04
--- /dev/null
+++ b/testenv/Test-metalink-xml-prefix.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test Metalink/XML directory prefix support in Wget.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["subdir/File1", "dir/" + XmlName + ".#1", File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["/subdir/File2", None, File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["~/subdir/File3", None, File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["../subdir/File4", None, File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["subdir/File5", "dir/" + XmlName + ".#2", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--directory-prefix dir " + \
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-relpath-trust.py b/testenv/Test-metalink-xml-relpath-trust.py
new file mode 100755
index 0000000..d2b4fc0
--- /dev/null
+++ b/testenv/Test-metalink-xml-relpath-trust.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test if Metalink/XML forbids relative paths.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["./File1", None, File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["../File2", None, File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["dir/./File3", None, File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["dir/../File4", None, File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["File5", "File5", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--trust-server-names " + \
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-relpath.py b/testenv/Test-metalink-xml-relpath.py
new file mode 100755
index 0000000..9405410
--- /dev/null
+++ b/testenv/Test-metalink-xml-relpath.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test if Metalink/XML forbids relative paths.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["./File1", None, File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["../File2", None, File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["dir/./File3", None, File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["dir/../File4", None, File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["File5", XmlName + ".#1", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-relprefix-trust.py b/testenv/Test-metalink-xml-relprefix-trust.py
new file mode 100755
index 0000000..e19a8dc
--- /dev/null
+++ b/testenv/Test-metalink-xml-relprefix-trust.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test Metalink/XML relative directory prefix support in Wget.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["subdir/File1", "File1", File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["/subdir/File2", None, File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["~/subdir/File3", None, File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["../subdir/File4", None, File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["subdir/File5", "File5", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--trust-server-names " + \
+ "--directory-prefix ../dir " + \
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-relprefix.py b/testenv/Test-metalink-xml-relprefix.py
new file mode 100755
index 0000000..98718c7
--- /dev/null
+++ b/testenv/Test-metalink-xml-relprefix.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test Metalink/XML relative directory prefix support in Wget.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type (http, ftp, etc.)
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["subdir/File1", XmlName + ".#1", File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["/subdir/File2", None, File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["~/subdir/File3", None, File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["../subdir/File4", None, File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["subdir/File5", XmlName + ".#2", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--directory-prefix ../dir " + \
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-size.py b/testenv/Test-metalink-xml-size.py
new file mode 100755
index 0000000..3250967
--- /dev/null
+++ b/testenv/Test-metalink-xml-size.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test Metalink/XML file size check in Wget.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type (http, ftp, etc.)
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["File1", XmlName + ".#1", File1, "", True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["File2", None, File2, 2, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["File3", XmlName + ".#3", File3, 0, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["File4", XmlName + ".#4", File4, -5, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["File5", XmlName + ".#5", File5, True, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--input-metalink " + XmlName, 1
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-trust.py b/testenv/Test-metalink-xml-trust.py
new file mode 100755
index 0000000..88049ca
--- /dev/null
+++ b/testenv/Test-metalink-xml-trust.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test Metalink/XML file support in Wget.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type (http, ftp, etc.)
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["File1", "File1", File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["File2", "File2", File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["File3", "File3", File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["File4", "File4", File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["File5", "File5", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--trust-server-names " + \
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-metalink-xml-urlbreak.py b/testenv/Test-metalink-xml-urlbreak.py
new file mode 100755
index 0000000..e53ae11
--- /dev/null
+++ b/testenv/Test-metalink-xml-urlbreak.py
@@ -0,0 +1,236 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+import hashlib
+
+"""
+ This is to test Metalink/XML white spaces in url resources.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+############# File Definitions ###############################################
+bad = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+File1_sha256 = hashlib.sha256 (File1.encode ('UTF-8')).hexdigest ()
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+File2_sha256 = hashlib.sha256 (File2.encode ('UTF-8')).hexdigest ()
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+File3_sha256 = hashlib.sha256 (File3.encode ('UTF-8')).hexdigest ()
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+File4_sha256 = hashlib.sha256 (File4.encode ('UTF-8')).hexdigest ()
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+File5_sha256 = hashlib.sha256 (File5.encode ('UTF-8')).hexdigest ()
+
+MetaXml = \
+"""<?xml version="1.0" encoding="utf-8"?>
+<metalink version="3.0" xmlns="http://www.metalinker.org/">
+ <publisher>
+ <name>GNU Wget</name>
+ </publisher>
+ <license>
+ <name>GNU GPL</name>
+ <url>http://www.gnu.org/licenses/gpl.html</url>
+ </license>
+ <identity>Wget Test Files</identity>
+ <version>1.2.3</version>
+ <description>Wget Test Files description</description>
+ <files>
+ <file name="File1">
+ <verification>
+ <hash type="sha256">{{FILE1_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file
+ </url>
+ <url type="http" preference="40">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/404
+ </url>
+ <url type="http" preference="25">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/File1_lowPref
+ </url>
+ <url type="http" preference="30">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/File1
+ </url>
+ </resources>
+ </file>
+ <file name="File2">
+ <verification>
+ <hash type="sha256">{{FILE2_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file
+ </url>
+ <url type="http" preference="40">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/404
+ </url>
+ <url type="http" preference="25">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/File2_lowPref
+ </url>
+ <url type="http" preference="30">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/File2
+ </url>
+ </resources>
+ </file>
+ <file name="File3">
+ <verification>
+ <hash type="sha256">{{FILE3_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file
+ </url>
+ <url type="http" preference="40">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/404
+ </url>
+ <url type="http" preference="25">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/File3_lowPref
+ </url>
+ <url type="http" preference="30">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/File3
+ </url>
+ </resources>
+ </file>
+ <file name="File4">
+ <verification>
+ <hash type="sha256">{{FILE4_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file
+ </url>
+ <url type="http" preference="40">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/404
+ </url>
+ <url type="http" preference="25">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/File4_lowPref
+ </url>
+ <url type="http" preference="30">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/File4
+ </url>
+ </resources>
+ </file>
+ <file name="File5">
+ <verification>
+ <hash type="sha256">{{FILE5_HASH}}</hash>
+ </verification>
+ <resources>
+ <url type="http" preference="35">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file
+ </url>
+ <url type="http" preference="40">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/404
+ </url>
+ <url type="http" preference="25">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/File5_lowPref
+ </url>
+ <url type="http" preference="30">
+ http://{{SRV_HOST}}:{{SRV_PORT}}/File5
+ </url>
+ </resources>
+ </file>
+ </files>
+</metalink>
+"""
+
+wrong_file = WgetFile ("wrong_file", bad)
+
+File1_orig = WgetFile ("File1", File1)
+File1_down = WgetFile ("test.metalink.#1", File1)
+File1_nono = WgetFile ("File1_lowPref", File1_lowPref)
+
+File2_orig = WgetFile ("File2", File2)
+File2_down = WgetFile ("test.metalink.#2", File2)
+File2_nono = WgetFile ("File2_lowPref", File2_lowPref)
+
+File3_orig = WgetFile ("File3", File3)
+File3_down = WgetFile ("test.metalink.#3", File3)
+File3_nono = WgetFile ("File3_lowPref", File3_lowPref)
+
+File4_orig = WgetFile ("File4", File4)
+File4_down = WgetFile ("test.metalink.#4", File4)
+File4_nono = WgetFile ("File4_lowPref", File4_lowPref)
+
+File5_orig = WgetFile ("File5", File5)
+File5_down = WgetFile ("test.metalink.#5", File5)
+File5_nono = WgetFile ("File5_lowPref", File5_lowPref)
+
+MetaFile = WgetFile ("test.metalink", MetaXml)
+
+WGET_OPTIONS = "--input-metalink test.metalink"
+WGET_URLS = [[]]
+
+Files = [[
+ wrong_file,
+ File1_orig, File1_nono,
+ File2_orig, File2_nono,
+ File3_orig, File3_nono,
+ File4_orig, File4_nono,
+ File5_orig, File5_nono
+]]
+Existing_Files = [MetaFile]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [
+ File1_down,
+ File2_down,
+ File3_down,
+ File4_down,
+ File5_down,
+ MetaFile
+]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+http_test = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+)
+
+http_test.server_setup()
+### Get and use dynamic server sockname
+srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
+
+MetaXml = MetaXml.replace('{{FILE1_HASH}}', File1_sha256)
+MetaXml = MetaXml.replace('{{FILE2_HASH}}', File2_sha256)
+MetaXml = MetaXml.replace('{{FILE3_HASH}}', File3_sha256)
+MetaXml = MetaXml.replace('{{FILE4_HASH}}', File4_sha256)
+MetaXml = MetaXml.replace('{{FILE5_HASH}}', File5_sha256)
+MetaXml = MetaXml.replace('{{SRV_HOST}}', srv_host)
+MetaXml = MetaXml.replace('{{SRV_PORT}}', str (srv_port))
+MetaFile.content = MetaXml
+
+err = http_test.begin ()
+
+exit (err)
diff --git a/testenv/Test-metalink-xml.py b/testenv/Test-metalink-xml.py
new file mode 100644
index 0000000..788d375
--- /dev/null
+++ b/testenv/Test-metalink-xml.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+
+from sys import exit
+from misc.metalinkv3_xml import Metalinkv3_XML
+
+"""
+ This is to test Metalink/XML file support in Wget.
+
+ With --trust-server-names, trust the metalink:file names.
+
+ Without --trust-server-names, don't trust the metalink:file names:
+ use the basename of --input-metalink, and add a sequential number
+ (e.g. .#1, .#2, etc.).
+
+ Strip the directory from unsafe paths.
+"""
+
+############# File Definitions ###############################################
+wrong_file = "Ouch!"
+
+File1 = "Would you like some Tea?"
+File1_lowPref = "Do not take this"
+
+File2 = "This is gonna be good"
+File2_lowPref = "Not this one too"
+
+File3 = "A little more, please"
+File3_lowPref = "That's just too much"
+
+File4 = "Maybe a biscuit?"
+File4_lowPref = "No, thanks"
+
+File5 = "More Tea...?"
+File5_lowPref = "I have to go..."
+
+############# Metalink/XML ###################################################
+Meta = Metalinkv3_XML()
+
+# file_name: metalink:file "name" field
+# save_name: metalink:file save name, if None the file is rejected
+# content : metalink:file content
+#
+# size:
+# True auto-compute size
+# None no <size></size>
+# any use this size
+#
+# hash_sha256:
+# False no <verification></verification>
+# True auto-compute sha256
+# None no <hash></hash>
+# any use this hash
+#
+# srv_file : metalink:url server file
+# srv_content: metalink:url server file content, if None the file doesn't exist
+# utype : metalink:url type (http, ftp, etc.)
+# location : metalink:url location (default 'no location field')
+# preference : metalink:url preference (default 999999)
+
+XmlName = "test.metalink"
+
+Meta.xml (
+ # Metalink/XML file name
+ XmlName,
+ # file_name, save_name, content, size, hash_sha256
+ ["File1", XmlName + ".#1", File1, None, True,
+ # srv_file, srv_content, utype, location, preference
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File1_lowPref", File1_lowPref, "http", None, 25],
+ ["File1", File1, "http", None, 30]],
+ ["File2", XmlName + ".#2", File2, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File2_lowPref", File2_lowPref, "http", None, 25],
+ ["File2", File2, "http", None, 30]],
+ ["File3", XmlName + ".#3", File3, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File3_lowPref", File3_lowPref, "http", None, 25],
+ ["File3", File3, "http", None, 30]],
+ ["File4", XmlName + ".#4", File4, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File4_lowPref", File4_lowPref, "http", None, 25],
+ ["File4", File4, "http", None, 30]],
+ ["File5", XmlName + ".#5", File5, None, True,
+ ["wrong_file", wrong_file, "http", None, 35],
+ ["404", None, "http", None, 40],
+ ["File5_lowPref", File5_lowPref, "http", None, 25],
+ ["File5", File5, "http", None, 30]],
+)
+
+Meta.print_meta ()
+
+err = Meta.http_test (
+ "--input-metalink " + XmlName, 0
+)
+
+exit (err)
diff --git a/testenv/Test-missing-scheme-retval.py b/testenv/Test-missing-scheme-retval.py
new file mode 100755
index 0000000..dca3a72
--- /dev/null
+++ b/testenv/Test-missing-scheme-retval.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from test.base_test import HTTP
+from misc.wget_file import WgetFile
+import os
+
+"""
+ This test ensures that Wget complains about missing scheme
+"""
+############# File Definitions ###############################################
+A_File = WgetFile ("bar", 'Content')
+
+# put the URL into 'options' to avoid prepending scheme/localhost/port
+WGET_OPTIONS = "/foo/bar"
+WGET_URLS = [[]]
+
+Files = [[A_File]]
+
+ExpectedReturnCode = 1
+ExpectedDownloadedFiles = []
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-no_proxy-env.py b/testenv/Test-no_proxy-env.py
new file mode 100755
index 0000000..105a85a
--- /dev/null
+++ b/testenv/Test-no_proxy-env.py
@@ -0,0 +1,161 @@
+#!/usr/bin/env python3
+import socket
+from sys import exit
+from test.http_test import HTTPTest
+from test.base_test import SKIP_TEST
+from test.base_test import HTTP
+from misc.wget_file import WgetFile
+
+"""
+ This test ensures, that domains with and without leftmost dot defined in
+ no_proxy environment variable are accepted by wget. The idea is to use
+ non-existing proxy server address and detect whether files are downloaded
+ when proxy settings are omitted based on no_proxy environment variable
+ value.
+
+ current wget's behavior:
+ - "no_proxy=.mit.edu"
+ - will match the domain and subdomains e.g. "www.mit.edu" or "www.subdomain.mit.edu" (Case #4)
+ - will NOT match the host "mit.edu" (Case #3)
+ - "no_proxy=mit.edu"
+ - will match the domain and subdomains e.g. "www.mit.edu" or "www.subdomain.mit.edu" (Case #2)
+ - will match the host "mit.edu" (Case #1)
+ - downside: cannot match only the host
+"""
+
+# Check whether the system supports translating localhost subdomains
+# to localhost address and if not, skip it.
+hostnames_to_check = [
+ "working1.localhost",
+ "working2.localhost",
+ "www.working1.localhost",
+ "www.working2.localhost",
+]
+for hostname in hostnames_to_check:
+ try:
+ ip = socket.gethostbyname(hostname)
+ except socket.gaierror as _:
+ # resolution of the name fails
+ # return value 77 -> SKIP
+ exit(SKIP_TEST)
+
+# File Definitions
+File1 = "Would you like some Tea?"
+File2 = "With lemon or cream?"
+
+A_File = WgetFile ("File1", File1)
+B_File = WgetFile ("File2", File2)
+
+WGET_URLS = [["File1", "File2"]]
+WGET_ENVS = {
+ "http_proxy": "nonexisting.localhost:8080",
+ "no_proxy": "working1.localhost,.working2.localhost"
+}
+
+Servers = [HTTP]
+Files = [[A_File, B_File]]
+
+ExpectedReturnCodeWorking = 0
+ExpectedReturnCodeNotWorking = 4 # network error (non-existing proxy address)
+
+ExpectedDownloadedFilesWorking = [A_File, B_File]
+
+# Pre and Post Test Hooks
+test_options = {
+ "Urls" : WGET_URLS,
+ "EnvironmentVariables": WGET_ENVS
+}
+post_test_working = {
+ "ExpectedFiles" : ExpectedDownloadedFilesWorking,
+ "ExpectedRetcode" : ExpectedReturnCodeWorking
+}
+post_test_not_working = {
+ "ExpectedRetcode" : ExpectedReturnCodeNotWorking
+}
+
+# Case #1:
+# - Requested domain matches exactly the domain definition in no_proxy.
+# - Domain definition in no_proxy is NOT dot-prefixed
+# Expected result: proxy settings don't apply and files are downloaded.
+pre_case_1 = {
+ "ServerFiles" : Files,
+ "Domains" : ["working1.localhost"]
+}
+
+err_case_1 = HTTPTest (
+ pre_hook=pre_case_1,
+ test_params=test_options,
+ post_hook=post_test_working,
+ protocols=Servers
+).begin ()
+
+# Case #2:
+# - Requested domain is sub-domain of a domain definition in no_proxy.
+# - Domain definition in no_proxy is NOT dot-prefixed
+# Expected result: proxy settings don't apply and files are downloaded.
+pre_case_2 = {
+ "ServerFiles" : Files,
+ "Domains" : ["www.working1.localhost"]
+}
+
+err_case_2 = HTTPTest (
+ pre_hook=pre_case_2,
+ test_params=test_options,
+ post_hook=post_test_working,
+ protocols=Servers
+).begin ()
+
+# Case #3:
+# - Requested domain matches exactly the domain definition in no_proxy,
+# except for the leftmost dot (".") in no_proxy domain definition.
+# - Domain definition in no_proxy IS dot-prefixed
+# Expected result: proxy settings apply and files are downloaded. This is
+# due to the mismatch in leftmost dot.
+# NOTE: This is inconsistent with curl's behavior, but has less drawbacks.
+pre_case_3 = {
+ "ServerFiles" : Files,
+ "Domains" : ["working2.localhost"]
+}
+
+err_case_3 = HTTPTest (
+ pre_hook=pre_case_3,
+ test_params=test_options,
+ post_hook=post_test_not_working,
+ protocols=Servers
+).begin ()
+
+# Case #4:
+# - Requested domain is sub-domain of a domain definition in no_proxy.
+# - Domain definition in no_proxy IS dot-prefixed
+# Expected result: proxy settings don't apply and files are downloaded.
+pre_case_4 = {
+ "ServerFiles" : Files,
+ "Domains" : ["www.working2.localhost"]
+}
+
+err_case_4 = HTTPTest (
+ pre_hook=pre_case_4,
+ test_params=test_options,
+ post_hook=post_test_working,
+ protocols=Servers
+).begin ()
+
+# Case #5
+# - Requested domain does not match a domain definition in no_proxy.
+# - Requested domain is NOT sub-domain of a domain definition in no_proxy.
+# Expected result: proxy settings apply and files are NOT downloaded due to
+# network error when using proxy with non-existing URL.
+pre_case_5 = {
+ "ServerFiles" : Files,
+ "Domains" : ["www.example.localhost"]
+}
+
+err_case_5 = HTTPTest (
+ pre_hook=pre_case_5,
+ test_params=test_options,
+ post_hook=post_test_not_working,
+ protocols=Servers
+).begin ()
+
+# Combine error codes from all test cases
+exit (max(err_case_1, err_case_2, err_case_3, err_case_4, err_case_5))
diff --git a/testenv/Test-pinnedpubkey-der-https.py b/testenv/Test-pinnedpubkey-der-https.py
new file mode 100755
index 0000000..1e55d68
--- /dev/null
+++ b/testenv/Test-pinnedpubkey-der-https.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from test.base_test import HTTPS, SKIP_TEST
+from misc.wget_file import WgetFile
+import os
+
+"""
+ This test ensures that Wget can download files from HTTPS Servers
+"""
+if os.getenv('SSL_TESTS') is None:
+ exit (SKIP_TEST)
+
+############# File Definitions ###############################################
+File1 = "Would you like some Tea?"
+File2 = "With lemon or cream?"
+File3 = "Sure you're joking Mr. Feynman"
+
+A_File = WgetFile ("File1", File1)
+B_File = WgetFile ("File2", File2)
+C_File = WgetFile ("File3", File3)
+
+CAFILE = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs', 'ca-cert.pem'))
+PINNEDPUBKEY = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs', 'server-pubkey.der'))
+WGET_OPTIONS = "--pinnedpubkey=" + PINNEDPUBKEY + " --ca-certificate=" + CAFILE
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+Existing_Files = [C_File]
+
+Servers = [HTTPS]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File, B_File, C_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+ protocols=Servers
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-pinnedpubkey-der-no-check-https.py b/testenv/Test-pinnedpubkey-der-no-check-https.py
new file mode 100755
index 0000000..44a7098
--- /dev/null
+++ b/testenv/Test-pinnedpubkey-der-no-check-https.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from test.base_test import HTTPS, SKIP_TEST
+from misc.wget_file import WgetFile
+import os
+
+"""
+ This test ensures that Wget can download files from HTTPS Servers
+"""
+if os.getenv('SSL_TESTS') is None:
+ exit (SKIP_TEST)
+
+############# File Definitions ###############################################
+File1 = "Would you like some Tea?"
+File2 = "With lemon or cream?"
+File3 = "Sure you're joking Mr. Feynman"
+
+A_File = WgetFile ("File1", File1)
+B_File = WgetFile ("File2", File2)
+C_File = WgetFile ("File3", File3)
+
+PINNEDPUBKEY = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs', 'server-pubkey.der'))
+WGET_OPTIONS = "--no-check-certificate --pinnedpubkey=" + PINNEDPUBKEY
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+Existing_Files = [C_File]
+
+Servers = [HTTPS]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File, B_File, C_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+ protocols=Servers
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-pinnedpubkey-hash-https.py b/testenv/Test-pinnedpubkey-hash-https.py
new file mode 100755
index 0000000..5cdc987
--- /dev/null
+++ b/testenv/Test-pinnedpubkey-hash-https.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from test.base_test import HTTPS, SKIP_TEST
+from misc.wget_file import WgetFile
+import os
+
+"""
+ This test ensures that Wget can download files from HTTPS Servers
+"""
+if os.getenv('SSL_TESTS') is None:
+ exit (SKIP_TEST)
+
+############# File Definitions ###############################################
+File1 = "Would you like some Tea?"
+File2 = "With lemon or cream?"
+File3 = "Sure you're joking Mr. Feynman"
+
+A_File = WgetFile ("File1", File1)
+B_File = WgetFile ("File2", File2)
+C_File = WgetFile ("File3", File3)
+
+CERTDIR = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs'))
+CAFILE = CERTDIR + '/ca-cert.pem'
+KEYFILE = CERTDIR + '/server-pubkey-sha256.base64'
+with open(KEYFILE, 'r') as f:
+ KEY = f.read().replace('\n', '')
+WGET_OPTIONS = "--pinnedpubkey=sha256//" + KEY + " --ca-certificate=" + CAFILE
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+Existing_Files = [C_File]
+
+Servers = [HTTPS]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File, B_File, C_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+ protocols=Servers
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-pinnedpubkey-hash-no-check-fail-https.py b/testenv/Test-pinnedpubkey-hash-no-check-fail-https.py
new file mode 100755
index 0000000..5203039
--- /dev/null
+++ b/testenv/Test-pinnedpubkey-hash-no-check-fail-https.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from test.base_test import HTTPS, SKIP_TEST
+from misc.wget_file import WgetFile
+import os
+
+"""
+ This test ensures that Wget can download files from HTTPS Servers
+"""
+if os.getenv('SSL_TESTS') is None:
+ exit (SKIP_TEST)
+
+############# File Definitions ###############################################
+File1 = "Would you like some Tea?"
+File2 = "With lemon or cream?"
+
+A_File = WgetFile ("File1", File1)
+B_File = WgetFile ("File2", File2)
+
+WGET_OPTIONS = "--no-check-certificate --pinnedpubkey=sha256//invalid"
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+
+Servers = [HTTPS]
+
+ExpectedReturnCode = 5
+ExpectedDownloadedFiles = []
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+ protocols=Servers
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-pinnedpubkey-pem-fail-https.py b/testenv/Test-pinnedpubkey-pem-fail-https.py
new file mode 100755
index 0000000..c6f7f1e
--- /dev/null
+++ b/testenv/Test-pinnedpubkey-pem-fail-https.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from test.base_test import HTTPS, SKIP_TEST
+from misc.wget_file import WgetFile
+import os
+
+"""
+ This test ensures that Wget can download files from HTTPS Servers
+"""
+if os.getenv('SSL_TESTS') is None:
+ exit (SKIP_TEST)
+
+############# File Definitions ###############################################
+File1 = "Would you like some Tea?"
+File2 = "With lemon or cream?"
+
+A_File = WgetFile ("File1", File1)
+B_File = WgetFile ("File2", File2)
+
+CAFILE = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs', 'ca-cert.pem'))
+PINNEDPUBKEY = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs', 'ca-key.pem'))
+WGET_OPTIONS = "--pinnedpubkey=" + PINNEDPUBKEY + " --ca-certificate=" + CAFILE
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+
+Servers = [HTTPS]
+
+ExpectedReturnCode = 5
+ExpectedDownloadedFiles = []
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+ protocols=Servers
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-pinnedpubkey-pem-https.py b/testenv/Test-pinnedpubkey-pem-https.py
new file mode 100755
index 0000000..dcc0c55
--- /dev/null
+++ b/testenv/Test-pinnedpubkey-pem-https.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from test.base_test import HTTPS, SKIP_TEST
+from misc.wget_file import WgetFile
+import os
+
+"""
+ This test ensures that Wget can download files from HTTPS Servers
+"""
+if os.getenv('SSL_TESTS') is None:
+ exit (SKIP_TEST)
+
+############# File Definitions ###############################################
+File1 = "Would you like some Tea?"
+File2 = "With lemon or cream?"
+File3 = "Sure you're joking Mr. Feynman"
+
+A_File = WgetFile ("File1", File1)
+B_File = WgetFile ("File2", File2)
+C_File = WgetFile ("File3", File3)
+
+CAFILE = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs', 'ca-cert.pem'))
+PINNEDPUBKEY = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs', 'server-pubkey.pem'))
+WGET_OPTIONS = "--pinnedpubkey=" + PINNEDPUBKEY + " --ca-certificate=" + CAFILE
+WGET_URLS = [["File1", "File2"]]
+
+Files = [[A_File, B_File]]
+Existing_Files = [C_File]
+
+Servers = [HTTPS]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [A_File, B_File, C_File]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+ protocols=Servers
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-recursive-basic.py b/testenv/Test-recursive-basic.py
new file mode 100755
index 0000000..6fb2f5e
--- /dev/null
+++ b/testenv/Test-recursive-basic.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from test.base_test import HTTP, HTTPS
+from misc.wget_file import WgetFile
+
+"""
+ Basic test of --recursive.
+"""
+############# File Definitions ###############################################
+File1 = """<html><body>
+<a href=\"/a/File2.html\">text</a>
+<a href=\"/b/File3.html\">text</a>
+</body></html>"""
+File2 = "With lemon or cream?"
+File3 = "Surely you're joking Mr. Feynman"
+
+File1_File = WgetFile ("a/File1.html", File1)
+File2_File = WgetFile ("a/File2.html", File2)
+File3_File = WgetFile ("b/File3.html", File3)
+
+WGET_OPTIONS = "--recursive --no-host-directories"
+WGET_URLS = [["a/File1.html"]]
+
+Servers = [HTTP]
+
+Files = [[File1_File, File2_File, File3_File]]
+Existing_Files = []
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [File1_File, File2_File, File3_File]
+Request_List = [["GET /a/File1.html",
+ "GET /robots.txt",
+ "GET /a/File2.html",
+ "GET /b/File3.html"]]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode,
+ "FilesCrawled" : Request_List
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+ protocols=Servers
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-recursive-include.py b/testenv/Test-recursive-include.py
new file mode 100755
index 0000000..1fe33cd
--- /dev/null
+++ b/testenv/Test-recursive-include.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from test.base_test import HTTP, HTTPS
+from misc.wget_file import WgetFile
+
+"""
+ Basic test of --recursive.
+"""
+############# File Definitions ###############################################
+File1 = """<html><body>
+<a href=\"/a/File2.html\">text</a>
+<a href=\"/b/File3.html\">text</a>
+</body></html>"""
+File2 = "With lemon or cream?"
+File3 = "Surely you're joking Mr. Feynman"
+
+File1_File = WgetFile ("a/File1.html", File1)
+File2_File = WgetFile ("a/File2.html", File2)
+File3_File = WgetFile ("b/File3.html", File3)
+
+WGET_OPTIONS = "--recursive --no-host-directories --include-directories=a"
+WGET_URLS = [["a/File1.html"]]
+
+Servers = [HTTP]
+
+Files = [[File1_File, File2_File, File3_File]]
+Existing_Files = []
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [File1_File, File2_File]
+Request_List = [["GET /a/File1.html",
+ "GET /a/File2.html"]]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+ protocols=Servers
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-recursive-redirect.py b/testenv/Test-recursive-redirect.py
new file mode 100644
index 0000000..8a114a5
--- /dev/null
+++ b/testenv/Test-recursive-redirect.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from test.base_test import HTTP, HTTPS
+from misc.wget_file import WgetFile
+
+"""
+ Basic test of --recursive.
+"""
+############# File Definitions ###############################################
+File1 = """<html><body>
+<a href=\"/a/File2.html\">text</a>
+<a href=\"/b/File3.html\">text</a>
+</body></html>"""
+File2 = "With lemon or cream?"
+File3 = "Surely you're joking Mr. Feynman"
+
+File1_rules = {
+ "Response" : 301,
+ "SendHeader" : {"Location" : "/b/File1.html"}
+}
+
+File1_File = WgetFile ("a/File1.html", "", rules=File1_rules)
+File1_Redirected = WgetFile ("b/File1.html", File1)
+File1_Retrieved = WgetFile ("a/File1.html", File1)
+File2_File = WgetFile ("a/File2.html", File2)
+File3_File = WgetFile ("b/File3.html", File3)
+
+WGET_OPTIONS = "--recursive --no-host-directories --include-directories=a"
+WGET_URLS = [["a/File1.html"]]
+
+Servers = [HTTP]
+
+Files = [[File1_Redirected, File1_File, File2_File, File3_File]]
+Existing_Files = []
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [File1_Retrieved, File2_File]
+Request_List = [["GET /a/File1.html",
+ "GET /a/File2.html",
+ "GET /b/File3.html"]]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+ protocols=Servers
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-redirect-crash.py b/testenv/Test-redirect-crash.py
new file mode 100755
index 0000000..1f5bb0d
--- /dev/null
+++ b/testenv/Test-redirect-crash.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+import os
+
+# This test caused wget up to 1.16 to crash
+#os.environ["LC_ALL"] = "en_US.UTF-8"
+
+urls = [
+ "File%20formats/Images/SVG,%20Scalable%20Vector%20Graphics/html,%20W3C%20v1.2%20rec%20(tiny)/directory",
+ "File formats/Images/SVG, Scalable Vector Graphics/html, W3C v1.2 rec (tiny)/directory/",
+ "File%20formats/Images/SVG,%20Scalable%20Vector%20Graphics/html,%20W3C%20v1.2%20rec%20(tiny)/directory/somefile.rng",
+ "File%20formats/Images/SVG%2C%20Scalable%20Vector%20Graphics/html%2c%20W3C%20v1.2%20rec%20%28tiny%29/directory/somefile.rng",
+ "File%20formats/Images/SVG%2C%20Scalable%20Vector%20Graphics/html%2c%20W3C%20v1.2%20rec%20%28tiny%29/directory/",
+ "File%20formats/Images/SVG%2C%20Scalable%20Vector%20Graphics/html%2C%20W3C%20v1.2%20rec%20%28tiny%29/directory"]
+
+
+redirected = [
+ "File%20formats/Images/SVG,%20Scalable%20Vector%20Graphics/html,%20W3C%20v1.2%20rec%20(tiny)/directory/"
+]
+
+############# File Definitions ###############################################
+Index = ""
+for i in urls:
+ Index = Index + "<a href='/%s'></a>" % i
+
+File1 = ""
+
+def get_redirect(url):
+ data = {
+ "File%20formats/Images/SVG,%20Scalable%20Vector%20Graphics/html,%20W3C%20v1.2%20rec%20(tiny)/directory" :
+ "File%20formats/Images/SVG,%20Scalable%20Vector%20Graphics/html,%20W3C%20v1.2%20rec%20(tiny)/directory/",
+ "File%20formats/Images/SVG%2C%20Scalable%20Vector%20Graphics/html%2C%20W3C%20v1.2%20rec%20%28tiny%29/directory" :
+ "File%20formats/Images/SVG,%20Scalable%20Vector%20Graphics/html,%20W3C%20v1.2%20rec%20(tiny)/directory/"
+ }
+ dest = data.get(url)
+ if dest:
+ return {"Response" : 301,
+ "SendHeader" : {"Location" : "/%s" % dest}}
+ return None
+
+
+index_url = "File%20formats/Images/SVG,%20Scalable%20Vector%20Graphics/html,%20W3C%20v1.2%20rec%20(tiny)/index.html"
+Index_File = WgetFile (index_url, Index)
+Files = ([Index_File] + [WgetFile(i, File1, rules=get_redirect(i)) for i in (redirected + urls)])
+
+WGET_OPTIONS = "--recursive -e robots=off"
+
+WGET_URLS = [[index_url]]
+
+ExpectedReturnCode = 0
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : [Files]
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedRetcode" : ExpectedReturnCode,
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-redirect.py b/testenv/Test-redirect.py
new file mode 100755
index 0000000..02adf52
--- /dev/null
+++ b/testenv/Test-redirect.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+from sys import exit
+from test.http_test import HTTPTest
+from test.base_test import HTTP, HTTPS
+from misc.wget_file import WgetFile
+
+"""
+ This is a Prototype Test File.
+ Ideally this File should be copied and edited to write new tests.
+"""
+############# File Definitions ###############################################
+File2 = "Would you like some Tea?"
+
+File1_rules = {
+ "Response" : 301,
+ "SendHeader" : {"Location" : "/File2.txt"}
+}
+
+# /File1.txt is only a redirect, and so has no file content.
+File1_File = WgetFile ("File1.txt", "", rules=File1_rules)
+# File1_Retrieved is what will be retrieved for URL /File1.txt.
+File1_Retrieved = WgetFile ("File1.txt", File2)
+File2_File = WgetFile ("File2.txt", File2)
+
+WGET_OPTIONS = ""
+WGET_URLS = [["File1.txt"]]
+
+Servers = [HTTP]
+
+Files = [[File1_File, File2_File]]
+Existing_Files = []
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [File1_Retrieved]
+
+################ Pre and Post Test Hooks #####################################
+pre_test = {
+ "ServerFiles" : Files,
+ "LocalFiles" : Existing_Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+ protocols=Servers
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-reserved-chars.py b/testenv/Test-reserved-chars.py
new file mode 100755
index 0000000..fb617f5
--- /dev/null
+++ b/testenv/Test-reserved-chars.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+from sys import exit
+from os import environ # to set LC_ALL
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+
+"""
+This test ensures that Wget keeps reserved characters in URLs in non-UTF-8 charsets.
+"""
+# This bug only happened with ASCII charset,
+# so we need to set LC_ALL="C" in order to reproduce it.
+environ["LC_ALL"] = "C"
+
+######### File Definitions #########
+RequestList = [
+ [
+ "HEAD /base.html",
+ "GET /base.html",
+ "GET /robots.txt",
+ "HEAD /a%2Bb.html",
+ "GET /a%2Bb.html"
+ ]
+]
+A_File_Name = "base.html"
+B_File_Name = "a%2Bb.html"
+A_File = WgetFile (A_File_Name, "<a href=\"a%2Bb.html\">")
+B_File = WgetFile (B_File_Name, "this is file B")
+
+WGET_OPTIONS = " --spider -r"
+WGET_URLS = [[A_File_Name]]
+
+Files = [[A_File, B_File]]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = []
+
+######### Pre and Post Test Hooks #########
+pre_test = {
+ "ServerFiles" : Files
+}
+test_options = {
+ "WgetCommands" : WGET_OPTIONS,
+ "Urls" : WGET_URLS
+}
+post_test = {
+ "ExpectedFiles" : ExpectedDownloadedFiles,
+ "ExpectedRetcode" : ExpectedReturnCode,
+ "FilesCrawled" : RequestList
+}
+
+err = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/certs/README b/testenv/certs/README
new file mode 100644
index 0000000..2aabd3f
--- /dev/null
+++ b/testenv/certs/README
@@ -0,0 +1,87 @@
+To create the server RSA private key:
+$ certtool --generate-privkey --outfile server-key.pem --rsa
+
+
+To create a self signed CA certificate:
+$ certtool --generate-privkey --outfile ca-key.pem
+$ certtool --generate-self-signed --load-privkey ca-key.pem --outfile ca-cert.pem
+Common name: GNU Wget
+UID:
+Organizational unit name: Wget
+Organization name: GNU
+Locality name:
+State or province name:
+Country name (2 chars):
+Enter the subject's domain component (DC):
+This field should not be used in new certificates.
+E-mail:
+Enter the certificate's serial number in decimal (default: 6080487640893163573):
+
+Activation/Expiration time.
+The certificate will expire in (days): -1
+
+Extensions.
+Does the certificate belong to an authority? (y/N): y
+Path length constraint (decimal, -1 for no constraint):
+Is this a TLS web client certificate? (y/N):
+Will the certificate be used for IPsec IKE operations? (y/N):
+Is this a TLS web server certificate? (y/N):
+Enter a dnsName of the subject of the certificate:
+Enter a URI of the subject of the certificate:
+Enter the IP address of the subject of the certificate:
+Enter the e-mail of the subject of the certificate:
+Will the certificate be used to sign OCSP requests? (y/N):
+Will the certificate be used to sign code? (y/N):
+Will the certificate be used for time stamping? (y/N):
+Will the certificate be used to sign other certificates? (y/N): y
+Will the certificate be used to sign CRLs? (y/N): y
+Enter the URI of the CRL distribution point:
+
+
+To generate a server certificate using the private key only:
+$ certtool --generate-certificate --load-privkey server-key.pem --outfile server-cert.pem --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem
+Common name: 127.0.0.1
+UID:
+Organizational unit name: Wget
+Organization name: GNU
+Locality name:
+State or province name:
+Country name (2 chars):
+Enter the subject's domain component (DC):
+This field should not be used in new certificates.
+E-mail:
+Enter the certificate's serial number in decimal (default: 6080488276853553635):
+
+Activation/Expiration time.
+The certificate will expire in (days): -1
+
+Extensions.
+Does the certificate belong to an authority? (y/N):
+Is this a TLS web client certificate? (y/N):
+Will the certificate be used for IPsec IKE operations? (y/N):
+Is this a TLS web server certificate? (y/N): y
+Enter a dnsName of the subject of the certificate: 127.0.0.1
+Enter a dnsName of the subject of the certificate: localhost
+Enter a dnsName of the subject of the certificate:
+Enter a URI of the subject of the certificate:
+Enter the IP address of the subject of the certificate:
+Will the certificate be used for signing (DHE and RSA-EXPORT ciphersuites)? (Y/n):
+Will the certificate be used for encryption (RSA ciphersuites)? (Y/n):
+
+
+To create a CRL for the server certificate:
+$ certtool --generate-crl --load-ca-privkey ca-key.pem --load-ca-certificate ca-cert.pem --load-certificate server-cert.pem --outfile server-crl.pem
+Generating a signed CRL...
+Update times.
+The certificate will expire in (days): -1
+CRL Number (default: 6080006793650397145):
+
+To generate a public key in PEM format:
+$ openssl x509 -noout -pubkey < server-cert.pem > server-pubkey.pem
+
+To generate a public key in DER format:
+$ openssl x509 -noout -pubkey < server-cert.pem | openssl asn1parse -noout -inform pem -out server-pubkey.der
+
+To generate a sha256 hash of the public key:
+$ openssl x509 -noout -pubkey < server-cert.pem | openssl asn1parse -noout -inform pem -out /dev/stdout | openssl dgst -sha256 -binary | openssl base64
+mHiEhWHvusnzP7COZk+SzSJ+Gl7nZT+ADx0PUnDD7mM=
diff --git a/testenv/certs/ca-cert.pem b/testenv/certs/ca-cert.pem
new file mode 100644
index 0000000..2c06476
--- /dev/null
+++ b/testenv/certs/ca-cert.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDJzCCAg+gAwIBAgIIWRQ9uws3g5owDQYJKoZIhvcNAQELBQAwMDERMA8GA1UE
+AxMIR05VIFdnZXQxDTALBgNVBAsTBFdnZXQxDDAKBgNVBAoTA0dOVTAgFw0xNzA1
+MTExMDMyMzdaGA85OTk5MTIzMTIzNTk1OVowMDERMA8GA1UEAxMIR05VIFdnZXQx
+DTALBgNVBAsTBFdnZXQxDDAKBgNVBAoTA0dOVTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAL9iEdf4LGibJ/noLVRWzDDG4ryvnlcz2PMBF29n5aXvWipM
+M/NuJ0kq1n0YoEJn/zg5DZStsfdZKaXz5lpApVEREAdyOHf7BxZ86gpBSpjcLVU+
+A7C+O1bpoGRemY0qk2EA9zAx91YRY9Yiq0TDP2gmV8J7Q/uu7CsOlD13xW31DkXn
+KW+3wmT2RVRWErcYHBe3Mh/gwAy1+UAhI4i2B9XrOhV63cPsqYMAZfh7i5EP+IBN
+CS0CuTwCkmHi8tCRAVD6L5DF0/q/Wj5EARf/Vg+rlD4mtBER2zCE9DMvOIQaxvXe
+buYFz5x9WcSiK/IiTmAsnVY2J3Z9tc7NiBMcC+sCAwEAAaNDMEEwDwYDVR0TAQH/
+BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBTzPk44hEqpvsFvx2Gj
+UNpuKYvrVDANBgkqhkiG9w0BAQsFAAOCAQEAAsAugT64gwFMMtwDJo5r3/f9sMPA
+lWi1N7Nz8LjBa6Vqrk/3No3Fxxidb3IMO5RGecgZdGV/CL5lG7yjzgVB2ADx+68K
+TmcNEO4CDja5vDyRpG7NPGmhtc48iiOsnEhhWCw084S2rUKf7hAX3+yKg63Uwuik
+C0xHT6HwbrWcmWFQAQOqucPWEwzGRMjqn++3cHAG8XlNSL8tWIr7NmTKr7yufLPC
+HcDAVgJsBHTOWgs/Casq4EovO83hgustD6rAWJOf89DP6bB2yOPEHKVq6cBsuGDM
+F+V2Cr2ytyGPHrOCfH3IzCpQ45cxZX4TaJ7tgV9x7WlMLoNaZgo1ijsKOw==
+-----END CERTIFICATE-----
diff --git a/testenv/certs/ca-key.pem b/testenv/certs/ca-key.pem
new file mode 100644
index 0000000..ac51f60
--- /dev/null
+++ b/testenv/certs/ca-key.pem
@@ -0,0 +1,144 @@
+Public Key Info:
+ Public Key Algorithm: RSA
+ Key Security Level: Medium (2048 bits)
+
+modulus:
+ 00:bf:62:11:d7:f8:2c:68:9b:27:f9:e8:2d:54:56:
+ cc:30:c6:e2:bc:af:9e:57:33:d8:f3:01:17:6f:67:
+ e5:a5:ef:5a:2a:4c:33:f3:6e:27:49:2a:d6:7d:18:
+ a0:42:67:ff:38:39:0d:94:ad:b1:f7:59:29:a5:f3:
+ e6:5a:40:a5:51:11:10:07:72:38:77:fb:07:16:7c:
+ ea:0a:41:4a:98:dc:2d:55:3e:03:b0:be:3b:56:e9:
+ a0:64:5e:99:8d:2a:93:61:00:f7:30:31:f7:56:11:
+ 63:d6:22:ab:44:c3:3f:68:26:57:c2:7b:43:fb:ae:
+ ec:2b:0e:94:3d:77:c5:6d:f5:0e:45:e7:29:6f:b7:
+ c2:64:f6:45:54:56:12:b7:18:1c:17:b7:32:1f:e0:
+ c0:0c:b5:f9:40:21:23:88:b6:07:d5:eb:3a:15:7a:
+ dd:c3:ec:a9:83:00:65:f8:7b:8b:91:0f:f8:80:4d:
+ 09:2d:02:b9:3c:02:92:61:e2:f2:d0:91:01:50:fa:
+ 2f:90:c5:d3:fa:bf:5a:3e:44:01:17:ff:56:0f:ab:
+ 94:3e:26:b4:11:11:db:30:84:f4:33:2f:38:84:1a:
+ c6:f5:de:6e:e6:05:cf:9c:7d:59:c4:a2:2b:f2:22:
+ 4e:60:2c:9d:56:36:27:76:7d:b5:ce:cd:88:13:1c:
+ 0b:eb:
+
+public exponent:
+ 01:00:01:
+
+private exponent:
+ 45:0c:7f:fd:98:a7:85:12:3d:a9:17:90:8b:36:49:
+ b3:6b:7e:50:af:58:04:84:4b:48:d9:62:f8:29:d7:
+ 1c:38:30:22:c4:9d:95:bd:6f:65:21:94:83:4b:c8:
+ 3e:4d:41:32:aa:ba:f0:a2:7e:6c:0c:7a:4f:4a:a1:
+ 18:7c:ec:68:44:2c:b1:53:0f:76:92:56:2b:51:e4:
+ 2a:d1:05:b6:02:f2:44:27:fc:b2:de:df:8f:ea:f8:
+ 98:5d:dd:2e:a6:66:c7:ff:ce:2f:50:47:b9:80:ca:
+ b1:6e:8e:b6:5f:6f:58:07:45:70:80:82:b5:a2:95:
+ c8:af:18:e2:d8:7c:9d:bf:c5:a9:da:4f:af:08:37:
+ 92:27:94:12:c0:94:70:90:ff:e4:05:8b:ed:18:a9:
+ 19:3c:47:3a:7c:fe:4f:9c:15:ab:f6:7e:48:2a:58:
+ d7:14:67:96:bd:e6:fa:9f:3a:51:0c:63:49:14:d5:
+ 9d:e9:a8:24:19:2a:83:e4:fe:e2:ec:db:f9:13:33:
+ a6:d3:62:d2:6b:7e:a9:5b:93:73:f5:c9:d0:ad:58:
+ 11:cb:77:d3:13:3c:bf:37:f9:64:95:c7:4c:69:f2:
+ 6e:b8:36:69:57:93:4a:03:06:58:8a:51:3d:d6:97:
+ 61:2f:7c:76:33:14:88:51:45:68:4e:29:fe:12:43:
+ 69:
+
+prime1:
+ 00:e0:e6:81:38:18:3e:c8:98:51:71:2d:5f:22:8c:
+ 93:95:37:17:47:00:4f:6a:87:98:73:8d:f3:c3:02:
+ f7:e1:9d:a0:5c:a5:10:a6:0d:88:5d:e0:72:10:93:
+ 24:af:6e:a4:0e:55:5c:03:37:5f:1d:90:41:c2:d6:
+ e3:a6:ba:20:08:0b:01:31:eb:fc:7e:97:66:3c:fe:
+ b5:ab:4c:0b:2f:18:16:f3:28:47:70:41:dc:cf:04:
+ 9c:7e:28:78:3b:3f:31:cf:b1:77:2c:6d:c9:bf:ad:
+ 19:ff:03:1f:c6:98:9a:60:47:a5:1d:c4:52:c5:9e:
+ 77:5a:cc:a4:e3:96:81:d4:4d:
+
+prime2:
+ 00:d9:d9:0c:6e:81:bb:0e:5d:c6:92:cc:48:70:b8:
+ da:60:e8:56:e7:2a:20:da:29:0f:c9:f0:9f:b8:9f:
+ df:d9:a1:68:7e:ce:3e:7c:f2:00:66:68:79:c4:01:
+ fa:b9:71:3e:73:06:3f:85:5c:83:33:ee:58:77:50:
+ 89:aa:90:33:d0:6c:aa:6f:34:b2:30:8b:e9:a9:82:
+ df:e2:7f:04:09:9f:14:9a:db:c7:cb:e5:85:46:b2:
+ 42:d0:a7:fe:7a:e3:ff:1e:84:9c:36:50:e3:de:fb:
+ 11:1c:34:09:fe:46:db:45:c3:50:19:f1:25:c0:e3:
+ 5c:d5:0d:88:13:e1:9a:5d:17:
+
+coefficient:
+ 00:ca:79:cb:79:87:91:9f:9a:99:0b:5d:c5:78:21:
+ a7:60:c6:8a:2d:a5:b5:87:a2:d6:df:b0:17:5f:bf:
+ e1:ce:f0:ca:89:18:0e:e0:4a:7f:00:e5:41:2d:04:
+ 5b:05:51:e5:08:89:dd:80:82:c7:94:94:1c:f4:0f:
+ 1b:9a:d0:72:83:bb:e9:ca:d5:09:0d:4b:c0:b7:6a:
+ a7:b4:c3:df:4e:f1:7f:0f:57:ad:25:ff:e4:d3:ef:
+ 05:95:31:ca:00:54:97:4b:2d:56:aa:1a:89:d8:a0:
+ d6:dc:64:88:88:36:26:92:39:57:8b:da:18:23:77:
+ c3:e3:39:0e:95:f7:3c:77:fe:
+
+exp1:
+ 00:99:f2:8f:4f:93:a1:1e:74:cd:82:f8:78:df:d0:
+ 74:91:b6:a5:53:6f:cd:ec:f1:26:95:2a:fd:4a:67:
+ 34:c1:16:c2:17:c8:d1:ed:a8:e3:c8:c7:03:ad:7e:
+ db:a4:ce:ca:b4:19:10:24:0f:7a:27:65:80:ee:5b:
+ 64:77:d3:7e:6b:a3:04:cd:64:69:71:4a:37:ac:d6:
+ fa:0a:68:c2:5b:19:55:54:5b:25:13:9d:b2:05:6f:
+ 75:a4:12:15:c3:10:8e:0b:4a:c2:76:02:2d:10:ec:
+ f0:17:94:ce:e2:85:c1:5e:d8:8c:19:25:33:37:9d:
+ 32:bc:4f:cb:2b:12:f2:8a:1d:
+
+exp2:
+ 3e:53:68:c9:1c:f8:a5:6d:92:e8:60:e5:c0:ca:42:
+ 40:43:78:c9:7e:36:13:f4:77:7d:f1:07:e1:4c:6c:
+ 40:d9:7b:09:fc:7b:c8:47:7c:71:d0:26:36:3b:d2:
+ bd:c7:76:74:76:2f:2a:3a:83:97:11:f3:e1:7e:fb:
+ 43:ff:29:b3:d1:c3:19:39:dc:59:23:4e:60:9e:fe:
+ ea:d0:28:19:90:97:d6:8e:56:a5:31:2f:66:40:8d:
+ f9:20:77:20:35:a6:c1:d6:72:d2:df:65:b2:5f:e6:
+ 4f:49:5c:2a:91:9f:1e:60:78:c4:53:47:d7:dd:b4:
+ ab:87:c9:8c:d6:98:d1:55:
+
+
+Public Key ID: F3:3E:4E:38:84:4A:A9:BE:C1:6F:C7:61:A3:50:DA:6E:29:8B:EB:54
+Public key's random art:
++--[ RSA 2048]----+
+| |
+| |
+| |
+| .. . |
+| Eo . S |
+| .+o..+. + |
+| .+o.= oo o |
+|.o.o* o +. |
+|+o+*.. .o. |
++-----------------+
+
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAv2IR1/gsaJsn+egtVFbMMMbivK+eVzPY8wEXb2flpe9aKkwz
+824nSSrWfRigQmf/ODkNlK2x91kppfPmWkClUREQB3I4d/sHFnzqCkFKmNwtVT4D
+sL47VumgZF6ZjSqTYQD3MDH3VhFj1iKrRMM/aCZXwntD+67sKw6UPXfFbfUORecp
+b7fCZPZFVFYStxgcF7cyH+DADLX5QCEjiLYH1es6FXrdw+ypgwBl+HuLkQ/4gE0J
+LQK5PAKSYeLy0JEBUPovkMXT+r9aPkQBF/9WD6uUPia0ERHbMIT0My84hBrG9d5u
+5gXPnH1ZxKIr8iJOYCydVjYndn21zs2IExwL6wIDAQABAoIBAEUMf/2Yp4USPakX
+kIs2SbNrflCvWASES0jZYvgp1xw4MCLEnZW9b2UhlINLyD5NQTKquvCifmwMek9K
+oRh87GhELLFTD3aSVitR5CrRBbYC8kQn/LLe34/q+Jhd3S6mZsf/zi9QR7mAyrFu
+jrZfb1gHRXCAgrWilcivGOLYfJ2/xanaT68IN5InlBLAlHCQ/+QFi+0YqRk8Rzp8
+/k+cFav2fkgqWNcUZ5a95vqfOlEMY0kU1Z3pqCQZKoPk/uLs2/kTM6bTYtJrfqlb
+k3P1ydCtWBHLd9MTPL83+WSVx0xp8m64NmlXk0oDBliKUT3Wl2EvfHYzFIhRRWhO
+Kf4SQ2kCgYEA4OaBOBg+yJhRcS1fIoyTlTcXRwBPaoeYc43zwwL34Z2gXKUQpg2I
+XeByEJMkr26kDlVcAzdfHZBBwtbjprogCAsBMev8fpdmPP61q0wLLxgW8yhHcEHc
+zwScfih4Oz8xz7F3LG3Jv60Z/wMfxpiaYEelHcRSxZ53Wsyk45aB1E0CgYEA2dkM
+boG7Dl3GksxIcLjaYOhW5yog2ikPyfCfuJ/f2aFofs4+fPIAZmh5xAH6uXE+cwY/
+hVyDM+5Yd1CJqpAz0GyqbzSyMIvpqYLf4n8ECZ8UmtvHy+WFRrJC0Kf+euP/HoSc
+NlDj3vsRHDQJ/kbbRcNQGfElwONc1Q2IE+GaXRcCgYEAmfKPT5OhHnTNgvh439B0
+kbalU2/N7PEmlSr9Smc0wRbCF8jR7ajjyMcDrX7bpM7KtBkQJA96J2WA7ltkd9N+
+a6MEzWRpcUo3rNb6CmjCWxlVVFslE52yBW91pBIVwxCOC0rCdgItEOzwF5TO4oXB
+XtiMGSUzN50yvE/LKxLyih0CgYA+U2jJHPilbZLoYOXAykJAQ3jJfjYT9Hd98Qfh
+TGxA2XsJ/HvIR3xx0CY2O9K9x3Z0di8qOoOXEfPhfvtD/ymz0cMZOdxZI05gnv7q
+0CgZkJfWjlalMS9mQI35IHcgNabB1nLS32WyX+ZPSVwqkZ8eYHjEU0fX3bSrh8mM
+1pjRVQKBgQDKect5h5GfmpkLXcV4IadgxootpbWHotbfsBdfv+HO8MqJGA7gSn8A
+5UEtBFsFUeUIid2AgseUlBz0Dxua0HKDu+nK1QkNS8C3aqe0w99O8X8PV60l/+TT
+7wWVMcoAVJdLLVaqGonYoNbcZIiINiaSOVeL2hgjd8PjOQ6V9zx3/g==
+-----END RSA PRIVATE KEY-----
diff --git a/testenv/certs/ca-template.cfg b/testenv/certs/ca-template.cfg
new file mode 100644
index 0000000..087cd70
--- /dev/null
+++ b/testenv/certs/ca-template.cfg
@@ -0,0 +1,246 @@
+# X.509 Certificate options
+#
+# DN options
+
+# The organization of the subject.
+organization = "GNU"
+
+# The organizational unit of the subject.
+unit = "Wget"
+
+# The locality of the subject.
+# locality =
+
+# The state of the certificate owner.
+# state = ""
+
+# The country of the subject. Two letter code.
+# country = GR
+
+# The common name of the certificate owner.
+cn = "GNU Wget"
+
+# A user id of the certificate owner.
+#uid = ""
+
+# Set domain components
+#dc = "name"
+#dc = "domain"
+
+# If the supported DN OIDs are not adequate you can set
+# any OID here.
+# For example set the X.520 Title and the X.520 Pseudonym
+# by using OID and string pairs.
+#dn_oid = 2.5.4.12 Dr.
+#dn_oid = 2.5.4.65 jackal
+
+# This is deprecated and should not be used in new
+# certificates.
+# pkcs9_email = "bug-wget@gnu.org"
+
+# An alternative way to set the certificate's distinguished name directly
+# is with the "dn" option. The attribute names allowed are:
+# C (country), street, O (organization), OU (unit), title, CN (common name),
+# L (locality), ST (state), placeOfBirth, gender, countryOfCitizenship,
+# countryOfResidence, serialNumber, telephoneNumber, surName, initials,
+# generationQualifier, givenName, pseudonym, dnQualifier, postalCode, name,
+# businessCategory, DC, UID, jurisdictionOfIncorporationLocalityName,
+# jurisdictionOfIncorporationStateOrProvinceName,
+# jurisdictionOfIncorporationCountryName, XmppAddr, and numeric OIDs.
+
+#dn = "cn = Nikos,st = New Something,C=GR,surName=Mavrogiannopoulos,2.5.4.9=Arkadias"
+
+# The serial number of the certificate
+# Comment the field for a time-based serial number.
+# serial = 007
+
+# In how many days, counting from today, this certificate will expire.
+# Use -1 if there is no expiration date.
+expiration_days = -1
+
+# Alternatively you may set concrete dates and time. The GNU date string
+# formats are accepted. See:
+# http://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html
+
+#activation_date = "2004-02-29 16:21:42"
+#expiration_date = "2025-02-29 16:24:41"
+
+# X.509 v3 extensions
+
+# A dnsname in case of a WWW server.
+#dns_name = "www.none.org"
+#dns_name = "www.morethanone.org"
+
+# A subject alternative name URI
+#uri = "http://www.example.com"
+
+# An IP address in case of a server.
+#ip_address = "192.168.1.1"
+
+# An email in case of a person
+# email = "none@none.org"
+
+# Challenge password used in certificate requests
+challenge_password = 123456
+
+# Password when encrypting a private key
+#password = secret
+
+# An URL that has CRLs (certificate revocation lists)
+# available. Needed in CA certificates.
+#crl_dist_points = "http://www.getcrl.crl/getcrl/"
+
+# Whether this is a CA certificate or not
+ca
+
+# Subject Unique ID (in hex)
+#subject_unique_id = 00153224
+
+# Issuer Unique ID (in hex)
+#issuer_unique_id = 00153225
+
+#### Key usage
+
+# The following key usage flags are used by CAs and end certificates
+
+# Whether this certificate will be used to sign data (needed
+# in TLS DHE ciphersuites). This is the digitalSignature flag
+# in RFC5280 terminology.
+# signing_key
+
+# Whether this certificate will be used to encrypt data (needed
+# in TLS RSA ciphersuites). Note that it is preferred to use different
+# keys for encryption and signing. This is the keyEncipherment flag
+# in RFC5280 terminology.
+# encryption_key
+
+# Whether this key will be used to sign other certificates. The
+# keyCertSign flag in RFC5280 terminology.
+cert_signing_key
+
+# Whether this key will be used to sign CRLs. The
+# cRLSign flag in RFC5280 terminology.
+crl_signing_key
+
+# The keyAgreement flag of RFC5280. It's purpose is loosely
+# defined. Not use it unless required by a protocol.
+#key_agreement
+
+# The dataEncipherment flag of RFC5280. It's purpose is loosely
+# defined. Not use it unless required by a protocol.
+#data_encipherment
+
+# The nonRepudiation flag of RFC5280. It's purpose is loosely
+# defined. Not use it unless required by a protocol.
+#non_repudiation
+
+#### Extended key usage (key purposes)
+
+# The following extensions are used in an end certificate
+# to clarify its purpose. Some CAs also use it to indicate
+# the types of certificates they are purposed to sign.
+
+# Whether this certificate will be used for a TLS client;
+# this sets the id-kp-serverAuth (1.3.6.1.5.5.7.3.1) of
+# extended key usage.
+#tls_www_client
+
+# Whether this certificate will be used for a TLS server;
+# This sets the id-kp-clientAuth (1.3.6.1.5.5.7.3.2) of
+# extended key usage.
+#tls_www_server
+
+# Whether this key will be used to sign code. This sets the
+# id-kp-codeSigning (1.3.6.1.5.5.7.3.3) of extended key usage
+# extension.
+#code_signing_key
+
+# Whether this key will be used to sign OCSP data. This sets the
+# id-kp-OCSPSigning (1.3.6.1.5.5.7.3.9) of extended key usage extension.
+#ocsp_signing_key
+
+# Whether this key will be used for time stamping. This sets the
+# id-kp-timeStamping (1.3.6.1.5.5.7.3.8) of extended key usage extension.
+#time_stamping_key
+
+# Whether this key will be used for email protection. This sets the
+# id-kp-emailProtection (1.3.6.1.5.5.7.3.4) of extended key usage extension.
+#email_protection_key
+
+# Whether this key will be used for IPsec IKE operations (1.3.6.1.5.5.7.3.17).
+#ipsec_ike_key
+
+## adding custom key purpose OIDs
+
+# for microsoft smart card logon
+# key_purpose_oid = 1.3.6.1.4.1.311.20.2.2
+
+# for email protection
+# key_purpose_oid = 1.3.6.1.5.5.7.3.4
+
+# for any purpose (must not be used in intermediate CA certificates)
+# key_purpose_oid = 2.5.29.37.0
+
+### end of key purpose OIDs
+
+# When generating a certificate from a certificate
+# request, then honor the extensions stored in the request
+# and store them in the real certificate.
+honor_crq_extensions
+
+# Path length constraint. Sets the maximum number of
+# certificates that can be used to certify this certificate.
+# (i.e. the certificate chain length)
+#path_len = -1
+#path_len = 2
+
+# OCSP URI
+# ocsp_uri = http://my.ocsp.server/ocsp
+
+# CA issuers URI
+# ca_issuers_uri = http://my.ca.issuer
+
+# Certificate policies
+#policy1 = 1.3.6.1.4.1.5484.1.10.99.1.0
+#policy1_txt = "This is a long policy to summarize"
+#policy1_url = http://www.example.com/a-policy-to-read
+
+#policy2 = 1.3.6.1.4.1.5484.1.10.99.1.1
+#policy2_txt = "This is a short policy"
+#policy2_url = http://www.example.com/another-policy-to-read
+
+# Name constraints
+
+# DNS
+#nc_permit_dns = example.com
+#nc_exclude_dns = test.example.com
+
+# EMAIL
+#nc_permit_email = "nmav@ex.net"
+
+# Exclude subdomains of example.com
+#nc_exclude_email = .example.com
+
+# Exclude all e-mail addresses of example.com
+#nc_exclude_email = example.com
+
+# Options for proxy certificates
+#proxy_policy_language = 1.3.6.1.5.5.7.21.1
+
+# Options for generating a CRL
+
+# The number of days the next CRL update will be due.
+# next CRL update will be in 43 days
+#crl_next_update = 43
+
+# this is the 5th CRL by this CA
+# Comment the field for a time-based number.
+#crl_number = 5
+
+# Specify the update dates more precisely.
+#crl_this_update_date = "2004-02-29 16:21:42"
+#crl_next_update_date = "2025-02-29 16:24:41"
+
+# The date that the certificates will be made seen as
+# being revoked.
+#crl_revocation_date = "2025-02-29 16:24:41"
diff --git a/testenv/certs/make_ca.sh b/testenv/certs/make_ca.sh
new file mode 100755
index 0000000..f9b5676
--- /dev/null
+++ b/testenv/certs/make_ca.sh
@@ -0,0 +1,23 @@
+#!/bin/sh -e
+
+# create a self signed CA certificate
+certtool --generate-privkey --outfile ca-key.pem
+certtool --generate-self-signed --load-privkey ca-key.pem --template=ca-template.cfg --outfile ca-cert.pem
+
+# create the server RSA private key
+certtool --generate-privkey --outfile server-key.pem --rsa
+
+# generate a server certificate using the private key only
+certtool --generate-certificate --load-privkey server-key.pem --template=server-template.cfg --outfile server-cert.pem --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem
+
+# create a CRL for the server certificate
+certtool --generate-crl --load-ca-privkey ca-key.pem --load-ca-certificate ca-cert.pem --load-certificate server-cert.pem --outfile server-crl.pem --template=server-template.cfg
+
+# generate a public key in PEM format
+openssl x509 -noout -pubkey < server-cert.pem > server-pubkey.pem
+
+# generate a public key in DER format
+openssl x509 -noout -pubkey < server-cert.pem | openssl asn1parse -noout -inform pem -out server-pubkey.der
+
+# generate a sha256 hash of the public key
+openssl x509 -noout -pubkey < server-cert.pem | openssl asn1parse -noout -inform pem -out /dev/stdout | openssl dgst -sha256 -binary | openssl base64 > server-pubkey-sha256.base64
diff --git a/testenv/certs/server-cert.pem b/testenv/certs/server-cert.pem
new file mode 100644
index 0000000..c9f474a
--- /dev/null
+++ b/testenv/certs/server-cert.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIMWWD1GB1UFkEICdQvMA0GCSqGSIb3DQEBCwUAMDAxETAP
+BgNVBAMTCEdOVSBXZ2V0MQ0wCwYDVQQLEwRXZ2V0MQwwCgYDVQQKEwNHTlUwIBcN
+MTcwNzA4MTUwNzA0WhgPOTk5OTEyMzEyMzU5NTlaMDExEjAQBgNVBAMTCTEyNy4w
+LjAuMTENMAsGA1UECxMEV2dldDEMMAoGA1UEChMDR05VMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAyMLca3nkR9K2XqYTfvX6kPf9ylHkwvGR1sGyzkyU
+g/ZMOGI84i0teaXyjGzgGNSbfB+fcZX2IkuZvNshYv7SRtGRDYsI8pR/4KWffPZk
+T6tfB1aVPyBV+/nU6l+SnaUsNVSot80pEZCCK+NIKYupjYup4HRJpU2+5oPcSmpn
+IgfQTlJmCOoEeBFG28aRzLSs6anlIjY0BIu6BSKhdr04taOlgPCh2x3cRGUvQMnV
+olbxMLxOqLHiLSixbNqv4tcEiKfRC9qv3+5Ec3SnWSrenReA0cqpamJNPnj5ZjHs
+96a/ipFfPXWzCInNQv4/DUO6tD2yZvMOACzPtXYUmdR4JwIDAQABo4GNMIGKMAwG
+A1UdEwEB/wQCMAAwFAYDVR0RBA0wC4IJbG9jYWxob3N0MBMGA1UdJQQMMAoGCCsG
+AQUFBwMBMA8GA1UdDwEB/wQFAwMHoAAwHQYDVR0OBBYEFJfm323LJbKTM/tMKSt0
+qlUqewbnMB8GA1UdIwQYMBaAFPM+TjiESqm+wW/HYaNQ2m4pi+tUMA0GCSqGSIb3
+DQEBCwUAA4IBAQC1a0NQfmqT8Ky/BFo5H+G+GoQTlqi3J83ujAMdLUD57zYCEyDL
+XzAhMPfrOSLPDcQb0ooD1Ie+Rz8Xs1h00cD2OGKwH479+nisF5ksqJVJ4fn/aNFE
+6W2Xb3MCB+4FRdmy0UeDDA6N2OpVskCM30s9tmovlBLVK46HogdLvy/O1o7z/gbx
+vV8luevxobnevZ3NdWLyVE3BJZiThBHmZUvL1XNy4KAR4wDAkbCwoTN/JkehTu0i
+WR6DaG7N7M6psc7rctfzRqimlAkxnoAUwc8LwNLTB3v613xXX8iSUsLKsh6pQfZR
+e5wnYQIS4MzowvDx8WevTPMRKlN72d8HHuv9
+-----END CERTIFICATE-----
diff --git a/testenv/certs/server-crl.pem b/testenv/certs/server-crl.pem
new file mode 100644
index 0000000..ca70479
--- /dev/null
+++ b/testenv/certs/server-crl.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1jCBvwIBATANBgkqhkiG9w0BAQsFADAwMREwDwYDVQQDEwhHTlUgV2dldDEN
+MAsGA1UECxMEV2dldDEMMAoGA1UEChMDR05VFw0xNzA3MDgxNTA3MDRaFw0xODA3
+MDgxNTA3MDRaMB8wHQIMWWD1GB1UFkEICdQvFw0xNzA3MDgxNTA3MDRaoDowODAf
+BgNVHSMEGDAWgBTzPk44hEqpvsFvx2GjUNpuKYvrVDAVBgNVHRQEDgIMWWD1GB4C
+YfERSnyEMA0GCSqGSIb3DQEBCwUAA4IBAQAAKu+Lum1l/XtcCJ43WveouPK97iOE
+bjUZWaGYx8Ys/iBdhTa1GXG+E+JuyqgyHTW0HrWJi1D+GiYmsjPJXoEgVgtxXEQ7
+8b3NyIQ8OCsSTTlVCmLECN9R0xlsitzH+HXOaIEs5sbmIxCnxu+brqno9gQocmCv
+LHYvoSxsSsOCkkmodbYtKssl2dBonvQPSijN/z3NhZ259e2U3Yv4V7/MrEoTvOxg
+M0GC0u0Nx86EWbq0sWeiUu270Qk9En5YGNtRhkeq0bXerJswmMAmvrtuKdyfouny
+4WMvtn30xsO3WwWSV2oyrDSN/IQdDbcmul/bg8ewqlnN77cVf2m70c/W
+-----END X509 CRL-----
diff --git a/testenv/certs/server-key.pem b/testenv/certs/server-key.pem
new file mode 100644
index 0000000..80d61cc
--- /dev/null
+++ b/testenv/certs/server-key.pem
@@ -0,0 +1,144 @@
+Public Key Info:
+ Public Key Algorithm: RSA
+ Key Security Level: Medium (2048 bits)
+
+modulus:
+ 00:c8:c2:dc:6b:79:e4:47:d2:b6:5e:a6:13:7e:f5:
+ fa:90:f7:fd:ca:51:e4:c2:f1:91:d6:c1:b2:ce:4c:
+ 94:83:f6:4c:38:62:3c:e2:2d:2d:79:a5:f2:8c:6c:
+ e0:18:d4:9b:7c:1f:9f:71:95:f6:22:4b:99:bc:db:
+ 21:62:fe:d2:46:d1:91:0d:8b:08:f2:94:7f:e0:a5:
+ 9f:7c:f6:64:4f:ab:5f:07:56:95:3f:20:55:fb:f9:
+ d4:ea:5f:92:9d:a5:2c:35:54:a8:b7:cd:29:11:90:
+ 82:2b:e3:48:29:8b:a9:8d:8b:a9:e0:74:49:a5:4d:
+ be:e6:83:dc:4a:6a:67:22:07:d0:4e:52:66:08:ea:
+ 04:78:11:46:db:c6:91:cc:b4:ac:e9:a9:e5:22:36:
+ 34:04:8b:ba:05:22:a1:76:bd:38:b5:a3:a5:80:f0:
+ a1:db:1d:dc:44:65:2f:40:c9:d5:a2:56:f1:30:bc:
+ 4e:a8:b1:e2:2d:28:b1:6c:da:af:e2:d7:04:88:a7:
+ d1:0b:da:af:df:ee:44:73:74:a7:59:2a:de:9d:17:
+ 80:d1:ca:a9:6a:62:4d:3e:78:f9:66:31:ec:f7:a6:
+ bf:8a:91:5f:3d:75:b3:08:89:cd:42:fe:3f:0d:43:
+ ba:b4:3d:b2:66:f3:0e:00:2c:cf:b5:76:14:99:d4:
+ 78:27:
+
+public exponent:
+ 01:00:01:
+
+private exponent:
+ 00:92:80:1f:f9:0d:e9:d7:bf:9b:f5:55:9b:c4:7a:
+ 1b:6e:ce:89:14:aa:ce:14:b3:d3:88:b3:b0:97:7a:
+ aa:a5:e1:85:9d:5f:92:ae:39:e9:85:6b:e3:a3:35:
+ 90:12:8e:93:27:f0:ab:99:67:a5:45:41:85:de:9a:
+ c9:b2:43:e1:8e:6c:3f:3d:72:c8:04:bc:f8:d4:26:
+ 08:4c:58:40:bb:22:83:26:07:b8:c1:68:07:56:e8:
+ e8:c6:5f:17:ce:92:49:c0:61:16:fd:89:68:fe:b8:
+ 45:45:61:85:b7:4b:83:5f:17:1b:cf:ff:0b:fe:e4:
+ cc:f9:ca:1f:66:ee:5e:74:25:94:7a:27:0e:0f:43:
+ 50:14:48:ad:c6:8a:e1:ac:ff:8e:10:ed:e6:92:48:
+ c8:94:c1:3a:2c:db:86:71:66:8e:19:93:13:ed:f9:
+ 47:06:5e:8b:e2:2e:cb:3a:c2:b3:5e:8d:31:e4:c5:
+ a7:cd:3f:09:70:e4:02:5d:34:2a:4d:b7:f5:06:e2:
+ f5:3b:8f:b6:ad:4a:22:b8:fe:43:a7:4d:67:ef:c3:
+ e1:ed:83:e2:d5:f2:d0:37:0f:56:ab:5b:47:69:0a:
+ 14:03:2c:43:a3:73:e9:05:72:5e:df:68:9c:67:4b:
+ 08:64:2d:c2:67:23:aa:e5:35:88:56:99:95:17:60:
+ 20:01:
+
+prime1:
+ 00:ea:ca:12:86:c0:25:b8:ab:fd:44:2c:1a:3f:1b:
+ 19:68:d4:26:6e:9c:ad:6d:35:12:29:9f:40:c2:4c:
+ 96:ef:8b:08:61:39:08:b7:8a:1f:81:97:71:ff:af:
+ 5a:5b:db:9a:2f:2f:29:ab:92:bb:c5:51:a2:84:c5:
+ f4:88:79:ac:a2:b8:17:1e:4a:66:62:be:e5:ab:fd:
+ 01:42:6b:16:f9:73:7b:cd:3e:f7:5c:5c:95:dd:79:
+ 73:c4:60:a8:cf:95:80:ba:7d:02:14:9c:7e:58:4f:
+ 8c:08:2c:b8:46:31:23:b2:1a:c3:38:78:5c:ea:50:
+ 9d:42:23:31:30:9a:0f:3f:27:
+
+prime2:
+ 00:da:e5:d3:66:0f:34:53:8c:e8:bf:5f:1e:46:93:
+ 47:df:30:57:be:1f:30:6a:7e:e9:f0:6b:3f:61:89:
+ 51:e2:0b:da:51:09:65:f6:23:3a:61:86:02:46:0a:
+ cf:11:73:7c:2d:65:bd:64:b8:0e:24:d2:b7:51:8f:
+ 39:b4:a2:1b:e4:9a:bc:66:31:e2:00:eb:3e:20:06:
+ 97:0a:a0:bb:82:da:bf:d5:e9:20:77:a7:55:86:69:
+ ce:eb:38:d3:f4:ad:82:9e:ce:02:05:c5:11:aa:c0:
+ b9:66:6f:e7:f4:26:57:72:fa:50:0b:ad:76:44:86:
+ e0:3e:f7:c0:3e:f3:94:9f:01:
+
+coefficient:
+ 00:94:f2:42:a9:1a:62:1c:7a:bf:34:1b:a7:87:ae:
+ bd:3a:d9:f1:8c:4e:f6:f5:27:5a:ae:f1:1e:15:06:
+ a6:d0:e4:e0:ec:3a:40:02:13:b9:31:9a:cd:3a:c6:
+ 34:7d:c6:9d:9e:60:5b:ca:03:88:87:56:f0:e1:ea:
+ 37:96:2b:53:40:b2:78:4e:80:e2:e0:24:8c:83:0e:
+ f8:77:a4:64:d5:cc:09:6c:d6:52:49:f9:55:61:16:
+ 72:b5:d2:ea:e1:61:fb:31:24:f0:30:8c:fe:5c:29:
+ 71:06:09:11:4d:ef:51:a6:33:62:54:d2:c7:de:ba:
+ 78:17:b1:27:50:f4:ef:c4:3a:
+
+exp1:
+ 1f:36:0d:90:6c:2a:97:8a:05:78:f2:83:ea:af:a7:
+ 89:0f:ea:ab:f9:97:f4:54:81:bd:96:b5:fd:1e:41:
+ 52:46:a1:2e:8b:6e:65:37:af:48:82:e1:5c:a3:ea:
+ d7:1b:32:3b:e3:81:1e:95:ba:f0:58:11:ca:a4:a6:
+ 05:1e:67:9c:99:ec:38:d2:9b:19:b5:56:c2:ae:37:
+ 64:a4:e7:c0:f1:61:1b:bf:ab:12:54:1c:77:fc:95:
+ 2f:1d:ca:53:0e:04:b6:c5:b7:69:16:04:95:a8:bd:
+ 6c:b8:c5:26:4f:91:f7:33:27:90:72:2f:a7:d6:5f:
+ 91:53:2c:4e:d1:ac:05:31:
+
+exp2:
+ 00:83:a4:55:a6:fa:1b:d8:e7:54:0d:ca:f1:55:36:
+ 3b:b1:f0:cb:c3:cd:d3:fb:27:ca:1e:c9:10:bb:e2:
+ ae:78:c7:f2:0a:6c:21:82:8e:1b:0d:0d:5f:8e:a9:
+ ef:6f:aa:49:12:b0:2d:df:45:85:54:05:d9:33:56:
+ 74:38:ba:89:15:c9:2c:e6:34:b7:9b:1f:de:23:ba:
+ 72:d9:74:62:70:46:87:b9:e8:52:9b:42:e9:ff:44:
+ e0:a8:bb:6b:54:a9:88:75:62:a4:fa:bd:52:6b:a3:
+ 2d:9c:7a:4e:3f:99:53:5c:15:47:50:4e:88:62:9b:
+ ce:7e:6f:d6:90:c5:42:2b:01:
+
+
+Public Key ID: 97:E6:DF:6D:CB:25:B2:93:33:FB:4C:29:2B:74:AA:55:2A:7B:06:E7
+Public key's random art:
++--[ RSA 2048]----+
+| |
+| |
+| |
+| . |
+| S + . |
+| .+oo. . |
+| .=+oo.+ .|
+| +E.=O.oo|
+| o+ .=*++o|
++-----------------+
+
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAyMLca3nkR9K2XqYTfvX6kPf9ylHkwvGR1sGyzkyUg/ZMOGI8
+4i0teaXyjGzgGNSbfB+fcZX2IkuZvNshYv7SRtGRDYsI8pR/4KWffPZkT6tfB1aV
+PyBV+/nU6l+SnaUsNVSot80pEZCCK+NIKYupjYup4HRJpU2+5oPcSmpnIgfQTlJm
+COoEeBFG28aRzLSs6anlIjY0BIu6BSKhdr04taOlgPCh2x3cRGUvQMnVolbxMLxO
+qLHiLSixbNqv4tcEiKfRC9qv3+5Ec3SnWSrenReA0cqpamJNPnj5ZjHs96a/ipFf
+PXWzCInNQv4/DUO6tD2yZvMOACzPtXYUmdR4JwIDAQABAoIBAQCSgB/5DenXv5v1
+VZvEehtuzokUqs4Us9OIs7CXeqql4YWdX5KuOemFa+OjNZASjpMn8KuZZ6VFQYXe
+msmyQ+GObD89csgEvPjUJghMWEC7IoMmB7jBaAdW6OjGXxfOkknAYRb9iWj+uEVF
+YYW3S4NfFxvP/wv+5Mz5yh9m7l50JZR6Jw4PQ1AUSK3GiuGs/44Q7eaSSMiUwTos
+24ZxZo4ZkxPt+UcGXoviLss6wrNejTHkxafNPwlw5AJdNCpNt/UG4vU7j7atSiK4
+/kOnTWfvw+Htg+LV8tA3D1arW0dpChQDLEOjc+kFcl7faJxnSwhkLcJnI6rlNYhW
+mZUXYCABAoGBAOrKEobAJbir/UQsGj8bGWjUJm6crW01EimfQMJMlu+LCGE5CLeK
+H4GXcf+vWlvbmi8vKauSu8VRooTF9Ih5rKK4Fx5KZmK+5av9AUJrFvlze80+91xc
+ld15c8RgqM+VgLp9AhScflhPjAgsuEYxI7Iawzh4XOpQnUIjMTCaDz8nAoGBANrl
+02YPNFOM6L9fHkaTR98wV74fMGp+6fBrP2GJUeIL2lEJZfYjOmGGAkYKzxFzfC1l
+vWS4DiTSt1GPObSiG+SavGYx4gDrPiAGlwqgu4Lav9XpIHenVYZpzus40/Stgp7O
+AgXFEarAuWZv5/QmV3L6UAutdkSG4D73wD7zlJ8BAoGAHzYNkGwql4oFePKD6q+n
+iQ/qq/mX9FSBvZa1/R5BUkahLotuZTevSILhXKPq1xsyO+OBHpW68FgRyqSmBR5n
+nJnsONKbGbVWwq43ZKTnwPFhG7+rElQcd/yVLx3KUw4EtsW3aRYElai9bLjFJk+R
+9zMnkHIvp9ZfkVMsTtGsBTECgYEAg6RVpvob2OdUDcrxVTY7sfDLw83T+yfKHskQ
+u+KueMfyCmwhgo4bDQ1fjqnvb6pJErAt30WFVAXZM1Z0OLqJFcks5jS3mx/eI7py
+2XRicEaHuehSm0Lp/0TgqLtrVKmIdWKk+r1Sa6MtnHpOP5lTXBVHUE6IYpvOfm/W
+kMVCKwECgYEAlPJCqRpiHHq/NBunh669OtnxjE729SdarvEeFQam0OTg7DpAAhO5
+MZrNOsY0fcadnmBbygOIh1bw4eo3litTQLJ4ToDi4CSMgw74d6Rk1cwJbNZSSflV
+YRZytdLq4WH7MSTwMIz+XClxBgkRTe9RpjNiVNLH3rp4F7EnUPTvxDo=
+-----END RSA PRIVATE KEY-----
diff --git a/testenv/certs/server-pubkey-sha256.base64 b/testenv/certs/server-pubkey-sha256.base64
new file mode 100644
index 0000000..6c24e4f
--- /dev/null
+++ b/testenv/certs/server-pubkey-sha256.base64
@@ -0,0 +1 @@
+mHiEhWHvusnzP7COZk+SzSJ+Gl7nZT+ADx0PUnDD7mM=
diff --git a/testenv/certs/server-pubkey.der b/testenv/certs/server-pubkey.der
new file mode 100644
index 0000000..6db082a
--- /dev/null
+++ b/testenv/certs/server-pubkey.der
Binary files differ
diff --git a/testenv/certs/server-pubkey.pem b/testenv/certs/server-pubkey.pem
new file mode 100644
index 0000000..44a3628
--- /dev/null
+++ b/testenv/certs/server-pubkey.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyMLca3nkR9K2XqYTfvX6
+kPf9ylHkwvGR1sGyzkyUg/ZMOGI84i0teaXyjGzgGNSbfB+fcZX2IkuZvNshYv7S
+RtGRDYsI8pR/4KWffPZkT6tfB1aVPyBV+/nU6l+SnaUsNVSot80pEZCCK+NIKYup
+jYup4HRJpU2+5oPcSmpnIgfQTlJmCOoEeBFG28aRzLSs6anlIjY0BIu6BSKhdr04
+taOlgPCh2x3cRGUvQMnVolbxMLxOqLHiLSixbNqv4tcEiKfRC9qv3+5Ec3SnWSre
+nReA0cqpamJNPnj5ZjHs96a/ipFfPXWzCInNQv4/DUO6tD2yZvMOACzPtXYUmdR4
+JwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/testenv/certs/server-template.cfg b/testenv/certs/server-template.cfg
new file mode 100644
index 0000000..00389aa
--- /dev/null
+++ b/testenv/certs/server-template.cfg
@@ -0,0 +1,245 @@
+# X.509 Certificate options
+#
+# DN options
+
+# The organization of the subject.
+organization = "GNU"
+
+# The organizational unit of the subject.
+unit = "Wget"
+
+# The locality of the subject.
+# locality =
+
+# The state of the certificate owner.
+# state = ""
+
+# The country of the subject. Two letter code.
+# country = GR
+
+# The common name of the certificate owner.
+cn = "127.0.0.1"
+
+# A user id of the certificate owner.
+#uid = ""
+
+# Set domain components
+#dc = "name"
+#dc = "domain"
+
+# If the supported DN OIDs are not adequate you can set
+# any OID here.
+# For example set the X.520 Title and the X.520 Pseudonym
+# by using OID and string pairs.
+#dn_oid = 2.5.4.12 Dr.
+#dn_oid = 2.5.4.65 jackal
+
+# This is deprecated and should not be used in new
+# certificates.
+# pkcs9_email = "bug-wget@gnu.org"
+
+# An alternative way to set the certificate's distinguished name directly
+# is with the "dn" option. The attribute names allowed are:
+# C (country), street, O (organization), OU (unit), title, CN (common name),
+# L (locality), ST (state), placeOfBirth, gender, countryOfCitizenship,
+# countryOfResidence, serialNumber, telephoneNumber, surName, initials,
+# generationQualifier, givenName, pseudonym, dnQualifier, postalCode, name,
+# businessCategory, DC, UID, jurisdictionOfIncorporationLocalityName,
+# jurisdictionOfIncorporationStateOrProvinceName,
+# jurisdictionOfIncorporationCountryName, XmppAddr, and numeric OIDs.
+
+#dn = "cn = Nikos,st = New Something,C=GR,surName=Mavrogiannopoulos,2.5.4.9=Arkadias"
+
+# The serial number of the certificate
+# Comment the field for a time-based serial number.
+# serial = 007
+
+# In how many days, counting from today, this certificate will expire.
+# Use -1 if there is no expiration date.
+expiration_days = -1
+
+# Alternatively you may set concrete dates and time. The GNU date string
+# formats are accepted. See:
+# http://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html
+
+#activation_date = "2004-02-29 16:21:42"
+#expiration_date = "2025-02-29 16:24:41"
+
+# X.509 v3 extensions
+
+# A dnsname in case of a WWW server.
+dns_name = "localhost"
+
+# A subject alternative name URI
+#uri = "http://www.example.com"
+
+# An IP address in case of a server.
+# ip_address = "127.0.0.1"
+
+# An email in case of a person
+# email = "none@none.org"
+
+# Challenge password used in certificate requests
+challenge_password = 123456
+
+# Password when encrypting a private key
+#password = secret
+
+# An URL that has CRLs (certificate revocation lists)
+# available. Needed in CA certificates.
+#crl_dist_points = "http://www.getcrl.crl/getcrl/"
+
+# Whether this is a CA certificate or not
+# ca
+
+# Subject Unique ID (in hex)
+#subject_unique_id = 00153224
+
+# Issuer Unique ID (in hex)
+#issuer_unique_id = 00153225
+
+#### Key usage
+
+# The following key usage flags are used by CAs and end certificates
+
+# Whether this certificate will be used to sign data (needed
+# in TLS DHE ciphersuites). This is the digitalSignature flag
+# in RFC5280 terminology.
+signing_key
+
+# Whether this certificate will be used to encrypt data (needed
+# in TLS RSA ciphersuites). Note that it is preferred to use different
+# keys for encryption and signing. This is the keyEncipherment flag
+# in RFC5280 terminology.
+encryption_key
+
+# Whether this key will be used to sign other certificates. The
+# keyCertSign flag in RFC5280 terminology.
+# cert_signing_key
+
+# Whether this key will be used to sign CRLs. The
+# cRLSign flag in RFC5280 terminology.
+# crl_signing_key
+
+# The keyAgreement flag of RFC5280. It's purpose is loosely
+# defined. Not use it unless required by a protocol.
+#key_agreement
+
+# The dataEncipherment flag of RFC5280. It's purpose is loosely
+# defined. Not use it unless required by a protocol.
+#data_encipherment
+
+# The nonRepudiation flag of RFC5280. It's purpose is loosely
+# defined. Not use it unless required by a protocol.
+#non_repudiation
+
+#### Extended key usage (key purposes)
+
+# The following extensions are used in an end certificate
+# to clarify its purpose. Some CAs also use it to indicate
+# the types of certificates they are purposed to sign.
+
+# Whether this certificate will be used for a TLS client;
+# this sets the id-kp-serverAuth (1.3.6.1.5.5.7.3.1) of
+# extended key usage.
+#tls_www_client
+
+# Whether this certificate will be used for a TLS server;
+# This sets the id-kp-clientAuth (1.3.6.1.5.5.7.3.2) of
+# extended key usage.
+tls_www_server
+
+# Whether this key will be used to sign code. This sets the
+# id-kp-codeSigning (1.3.6.1.5.5.7.3.3) of extended key usage
+# extension.
+#code_signing_key
+
+# Whether this key will be used to sign OCSP data. This sets the
+# id-kp-OCSPSigning (1.3.6.1.5.5.7.3.9) of extended key usage extension.
+#ocsp_signing_key
+
+# Whether this key will be used for time stamping. This sets the
+# id-kp-timeStamping (1.3.6.1.5.5.7.3.8) of extended key usage extension.
+#time_stamping_key
+
+# Whether this key will be used for email protection. This sets the
+# id-kp-emailProtection (1.3.6.1.5.5.7.3.4) of extended key usage extension.
+#email_protection_key
+
+# Whether this key will be used for IPsec IKE operations (1.3.6.1.5.5.7.3.17).
+#ipsec_ike_key
+
+## adding custom key purpose OIDs
+
+# for microsoft smart card logon
+# key_purpose_oid = 1.3.6.1.4.1.311.20.2.2
+
+# for email protection
+# key_purpose_oid = 1.3.6.1.5.5.7.3.4
+
+# for any purpose (must not be used in intermediate CA certificates)
+# key_purpose_oid = 2.5.29.37.0
+
+### end of key purpose OIDs
+
+# When generating a certificate from a certificate
+# request, then honor the extensions stored in the request
+# and store them in the real certificate.
+honor_crq_extensions
+
+# Path length constraint. Sets the maximum number of
+# certificates that can be used to certify this certificate.
+# (i.e. the certificate chain length)
+#path_len = -1
+#path_len = 2
+
+# OCSP URI
+# ocsp_uri = http://my.ocsp.server/ocsp
+
+# CA issuers URI
+# ca_issuers_uri = http://my.ca.issuer
+
+# Certificate policies
+#policy1 = 1.3.6.1.4.1.5484.1.10.99.1.0
+#policy1_txt = "This is a long policy to summarize"
+#policy1_url = http://www.example.com/a-policy-to-read
+
+#policy2 = 1.3.6.1.4.1.5484.1.10.99.1.1
+#policy2_txt = "This is a short policy"
+#policy2_url = http://www.example.com/another-policy-to-read
+
+# Name constraints
+
+# DNS
+#nc_permit_dns = example.com
+#nc_exclude_dns = test.example.com
+
+# EMAIL
+#nc_permit_email = "nmav@ex.net"
+
+# Exclude subdomains of example.com
+#nc_exclude_email = .example.com
+
+# Exclude all e-mail addresses of example.com
+#nc_exclude_email = example.com
+
+# Options for proxy certificates
+#proxy_policy_language = 1.3.6.1.5.5.7.21.1
+
+# Options for generating a CRL
+
+# The number of days the next CRL update will be due.
+# next CRL update will be in 43 days
+#crl_next_update = 43
+
+# this is the 5th CRL by this CA
+# Comment the field for a time-based number.
+#crl_number = 5
+
+# Specify the update dates more precisely.
+#crl_this_update_date = "2004-02-29 16:21:42"
+#crl_next_update_date = "2025-02-29 16:24:41"
+
+# The date that the certificates will be made seen as
+# being revoked.
+#crl_revocation_date = "2025-02-29 16:24:41"
diff --git a/testenv/conf/__init__.py b/testenv/conf/__init__.py
new file mode 100644
index 0000000..55433c9
--- /dev/null
+++ b/testenv/conf/__init__.py
@@ -0,0 +1,48 @@
+import os
+
+# this file implements the mechanism of conf class auto-registration,
+# don't modify this file if you have no idea what you're doing
+
+
+def gen_hook():
+ hook_table = {}
+
+ class Wrapper:
+ """
+ Decorator class which implements the conf class registration.
+ """
+ def __init__(self, alias=None):
+ self.alias = alias
+
+ def __call__(self, cls):
+ # register the class object with the name of the class
+ hook_table[cls.__name__] = cls
+ if self.alias:
+ # also register the alias of the class
+ hook_table[self.alias] = cls
+
+ return cls
+
+ def find_hook(name):
+ try:
+ return hook_table[name]
+ except:
+ raise AttributeError
+
+ return Wrapper, find_hook
+
+_register, find_conf = gen_hook()
+hook = rule = _register
+
+__all__ = ['hook', 'rule']
+
+for module in os.listdir(os.path.dirname(__file__)):
+ # import every module under this package except __init__.py,
+ # so that the decorator `register` applies
+ # (nothing happens if the script is not loaded)
+ if module != '__init__.py' and module.endswith('.py'):
+ module_name = module[:-3]
+ mod = __import__('%s.%s' % (__name__, module_name),
+ globals(),
+ locals())
+ __all__.append(module_name)
diff --git a/testenv/conf/authentication.py b/testenv/conf/authentication.py
new file mode 100644
index 0000000..ca5149c
--- /dev/null
+++ b/testenv/conf/authentication.py
@@ -0,0 +1,23 @@
+from conf import rule
+
+""" Rule: Authentication
+This file defines an authentication rule which when applied to any file will
+cause the server to prompt the client for the required authentication details
+before serving it.
+auth_type must be either of: Basic, Digest, Both or Both-inline
+When auth_type is Basic or Digest, the server asks for the respective
+authentication in its response. When auth_type is Both, the server sends two
+Authenticate headers, one requesting Basic and the other requesting Digest
+authentication. If auth_type is Both-inline, the server sends only one
+Authenticate header, but lists both Basic and Digest as supported mechanisms in
+that.
+"""
+
+
+@rule()
+class Authentication:
+ def __init__(self, auth_obj):
+ self.auth_type = auth_obj['Type']
+ self.auth_user = auth_obj['User']
+ self.auth_pass = auth_obj['Pass']
+ self.auth_parm = auth_obj.get('Parm', None)
diff --git a/testenv/conf/domains.py b/testenv/conf/domains.py
new file mode 100644
index 0000000..ac03fe1
--- /dev/null
+++ b/testenv/conf/domains.py
@@ -0,0 +1,9 @@
+from conf import hook
+
+@hook(alias='Domains')
+class Domains:
+ def __init__(self, domains):
+ self.domains = domains
+
+ def __call__(self, test_obj):
+ test_obj.domains = self.domains
diff --git a/testenv/conf/environment_variables.py b/testenv/conf/environment_variables.py
new file mode 100644
index 0000000..323c051
--- /dev/null
+++ b/testenv/conf/environment_variables.py
@@ -0,0 +1,14 @@
+from conf import hook
+
+""" Test Option: EnvironmentVariables
+This hook is used to define environment variables used for execution of wget
+command in test."""
+
+
+@hook(alias='EnvironmentVariables')
+class URLs:
+ def __init__(self, envs):
+ self.envs = envs
+
+ def __call__(self, test_obj):
+ test_obj.envs.update(**self.envs)
diff --git a/testenv/conf/expect_header.py b/testenv/conf/expect_header.py
new file mode 100644
index 0000000..055099f
--- /dev/null
+++ b/testenv/conf/expect_header.py
@@ -0,0 +1,12 @@
+from conf import rule
+
+""" Rule: ExpectHeader
+This rule defines a dictionary of headers and their value which the server
+should expect in each request for the file to which the rule was applied.
+"""
+
+
+@rule()
+class ExpectHeader:
+ def __init__(self, header_obj):
+ self.headers = header_obj
diff --git a/testenv/conf/expected_files.py b/testenv/conf/expected_files.py
new file mode 100644
index 0000000..65adb70
--- /dev/null
+++ b/testenv/conf/expected_files.py
@@ -0,0 +1,58 @@
+from difflib import unified_diff
+import os
+import sys
+from conf import hook
+from exc.test_failed import TestFailed
+
+""" Post-Test Hook: ExpectedFiles
+This is a Post-Test hook that checks the test directory for the files it
+contains. A dictionary object is passed to it, which contains a mapping of
+filenames and contents of all the files that the directory is expected to
+contain.
+Raises a TestFailed exception if the expected files are not found or if extra
+files are found, else returns gracefully.
+"""
+
+
+@hook()
+class ExpectedFiles:
+ def __init__(self, expected_fs):
+ self.expected_fs = expected_fs
+
+ @staticmethod
+ def gen_local_fs_snapshot():
+ snapshot = {}
+ for parent, dirs, files in os.walk('.'):
+ for name in files:
+ # pubring.gpg, pubring.kbx, dirmngr.conf, gpg.conf will be created by libgpgme
+ # if $HOME doesn't contain the .gnupg directory.
+ # setting $HOME to CWD (in base_test.py) breaks two Metalink tests, so we skip this file here.
+ if name in [ 'pubring.gpg', 'pubring.kbx', 'dirmngr.conf', 'gpg.conf' ]:
+ continue
+
+ f = {'content': ''}
+ file_path = os.path.join(parent, name)
+ with open(file_path) as fp:
+ f['content'] = fp.read()
+ snapshot[file_path[2:]] = f
+
+ return snapshot
+
+ def __call__(self, test_obj):
+ local_fs = self.gen_local_fs_snapshot()
+ for file in self.expected_fs:
+ if file.name in local_fs:
+ local_file = local_fs.pop(file.name)
+ formatted_content = test_obj._replace_substring(file.content)
+ if formatted_content != local_file['content']:
+ for line in unified_diff(local_file['content'],
+ formatted_content,
+ fromfile='Actual',
+ tofile='Expected'):
+ print(line, file=sys.stderr)
+ raise TestFailed('Contents of %s do not match' % file.name)
+ else:
+ raise TestFailed('Expected file %s not found.' % file.name)
+ if local_fs:
+ print(local_fs)
+ raise TestFailed('Extra files downloaded.')
diff --git a/testenv/conf/expected_ret_code.py b/testenv/conf/expected_ret_code.py
new file mode 100644
index 0000000..87cba13
--- /dev/null
+++ b/testenv/conf/expected_ret_code.py
@@ -0,0 +1,27 @@
+from exc.test_failed import TestFailed
+from conf import hook
+
+""" Post-Test Hook: ExpectedRetCode
+This is a post-test hook which checks if the exit code of the Wget instance
+under test is the same as that expected. As a result, this is a very important
+post test hook which is checked in all the tests.
+Returns a TestFailed exception if the return code does not match the expected
+value. Else returns gracefully.
+"""
+
+
+@hook(alias='ExpectedRetcode')
+class ExpectedRetCode:
+ def __init__(self, expected_ret_code):
+ self.expected_ret_code = expected_ret_code
+
+ def __call__(self, test_obj):
+ if test_obj.ret_code != self.expected_ret_code:
+ if test_obj.ret_code == 45:
+ failure = "Memory Leak Found by Valgrind"
+ else:
+ failure = "Return codes do not match.\n" \
+ "Expected: %s\n" \
+ "Actual: %s" % (self.expected_ret_code,
+ test_obj.ret_code)
+ raise TestFailed(failure)
diff --git a/testenv/conf/files_crawled.py b/testenv/conf/files_crawled.py
new file mode 100644
index 0000000..7db8392
--- /dev/null
+++ b/testenv/conf/files_crawled.py
@@ -0,0 +1,27 @@
+from misc.colour_terminal import print_red
+from conf import hook
+from exc.test_failed import TestFailed
+
+""" Post-Test Hook: FilesCrawled
+This is a post test hook that is invoked in tests that check wget's behaviour
+in recursive mode. It expects an ordered list of the request lines that Wget
+must send to the server. If the requests received by the server do not match
+the provided list, IN THE GIVEN ORDER, then it raises a TestFailed exception.
+Such a test can be used to check the implementation of the recursion algorithm
+in Wget too.
+"""
+
+
+@hook()
+class FilesCrawled:
+ def __init__(self, request_headers):
+ self.request_headers = request_headers
+
+ def __call__(self, test_obj):
+ for headers, remaining in zip(map(set, self.request_headers),
+ test_obj.request_remaining()):
+ diff = headers.symmetric_difference(remaining)
+
+ if diff:
+ print_red(str(diff))
+ raise TestFailed('Not all files were crawled correctly.')
diff --git a/testenv/conf/hook_sample.py b/testenv/conf/hook_sample.py
new file mode 100644
index 0000000..591ec3b
--- /dev/null
+++ b/testenv/conf/hook_sample.py
@@ -0,0 +1,22 @@
+from exc.test_failed import TestFailed
+from conf import hook
+
+""" Hook: SampleHook
+This a sample file for how a new hook should be defined.
+Any errors should always be reported by raising a TestFailed exception instead
+of returning a true or false value.
+"""
+
+
+@hook(alias='SampleHookAlias')
+class SampleHook:
+ def __init__(self, sample_hook_arg):
+ # do conf initialization here
+ self.arg = sample_hook_arg
+
+ def __call__(self, test_obj):
+ # implement hook here
+ # if you need the test case instance, refer to test_obj
+ if False:
+ raise TestFailed("Reason")
+ pass
diff --git a/testenv/conf/local_files.py b/testenv/conf/local_files.py
new file mode 100644
index 0000000..908ced1
--- /dev/null
+++ b/testenv/conf/local_files.py
@@ -0,0 +1,26 @@
+from os import utime
+from time import strptime
+from calendar import timegm
+from conf import hook
+
+""" Pre-Test Hook: LocalFiles
+This is a pre-test hook used to generate the specific environment before a test
+is run. The LocalFiles hook creates the files which should exist on disk before
+invoking Wget.
+"""
+
+
+@hook()
+class LocalFiles:
+ def __init__(self, local_files):
+ self.local_files = local_files
+
+ def __call__(self, _):
+ for f in self.local_files:
+ with open(f.name, 'w') as fp:
+ fp.write(f.content)
+ if f.timestamp is not None:
+ tstamp = timegm(strptime(f.timestamp, '%Y-%m-%d %H:%M:%S'))
+ atime = tstamp
+ mtime = tstamp
+ utime(f.name, (atime, mtime))
diff --git a/testenv/conf/reject_header.py b/testenv/conf/reject_header.py
new file mode 100644
index 0000000..0dcf463
--- /dev/null
+++ b/testenv/conf/reject_header.py
@@ -0,0 +1,13 @@
+from conf import rule
+
+""" Rule: RejectHeader
+This is a server side rule which expects a dictionary object of Headers and
+their values which should be blacklisted by the server for a particular file's
+requests.
+"""
+
+
+@rule()
+class RejectHeader:
+ def __init__(self, header_obj):
+ self.headers = header_obj
diff --git a/testenv/conf/response.py b/testenv/conf/response.py
new file mode 100644
index 0000000..976a9ce
--- /dev/null
+++ b/testenv/conf/response.py
@@ -0,0 +1,11 @@
+from conf import rule
+
+""" Rule: Response
+When this rule is set against a certain file, the server will unconditionally
+respond to any request for the said file with the provided response code. """
+
+
+@rule()
+class Response:
+ def __init__(self, ret_code):
+ self.response_code = ret_code
diff --git a/testenv/conf/rule_sample.py b/testenv/conf/rule_sample.py
new file mode 100644
index 0000000..6345a3c
--- /dev/null
+++ b/testenv/conf/rule_sample.py
@@ -0,0 +1,10 @@
+from conf import rule
+
+
+@rule(alias='SampleRuleAlias')
+class SampleRule:
+ def __init__(self, rule):
+ # do rule initialization here
+ # you may also need to implement a method the same name of this
+ # class in server/protocol/protocol_server.py to apply this rule.
+ self.rule = rule
diff --git a/testenv/conf/send_header.py b/testenv/conf/send_header.py
new file mode 100644
index 0000000..1ac54cc
--- /dev/null
+++ b/testenv/conf/send_header.py
@@ -0,0 +1,12 @@
+from conf import rule
+
+""" Rule: SendHeader
+Have the server send custom headers when responding to a request for the file
+this rule is applied to. The header_obj object is expected to be dictionary
+mapping headers to their contents. """
+
+
+@rule()
+class SendHeader:
+ def __init__(self, header_obj):
+ self.headers = header_obj
diff --git a/testenv/conf/server_files.py b/testenv/conf/server_files.py
new file mode 100644
index 0000000..eaa9cd0
--- /dev/null
+++ b/testenv/conf/server_files.py
@@ -0,0 +1,26 @@
+from conf import hook
+
+""" Pre-Test Hook: ServerFiles
+This hook is used to define a set of files on the server's virtual filesystem.
+server_files is expected to be dictionary that maps filenames to their
+contents. In the future, this can be used to add additional metadata to the
+files using the WgetFile class too.
+
+This hook also does some additional processing on the contents of the file. Any
+text between {{and}} is replaced by the contents of a class variable of the
+same name. This is useful in creating files that contain an absolute link to
+another file on the same server. """
+
+
+@hook()
+class ServerFiles:
+ def __init__(self, server_files):
+ self.server_files = server_files
+
+ def __call__(self, test_obj):
+ for server, files in zip(test_obj.servers, self.server_files):
+ files_content = {f.name: test_obj._replace_substring(f.content)
+ for f in files}
+ files_rules = {f.name: test_obj.get_server_rules(f)
+ for f in files}
+ server.server_conf(files_content, files_rules)
diff --git a/testenv/conf/urls.py b/testenv/conf/urls.py
new file mode 100644
index 0000000..f34c13e
--- /dev/null
+++ b/testenv/conf/urls.py
@@ -0,0 +1,14 @@
+from conf import hook
+
+""" Pre-Test Hook: URLS
+This hook is used to define the paths of the files on the test server that wget
+will send a request for. """
+
+
+@hook(alias='Urls')
+class URLs:
+ def __init__(self, urls):
+ self.urls = urls
+
+ def __call__(self, test_obj):
+ test_obj.urls = self.urls
diff --git a/testenv/conf/wget_commands.py b/testenv/conf/wget_commands.py
new file mode 100644
index 0000000..fb379be
--- /dev/null
+++ b/testenv/conf/wget_commands.py
@@ -0,0 +1,15 @@
+from conf import hook
+
+""" Pre-Test Hook: WgetCommands
+This hook is used to specify the test specific switches that must be passed to
+wget on invocation. Default switches are hard coded in the test suite itself.
+"""
+
+
+@hook()
+class WgetCommands:
+ def __init__(self, commands):
+ self.commands = commands
+
+ def __call__(self, test_obj):
+ test_obj.wget_options = test_obj._replace_substring(self.commands)
diff --git a/testenv/exc/__init__.py b/testenv/exc/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testenv/exc/__init__.py
diff --git a/testenv/exc/server_error.py b/testenv/exc/server_error.py
new file mode 100644
index 0000000..fe359f5
--- /dev/null
+++ b/testenv/exc/server_error.py
@@ -0,0 +1,19 @@
+
+class ServerError (Exception):
+ """ A custom exception which is raised by the test servers. Often used to
+ handle control flow. """
+
+ def __init__(self, err_message):
+ self.err_message = err_message
+
+class NoBodyServerError (Exception):
+ """ A custom exception which is raised by the test servers.
+ Used if no body should be sent in response. """
+
+ def __init__(self, err_message):
+ self.err_message = err_message
+
+class AuthError (ServerError):
+ """ A custom exception raised byt he servers when authentication of the
+ request fails. """
+ pass
diff --git a/testenv/exc/test_failed.py b/testenv/exc/test_failed.py
new file mode 100644
index 0000000..89f7960
--- /dev/null
+++ b/testenv/exc/test_failed.py
@@ -0,0 +1,7 @@
+
+class TestFailed(Exception):
+
+ """ A Custom Exception raised by the Test Environment. """
+
+ def __init__(self, error):
+ self.error = error
diff --git a/testenv/misc/__init__.py b/testenv/misc/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testenv/misc/__init__.py
diff --git a/testenv/misc/colour_terminal.py b/testenv/misc/colour_terminal.py
new file mode 100644
index 0000000..bc549a2
--- /dev/null
+++ b/testenv/misc/colour_terminal.py
@@ -0,0 +1,46 @@
+from functools import partial
+import platform
+from os import getenv
+import sys
+
+""" This module allows printing coloured output to the terminal when running a
+Wget Test under certain conditions.
+The output is coloured only on Linux systems. This is because coloured output
+in the terminal on Windows requires too much effort for what is simply a
+convenience. This might work on OSX terminals, but without a confirmation, it
+remains unsupported.
+
+Another important aspect is that the coloured output is printed only if the
+environment variable MAKE_CHECK is not set. This variable is set when running
+the test suite through, `make check`. In that case, the output is not only
+printed to the terminal but also copied to a log file where the ANSI escape
+codes on;y add clutter. """
+
+
+T_COLORS = {
+ 'PURPLE': '\033[95m',
+ 'BLUE': '\033[94m',
+ 'GREEN': '\033[92m',
+ 'YELLOW': '\033[93m',
+ 'RED': '\033[91m',
+ 'ENDC': '\033[0m'
+}
+
+system = True if platform.system() in ('Linux', 'Darwin') else False
+check = False if getenv("MAKE_CHECK") == 'True' else True
+
+
+def printer(color, string):
+ if sys.stdout.isatty() and system and check:
+ print(T_COLORS.get(color) + string + T_COLORS.get('ENDC'))
+ else:
+ print(string)
+
+
+print_blue = partial(printer, 'BLUE')
+print_red = partial(printer, 'RED')
+print_green = partial(printer, 'GREEN')
+print_purple = partial(printer, 'PURPLE')
+print_yellow = partial(printer, 'YELLOW')
+
+# vim: set ts=8 sw=3 tw=80 et :
diff --git a/testenv/misc/metalinkv3_xml.py b/testenv/misc/metalinkv3_xml.py
new file mode 100644
index 0000000..794bf87
--- /dev/null
+++ b/testenv/misc/metalinkv3_xml.py
@@ -0,0 +1,305 @@
+from test.http_test import HTTPTest
+from misc.wget_file import WgetFile
+import hashlib
+
+class Metalinkv3_XML:
+
+ """ Metalink/XML v3 object """
+
+ # Initialize the Metalink object
+ def __init__ (self):
+ self.reset ()
+
+ # Reset the Metalink object
+ def reset (self):
+ self.LocalFiles = [] # list of WgetFile objects
+ self.ServerFiles = [[]] # list of WgetFile objects
+ self.ExpectedFiles = [] # list of WgetFile objects
+ self.LocalFiles_Set = [] # used as `list (set (var))`
+ self.ServerFiles_Set = [[]] # used as `list (set (var))`
+ self.ExpectedFiles_Set = [] # used as `list (set (var))`
+ self.Xml = '' # Metalink/XML content
+ self.XmlName = '' # Metalink/XML file name
+ self.XmlFile = None # Metalink/XML WgetFile object
+ self.Xml_Header = '<?xml version="1.0" encoding="utf-8"?>\n' + \
+ '<metalink version="3.0" xmlns="http://www.metalinker.org/">\n' + \
+ ' <publisher>\n' + \
+ ' <name>GNU Wget</name>\n' + \
+ ' </publisher>\n' + \
+ ' <license>\n' + \
+ ' <name>GNU GPL</name>\n' + \
+ ' <url>http://www.gnu.org/licenses/gpl.html</url>\n' + \
+ ' </license>\n' + \
+ ' <identity>Wget Test Files</identity>\n' + \
+ ' <version>1.2.3</version>\n' + \
+ ' <description>Wget Test Files description</description>\n' + \
+ ' <files>\n'
+ self.Xml_Footer = ' </files>\n' + \
+ '</metalink>\n'
+
+ # Print the Metalink object.
+ def print_meta (self):
+
+ print (self.Xml)
+ print ("LocalFiles = " + str (self.LocalFiles_Set))
+ print ("ServerFiles = " + str (self.ServerFiles_Set))
+ print ("ExpectedFiles = " + str (self.ExpectedFiles_Set))
+
+ # Add LocalFiles as WgetFile objects
+ #
+ # ["file_name", "content"],
+ # ["file_name", "content"]
+ def add_LocalFiles (self, *local_files):
+
+ for (file_name, content) in local_files:
+ if not file_name in self.LocalFiles_Set:
+ self.LocalFiles_Set.append (file_name)
+ self.LocalFiles.append (WgetFile (file_name, content))
+
+ # Add ServerFiles as WgetFile objects
+ #
+ # ["file_name", "content"],
+ # ["file_name", "content"]
+ def add_ServerFiles (self, *server_files):
+
+ for (file_name, content) in server_files:
+ if not file_name in self.ServerFiles_Set[0]:
+ self.ServerFiles_Set[0].append (file_name)
+ self.ServerFiles[0].append (WgetFile (file_name, content))
+
+ # Add ExpectedFiles as WgetFile objects
+ #
+ # ["file_name", "content"],
+ # ["file_name", "content"]
+ def add_ExpectedFiles (self, *expected_files):
+
+ for (file_name, content) in expected_files:
+ if not file_name in self.ExpectedFiles_Set:
+ self.ExpectedFiles_Set.append (file_name)
+ self.ExpectedFiles.append (WgetFile (file_name, content))
+
+ # Run a Wget HTTP test for the Metalink object.
+ def http_test (self, command_line, expected_retcode):
+
+ pre_test = {
+ "ServerFiles" : self.ServerFiles, # list of WgetFile objects as [[]]
+ "LocalFiles" : self.LocalFiles, # list of WgetFile objects as []
+ }
+
+ test_options = {
+ "WgetCommands" : command_line, # Wget cli
+ "Urls" : [[]], # Wget urls
+ }
+
+ post_test = {
+ "ExpectedFiles" : self.ExpectedFiles, # list of WgetFile objects as []
+ "ExpectedRetcode" : expected_retcode, # Wget return status code
+ }
+
+ http_test = HTTPTest (
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+ )
+
+ http_test.server_setup()
+ # Get and use dynamic server sockname
+ srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
+
+ self.set_srv (srv_host, srv_port)
+
+ err = http_test.begin ()
+
+ return err
+
+ # Set the Wget server host and port in the Metalink/XML content.
+ def set_srv (self, srv_host, srv_port):
+
+ self.Xml = self.Xml.replace('{{SRV_HOST}}', srv_host)
+ self.Xml = self.Xml.replace('{{SRV_PORT}}', str (srv_port))
+
+ if self.XmlFile is not None:
+ self.XmlFile.content = self.Xml
+
+ # Create the Metalink/XML file.
+ #
+ # Add the Metalink/XML file to the list of ExpectedFiles.
+ #
+ # size:
+ # True auto-compute size
+ # None no <size></size>
+ # any use this size
+ #
+ # hash_sha256:
+ # False no <verification></verification>
+ # True auto-compute sha256
+ # None no <hash></hash>
+ # any use this hash
+ #
+ # ARGUMENTS:
+ #
+ # "xml_name", # Metalink/XML file name
+ # ["file_name", "save_name", "content", size, hash_sha256, # metalink:file
+ # ["srv_file", "srv_content", utype, location, preference], # resource
+ # ["srv_file", "srv_content", utype, location, preference]], # resource
+ # ["file_name", "save_name", "content", size, hash_sha256,
+ # ["srv_file", "srv_content", utype, location, preference],
+ # ["srv_file", "srv_content", utype, location, preference]]
+ def xml (self, xml_name, *xml_data):
+
+ self.Xml = self.Xml_Header
+
+ for (file_name, save_name, content, size, hash_sha256, *resources) in xml_data:
+ self.Xml += self.file_tag (file_name, save_name, content, size, hash_sha256, resources) + '\n'
+
+ self.Xml += self.Xml_Footer
+
+ self.XmlName = xml_name
+ self.XmlFile = WgetFile (xml_name, self.Xml)
+
+ if not xml_name in self.LocalFiles_Set:
+ self.LocalFiles_Set.append (xml_name)
+ self.LocalFiles.append (self.XmlFile)
+
+ if not xml_name in self.ExpectedFiles_Set:
+ self.ExpectedFiles_Set.append (xml_name)
+ self.ExpectedFiles.append (self.XmlFile)
+
+ # Create the file tag.
+ #
+ # Add the file to be saved to the list of ExpectedFiles.
+ #
+ # size:
+ # True auto-compute size
+ # None no <size></size>
+ # any use this size
+ #
+ # hash_sha256:
+ # False no <verification></verification>
+ # True auto-compute sha256
+ # None no <hash></hash>
+ # any use this hash
+ #
+ # ARGUMENTS:
+ #
+ # ["file_name", "save_name", "content", size, hash_sha256, # metalink:file
+ # ["srv_file", "srv_content", utype, location, preference], # resource
+ # ["srv_file", "srv_content", utype, location, preference]] # resource
+ def file_tag (self, file_name, save_name, content, size, hash_sha256, resources):
+
+ Tag = ' <file name="' + file_name + '">\n'
+
+ if save_name is not None:
+ self.add_ExpectedFiles ([save_name, content])
+
+ size_Tag = self.size_tag (content, size)
+
+ if size_Tag is not None:
+ Tag += size_Tag + '\n'
+
+ verification_Tag = self.verification_tag (content, hash_sha256)
+
+ if verification_Tag is not None:
+ Tag += verification_Tag + '\n'
+
+ Tag += self.resources_tag (resources) + '\n'
+
+ Tag += ' </file>'
+
+ return Tag
+
+ # Create the size tag.
+ #
+ # size:
+ # True auto-compute size
+ # None no <size></size>
+ # any use this size
+ #
+ # ARGUMENTS:
+ #
+ # "content", size
+ def size_tag (self, content = None, size = None):
+
+ Tag = None
+
+ if content is not None and size is True:
+ size = len (content)
+
+ if size is not None:
+ Tag = ' <size>' + str (size) + '</size>'
+
+ return Tag
+
+ # Create the verification tag.
+ #
+ # hash_sha256:
+ # False no <verification></verification>
+ # True auto-compute sha256
+ # None no <hash></hash>
+ # any use this hash
+ #
+ # ARGUMENTS:
+ #
+ # "content", hash_sha256
+ def verification_tag (self, content = None, hash_sha256 = None):
+
+ Tag = None
+
+ if hash_sha256 is not False:
+
+ if content is not None and hash_sha256 is True:
+ hash_sha256 = hashlib.sha256 (content.encode ('UTF-8')).hexdigest ()
+
+ if hash_sha256 is None:
+ Tag = ' <verification>\n' + \
+ ' </verification>'
+ else:
+ Tag = ' <verification>\n' + \
+ ' <hash type="sha256">' + str (hash_sha256) + '</hash>\n' + \
+ ' </verification>'
+
+ return Tag
+
+ # Create the resources tag.
+ #
+ # ARGUMENTS:
+ #
+ # ["srv_file", "srv_content", utype, location, preference], # resource
+ # ["srv_file", "srv_content", utype, location, preference] # resource
+ def resources_tag (self, resources):
+
+ Tag = ' <resources>\n'
+
+ for (srv_file, srv_content, utype, location, preference) in resources:
+ Tag += self.url_tag (srv_file, srv_content, utype, location, preference) + '\n'
+
+ Tag += ' </resources>'
+
+ return Tag
+
+ # Create the url tag.
+ #
+ # Add the file to the list of Files when there is a content.
+ #
+ # ARGUMENTS:
+ #
+ # "srv_file", "srv_content", utype, location, preference # resource
+ def url_tag (self, srv_file, srv_content = None, utype = "http", location = None, preference = 999999):
+
+ Loc = ''
+
+ if location is not None:
+ Loc = 'location="' + location + '" '
+
+ Tag = ' ' + \
+ '<url ' + \
+ 'type="' + utype + '" ' + \
+ Loc + \
+ 'preference="' + str (preference) + '">' + \
+ 'http://{{SRV_HOST}}:{{SRV_PORT}}/' + srv_file + \
+ '</url>'
+
+ if srv_content is not None:
+ self.add_ServerFiles ([srv_file, srv_content])
+
+ return Tag
diff --git a/testenv/misc/wget_file.py b/testenv/misc/wget_file.py
new file mode 100644
index 0000000..c2a7239
--- /dev/null
+++ b/testenv/misc/wget_file.py
@@ -0,0 +1,16 @@
+
+class WgetFile:
+
+ """ WgetFile is a File Data Container object """
+
+ def __init__(
+ self,
+ name,
+ content="Test Contents",
+ timestamp=None,
+ rules=None
+ ):
+ self.name = name
+ self.content = content
+ self.timestamp = timestamp
+ self.rules = rules or {}
diff --git a/testenv/server/__init__.py b/testenv/server/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testenv/server/__init__.py
diff --git a/testenv/server/ftp/__init__.py b/testenv/server/ftp/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testenv/server/ftp/__init__.py
diff --git a/testenv/server/ftp/ftp_server.py b/testenv/server/ftp/ftp_server.py
new file mode 100644
index 0000000..f7d7771
--- /dev/null
+++ b/testenv/server/ftp/ftp_server.py
@@ -0,0 +1,162 @@
+import os
+import re
+import threading
+import socket
+import pyftpdlib.__main__
+from pyftpdlib.ioloop import IOLoop
+import pyftpdlib.handlers as Handle
+from pyftpdlib.servers import FTPServer
+from pyftpdlib.authorizers import DummyAuthorizer
+from pyftpdlib._compat import PY3, u, b, getcwdu, callable
+
+class FTPDHandler (Handle.FTPHandler):
+
+ def ftp_LIST (self, path):
+ try:
+ iterator = self.run_as_current_user(self.fs.get_list_dir, path)
+ except (OSError, FilesystemError):
+ err = sys.exc_info()[1]
+ why = _strerror (err)
+ self.respond ('550 %s. ' % why)
+ else:
+ if self.isRule ("Bad List") is True:
+ iter_list = list ()
+ for flist in iterator:
+ line = re.compile (r'(\s+)').split (flist.decode ('utf-8'))
+ line[8] = '0'
+ iter_l = ''.join (line).encode ('utf-8')
+ iter_list.append (iter_l)
+ iterator = (n for n in iter_list)
+ producer = Handle.BufferedIteratorProducer (iterator)
+ self.push_dtp_data (producer, isproducer=True, cmd="LIST")
+ return path
+
+ def ftp_PASV (self, line):
+ if self._epsvall:
+ self.respond ("501 PASV not allowed after EPSV ALL.")
+ return
+ self._make_epasv(extmode=False)
+ if self.isRule ("FailPASV") is True:
+ del self.server.global_rules["FailPASV"]
+ self.socket.close ()
+
+ def isRule (self, rule):
+ rule_obj = self.server.global_rules[rule]
+ return False if not rule_obj else rule_obj[0]
+
+class FTPDServer (FTPServer):
+
+ def set_global_rules (self, rules):
+ self.global_rules = rules
+
+class FTPd(threading.Thread):
+ """A threaded FTP server used for running tests.
+
+ This is basically a modified version of the FTPServer class which
+ wraps the polling loop into a thread.
+
+ The instance returned can be used to start(), stop() and
+ eventually re-start() the server.
+ """
+ handler = FTPDHandler
+ server_class = FTPDServer
+
+ def __init__(self, addr=None):
+ os.mkdir ('server')
+ os.chdir ('server')
+ try:
+ HOST = socket.gethostbyname ('localhost')
+ except socket.error:
+ HOST = 'localhost'
+ USER = 'user'
+ PASSWD = '12345'
+ HOME = getcwdu ()
+
+ threading.Thread.__init__(self)
+ self.__serving = False
+ self.__stopped = False
+ self.__lock = threading.Lock()
+ self.__flag = threading.Event()
+ if addr is None:
+ addr = (HOST, 0)
+
+ authorizer = DummyAuthorizer()
+ authorizer.add_user(USER, PASSWD, HOME, perm='elradfmwM') # full perms
+ authorizer.add_anonymous(HOME)
+ self.handler.authorizer = authorizer
+ # lowering buffer sizes = more cycles to transfer data
+ # = less false positive test failures
+ self.handler.dtp_handler.ac_in_buffer_size = 32768
+ self.handler.dtp_handler.ac_out_buffer_size = 32768
+ self.server = self.server_class(addr, self.handler)
+ self.host, self.port = self.server.socket.getsockname()[:2]
+ os.chdir ('..')
+
+ def set_global_rules (self, rules):
+ self.server.set_global_rules (rules)
+
+ def __repr__(self):
+ status = [self.__class__.__module__ + "." + self.__class__.__name__]
+ if self.__serving:
+ status.append('active')
+ else:
+ status.append('inactive')
+ status.append('%s:%s' % self.server.socket.getsockname()[:2])
+ return '<%s at %#x>' % (' '.join(status), id(self))
+
+ @property
+ def running(self):
+ return self.__serving
+
+ def start(self, timeout=0.001):
+ """Start serving until an explicit stop() request.
+ Polls for shutdown every 'timeout' seconds.
+ """
+ if self.__serving:
+ raise RuntimeError("Server already started")
+ if self.__stopped:
+ # ensure the server can be started again
+ FTPd.__init__(self, self.server.socket.getsockname(), self.handler)
+ self.__timeout = timeout
+ threading.Thread.start(self)
+ self.__flag.wait()
+
+ def run(self):
+ self.__serving = True
+ self.__flag.set()
+ while self.__serving:
+ self.__lock.acquire()
+ self.server.serve_forever(timeout=self.__timeout, blocking=False)
+ self.__lock.release()
+ self.server.close_all()
+
+ def stop(self):
+ """Stop serving (also disconnecting all currently connected
+ clients) by telling the serve_forever() loop to stop and
+ waits until it does.
+ """
+ if not self.__serving:
+ raise RuntimeError("Server not started yet")
+ self.__serving = False
+ self.__stopped = True
+ self.join()
+
+
+def mk_file_sys (file_list):
+ os.chdir ('server')
+ for name, content in file_list.items ():
+ file_h = open (name, 'w')
+ file_h.write (content)
+ file_h.close ()
+ os.chdir ('..')
+
+def filesys ():
+ fileSys = dict ()
+ os.chdir ('server')
+ for parent, dirs, files in os.walk ('.'):
+ for filename in files:
+ file_handle = open (filename, 'r')
+ file_content = file_handle.read ()
+ fileSys[filename] = file_content
+ os.chdir ('..')
+ return fileSys
diff --git a/testenv/server/http/__init__.py b/testenv/server/http/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testenv/server/http/__init__.py
diff --git a/testenv/server/http/http_server.py b/testenv/server/http/http_server.py
new file mode 100644
index 0000000..2cc82fb
--- /dev/null
+++ b/testenv/server/http/http_server.py
@@ -0,0 +1,492 @@
+from http.server import HTTPServer, BaseHTTPRequestHandler
+from exc.server_error import ServerError, AuthError, NoBodyServerError
+from socketserver import BaseServer
+from posixpath import basename, splitext
+from base64 import b64encode
+from random import random
+from hashlib import md5
+import threading
+import socket
+import os
+
+
+class StoppableHTTPServer(HTTPServer):
+ """ This class extends the HTTPServer class from default http.server library
+ in Python 3. The StoppableHTTPServer class is capable of starting an HTTP
+ server that serves a virtual set of files made by the WgetFile class and
+ has most of its properties configurable through the server_conf()
+ method. """
+
+ request_headers = list()
+
+ """ Define methods for configuring the Server. """
+
+ def server_conf(self, filelist, conf_dict):
+ """ Set Server Rules and File System for this instance. """
+ self.server_configs = conf_dict
+ self.fileSys = filelist
+
+ def get_req_headers(self):
+ return self.request_headers
+
+
+class HTTPSServer(StoppableHTTPServer):
+ """ The HTTPSServer class extends the StoppableHTTPServer class with
+ additional support for secure connections through SSL. """
+
+ def __init__(self, address, handler):
+ import ssl
+ BaseServer.__init__(self, address, handler)
+ # step one up because test suite change directory away from $srcdir
+ # (don't do that !!!)
+ CERTFILE = os.path.abspath(os.path.join('..',
+ os.getenv('srcdir', '.'),
+ 'certs',
+ 'server-cert.pem'))
+ KEYFILE = os.path.abspath(os.path.join('..',
+ os.getenv('srcdir', '.'),
+ 'certs',
+ 'server-key.pem'))
+ self.socket = ssl.wrap_socket(
+ sock=socket.socket(self.address_family, self.socket_type),
+ certfile=CERTFILE,
+ keyfile=KEYFILE,
+ server_side=True
+ )
+ self.server_bind()
+ self.server_activate()
+
+
+class _Handler(BaseHTTPRequestHandler):
+ """ This is a private class which tells the server *HOW* to handle each
+ request. For each HTTP Request Command that the server should be capable of
+ responding to, there must exist a do_REQUESTNAME() method which details the
+ steps in which such requests should be processed. The rest of the methods
+ in this class are auxiliary methods created to help in processing certain
+ requests. """
+
+ def get_rule_list(self, name):
+ return self.rules.get(name)
+
+ # The default protocol version of the server we run is HTTP/1.1 not
+ # HTTP/1.0 which is the default with the http.server module.
+ protocol_version = 'HTTP/1.1'
+
+ """ Define functions for various HTTP Requests. """
+
+ def do_HEAD(self):
+ self.send_head("HEAD")
+
+ def do_GET(self):
+ """ Process HTTP GET requests. This is the same as processing HEAD
+ requests and then actually transmitting the data to the client. If
+ send_head() does not specify any "start" offset, we send the complete
+ data, else transmit only partial data. """
+
+ content, start = self.send_head("GET")
+ if content:
+ if start is None:
+ self.wfile.write(content.encode('utf-8'))
+ else:
+ self.wfile.write(content.encode('utf-8')[start:])
+
+ def do_POST(self):
+ """ According to RFC 7231 sec 4.3.3, if the resource requested in a POST
+ request does not exist on the server, the first POST request should
+ create that resource. PUT requests are otherwise used to create a
+ resource. Hence, we call the handle for processing PUT requests if the
+ resource requested does not already exist.
+
+ Currently, when the server receives a POST request for a resource, we
+ simply append the body data to the existing file and return the new
+ file to the client. If the file does not exist, a new file is created
+ using the contents of the request body. """
+
+ path = self.path[1:]
+ if path in self.server.fileSys:
+ self.rules = self.server.server_configs.get(path)
+ if not self.rules:
+ self.rules = dict()
+
+ if not self.custom_response():
+ return(None, None)
+
+ body_data = self.get_body_data()
+ self.send_response(200)
+ self.add_header("Content-type", "text/plain")
+ content = self.server.fileSys.pop(path) + "\n" + body_data
+ total_length = len(content)
+ self.server.fileSys[path] = content
+ self.add_header("Content-Length", total_length)
+ self.add_header("Location", self.path)
+ self.finish_headers()
+ try:
+ self.wfile.write(content.encode('utf-8'))
+ except Exception:
+ pass
+ else:
+ self.send_put(path)
+
+ def do_PUT(self):
+ path = self.path[1:]
+ self.rules = self.server.server_configs.get(path)
+ if not self.custom_response():
+ return(None, None)
+ self.send_put(path)
+
+ """ End of HTTP Request Method Handlers. """
+
+ """ Helper functions for the Handlers. """
+
+ def parse_range_header(self, header_line, length):
+ import re
+ if header_line is None:
+ return None
+ if not header_line.startswith("bytes="):
+ raise ServerError("Cannot parse header Range: %s" %
+ (header_line))
+ regex = re.match(r"^bytes=(\d*)\-$", header_line)
+ range_start = int(regex.group(1))
+ if range_start >= length:
+ raise ServerError("Range Overflow")
+ return range_start
+
+ def get_body_data(self):
+ cLength_header = self.headers.get("Content-Length")
+ cLength = int(cLength_header) if cLength_header is not None else 0
+ body_data = self.rfile.read(cLength).decode('utf-8')
+ return body_data
+
+ def send_put(self, path):
+ if path in self.server.fileSys:
+ self.server.fileSys.pop(path, None)
+ self.send_response(204)
+ else:
+ self.rules = dict()
+ self.send_response(201)
+ body_data = self.get_body_data()
+ self.server.fileSys[path] = body_data
+ self.add_header("Location", self.path)
+ self.finish_headers()
+
+ """ This empty method is called automatically when all the rules are
+ processed for a given request. However, send_header() should only be called
+ AFTER a response has been sent. But, at the moment of processing the rules,
+ the appropriate response has not yet been identified. As a result, we defer
+ the processing of this rule till later. Each do_* request handler MUST call
+ finish_headers() instead of end_headers(). The finish_headers() method
+ takes care of sending the appropriate headers before completing the
+ response. """
+ def SendHeader(self, header_obj):
+ pass
+
+ def send_cust_headers(self):
+ header_obj = self.get_rule_list('SendHeader')
+ if header_obj:
+ for header in header_obj.headers:
+ self.add_header(header, header_obj.headers[header])
+
+ def finish_headers(self):
+ self.send_cust_headers()
+ try:
+ for keyword, value in self._headers_dict.items():
+ if isinstance(value, list):
+ for value_el in value:
+ self.send_header(keyword, value_el)
+ else:
+ self.send_header(keyword, value)
+ # Clear the dictionary of existing headers for the next request
+ self._headers_dict.clear()
+ except AttributeError:
+ pass
+ self.end_headers()
+
+ def Response(self, resp_obj):
+ self.send_response(resp_obj.response_code)
+ if resp_obj.response_code == 304:
+ raise NoBodyServerError("Conditional get falling to head")
+ raise ServerError("Custom Response code sent.")
+
+ def custom_response(self):
+ codes = self.get_rule_list('Response')
+ if codes:
+ self.send_response(codes.response_code)
+ self.finish_headers()
+ return False
+ else:
+ return True
+
+ def add_header(self, keyword, value):
+ if not hasattr(self, "_headers_dict"):
+ self._headers_dict = dict()
+ self._headers_dict[keyword.lower()] = value
+
+ def base64(self, data):
+ string = b64encode(data.encode('utf-8'))
+ return string.decode('utf-8')
+
+ """ Send an authentication challenge.
+ This method calls self.send_header() directly instead of using the
+ add_header() method because sending multiple WWW-Authenticate headers
+ actually makes sense and we do use that feature in some tests. """
+ def send_challenge(self, auth_type, auth_parm):
+ auth_type = auth_type.lower()
+ if auth_type == "both":
+ self.send_challenge("basic", auth_parm)
+ self.send_challenge("digest", auth_parm)
+ return
+ if auth_type == "basic":
+ challenge_str = 'BasIc realm="Wget-Test"'
+ elif auth_type == "digest" or auth_type == "both_inline":
+ self.nonce = md5(str(random()).encode('utf-8')).hexdigest()
+ self.opaque = md5(str(random()).encode('utf-8')).hexdigest()
+ # 'DIgest' to provoke a Wget failure with turkish locales
+ challenge_str = 'DIgest realm="Test", nonce="%s", opaque="%s"' % (
+ self.nonce,
+ self.opaque)
+ try:
+ if auth_parm['qop']:
+ challenge_str += ', qop="%s"' % auth_parm['qop']
+ except KeyError:
+ pass
+ if auth_type == "both_inline":
+ # 'BasIc' to provoke a Wget failure with turkish locales
+ challenge_str = 'BasIc realm="Wget-Test", ' + challenge_str
+ self.send_header("WWW-Authenticate", challenge_str)
+
+ def authorize_basic(self, auth_header, auth_rule):
+ if auth_header is None or auth_header.split(' ')[0].lower() != 'basic':
+ return False
+ else:
+ self.user = auth_rule.auth_user
+ self.passw = auth_rule.auth_pass
+ auth_str = "basic " + self.base64(self.user + ":" + self.passw)
+ return True if auth_str.lower() == auth_header.lower() else False
+
+ def parse_auth_header(self, auth_header):
+ n = len("digest ")
+ auth_header = auth_header[n:].strip()
+ items = auth_header.split(", ")
+ keyvals = [i.split("=", 1) for i in items]
+ keyvals = [(k.strip(), v.strip().replace('"', '')) for k, v in keyvals]
+ return dict(keyvals)
+
+ def KD(self, secret, data):
+ return self.H(secret + ":" + data)
+
+ def H(self, data):
+ return md5(data.encode('utf-8')).hexdigest()
+
+ def A1(self):
+ return "%s:%s:%s" % (self.user, "Test", self.passw)
+
+ def A2(self, params):
+ return "%s:%s" % (self.command, params["uri"])
+
+ def check_response(self, params):
+ if "qop" in params:
+ data_str = params['nonce'] \
+ + ":" + params['nc'] \
+ + ":" + params['cnonce'] \
+ + ":" + params['qop'] \
+ + ":" + self.H(self.A2(params))
+ else:
+ data_str = params['nonce'] + ":" + self.H(self.A2(params))
+ resp = self.KD(self.H(self.A1()), data_str)
+
+ return True if resp == params['response'] else False
+
+ def authorize_digest(self, auth_header, auth_rule):
+ if auth_header is None or \
+ auth_header.split(' ')[0].lower() != 'digest':
+ return False
+ else:
+ self.user = auth_rule.auth_user
+ self.passw = auth_rule.auth_pass
+ params = self.parse_auth_header(auth_header)
+ if self.user != params['username'] or \
+ self.nonce != params['nonce'] or \
+ self.opaque != params['opaque']:
+ return False
+ req_attribs = ['username', 'realm', 'nonce', 'uri', 'response']
+ for attrib in req_attribs:
+ if attrib not in params:
+ return False
+ if not self.check_response(params):
+ return False
+
+ def authorize_both(self, auth_header, auth_rule):
+ return False
+
+ def authorize_both_inline(self, auth_header, auth_rule):
+ return False
+
+ def Authentication(self, auth_rule):
+ try:
+ self.handle_auth(auth_rule)
+ except AuthError as se:
+ self.send_response(401, "Authorization Required")
+ self.send_challenge(auth_rule.auth_type, auth_rule.auth_parm)
+ raise se
+
+ def handle_auth(self, auth_rule):
+ is_auth = True
+ auth_header = self.headers.get("Authorization")
+ required_auth = auth_rule.auth_type.lower()
+ if required_auth == "both" or required_auth == "both_inline":
+ if auth_header:
+ auth_type = auth_header.split(' ')[0].lower()
+ else:
+ auth_type = required_auth
+ else:
+ auth_type = required_auth
+ try:
+ assert hasattr(self, "authorize_" + auth_type)
+ is_auth = getattr(self, "authorize_" + auth_type)(auth_header,
+ auth_rule)
+ except AssertionError:
+ raise AuthError("Authentication Mechanism %s not supported" %
+ auth_type)
+ except AttributeError as ae:
+ raise AuthError(ae.__str__())
+ if is_auth is False:
+ raise AuthError("Unable to Authenticate")
+
+ def ExpectHeader(self, header_obj):
+ exp_headers = header_obj.headers
+ for header_line in exp_headers:
+ header_recd = self.headers.get(header_line)
+ if header_recd is None or header_recd != exp_headers[header_line]:
+ self.send_error(400, "Expected Header %s not found" %
+ header_line)
+ raise ServerError("Header " + header_line + " not found")
+
+ def RejectHeader(self, header_obj):
+ rej_headers = header_obj.headers
+ for header_line in rej_headers:
+ header_recd = self.headers.get(header_line)
+ if header_recd and header_recd == rej_headers[header_line]:
+ self.send_error(400, 'Blacklisted Header %s received' %
+ header_line)
+ raise ServerError("Header " + header_line + ' received')
+
+ def __log_request(self, method):
+ req = method + " " + self.path
+ self.server.request_headers.append(req)
+
+ def send_head(self, method):
+ """ Common code for GET and HEAD Commands.
+ This method is overridden to use the fileSys dict.
+
+ The method variable contains whether this was a HEAD or a GET Request.
+ According to RFC 2616, the server should not differentiate between
+ the two requests, however, we use it here for a specific test.
+ """
+
+ if self.path == "/":
+ path = "index.html"
+ else:
+ path = self.path[1:]
+
+ self.__log_request(method)
+
+ if path in self.server.fileSys:
+ self.rules = self.server.server_configs.get(path)
+
+ content = self.server.fileSys.get(path)
+ content_length = len(content)
+
+ for rule_name in self.rules:
+ try:
+ assert hasattr(self, rule_name)
+ getattr(self, rule_name)(self.rules[rule_name])
+ except AssertionError as ae:
+ msg = "Rule " + rule_name + " not defined"
+ self.send_error(500, msg)
+ return(None, None)
+ except AuthError as ae:
+ print(ae.__str__())
+ self.finish_headers()
+ return(None, None)
+ except NoBodyServerError as nbse:
+ print(nbse.__str__())
+ self.finish_headers()
+ return(None, None)
+ except ServerError as se:
+ print(se.__str__())
+ self.add_header("Content-Length", content_length)
+ self.finish_headers()
+ return(content, None)
+
+ try:
+ self.range_begin = self.parse_range_header(
+ self.headers.get("Range"), content_length)
+ except ServerError as ae:
+ # self.log_error("%s", ae.err_message)
+ if ae.err_message == "Range Overflow":
+ try:
+ self.overflows += 1
+ except AttributeError as s:
+ self.overflows = 0
+ self.send_response(416)
+ if self.overflows > 0:
+ self.add_header("Content-Length", 17)
+ self.finish_headers()
+ if self.overflows > 0:
+ return("Range Unsatisfied", 0)
+ return(None, None)
+ else:
+ self.range_begin = None
+ if self.range_begin is None:
+ self.send_response(200)
+ else:
+ self.send_response(206)
+ self.add_header("Accept-Ranges", "bytes")
+ self.add_header("Content-Range",
+ "bytes %d-%d/%d" % (self.range_begin,
+ content_length - 1,
+ content_length))
+ content_length -= self.range_begin
+ cont_type = self.guess_type(path)
+ self.add_header("Content-Type", cont_type)
+ self.add_header("Content-Length", content_length)
+ self.finish_headers()
+ return(content, self.range_begin)
+ else:
+ self.send_error(404, "Not Found")
+ return(None, None)
+
+ def guess_type(self, path):
+ base_name = basename("/" + path)
+ name, ext = splitext(base_name)
+ extension_map = {
+ ".txt": "text/plain",
+ ".css": "text/css",
+ ".html": "text/html"
+ }
+ return extension_map.get(ext, "text/plain")
+
+
+class HTTPd(threading.Thread):
+ server_class = StoppableHTTPServer
+ handler = _Handler
+
+ def __init__(self, addr=None):
+ threading.Thread.__init__(self)
+ if addr is None:
+ addr = ('localhost', 0)
+ self.server_inst = self.server_class(addr, self.handler)
+ self.server_address = self.server_inst.socket.getsockname()[:2]
+
+ def run(self):
+ self.server_inst.serve_forever()
+
+ def server_conf(self, file_list, server_rules):
+ self.server_inst.server_conf(file_list, server_rules)
+
+
+class HTTPSd(HTTPd):
+
+ server_class = HTTPSServer
+
+# vim: set ts=4 sts=4 sw=4 tw=79 et :
diff --git a/testenv/test/__init__.py b/testenv/test/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testenv/test/__init__.py
diff --git a/testenv/test/base_test.py b/testenv/test/base_test.py
new file mode 100644
index 0000000..7bd028d
--- /dev/null
+++ b/testenv/test/base_test.py
@@ -0,0 +1,279 @@
+import os
+import shutil
+import shlex
+import traceback
+import re
+import time
+import sys
+from subprocess import call
+from misc.colour_terminal import print_red, print_blue
+from exc.test_failed import TestFailed
+import conf
+
+HTTP = "HTTP"
+HTTPS = "HTTPS"
+
+SKIP_TEST = 77
+
+class BaseTest:
+
+ """
+ Class that defines methods common to both HTTP and FTP Tests.
+ Note that this is an abstract class, subclasses must implement
+ * stop_server()
+ * instantiate_server_by(protocol)
+ """
+
+ def __init__(self, pre_hook, test_params, post_hook, protocols, req_protocols):
+ """
+ Define the class-wide variables (or attributes).
+ Attributes should not be defined outside __init__.
+ """
+ self.name = os.path.basename(os.path.realpath(sys.argv[0]))
+ # if pre_hook == None, then {} (an empty dict object) is passed to
+ # self.pre_configs
+ self.pre_configs = pre_hook or {}
+
+ self.test_params = test_params or {}
+ self.post_configs = post_hook or {}
+ self.protocols = protocols
+
+ if req_protocols is None:
+ self.req_protocols = map(lambda p: p.lower(), self.protocols)
+ else:
+ self.req_protocols = req_protocols
+
+ self.servers = []
+ self.domains = []
+ self.ports = []
+
+ self.addr = None
+ self.port = -1
+
+ self.wget_options = ''
+ self.urls = []
+ self.envs = dict()
+
+ self.tests_passed = True
+ self.ready = False
+ self.init_test_env()
+
+ self.ret_code = 0
+
+ def get_test_dir(self):
+ return self.name + '-test'
+
+ def init_test_env(self):
+ test_dir = self.get_test_dir()
+ try:
+ os.mkdir(test_dir)
+ except FileExistsError:
+ shutil.rmtree(test_dir)
+ os.mkdir(test_dir)
+ os.chdir(test_dir)
+
+ def get_domain_addr(self, addr):
+ # TODO if there's a multiple number of ports, wouldn't it be
+ # overridden to the port of the last invocation?
+ # Set the instance variables 'addr' and 'port' so that
+ # they can be queried by test cases.
+ self.addr = str(addr[0])
+ self.port = str(addr[1])
+
+ return [self.addr, self.port]
+
+ def server_setup(self):
+ print_blue("Running Test %s" % self.name)
+ for protocol in self.protocols:
+ instance = self.instantiate_server_by(protocol)
+ self.servers.append(instance)
+
+ # servers instantiated by different protocols may differ in
+ # ports and etc.
+ # so we should record different domains respect to servers.
+ domain = self.get_domain_addr(instance.server_address)
+ self.domains.append('localhost')
+ self.ports.append(domain[1])
+
+ def exec_wget(self):
+ cmd_line = self.gen_cmd_line()
+ params = shlex.split(cmd_line)
+ print(params)
+ envs = {"HOME": os.getcwd()}
+ envs.update(**self.envs)
+ print(envs)
+
+ if os.getenv("SERVER_WAIT"):
+ time.sleep(float(os.getenv("SERVER_WAIT")))
+
+ try:
+ ret_code = call(params, env=envs)
+ except FileNotFoundError:
+ raise TestFailed("The Wget Executable does not exist at the "
+ "expected path.")
+
+ return ret_code
+
+ def gen_cmd_line(self):
+ test_path = os.path.abspath(".")
+ if os.getenv("WGET_PATH"):
+ wget_path = os.path.abspath(os.getenv("WGET_PATH"))
+ else:
+ wget_path = os.path.abspath(os.path.join(test_path,
+ "..", '..', 'src',
+ "wget"))
+ wget_options = '--debug --no-config %s' % self.wget_options
+
+ valgrind = os.getenv("VALGRIND_TESTS", "")
+ gdb = os.getenv("GDB_TESTS", "")
+
+ # GDB has precedence over Valgrind
+ # If both VALGRIND_TESTS and GDB_TESTS are defined,
+ # GDB will be executed.
+ if gdb == "1":
+ cmd_line = 'gdb --args %s %s ' % (wget_path, wget_options)
+ elif valgrind == "1":
+ cmd_line = 'valgrind --error-exitcode=301 ' \
+ '--leak-check=full ' \
+ '--track-origins=yes ' \
+ '--show-leak-kinds=all ' \
+ '--gen-suppressions=all ' \
+ '--suppressions=../valgrind-suppressions-ssl ' \
+ '%s %s ' % (wget_path, wget_options)
+ elif valgrind not in ("", "0"):
+ cmd_line = '%s %s %s ' % (os.getenv("VALGRIND_TESTS", ""),
+ wget_path,
+ wget_options)
+ else:
+ cmd_line = '%s %s ' % (wget_path, wget_options)
+
+ for req_protocol, urls, domain, port in zip(self.req_protocols,
+ self.urls,
+ self.domains,
+ self.ports):
+ # zip is function for iterating multiple lists at the same time.
+ # e.g. for item1, item2 in zip([1, 5, 3],
+ # ['a', 'e', 'c']):
+ # print(item1, item2)
+ # generates the following output:
+ # 1 a
+ # 5 e
+ # 3 c
+ for url in urls:
+ cmd_line += '%s://%s:%s/%s ' % (req_protocol, domain, port, url)
+
+
+ print(cmd_line)
+
+ return cmd_line
+
+ def __test_cleanup(self):
+ os.chdir('..')
+ try:
+ if not os.getenv("NO_CLEANUP"):
+ shutil.rmtree(self.get_test_dir())
+ except:
+ print("Unknown Exception while trying to remove Test Environment.")
+ self.tests_passed = False
+
+ def _exit_test(self):
+ self.__test_cleanup()
+
+ def begin(self):
+ return 0 if self.tests_passed else 100
+
+ def call_test(self):
+ self.hook_call(self.test_params, 'Test Option')
+
+ try:
+ self.ret_code = self.exec_wget()
+ except TestFailed as e:
+ raise e
+ finally:
+ self.stop_server()
+
+ def do_test(self):
+ self.pre_hook_call()
+ self.call_test()
+ self.post_hook_call()
+
+ def hook_call(self, configs, name):
+ for conf_name, conf_arg in configs.items():
+ try:
+ # conf.find_conf(conf_name) returns the required conf class,
+ # then the class is instantiated with conf_arg, then the
+ # conf instance is called with this test instance itself to
+ # invoke the desired hook
+ conf.find_conf(conf_name)(conf_arg)(self)
+ except AttributeError:
+ self.stop_server()
+ raise TestFailed("%s %s not defined." %
+ (name, conf_name))
+
+ def pre_hook_call(self):
+ self.hook_call(self.pre_configs, 'Pre Test Function')
+
+ def post_hook_call(self):
+ self.hook_call(self.post_configs, 'Post Test Function')
+
+ def _replace_substring(self, string):
+ """
+ Replace first occurrence of "{{name}}" in @string with
+ "getattr(self, name)".
+ """
+ pattern = re.compile(r'\{\{\w+\}\}')
+ match_obj = pattern.search(string)
+ if match_obj is not None:
+ rep = match_obj.group()
+ temp = getattr(self, rep.strip('{}'))
+ string = string.replace(rep, temp)
+ return string
+
+ def instantiate_server_by(self, protocol):
+ """
+ Subclasses must override this method to actually instantiate servers
+ for test cases.
+ """
+ raise NotImplementedError
+
+ def stop_server(self):
+ """
+ Subclasses must implement this method in order to stop certain
+ servers of different types.
+ """
+ raise NotImplementedError
+
+ @staticmethod
+ def get_server_rules(file_obj):
+ """
+ The handling of expect header could be made much better when the
+ options are parsed in a true and better fashion. For an example,
+ see the commented portion in Test-basic-auth.py.
+ """
+ server_rules = {}
+ for rule_name, rule in file_obj.rules.items():
+ server_rules[rule_name] = conf.find_conf(rule_name)(rule)
+ return server_rules
+
+ def __enter__(self):
+ """
+ Initialization for with statement.
+ """
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ """
+ If the with statement got executed with no exception raised, then
+ exc_type, exc_val, exc_tb are all None.
+ """
+ if exc_val:
+ self.tests_passed = False
+ if exc_type is TestFailed:
+ print_red('Error: %s.' % exc_val.error)
+ else:
+ print_red('Unhandled exception caught.')
+ print(exc_val)
+ traceback.print_tb(exc_tb)
+ self.__test_cleanup()
+
+ return self.tests_passed
diff --git a/testenv/test/http_test.py b/testenv/test/http_test.py
new file mode 100644
index 0000000..462ac6e
--- /dev/null
+++ b/testenv/test/http_test.py
@@ -0,0 +1,61 @@
+from misc.colour_terminal import print_green
+from server.http.http_server import HTTPd, HTTPSd
+from test.base_test import BaseTest, HTTP, HTTPS
+
+
+class HTTPTest(BaseTest):
+
+ """ Class for HTTP Tests. """
+
+ # Temp Notes: It is expected that when pre-hook functions are executed,
+ # only an empty test-dir exists. pre-hook functions are executed just prior
+ # to the call to Wget is made. post-hook functions will be executed
+ # immediately after the call to Wget returns.
+
+ def __init__(self,
+ pre_hook=None,
+ test_params=None,
+ post_hook=None,
+ protocols=(HTTP,),
+ req_protocols=None):
+ super(HTTPTest, self).__init__(pre_hook,
+ test_params,
+ post_hook,
+ protocols,
+ req_protocols)
+
+ def setup(self):
+ self.server_setup()
+ self.ready = True
+
+ def begin(self):
+ if not self.ready:
+ # this is to maintain compatibility with scripts that
+ # don't call setup()
+ self.setup()
+ with self:
+ # If any exception occurs, self.__exit__ will be immediately called.
+ # We must call the parent method in the end in order to verify
+ # whether the tests succeeded or not.
+ if self.ready:
+ self.do_test()
+ print_green("Test Passed.")
+ else:
+ self.tests_passed = False
+ return super(HTTPTest, self).begin()
+
+ def instantiate_server_by(self, protocol):
+ server = {HTTP: HTTPd,
+ HTTPS: HTTPSd}[protocol]()
+ server.start()
+
+ return server
+
+ def request_remaining(self):
+ return [s.server_inst.get_req_headers()
+ for s in self.servers]
+
+ def stop_server(self):
+ for server in self.servers:
+ server.server_inst.shutdown()
+# vim: set ts=4 sts=4 sw=4 tw=80 et :
diff --git a/testenv/valgrind-suppressions-ssl b/testenv/valgrind-suppressions-ssl
new file mode 100644
index 0000000..64af79e
--- /dev/null
+++ b/testenv/valgrind-suppressions-ssl
@@ -0,0 +1,49 @@
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Cond
+ ...
+ obj:*/libcrypto.so.*
+}
+
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Cond
+ ...
+ obj:*/libssl.so.*
+}
+
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Value8
+ ...
+ obj:*/libcrypto.so.*
+}
+
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Param
+ write(buf)
+ ...
+ obj:*/libcrypto.so.*
+}
+
+{
+ gnutls-false-positive
+ Memcheck:Cond
+ fun:decode_complex_string.isra.0
+ fun:_gnutls_x509_dn_to_string
+ ...
+}
+
+{
+ gnutls-false-positive
+ Memcheck:Cond
+ ...
+ fun:gnutls_x509_ext_import_subject_alt_names
+ fun:gnutls_x509_crt_import
+ fun:gnutls_x509_crt_list_import
+ fun:gnutls_x509_crt_list_import2
+ fun:gnutls_x509_trust_list_add_trust_mem
+ fun:gnutls_x509_trust_list_add_trust_file
+ fun:gnutls_x509_trust_list_add_system_trust
+}